imrishabh18/nema-23-stepper-controller

A 57 mm four-layer RP2040 NEMA23 stepper-controller PCB with USB‑C/USB‑PD power input, protected motor rail, DRV8452 dual-winding driver, bidirectional current sensing, temperature/enable interlock, optional magnetic encoder, RGB LED and buzzer status indicators, and motor/test connectors.

Version
1.2.3
License
unset
Stars
0

scripts/copper_geometry.py

"""Trace segments matching the pinned circuit-json-to-gerber export semantics."""
from shapely.strtree import STRtree
from shapely.ops import unary_union


def subtract_drills(shapes, metadata, barrels, drills, layer_of):
    """Remove drilled-away copper and keep separated physical pieces separate."""
    drill_shapes = [g for g, _ in drills]
    tree = STRtree(drill_shapes)
    new_shapes, new_metadata, mapping = [], [], {}
    for i, (shape, meta) in enumerate(zip(shapes, metadata)):
        nearby = [drill_shapes[k] for k in tree.query(shape) if layer_of(meta) in drills[k][1]]
        cut = shape.difference(unary_union(nearby)) if nearby else shape
        pieces = []
        def collect(g):
            if g.is_empty:
                return
            if g.geom_type in ('MultiPolygon', 'GeometryCollection'):
                for piece in g.geoms:
                    collect(piece)
            elif g.area > 1e-12:
                pieces.append(g)
        collect(cut)
        mapping[i] = list(range(len(new_shapes), len(new_shapes) + len(pieces)))
        new_shapes.extend(pieces)
        new_metadata.extend([meta] * len(pieces))
    return new_shapes, new_metadata, [[n for i in ids for n in mapping[i]] for ids in barrels]

def trace_segments(route):
    for a, b in zip(route, route[1:]):
        start = end = layer = width = None
        if a['route_type'] == 'wire':
            start, layer, width = a, a['layer'], a['width']
            if b['route_type'] in ('wire', 'via'):
                end = b
            elif b['route_type'] == 'through_pad':
                end = b['start'] if b['start_layer'] == layer else b['end'] if b['end_layer'] == layer else None
        elif b['route_type'] == 'wire':
            end, layer, width = b, b['layer'], b['width']
            if a['route_type'] == 'via':
                start = a
            elif a['route_type'] == 'through_pad':
                start = a['end'] if a['end_layer'] == layer else a['start'] if a['start_layer'] == layer else None
        if start is None or end is None or (start['x'] == end['x'] and start['y'] == end['y']):
            continue
        yield (start['x'], start['y']), (end['x'], end['y']), layer, width