Example #1
0
    def BuildFootprint(self):
        """
        Actually make the footprint. We defer all but the setup to
        the implmenting class
        """

        self.module = pcbnew.MODULE(None)  # create a new module
        # do it first, so if we return early, we don't segfault KiCad

        if not self.ProcessParameters():
            return

        self.draw = FootprintWizardDrawingAids.FootprintWizardDrawingAids(
            self.module)

        self.module.SetValue(self.GetValue())
        self.module.SetReference("%s**" % self.GetReferencePrefix())

        fpid = pcbnew.FPID(self.module.GetValue())  # the name in library
        self.module.SetFPID(fpid)

        self.SetModule3DModel()  # add a 3d module if specified

        thick = self.GetTextThickness()

        self.module.Reference().SetThickness(thick)
        self.module.Value().SetThickness(thick)

        self.BuildThisFootprint()  # implementer's build function
Example #2
0
 def new_module(self, reference, position=(0, 0)):
     """Create new module on the board"""
     module = pcbnew.MODULE(self._board)
     module.SetReference(reference)
     module.SetPosition(_to_wxpoint(position[0], position[1]))
     self._board.Add(module)
     return Module(module)
Example #3
0
 def copy_module(self, original, reference, position=(0, 0)):
     """Create a copy of an existing module on the board"""
     module = pcbnew.MODULE(self._board)
     module.Copy(original._module)
     module.SetReference(reference)
     module.SetPosition(_to_wxpoint(position[0], position[1]))
     self._board.Add(module)
     return Module(module)
Example #4
0
    def __call__(self, entity):
        """

        :param entity:
        :type entity: DXFEntity
        :return:
        """
        if isinstance(entity, Circle) and entity.dxftype == "CIRCLE":
            # Create a new module from the footprint
            fp = pcbnew.MODULE(self.footprint)
            fp.SetPosition(pcbpoint(entity.center).wxpoint())
            self.board.Add(fp)
        elif isinstance(entity, LWPolyline) and entity.dxftype == "LWPOLYLINE":
            angle = -longest_angle_for_polygon(entity.points)
            fp = pcbnew.MODULE(self.footprint)
            fp.SetPosition(pcbpoint(centeroidnp(entity.points)).wxpoint())
            fp.SetOrientation(angle * 10)
            self.board.Add(fp)
Example #5
0
def hole_module(board, size, drill_size, pos, net, pad_type="round"):
    pos = pcbnew.wxPoint(pos[0], pos[1])
    main_hole_size_wx = pcbnew.wxSize(size, size)
    main_hole_drill_size_wx = pcbnew.wxSize(drill_size, drill_size)
    module = pcbnew.MODULE(board)
    module.SetPosition(pos)
    hole_pad(board, module, main_hole_size_wx, main_hole_drill_size_wx, pos,
             net, pad_type)
    board.Add(module)
Example #6
0
    def BuildFootprint(self):
        """!
        Actually make the footprint. We defer all but the set-up to
        the implementing class
        """

        self.buildmessages = ""
        self.module = pcbnew.MODULE(None)  # create a new module

        # Perform default checks on all parameters
        for p in self.params:
            p.ClearErrors()
            p.Check()  # use defaults

        self.CheckParameters()  # User error checks

        if self.AnyErrors():  # Errors were detected!

            self.buildmessages = ("Cannot build footprint: "
                                  "Parameters have errors:\n")

            for p in self.params:
                if len(p.error_list) > 0:
                    self.buildmessages += "['{page}']['{name}']:\n".format(
                        page=p.page, name=p.name)

                    for error in p.error_list:
                        self.buildmessages += "\t" + error + "\n"

            return

        self.buildmessages = (
            "Building new {name} footprint with the following parameters:\n".
            format(name=self.name))

        self.buildmessages += self.Show()

        self.draw = FootprintWizardDrawingAids(self.module)

        self.module.SetValue(self.GetValue())
        self.module.SetReference("%s**" % self.GetReferencePrefix())

        fpid = pcbnew.LIB_ID("", self.module.GetValue()
                             )  # the lib name  (empty) and the name in library
        self.module.SetFPID(fpid)

        self.SetModule3DModel()  # add a 3D module if specified

        thick = self.GetTextThickness()

        self.module.Reference().SetThickness(thick)
        self.module.Value().SetThickness(thick)

        self.BuildThisFootprint()  # implementer's build function

        return
Example #7
0
    def TaperFootprint(self, center=pcbnew.wxPoint(0,0), angle_deg=0):
        self.module = pcbnew.MODULE(None)

        #                6
        # 5 +------------+
        #   |            |\
        #   |            | \ 7
        #   |            |  +---+ 0
        #   |            |  |   |
        #   |            |  +---+ 1
        #   |            | / 2
        #   |            |/
        # 4 +------------+
        #                3
        points = [(self.w2/2, -self.w2/2), (self.w2/2, self.w2/2), (-self.w2/2, self.w2/2), \
                  (-self.w2/2 - self.tlen, self.w1/2), (-(self.w1/2 + self.tlen + self.w2/2), self.w1/2), \
                  (-(self.w1/2 + self.tlen + self.w2/2), -self.w1/2), (-self.w2/2 - self.tlen, -self.w1/2), \
                  (-self.w2/2, -self.w2/2)]

        points = [pcbnew.wxPoint(*point) for point in points]

        # Custom pad for smaller W2 x W2 pad
        cs_pad = pcbnew.D_PAD(self.module)
        cs_pad.SetSize(pcbnew.wxSize(self.w2, self.w2))
        cs_pad.SetShape(pcbnew.PAD_SHAPE_CUSTOM)
        cs_pad.SetAnchorPadShape(pcbnew.PAD_SHAPE_RECT)
        cs_pad.SetAttribute(pcbnew.PAD_ATTRIB_SMD)
        cs_pad.SetLayerSet(pcbnew.LSET(pcbnew.F_Cu))
        cs_pad.AddPrimitive(points, 0)
        cs_pad.SetLocalClearance(1)
        cs_pad.SetNet(self.net)
        cs_pad.SetPadName("1")

        self.module.Add(cs_pad)
        self.module.Add(Layout.smdRectPad(self.module, pcbnew.wxSize(self.w1, self.w1), pcbnew.wxPoint(-(self.w1/2 + self.tlen + self.w2/2), 0), "1", angle_deg, self.net))

        # TODO: Address other layers...

        self.module.SetPosition(center)

        # Add to pcbnew
        pcbnew.GetBoard().Add(self.module)
        pcbnew.Refresh()
Example #8
0
def get_via_module(board, drill, diameter, net):
    n = 'VIA-{}-{}'.format(fmt(drill), fmt(diameter))

    # instantiate new module
    m = pcbnew.MODULE(board)
    m.SetReference('REF**')
    m.SetValue(n)
    m.SetLastEditTime(pcbnew.GetNewTimeStamp())

    # adjust reference and value display settings
    r = m.Reference()
    r.SetVisible(False)
    r.SetTextSize(pcbnew.wxSize(mm2kicad(0.3), mm2kicad(0.3)))
    r.SetThickness(mm2kicad(0.075))
    v = m.Value()
    v.SetVisible(False)
    v.SetTextSize(pcbnew.wxSize(mm2kicad(0.3), mm2kicad(0.3)))
    v.SetThickness(mm2kicad(0.075))
    #v.SetLayer() # TODO: Move value to F.Fab layer (F.SilkS is default)

    lib_id = pcbnew.LIB_ID(n)
    m.SetFPID(lib_id)

    # create through-hole pad
    pad = pcbnew.D_PAD(m)
    pad.SetPadName('1')
    pad.SetNet(net)
    pad.SetPosition(pcbnew.wxPoint(0, 0))

    pad.SetShape(pcbnew.PAD_SHAPE_CIRCLE)
    pad.SetSize(pcbnew.wxSize(diameter, diameter))

    pad.SetDrillShape(pcbnew.PAD_DRILL_SHAPE_CIRCLE)
    pad.SetDrillSize(pcbnew.wxSize(drill, drill))

    pad.SetLayerSet(pcbnew.LSET.AllCuMask())
    pad.SetZoneConnection(pcbnew.PAD_ZONE_CONN_FULL)

    # add pad to module
    m.Add(pad)

    return m
    def BuildFootprint(self):
        """
        Actually make the footprint. We defer all but the setup to
        the implementing class
        """

        self.buildmessages = ""

        self.module = pcbnew.MODULE(None)  # create a new module
        # do it first, so if we return early, we don't segfault KiCad

        if not self.ProcessParameters():
            self.buildmessages = "Cannot build footprint: Parameters have errors:\n"
            self.buildmessages += self._PrintParameterErrors()
            return

        self.buildmessages = (
            "Building new %s footprint with the following parameters:\n" %
            self.name)

        self.buildmessages += self._PrintParameterTable()

        self.draw = FootprintWizardDrawingAids.FootprintWizardDrawingAids(
            self.module)

        self.module.SetValue(self.GetValue())
        self.module.SetReference("%s**" % self.GetReferencePrefix())

        fpid = pcbnew.LIB_ID(self.module.GetValue())  # the name in library
        self.module.SetFPID(fpid)

        self.SetModule3DModel()  # add a 3d module if specified

        thick = self.GetTextThickness()

        self.module.Reference().SetThickness(thick)
        self.module.Value().SetThickness(thick)

        self.BuildThisFootprint()  # implementer's build function

        return
    def parse_footprints(self):
        # type: (list) -> list
        footprints = []
        for f in self.footprints:
            ref = f.GetReference()

            # bounding box
            if hasattr(pcbnew, 'MODULE'):
                f_copy = pcbnew.MODULE(f)
            else:
                f_copy = pcbnew.FOOTPRINT(f)
            f_copy.SetOrientation(0)
            f_copy.SetPosition(pcbnew.wxPoint(0, 0))
            mrect = f_copy.GetFootprintRect()
            bbox = {
                "pos": self.normalize(f.GetPosition()),
                "relpos": self.normalize(mrect.GetPosition()),
                "size": self.normalize(mrect.GetSize()),
                "angle": f.GetOrientation() * 0.1,
            }

            # graphical drawings
            drawings = []
            for d in f.GraphicalItems():
                # we only care about copper ones, silkscreen is taken care of
                if d.GetLayer() not in [pcbnew.F_Cu, pcbnew.B_Cu]:
                    continue
                drawing = self.parse_drawing(d)
                if not drawing:
                    continue
                drawings.append({
                    "layer": "F" if d.GetLayer() == pcbnew.F_Cu else "B",
                    "drawing": drawing,
                })

            # footprint pads
            pads = []
            for p in f.Pads():
                pad_dict = self.parse_pad(p)
                if pad_dict is not None:
                    pads.append((p.GetPadName(), pad_dict))

            if pads:
                # Try to guess first pin name.
                pads = sorted(pads, key=lambda el: el[0])
                pin1_pads = [p for p in pads if p[0] in ['1', 'A', 'A1', 'P1', 'PAD1']]
                if pin1_pads:
                    pin1_pad_name = pin1_pads[0][0]
                else:
                    # No pads have common first pin name, pick lexicographically smallest.
                    pin1_pad_name = pads[0][0]
                for pad_name, pad_dict in pads:
                    if pad_name == pin1_pad_name:
                        pad_dict['pin1'] = 1

            pads = [p[1] for p in pads]

            # add footprint
            footprints.append({
                "ref": ref,
                "bbox": bbox,
                "pads": pads,
                "drawings": drawings,
                "layer": {
                    pcbnew.F_Cu: "F",
                    pcbnew.B_Cu: "B"
                }.get(f.GetLayer())
            })

        return footprints
Example #11
0
    def parse_modules(self, pcb_modules):
        # type: (list) -> list
        modules = []
        for m in pcb_modules:  # type: pcbnew.MODULE
            ref = m.GetReference()

            # bounding box
            m_copy = pcbnew.MODULE(m)
            m_copy.SetOrientation(0)
            m_copy.SetPosition(pcbnew.wxPoint(0, 0))
            mrect = m_copy.GetFootprintRect()
            bbox = {
                "pos": self.normalize(m.GetPosition()),
                "relpos": self.normalize(mrect.GetPosition()),
                "size": self.normalize(mrect.GetSize()),
                "angle": m.GetOrientation() * 0.1,
            }

            # graphical drawings
            drawings = []
            for d in m.GraphicalItems():
                # we only care about copper ones, silkscreen is taken care of
                if d.GetLayer() not in [pcbnew.F_Cu, pcbnew.B_Cu]:
                    continue
                drawing = self.parse_drawing(d)
                if not drawing:
                    continue
                drawings.append({
                    "layer":
                    "F" if d.GetLayer() == pcbnew.F_Cu else "B",
                    "drawing":
                    drawing,
                })

            # footprint pads
            pads = []
            for p in m.Pads():
                pad_dict = self.parse_pad(p)
                if pad_dict is not None:
                    pads.append((p.GetPadName(), pad_dict))

            # If no pads have common 'first' pad name pick lexicographically.
            pin1_pads = [p for p in pads if 'pin1' in p[1]]
            if pads and not pin1_pads:
                pads = sorted(pads, key=lambda el: el[0])
                for pad_name, pad_dict in pads:
                    if pad_name:
                        pad_dict['pin1'] = 1
                        break

            pads = [p[1] for p in pads]

            # add module
            modules.append({
                "ref": ref,
                "bbox": bbox,
                "pads": pads,
                "drawings": drawings,
                "layer": {
                    pcbnew.F_Cu: "F",
                    pcbnew.B_Cu: "B"
                }.get(m.GetLayer())
            })

        return modules
Example #12
0
    def BuildFootprint(self):
        if self.has_errors():
            print "Cannot build footprint: Parameters have errors:"
            print self.parameter_errors
            return

        print "Building new QFP footprint with the following parameters:"
        self.print_parameter_table()

        self.module = pcbnew.MODULE(None)  # create a new module

        pads = self.parameters
        num_pads = int(pads["Pads"]["*n"])
        pad_width = pads["Pads"]["width"]
        pad_length = pads["Pads"]["length"]
        pad_pitch = pads["Pads"]["pitch"]
        pad_horizontal_pitch = pads["Pads"]["horizontal pitch"]
        pad_vertical_pitch = pads["Pads"]["vertical pitch"]

        package_width = pads["Package"]["width"]
        package_height = pads["Package"]["height"]

        side_length = pad_pitch * ((num_pads / 4) - 1)

        offsetX = pad_pitch * ((num_pads / 4) - 1) / 2
        text_size = pcbnew.wxSize(pcbnew.FromMM(0.8), pcbnew.FromMM(0.8))

        self.module.SetReference("QFP %d" % int(num_pads))
        self.module.Reference().SetPos0(pcbnew.wxPoint(0, pcbnew.FromMM(-0.8)))
        self.module.Reference().SetTextPosition(
            self.module.Reference().GetPos0())
        self.module.Reference().SetSize(text_size)

        self.module.SetValue("U**")
        self.module.Value().SetPos0(pcbnew.wxPoint(0, pcbnew.FromMM(+0.8)))
        self.module.Value().SetTextPosition(self.module.Value().GetPos0())
        self.module.Value().SetSize(text_size)

        fpid = pcbnew.FPID(self.module.GetReference())  #the name in library
        self.module.SetFPID(fpid)

        pad_size_left_right = pcbnew.wxSize(pad_length, pad_width)
        pad_size_bottom_top = pcbnew.wxSize(pad_width, pad_length)

        for cur_pad in range(0, num_pads):
            side = int(
                cur_pad /
                (num_pads / 4))  # 0 -> left, 1 -> bottom, 2 -> right, 3 -> top

            if side == 0 or side == 2:
                pad_size = pad_size_left_right

                pad_pos_x = -(pad_horizontal_pitch / 2)
                pad_pos_y = (cur_pad %
                             (num_pads / 4)) * pad_pitch - (side_length / 2)

                if side == 2:
                    pad_pos_x = -pad_pos_x
                    pad_pos_y = -pad_pos_y

            else:
                pad_size = pad_size_bottom_top

                pad_pos_x = (cur_pad %
                             (num_pads / 4)) * pad_pitch - (side_length / 2)
                pad_pos_y = -(pad_vertical_pitch / 2)

                if side == 1:
                    pad_pos_y = -pad_pos_y
                else:
                    pad_pos_x = -pad_pos_x

            pad_pos = pcbnew.wxPoint(pad_pos_x, pad_pos_y)

            pad = self.smd_rect_pad(self.module, pad_size, pad_pos,
                                    str(cur_pad + 1))

            self.module.Add(pad)

        half_package_width = package_width / 2
        half_package_height = package_height / 2

        package_pad_height_offset = abs(package_height -
                                        side_length) / 2 - pad_pitch
        package_pad_width_offset = abs(package_width -
                                       side_length) / 2 - pad_pitch

        # Bottom Left Edge, vertical line
        outline = pcbnew.EDGE_MODULE(self.module)
        outline.SetWidth(pcbnew.FromMM(0.2))
        outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT)
        outline.SetShape(pcbnew.S_SEGMENT)
        start = pcbnew.wxPoint(-half_package_width,
                               half_package_height - package_pad_height_offset)
        end = pcbnew.wxPoint(-half_package_width, half_package_height)
        outline.SetStartEnd(start, end)
        self.module.Add(outline)

        # Bottom Left Edge, horizontal line
        outline = pcbnew.EDGE_MODULE(self.module)
        outline.SetWidth(pcbnew.FromMM(0.2))
        outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT)
        outline.SetShape(pcbnew.S_SEGMENT)
        start = pcbnew.wxPoint(-half_package_width, half_package_height)
        end = pcbnew.wxPoint(-half_package_width + package_pad_width_offset,
                             half_package_height)
        outline.SetStartEnd(start, end)
        self.module.Add(outline)

        # Bottom Right Edge, vertical line
        outline = pcbnew.EDGE_MODULE(self.module)
        outline.SetWidth(pcbnew.FromMM(0.2))
        outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT)
        outline.SetShape(pcbnew.S_SEGMENT)
        start = pcbnew.wxPoint(half_package_width,
                               half_package_height - package_pad_height_offset)
        end = pcbnew.wxPoint(half_package_width, half_package_height)
        outline.SetStartEnd(start, end)
        self.module.Add(outline)

        # Bottom Right Edge, horizontal line
        outline = pcbnew.EDGE_MODULE(self.module)
        outline.SetWidth(pcbnew.FromMM(0.2))
        outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT)
        outline.SetShape(pcbnew.S_SEGMENT)
        start = pcbnew.wxPoint(half_package_width, half_package_height)
        end = pcbnew.wxPoint(half_package_width - package_pad_width_offset,
                             half_package_height)
        outline.SetStartEnd(start, end)
        self.module.Add(outline)

        # Top Right Edge, vertical line
        outline = pcbnew.EDGE_MODULE(self.module)
        outline.SetWidth(pcbnew.FromMM(0.2))
        outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT)
        outline.SetShape(pcbnew.S_SEGMENT)
        start = pcbnew.wxPoint(
            half_package_width,
            -half_package_height + package_pad_height_offset)
        end = pcbnew.wxPoint(half_package_width, -half_package_height)
        outline.SetStartEnd(start, end)
        self.module.Add(outline)

        # Top Right Edge, horizontal line
        outline = pcbnew.EDGE_MODULE(self.module)
        outline.SetWidth(pcbnew.FromMM(0.2))
        outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT)
        outline.SetShape(pcbnew.S_SEGMENT)
        start = pcbnew.wxPoint(half_package_width, -half_package_height)
        end = pcbnew.wxPoint(half_package_width - package_pad_width_offset,
                             -half_package_height)
        outline.SetStartEnd(start, end)
        self.module.Add(outline)

        # Top Left Edge, straight line
        outline = pcbnew.EDGE_MODULE(self.module)
        outline.SetWidth(pcbnew.FromMM(0.2))
        outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT)
        outline.SetShape(pcbnew.S_SEGMENT)
        start = pcbnew.wxPoint(
            -half_package_width,
            -half_package_height + package_pad_height_offset)
        end = pcbnew.wxPoint(-half_package_width + package_pad_width_offset,
                             -half_package_height)
        outline.SetStartEnd(start, end)
        self.module.Add(outline)
Example #13
0
    def ChamferFootprint(self, center=pcbnew.wxPoint(0, 0)):
        self.module = pcbnew.MODULE(None)  # Create new module
        self.angle = m.radians(self.angle_deg)

        # Calculate the miter
        w = self.width

        # Width of the corner from edge of the corner to inside corner
        corner_width = pcbnew.ToMM(w) / m.cos(self.angle / 2)

        # Get proportion of width to cut
        cut = self.OptimalMiter()
        print("Cut: {0:.2f}%".format(cut * 100))

        # Distance from uncut outside corner point to point 7
        cut = pcbnew.FromMM(cut * corner_width / m.cos(
            (m.pi - self.angle) / 2))

        # Distance between points 2 and 3 and points 3 and 4
        # Minimum of w/2 to satisfy DRC, otherwise pads are too close
        # and track connected to other pad overlaps the other one.
        # Rounded trace end can also stick out of the cut area
        # if a is too small.
        a = max(cut - self.width * m.tan(self.angle / 2), w / 2)

        # Distance between points 3 and 4
        x34 = a * m.sin(self.angle)
        y34 = a * m.cos(self.angle)

        # Distance between points 4 and 5
        x45 = self.width * m.cos(self.angle)
        y45 = self.width * m.sin(self.angle)

        # Distance from point 7 to 1 (no x-component)
        d71 = a + self.width * m.tan(self.angle / 2) - cut

        #   1  2
        #   +--+
        #   |  |3
        # 7 \  --+ 4
        #    \   |
        #     \--+ 5
        #     6
        dW = w / 55  # To prevent tracks from over-extending
        points = [
            (-w / 2, -d71 / 2), (w / 2, -d71 / 2), (w / 2, a - d71 / 2 + dW),
            (w / 2 + x34 - (d71 / 2 - d71 / 1e5 - dW) * m.sin(self.angle),
             a + y34 - d71 / 2 -
             (d71 / 2 - d71 / 1e5 - dW) * m.cos(self.angle) + dW),
            (w / 2 + x34 - x45 -
             (d71 / 2 - d71 / 1e5 - dW) * m.sin(self.angle), a + y34 + y45 -
             d71 / 2 - (d71 / 2 - d71 / 1e5 - dW) * m.cos(self.angle) + dW),
            (cut * m.sin(self.angle) - w / 2,
             a + self.width * m.tan(self.angle / 2) + cut * m.cos(self.angle) -
             d71 / 2 + dW),
            (-w / 2,
             a + self.width * m.tan(self.angle / 2) - cut - d71 / 2 + dW)
        ]

        # Last two points can be equal
        if points[-2] == points[-1]:
            points = points[:-1]

        points = [pcbnew.wxPoint(*point) for point in points]

        # Custom pad
        cs_pad = pcbnew.D_PAD(self.module)
        cs_pad.SetSize(pcbnew.wxSize(w, d71))
        cs_pad.SetShape(pcbnew.PAD_SHAPE_CUSTOM)
        cs_pad.SetAnchorPadShape(pcbnew.PAD_SHAPE_RECT)
        cs_pad.SetAttribute(pcbnew.PAD_ATTRIB_SMD)
        cs_pad.SetLayerSet(pcbnew.LSET(pcbnew.F_Cu))
        cs_pad.AddPrimitive(points, 0)
        cs_pad.SetLocalClearance(1)
        cs_pad.SetNet(self.net)
        cs_pad.SetPadName("1")

        self.module.Add(cs_pad)

        # Halfway between points 4 and 5
        posx = ((w / 2 + x34) + (w / 2 + x34 - x45)) / 2
        posy = ((a + y34 - d71 / 2) + (a + y34 + y45 - d71 / 2)) / 2

        # Position pad so that pad edge touches polygon edge
        posx -= (d71 / 2 - dW) * m.sin(self.angle)
        posy -= (d71 / 2 - dW) * m.cos(self.angle) - dW
        size_pad = pcbnew.wxSize(d71, w)
        self.module.Add(
            Layout.smdRectPad(self.module, pcbnew.wxSize(w, d71),
                              pcbnew.wxPoint(0, 0), "1", 0,
                              self.net))  # Alignment pad
        self.module.Add(
            Layout.smdRectPad(self.module, size_pad,
                              pcbnew.wxPoint(posx, posy), "1",
                              (self.angle_deg - 90) * 10, self.net))

        self.module.Rotate(self.module.GetPosition(),
                           (90 + self.angle_deg) * 100)

        # self.module.MoveAnchorPosition(pcbnew.wxPoint((d71/2 - a - w/2)*m.sin(self.angle), \
        #                                (d71/2 - a - w/2)*m.cos(self.angle)))
        self.module.SetPosition(center)

        if self.layer == pcbnew.B_Cu: self.module.Flip(self.module.GetCenter())
        elif self.layer == pcbnew.F_Cu:
            self.module.Rotate(self.module.GetPosition(),
                               (90 + self.angle_deg) * 100)

        # Find center of bounding box for placement

        # Add to Pcbnew
        pcbnew.GetBoard().Add(self.module)
        pcbnew.Refresh()
    def Run(self):
        """
        The entry function of the plugin that is executed on user action
        """
        board = pcbnew.GetBoard()

        # TODO also aggregate and bin by optional attributes, like tolerances
        radii = set()
        circles = []

        # TODO don't add an extra hole in same place -> overwrite

        # get circles drawn on board
        # TODO maybe include some means of filtering out possible circular board outline
        drawing_list = board.DrawingsList()
        for d in drawing_list:
            if d.GetLayerName() == 'Edge.Cuts':
                # to gaurd against random stuff being on edge cuts for some reason
                # causing weird errors
                assert type(
                    d) == pcbnew.DRAWSEGMENT, 'non-DRAWSEGMENT on Edge.Cuts'
                if d.GetShapeStr() == 'Circle':
                    # TODO check these are what i want, and don't need modification
                    # w/ thickness or whatever (check using dxf import)
                    r = d.GetRadius()
                    radii.add(r)
                    c = d.GetCenter()
                    circles.append((c.x, c.y, r))

                    # TODO make optional
                    # how to do?
                    board.RemoveNative(d)

        # TODO option to use nearest hole in existing library option / next largest
        # (report error)
        # TODO easiest way to get available footprints (and their radii?)
        # TODO option to take a set of target hole sizes (for DFM purposes)
        # TODO include either global use next largest / next smallest
        # (maybe ignore locked, and say that, to complement this?)
        # or let people check for each hole whether they want to use next up or down

        # TODO option to make new hole components and put in project specific library

        # TODO include field for library to be saved to (maybe mandatory if this option?)
        # TODO fail gracefully if board filename is empty (board not saved yet)
        target_footprint_lib = '.'.join(str(board.GetFileName()).split('.')[:-1]) \
            + '.pretty'

        if not os.path.exists(target_footprint_lib):
            print('creating project specific footprint library' + \
                ' {}'.format(target_footprint_lib))
            pcbnew.PCB_IO().FootprintLibCreate(target_footprint_lib)
        else:
            print('using footprint library {}'.format(target_footprint_lib))

        # make a new footprint for each distinct hole radius we need
        # save to project specific library by default
        for r in radii:
            r_mm = nm_to_mm(r)
            print('generating footprint for hole of radius {}mm'.format(r_mm))

            footprint = pcbnew.MODULE(None)
            # for non-electronic parts like these
            footprint.SetAttributes(pcbnew.MOD_VIRTUAL)
            footprint.SetLastEditTime()
            footprint.SetKeywords('non-plated through hole NPTH')

            # TODO it looks like the module itself needs to be specified to be on F.Cu?
            # how? (see github for example output)

            # TODO set tags to include non-plated through hole, npth?
            #footprint.SetDescription('{}mm diameter non-plated through hole')
            pad = pcbnew.D_PAD(footprint)

            # other library mounting hole pads seem to have this pad number
            pad.SetName('1')

            # TODO does this change the layers and stuff automatically? pad shape?
            pad.SetAttribute(pcbnew.PAD_ATTRIB_HOLE_NOT_PLATED)
            pad.SetShape(pcbnew.PAD_SHAPE_CIRCLE)
            # TODO do i need setsize / setstartend?
            # size seems to equal (r, r) for existing npth library parts

            # all holes in KiCad currently have to reside on one of the (external?)
            # copper layers (F.Cu should be one of these layers. mask the other?)
            pad.SetLayerSet(pcbnew.D_PAD_UnplatedHoleMask())

            # TODO are holes alone actually rendered, or do you need the other stuff?

            # there seems to be a PAD_DRILL_SHAPE_CIRCLE and PAD_DRILL_SHAPE_OBLONG
            # but when are they ever not circular? oblong = limited routing?
            # would advanced circuits do oblong, for instance?
            #pad.SetDrillShape() # huh???
            # TODO why isn't this a single number? what gens (drill X)?
            # TODO why is x in (size x x) slightly larger than 1.5?
            pad.SetDrillSize(pcbnew.wxSize(r, r))
            footprint.Add(pad)

            footprint_id = 'R{}mm_NPTH'.format(r_mm)
            footprint.SetReference(footprint_id)
            '''
            footprint.Reference().SetPosition(pcbnew.wxPoint()1)
            footprint.Value().SetPosition(pcbnew.wxPoint()1)
            '''

            # aiming for a visible layer that does not translate into manufacture
            comment_layer_id = get_layer_id_by_name('Cmts.User')
            footprint.Reference().SetLayer(comment_layer_id)
            footprint.Value().SetLayer(comment_layer_id)

            # this is the filename, preceeding .kicad_mod
            fpid = pcbnew.LIB_ID(footprint_id)
            footprint.SetFPID(fpid)

            # seems to work to lock all imports by default
            footprint.SetLocked(True)

            print('saving footprint to {}'.format(os.path.join(\
                target_footprint_lib, footprint_id + '.kicad_mod')))
            pcbnew.PCB_IO().FootprintSave(target_footprint_lib, footprint)

            for x, y, r_curr in circles:
                if r == r_curr:
                    f_new = pcbnew.PCB_IO().FootprintLoad(
                        target_footprint_lib, footprint_id)
                    f_new.SetPosition(pcbnew.wxPoint(x, y))
                    board.Add(f_new)
Example #15
0
n = 0
for module in modules:
    n += 1

newModules = []

i = 0

for sourceModule in modules:  # Iterate through each object to be copied
    for x in range(0, NUM_X):  # Iterate through x direction
        for y in range(0, NUM_Y):  # Iterate through y direction
            i += 1
            if ((x != 0)
                    or (y != 0)):  # Don't duplicate source object to location
                newModule = pcbnew.MODULE(sourceModule)
                newModule.SetPosition(
                    wxPoint(x * boardWidth + sourceModule.GetPosition().x,
                            y * boardHeight + sourceModule.GetPosition().y)
                )  # Move to correct location
                newModules.append(
                    newModule)  # Add to temporary list of objects
                if args.verbose:
                    progress(i, n * NUM_X * NUM_Y,
                             'Positioning modules')  # Progress bar

if args.verbose: print("\n")

i = 0
for module in newModules:  # add new objects to board
    board.Add(module)