def poly_points(track_start, track_end, track_width, clearance):
    """
    """
    delta = track_width / 2 + clearance
    dx = track_end.x - track_start.x
    dy = track_end.y - track_start.y
    theta = np.arctan2(dy, dx)
    len = np.sqrt(np.power(dx, 2) + np.power(dy, 2))
    dx_norm = dx / len
    dy_norm = dy / len

    delta_x = delta * -dy_norm
    delta_y = delta * dx_norm
    pt_delta = pcbnew.wxPoint(delta_x, delta_y)

    pts = []
    pts.append(track_start + pt_delta)
    for pt in semicircle_points(track_start, delta, theta, True):
        pts.append(pt)
    pts.append(track_start - pt_delta)
    pts.append(track_end - pt_delta)
    for pt in semicircle_points(track_end, delta, theta, False):
        pts.append(pt)
    pts.append(track_end + pt_delta)
    return pcbnew.wxPoint_Vector(pts)
Exemplo n.º 2
0
    def build(self):
        board = pcbnew.BOARD()

        # outline
        PcbPolygon(self.outline).build(board)

        # Add holes
        for h in self.holes:
            h.build(board)

        # Add ground plane
        signals = {}
        if self.fill_name:
            fill_net = pcbnew.NETINFO_ITEM(board, self.fill_name)
            board.Add(fill_net)
            signals[self.fill_name] = fill_net

            item = pcbnew.ZONE(board, False)
            poly = pcbnew.wxPoint_Vector()
            for x, y in self.outline.exterior.coords:
                poly.append(pcbnew.wxPointMM(x, y))
            item.AddPolygon(poly)
            item.SetNet(fill_net)
            lset = pcbnew.LSET()
            lset.AddLayer(pcbnew.F_Cu)
            lset.AddLayer(pcbnew.B_Cu)
            item.SetLayerSet(lset)
            board.Add(item)

        for component in self.components:
            component.build(board, signals)

        return board
Exemplo n.º 3
0
    def FilledBox(self, x1, y1, x2, y2):
        box = pcbnew.EDGE_MODULE(self.module)
        box.SetShape(pcbnew.S_POLYGON)

        corners = pcbnew.wxPoint_Vector()
        corners.append(pcbnew.wxPoint(x1, y1))
        corners.append(pcbnew.wxPoint(x2, y1))
        corners.append(pcbnew.wxPoint(x2, y2))
        corners.append(pcbnew.wxPoint(x1, y2))

        box.SetPolyPoints(corners)
        return box
def semicircle_points(circle_center, radius, angle_norm, is_start=True):
    """
    """
    num_points = 20

    angles = np.linspace(angle_norm + np.pi / 2, angle_norm + 3 * np.pi / 2,
                         num_points + 2)
    angles = angles[1:-1]
    if not is_start:
        angles = np.add(angles, np.pi)
    pts = []
    for ang in angles:
        pts.append(circle_center +
                   pcbnew.wxPoint(radius * np.cos(ang), radius * np.sin(ang)))
    return pcbnew.wxPoint_Vector(pts)
def LinesToPolygon(lines, deleteDupes = True):
        
        sourceLines = []
        # ignore lines that are points (same start and end)
        for line in lines:
            if not (_Equal(line.GetStart().x,line.GetEnd().x) and _Equal(line.GetStart().y,line.GetEnd().y)):
                sourceLines.append(line)
                

        # TODO: this dupe detection and closure detection is really slow and clunky. Consider re-writing for performance instead of readability

        # collect the indexes of all dupes
        dupes = []
        for idx, line in enumerate(sourceLines):
            
            for jdx, innerLine in enumerate(sourceLines):
                if(((_Equal(line.GetStart().x, innerLine.GetStart().x) and  _Equal(line.GetStart().y, innerLine.GetStart().y) and 
                _Equal(line.GetEnd().x, innerLine.GetEnd().x) and  _Equal(line.GetEnd().y, innerLine.GetEnd().y)) or                   
                (_Equal(line.GetStart().x, innerLine.GetEnd().x) and  _Equal(line.GetStart().y, innerLine.GetEnd().y) and
                _Equal(line.GetEnd().x, innerLine.GetStart().x) and  _Equal(line.GetEnd().y, innerLine.GetStart().y))) and 
                jdx != idx):
                    LogWarning("Duplicate found: Line1: [{},{}] [{},{}] Line2: [{},{}] [{},{}]".format(line.GetStart().x,line.GetStart().y,line.GetEnd().x,line.GetEnd().y,innerLine.GetStart().x,innerLine.GetStart().y,innerLine.GetEnd().x,innerLine.GetEnd().y))
                    # the two segments are identical or start and end positions are swapped
                    # dont consider them in the polygon 
                    dupes.append(jdx)
        # loop through and remove the duplicate elements from the source list
        temp = sourceLines.copy()
        sourceLines = []
        for idx, line in enumerate(temp):
            if not idx in dupes:
                # means this is a segment that does not have a dupe
                sourceLines.append(line)
        temp = None
        


        matchedLines = []
        matchedLines.append(sourceLines[0])
        del sourceLines[0]
        
        # search through the list of lines, finding another that ends or starts where the previous one ends
        while(len(sourceLines)):
            found = False
            for idx,line in enumerate(sourceLines):
                if (_Equal(line.GetStart().x, matchedLines[-1].GetStart().x) and _Equal(line.GetStart().y, matchedLines[-1].GetStart().y)):
                    # start matches start, flip the new line start stop positions
                    LogError("wtf this should not happen")
                    raise Exception("There are duplicate lines that have the same start and stop coordinates.")

                    
                if (_Equal(line.GetStart().x, matchedLines[-1].GetEnd().x) and _Equal(line.GetStart().y, matchedLines[-1].GetEnd().y)):
                    found = True
                    
                if (_Equal(line.GetEnd().x, matchedLines[-1].GetStart().x) and _Equal(line.GetEnd().y, matchedLines[-1].GetStart().y)):
                    if len(matchedLines) == 1:
                        #this can happen at the very first match. if that is the case
                        # it is likely the structure was drawn 'the other way' so it will be easier to 
                        # swap the first entry and proceed normally than to swap all subsequent entries
                        x1 = matchedLines[-1].GetStart().x
                        y1 = matchedLines[-1].GetStart().y
                        matchedLines[-1].SetStartX(matchedLines[-1].GetEnd().x)
                        matchedLines[-1].SetStartY(matchedLines[-1].GetEnd().y)
                        matchedLines[-1].SetEndX(x1)
                        matchedLines[-1].SetEndY(y1)

                        x1 = line.GetStart().x
                        y1 = line.GetStart().y
                        line.SetStartX(line.GetEnd().x)
                        line.SetStartY(line.GetEnd().y)
                        line.SetEndX(x1)
                        line.SetEndY(y1)
                        found = True

                    
                if (_Equal(line.GetEnd().x, matchedLines[-1].GetEnd().x) and _Equal(line.GetEnd().y, matchedLines[-1].GetEnd().y)):
                    x1 = line.GetStart().x
                    y1 = line.GetStart().y
                    line.SetStartX(line.GetEnd().x)
                    line.SetStartY(line.GetEnd().y)
                    line.SetEndX(x1)
                    line.SetEndY(y1)
                    found = True

                if(found):
                    #we found a perfect match!
                    matchedLines.append(line)
                    del sourceLines[idx]
                    break
            
            if(not found):
                raise Exception("Structure is not fully enclosed. Check to make sure every line or arc ends perfectly on another, ultimately forming a completely enclosed structure with no crossing / self-intersection")
        
        # now check the last lines closes with the first line
        #TODO: actual do this check...though it may not be necessary. Probably, the polygon will simply come out wrong :)
        
        
        #we made it through the whole structure and it appears to be enclose
        
        # create the polygon
        polygon = pcbnew.DRAWSEGMENT()
        points = pcbnew.wxPoint_Vector()
        
        
        # do the first one outside the loop since we also need the start point, not just the end point
        points.append(pcbnew.wxPoint(matchedLines[0].GetStart().x, matchedLines[0].GetStart().y))
        points.append(pcbnew.wxPoint(matchedLines[0].GetEnd().x, matchedLines[0].GetEnd().y))
        del matchedLines[0]

        # now just add the end points of each line
        for line in matchedLines:
            points.append(pcbnew.wxPoint(line.GetEnd().x, line.GetEnd().y))
        
        polygon.SetPolyPoints(points)

        return polygon
Exemplo n.º 6
0
def hole_pad(board,
             module,
             size,
             drill_size,
             pos,
             net,
             pad_type="round"):  # round|first_half|second_half
    pad = pcbnew.D_PAD(module)
    pad.SetSize(size)
    pad.SetDrillSize(drill_size)

    # pad.SetPos0(pos) # don't do this, pcbnew will freak out after save/open
    pad.SetPosition(pos)

    if    net == ensure_net(board, "VCC") \
       or net == ensure_net(board, "GND") \
       or net == 0:
        # thru-holes
        pad.SetAttribute(pcbnew.PAD_ATTRIB_STANDARD)
        pad.SetLayerSet(pad.StandardMask())
        if net == ensure_net(board, "VCC"):
            pad.SetShape(pcbnew.PAD_SHAPE_RECT)
            pad.SetOrientation(deg(45))
        else:
            pad.SetShape(pcbnew.PAD_SHAPE_CIRCLE)
    else:
        # bridge pads
        pad.SetAttribute(pcbnew.PAD_ATTRIB_SMD)

        if pad_type == "round":
            pad.SetShape(pcbnew.PAD_SHAPE_CIRCLE)
        else:
            pad.SetShape(pcbnew.PAD_SHAPE_CUSTOM)
            r = int(size.GetWidth() / 2)
            inverter = 1
            if pad_type == "first_half":
                inverter = -1

            hack_shift = int(r / 2)
            gap = int(GAP / 2) * inverter
            pad.SetPosition(
                pcbnew.wxPoint(pos.x, pos.y + hack_shift * inverter + gap))
            module.SetPosition(
                pcbnew.wxPoint(module.GetPosition().x,
                               module.GetPosition().y +
                               gap))  # XXX yet another hack
            pad.SetSize(pcbnew.wxSize(int(r * 0.9), int(
                r * 0.9)))  # base shape (a tad smaller)
            # ^ base shape size can't be 0 because 3d view asserts != 0
            # ^ base shape size can't be 1 because somehow you'll end up with no copper
            # ^ base shape size can't be small because KiCad will find a way to break apart

            points = pcbnew.wxPoint_Vector()
            points.append(pcbnew.wxPoint(-r, -hack_shift * inverter))
            for x in range(-r + int(COPPER_STEP_EVERY), +r,
                           int(COPPER_STEP_EVERY)):
                # y = sqrt(r**2 - x**2)
                points.append(
                    pcbnew.wxPoint(x,
                                   (int(math.sqrt(r**2 - x**2)) - hack_shift) *
                                   inverter))
            points.append(pcbnew.wxPoint(+r, -hack_shift * inverter))
            pad.AddPrimitive(points, 0)  # 0 thickness = filled

        layer_set = pad.SMDMask().RemoveLayer(board.GetLayerID("F.Paste"))
        if "_B" in board.GetNetsByNetcode()[net].GetNetname():
            # XXX we should be flipping the module, not the pad
            pad.SetLayerSet(pcbnew.FlipLayerMask(layer_set))
            pad.Rotate(pos, 90 * 10)
        else:
            pad.SetLayerSet(layer_set)
            pad.Rotate(pos, 0)

    pad.SetPadName("0")
    pad.SetNet(board.GetNetsByNetcode()[net])
    module.Add(pad)