def _generatePad(self): if self.chamfer_size[0] >= self.size[0] or self.chamfer_size[1] >= self.size[1]: raise ValueError('Chamfer size ({}) too large for given pad size ({})'.format(self.chamfer_size, self.size)) is_chamfered = False if self.corner_selection.isAnySelected() and self.chamfer_size[0] > 0 and self.chamfer_size[1] > 0: is_chamfered = True shortest_sidlength = min(self.size) radius = shortest_sidlength*self.radius_ratio if self.maximum_radius and radius > self.maximum_radius: radius = self.maximum_radius if is_chamfered and self.chamfer_size[0] == self.chamfer_size[1] and self.radius_ratio > 0: # We prefer the use of rounded rectangle over chamfered pads. r_chamfer = self.chamfer_size[0] + sqrt(2)*self.chamfer_size[0]/2 if radius >= r_chamfer: is_chamfered = False if is_chamfered: outside = Vector2D(self.size.x/2, self.size.y/2) inside = [Vector2D(outside.x, outside.y-self.chamfer_size.y), Vector2D(outside.x-self.chamfer_size.x, outside.y) ] polygon_width = 0 if radius > 0: shortest_sidlength = min(self.size-self.chamfer_size) if radius > shortest_sidlength/2: radius = shortest_sidlength/2 polygon_width = radius*2 outside -= radius inside[0] -= radius inside[1] -= radius points = [] corner_vectors = [ Vector2D(-1, -1), Vector2D(1, -1), Vector2D(1, 1), Vector2D(-1, 1) ] for i in range(4): if self.corner_selection[i]: points.append(corner_vectors[i]*inside[i % 2]) points.append(corner_vectors[i]*inside[(i+1) % 2]) else: points.append(corner_vectors[i]*outside) primitives = [Polygon(nodes=points, width=polygon_width, **self.mirror)] # TODO make size calculation more resilient size = min(self.size.x, self.size.y)-max(self.chamfer_size[0], self.chamfer_size[1])/sqrt(2) if size <= 0: raise ValueError('Anchor pad size calculation failed.' 'Chamfer size ({}) to large for given pad size ({})' .format(self.size, self.chamfer_size)) return Pad(primitives=primitives, at=self.at, shape=Pad.SHAPE_CUSTOM, size=size, **self.padargs) else: return Pad( at=self.at, shape=Pad.SHAPE_ROUNDRECT, size=self.size, **self.padargs )
def smd_chip(args): # init kicad footprint kicad_mod = Footprint(args['name']) kicad_mod.setDescription(args['description']) kicad_mod.setTags(args['tags']) kicad_mod.setAttribute('smd') # set general values text_x = 0. text_y = max([args['pad_y'] / 2., args['part_y'] / 2.]) + args['courtyard'] + 0.75 kicad_mod.append(Text(type='reference', text='REF**', at=[text_x, -text_y], layer='F.SilkS')) kicad_mod.append(Text(type='user', text='%R', at=[text_x, -text_y], layer='F.Fab')) kicad_mod.append(Text(type='value', text=args['name'], at=[text_x, text_y], layer='F.Fab')) # create silkscreen silk_x = args['part_x'] / 2. silk_y = max([args['pad_y'] / 2., args['part_y'] / 2.]) + min(max(0.15, args['courtyard'] - 0.05), 0.2) kicad_mod.append(Line(start=[silk_x, silk_y], end=[-silk_x, silk_y], layer='F.SilkS')) kicad_mod.append(Line(start=[silk_x, -silk_y], end=[-silk_x, -silk_y], layer='F.SilkS')) # create fabrication layer kicad_mod.append(RectLine(start=[args['part_x'] / 2., args['part_y'] / 2.], end=[-args['part_x'] / 2., -args['part_y'] / 2.], layer='F.Fab')) # create courtyard courtyard_x = args['courtyard'] + max([args['pad_spacing'] / 2. + args['pad_x'], args['part_x'] / 2.]) courtyard_y = args['courtyard'] + max([args['pad_y'] / 2., args['part_y'] / 2.]) kicad_mod.append(RectLine(start=[courtyard_x, courtyard_y], end=[-courtyard_x, -courtyard_y], layer='F.CrtYd')) # create pads pad_settings = {'type': Pad.TYPE_SMT, 'shape': Pad.SHAPE_RECT, 'size': [args['pad_x'], args['pad_y']], 'layers': Pad.LAYERS_SMT} pad_x_center = (args['pad_spacing'] + args['pad_x']) / 2. kicad_mod.append(Pad(number=1, at=[-pad_x_center, 0], **pad_settings)) kicad_mod.append(Pad(number=2, at=[pad_x_center, 0], **pad_settings)) # add model kicad_mod.append(Model(filename="{model_dir}.3dshapes/{name}.wrl".format(**args), at=[0, 0, 0], scale=[1, 1, 1], rotate=[0, 0, 0])) # write file file_handler = KicadFileHandler(kicad_mod) file_handler.writeFile('{}.kicad_mod'.format(args['name']))
def getVirtualChilds(self): at = self.reference_arc.getMidPoint() primitives = self._getArcPrimitives() for p in primitives: p.translate(-at) return [ Pad(number=self.number, type=Pad.TYPE_SMT, shape=Pad.SHAPE_CUSTOM, at=at, size=self.width / 2, layers=self.layers, primitives=primitives) ]
def getVirtualChilds(self): return [ Pad(number=self.number, type=Pad.TYPE_SMT, shape=Pad.SHAPE_CUSTOM, at=(self.at + Vector2D(self.radius, 0)), size=self.width, layers=self.layers, primitives=[ Circle(center=(-self.radius, 0), radius=self.radius, width=self.width) ]) ]
def buzzer_round_tht(args): # some variables buzzer_center = args['pad_spacing'] / 2. buzzer_radius = args['diameter'] / 2. # init kicad footprint kicad_mod = Footprint(args['name']) kicad_mod.setDescription(args['datasheet']) kicad_mod.setTags("buzzer round tht") # set general values kicad_mod.append(Text(type='reference', text='REF**', at=[buzzer_center, -buzzer_radius - 1], layer='F.SilkS')) kicad_mod.append(Text(type='user', text='%R', at=[buzzer_center, -buzzer_radius - 1], layer='F.Fab')) kicad_mod.append(Text(type='value', text=args['name'], at=[buzzer_center, buzzer_radius + 1], layer='F.Fab')) # create silkscreen kicad_mod.append(Circle(center=[buzzer_center, 0], radius=buzzer_radius + 0.1, layer='F.SilkS')) kicad_mod.append(Text(type='user', text='+', at=[0, -args['pad_size'] / 2 - 1], layer='F.SilkS')) kicad_mod.append(Text(type='user', text='+', at=[0, -args['pad_size']/2 - 1], layer='F.Fab')) # create fabrication layer kicad_mod.append(Circle(center=[buzzer_center, 0], radius=buzzer_radius, layer='F.Fab')) # create courtyard kicad_mod.append(Circle(center=[buzzer_center, 0], radius=buzzer_radius + args['courtyard'], layer='F.CrtYd')) # create pads kicad_mod.append(Pad(number=1, type=Pad.TYPE_THT, shape=Pad.SHAPE_RECT, at=[0, 0], size=args['pad_size'], drill=args['hole_size'], layers=Pad.LAYERS_THT)) kicad_mod.append(Pad(number=2, type=Pad.TYPE_THT, shape=Pad.SHAPE_CIRCLE, at=[args['pad_spacing'], 0], size=args['pad_size'], drill=args['hole_size'], layers=Pad.LAYERS_THT)) # write file file_handler = KicadFileHandler(kicad_mod) file_handler.writeFile('{}.kicad_mod'.format(args['name']))
def _generatePads(self): self.pads = [] if self.num_paste_zones > 1: layers = ['F.Cu', 'F.Mask'] self._generatePastePads() else: layers = ['F.Cu', 'F.Mask', 'F.Paste'] if not self.is_circle: self._generateCopperPads() else: self.pads.append( Pad(number=self.number, type=Pad.TYPE_SMT, shape=Pad.SHAPE_CIRCLE, at=(self.at), size=self.size, layers=layers))
def _generateCopperPads(self): # kicad_mod.append(c) layers = ['F.Cu'] if self.num_paste_zones == 1: if self.solder_paste_margin == 0: layers.append('F.Paste') else: self.pads.append( RingPadPrimitive(number="", at=self.at, width=self.width + 2 * self.solder_paste_margin, layers=['F.Paste'], radius=self.radius)) if self.solder_mask_margin == 0: # bug in kicad so any clearance other than 0 needs a workaround layers.append('F.Mask') else: self._generateMaskPads() self.pads.append( RingPadPrimitive(number=self.number, at=self.at, width=self.width, layers=layers, radius=self.radius)) a = 360 / self.num_anchor pos = Vector2D(self.radius, 0) for i in range(1, self.num_anchor): pos.rotate(a) self.pads.append( Pad( number=self.number, type=Pad.TYPE_SMT, shape=Pad.SHAPE_CIRCLE, at=(self.at + pos), size=self.width - 0.0001, layers=['F.Cu'], ))
def create_smd_shielding(name, **kwargs): kicad_mod = Footprint(name) # init kicad footprint kicad_mod.setDescription(kwargs['description']) kicad_mod.setTags('Shielding Cabinet') kicad_mod.setAttribute('smd') # do some pre calculations # TODO: when mirror=False, array has to have even number of array elements x_pad_positions = calculate_pad_spacer(kwargs['x_pad_spacer'], kwargs.get('x_pad_mirror', True)) y_pad_positions = calculate_pad_spacer(kwargs['y_pad_spacer'], kwargs.get('y_pad_mirror', True)) x_pad_min = min(x_pad_positions) x_pad_max = max(x_pad_positions) y_pad_min = min(y_pad_positions) y_pad_max = max(y_pad_positions) x_pad_min_center = x_pad_min + kwargs['pads_width']/2. x_pad_max_center = x_pad_max - kwargs['pads_width']/2. y_pad_min_center = y_pad_min + kwargs['pads_width']/2. y_pad_max_center = y_pad_max - kwargs['pads_width']/2. x_part_min = -kwargs['x_part_size'] / 2. x_part_max = kwargs['x_part_size'] / 2. y_part_min = -kwargs['y_part_size'] / 2. y_part_max = kwargs['y_part_size'] / 2. # set general values kicad_mod.append(Text(type='reference', text='REF**', at=[0, y_pad_min - kwargs['courtjard'] - 0.75], layer='F.SilkS')) kicad_mod.append(Text(type='value', text=name, at=[0, y_pad_max + kwargs['courtjard'] + 0.75], layer='F.Fab')) # create courtyard x_courtjard_min = round_to(x_pad_min - kwargs['courtjard'], 0.05) x_courtjard_max = round_to(x_pad_max + kwargs['courtjard'], 0.05) y_courtjard_min = round_to(y_pad_min - kwargs['courtjard'], 0.05) y_courtjard_max = round_to(y_pad_max + kwargs['courtjard'], 0.05) kicad_mod.append(RectLine(start=[x_courtjard_min, y_courtjard_min], end=[x_courtjard_max, y_courtjard_max], layer='F.CrtYd')) # create Fabriaction Layer kicad_mod.append(RectLine(start=[x_part_min, y_part_min], end=[x_part_max, y_part_max], layer='F.Fab')) # all pads have this kwargs, so we only write them one general_kwargs = {'number': 1, 'type': Pad.TYPE_SMT, 'shape': Pad.SHAPE_RECT, 'layers': ['F.Cu', 'F.Mask']} # create edge pads kicad_mod.append(Pad(at=[x_pad_min_center, y_pad_min_center], size=[kwargs['pads_width'], kwargs['pads_width']], **general_kwargs)) kicad_mod.append(Pad(at=[x_pad_max_center, y_pad_min_center], size=[kwargs['pads_width'], kwargs['pads_width']], **general_kwargs)) kicad_mod.append(Pad(at=[x_pad_max_center, y_pad_max_center], size=[kwargs['pads_width'], kwargs['pads_width']], **general_kwargs)) kicad_mod.append(Pad(at=[x_pad_min_center, y_pad_max_center], size=[kwargs['pads_width'], kwargs['pads_width']], **general_kwargs)) # iterate pairwise over pads for pad_start, pad_end in zip(x_pad_positions[0::2], x_pad_positions[1::2]): if pad_start == x_pad_min: pad_start += kwargs['pads_width'] if pad_end == x_pad_max: pad_end -= kwargs['pads_width'] kicad_mod.append(Pad(at=[(pad_start+pad_end)/2., y_pad_min_center], size=[abs(pad_start-pad_end), kwargs['pads_width']], **general_kwargs)) kicad_mod.append(Pad(at=[(pad_start+pad_end)/2., y_pad_max_center], size=[abs(pad_start-pad_end), kwargs['pads_width']], **general_kwargs)) for pad_start, pad_end in zip(y_pad_positions[0::2], y_pad_positions[1::2]): if pad_start == y_pad_min: pad_start += kwargs['pads_width'] if pad_end == y_pad_max: pad_end -= kwargs['pads_width'] kicad_mod.append(Pad(at=[x_pad_min_center, (pad_start+pad_end)/2.], size=[kwargs['pads_width'], abs(pad_start-pad_end)], **general_kwargs)) kicad_mod.append(Pad(at=[x_pad_max_center, (pad_start+pad_end)/2.], size=[kwargs['pads_width'], abs(pad_start-pad_end)], **general_kwargs)) # iterate pairwise over pads for silk screen for pad_start, pad_end in zip(x_pad_positions[1::2], x_pad_positions[2::2]): pad_start += 0.3 pad_end -= 0.3 kicad_mod.append(Line(start=[pad_start, y_part_min - 0.15], end=[pad_end, y_part_min - 0.15], layer='F.SilkS')) kicad_mod.append(Line(start=[pad_start, y_part_max + 0.15], end=[pad_end, y_part_max + 0.15], layer='F.SilkS')) for pad_start, pad_end in zip(y_pad_positions[1::2], y_pad_positions[2::2]): pad_start += 0.3 pad_end -= 0.3 # check if line has relevant length if pad_end - pad_start < 0.5: continue kicad_mod.append(Line(start=[x_part_min - 0.15, pad_start], end=[x_part_min - 0.15, pad_end], layer='F.SilkS')) kicad_mod.append(Line(start=[x_part_max + 0.15, pad_start], end=[x_part_max + 0.15, pad_end], layer='F.SilkS')) # write file file_handler = KicadFileHandler(kicad_mod) file_handler.writeFile('{name}.kicad_mod'.format(name=name))
def unserialize_pad(self, node): raise NotImplementedError() return Pad()
def create_shielding(name, outer_size, size, attachment_drill, attachment_diameter, attachment_positions): attachment_positions = sorted(attachment_positions) kicad_mod = Footprint(name) # init kicad footprint kicad_mod.setDescription( 'WE-SHC Shielding Cabinet THT {size}x{size}mm'.format(size=size)) kicad_mod.setTags('Shielding Cabinet') courtjard_size = outer_size / 2. + attachment_diameter / 2. + 0.25 # set general values kicad_mod.append( Text(type='reference', text='REF**', at=[0, -courtjard_size - 1], layer='F.SilkS')) kicad_mod.append( Text(type='value', text=name, at=[0, courtjard_size + 1], layer='F.Fab')) # create courtyard kicad_mod.append( RectLine(start=[-courtjard_size, -courtjard_size], end=[courtjard_size, courtjard_size], layer='F.CrtYd')) # create Fabriaction Layer kicad_mod.append( RectLine(start=[-size / 2., -size / 2.], end=[size / 2., size / 2.], layer='F.Fab')) general_kwargs = { 'number': 1, 'type': Pad.TYPE_THT, 'shape': Pad.SHAPE_CIRCLE, 'size': [attachment_diameter, attachment_diameter], 'drill': attachment_drill, 'layers': ['*.Cu', '*.Mask'] } # create pads for position in attachment_positions: kicad_mod.append( Pad(at=[outer_size / 2., position / 2.], **general_kwargs)) kicad_mod.append( Pad(at=[-outer_size / 2., position / 2.], **general_kwargs)) kicad_mod.append( Pad(at=[position / 2., outer_size / 2.], **general_kwargs)) kicad_mod.append( Pad(at=[position / 2., -outer_size / 2.], **general_kwargs)) if position != 0. or 2 * outer_size == 2 * position: kicad_mod.append( Pad(at=[outer_size / 2., -position / 2.], **general_kwargs)) kicad_mod.append( Pad(at=[-outer_size / 2., -position / 2.], **general_kwargs)) kicad_mod.append( Pad(at=[-position / 2., outer_size / 2.], **general_kwargs)) kicad_mod.append( Pad(at=[-position / 2., -outer_size / 2.], **general_kwargs)) # create silk screen silk_padding = 0.2 silk_outline = size / 2. + silk_padding pad_padding = 0.4 if attachment_positions[0] != 0.: line_end = attachment_positions[ 0] / 2. - attachment_diameter / 2. - pad_padding kicad_mod.append( Line(start=[silk_outline, line_end], end=[silk_outline, -line_end], layer='F.SilkS')) kicad_mod.append( Line(start=[-silk_outline, -line_end], end=[-silk_outline, line_end], layer='F.SilkS')) kicad_mod.append( Line(start=[line_end, silk_outline], end=[-line_end, silk_outline], layer='F.SilkS')) kicad_mod.append( Line(start=[line_end, -silk_outline], end=[-line_end, -silk_outline], layer='F.SilkS')) for begin, end in zip(attachment_positions, attachment_positions[1:]): line_begin = begin / 2. + attachment_diameter / 2. + pad_padding line_end = end / 2. - attachment_diameter / 2. - pad_padding kicad_mod.append( Line(start=[silk_outline, line_begin], end=[silk_outline, line_end], layer='F.SilkS')) kicad_mod.append( Line(start=[silk_outline, -line_begin], end=[silk_outline, -line_end], layer='F.SilkS')) kicad_mod.append( Line(start=[-silk_outline, line_begin], end=[-silk_outline, line_end], layer='F.SilkS')) kicad_mod.append( Line(start=[-silk_outline, -line_begin], end=[-silk_outline, -line_end], layer='F.SilkS')) kicad_mod.append( Line(start=[line_begin, silk_outline], end=[line_end, silk_outline], layer='F.SilkS')) kicad_mod.append( Line(start=[line_begin, -silk_outline], end=[line_end, -silk_outline], layer='F.SilkS')) kicad_mod.append( Line(start=[-line_begin, silk_outline], end=[-line_end, silk_outline], layer='F.SilkS')) kicad_mod.append( Line(start=[-line_begin, -silk_outline], end=[-line_end, -silk_outline], layer='F.SilkS')) if attachment_positions[-1] != outer_size: line_begin = attachment_positions[ -1] / 2. + attachment_diameter / 2. + pad_padding line_end = outer_size / 2. + silk_padding kicad_mod.append( Line(start=[silk_outline, line_begin], end=[silk_outline, line_end], layer='F.SilkS')) kicad_mod.append( Line(start=[silk_outline, -line_begin], end=[silk_outline, -line_end], layer='F.SilkS')) kicad_mod.append( Line(start=[-silk_outline, line_begin], end=[-silk_outline, line_end], layer='F.SilkS')) kicad_mod.append( Line(start=[-silk_outline, -line_begin], end=[-silk_outline, -line_end], layer='F.SilkS')) kicad_mod.append( Line(start=[line_begin, silk_outline], end=[line_end, silk_outline], layer='F.SilkS')) kicad_mod.append( Line(start=[line_begin, -silk_outline], end=[line_end, -silk_outline], layer='F.SilkS')) kicad_mod.append( Line(start=[-line_begin, silk_outline], end=[-line_end, silk_outline], layer='F.SilkS')) kicad_mod.append( Line(start=[-line_begin, -silk_outline], end=[-line_end, -silk_outline], layer='F.SilkS')) # fix KLC issue 6.3 # kicad_mod.insert(Translation(outer_size / 2., attachment_positions[-1] / 2.)) # write file file_handler = KicadFileHandler(kicad_mod) file_handler.writeFile('{name}.kicad_mod'.format(name=name))
def create_footprint(name, **kwargs): kicad_mod = Footprint(name) # init kicad footprint kicad_mod.setDescription(kwargs['description']) kicad_mod.setTags('Mounting Hole') # load some general values hole_x = float(kwargs['hole_x']) hole_y = float(kwargs['hole_y']) anular_ring = float(kwargs['anular_ring']) courtjard = float(kwargs['courtjard']) create_via = kwargs['via'] pad_x = hole_x + 2 * anular_ring pad_y = hole_y + 2 * anular_ring courtjard_x = pad_x + 2 * courtjard courtjard_y = pad_y + 2 * courtjard # set general values kicad_mod.append( Text(type='reference', text='REF**', at=[0, -courtjard_y / 2 - 0.75], layer='F.SilkS')) kicad_mod.append( Text(type='value', text=name, at=[0, courtjard_y / 2 + 0.75], layer='F.Fab')) # create courtyard if hole_x == hole_y: kicad_mod.append( Circle(center=[0, 0], radius=courtjard_x / 2., layer='F.CrtYd')) elif hole_x > hole_y: courtjard_length_x = courtjard_x - courtjard_y kicad_mod.append( RectLine(start=[courtjard_length_x / 2, courtjard_y / 2], end=[-courtjard_length_x / 2, courtjard_y / 2], layer='F.CrtYd')) kicad_mod.append( RectLine(start=[courtjard_length_x / 2, -courtjard_y / 2], end=[-courtjard_length_x / 2, -courtjard_y / 2], layer='F.CrtYd')) kicad_mod.append( Arc(center=[courtjard_length_x / 2, 0], start=[courtjard_length_x / 2, -courtjard_y / 2], angle=180, layer='F.CrtYd')) kicad_mod.append( Arc(center=[-courtjard_length_x / 2, 0], start=[-courtjard_length_x / 2, courtjard_y / 2], angle=180, layer='F.CrtYd')) else: # hole_x < hole_y courtjard_length_y = courtjard_y - courtjard_x kicad_mod.append( RectLine(start=[courtjard_x / 2, courtjard_length_y / 2], end=[courtjard_x / 2, -courtjard_length_y / 2], layer='F.CrtYd')) kicad_mod.append( RectLine(start=[-courtjard_x / 2, courtjard_length_y / 2], end=[-courtjard_x / 2, -courtjard_length_y / 2], layer='F.CrtYd')) kicad_mod.append( Arc(center=[0, courtjard_length_y / 2], start=[courtjard_x / 2, courtjard_length_y / 2], angle=180, layer='F.CrtYd')) kicad_mod.append( Arc(center=[0, -courtjard_length_y / 2], start=[-courtjard_x / 2, -courtjard_length_y / 2], angle=180, layer='F.CrtYd')) # create pads pad_kwargs = { 'number': 1, 'type': Pad.TYPE_THT, 'at': [0, 0], 'size': [pad_x, pad_y], 'layers': ['*.Cu', '*.Mask'] } if hole_x == hole_y: kicad_mod.append( Pad(**pad_kwargs, shape=Pad.SHAPE_CIRCLE, drill=hole_x)) else: kicad_mod.append( Pad(**pad_kwargs, shape=Pad.SHAPE_OVAL, drill=[hole_x, hole_y])) # create via's if create_via: via_count = int(kwargs['via_count']) via_diameter = float(kwargs['via_diameter']) x_size = hole_x + anular_ring y_size = hole_y + anular_ring circle_radius = min(x_size, y_size) / 2 circle_scope = min(x_size, y_size) * math.pi if hole_x > hole_y: line_scope_x = 2 * (x_size - y_size) line_scope_y = 0 else: line_scope_x = 0 line_scope_y = 2 * (y_size - x_size) line_scope = line_scope_x + line_scope_y vias_scope = circle_scope + line_scope for step in range(via_count): scope_step = (vias_scope / via_count * step - line_scope_y / 4 + vias_scope) % vias_scope # align on right center if scope_step <= circle_scope / 4: local_scope_pos = scope_step circle_pos = local_scope_pos / circle_scope * 2 * math.pi step_x = math.cos( circle_pos) * circle_radius + line_scope_x / 4 step_y = math.sin( circle_pos) * circle_radius + line_scope_y / 4 elif scope_step <= circle_scope / 4 + line_scope_x / 2: local_scope_pos = scope_step - circle_scope / 4 step_x = line_scope_x / 4 - local_scope_pos step_y = y_size / 2 elif scope_step <= circle_scope / 2 + line_scope_x / 2: local_scope_pos = scope_step - line_scope_x / 2 # angle of circle already included circle_pos = local_scope_pos / circle_scope * 2 * math.pi step_x = math.cos( circle_pos) * circle_radius - line_scope_x / 4 step_y = math.sin( circle_pos) * circle_radius + line_scope_y / 4 elif scope_step <= circle_scope / 2 + line_scope_x / 2 + line_scope_y / 2: local_scope_pos = scope_step - circle_scope / 2 - line_scope_x / 2 step_x = -x_size / 2 step_y = line_scope_y / 4 - local_scope_pos elif scope_step <= 3 * circle_scope / 4 + line_scope_x / 2 + line_scope_y / 2: local_scope_pos = scope_step - line_scope_x / 2 - line_scope_y / 2 # angle of circle already included circle_pos = local_scope_pos / circle_scope * 2 * math.pi step_x = math.cos( circle_pos) * circle_radius - line_scope_x / 4 step_y = math.sin( circle_pos) * circle_radius - line_scope_y / 4 elif scope_step <= 3 * circle_scope / 4 + line_scope_x + line_scope_y / 2: local_scope_pos = scope_step - 3 * circle_scope / 4 - line_scope_x / 2 - line_scope_y / 2 step_x = -line_scope_x / 4 + local_scope_pos step_y = -y_size / 2 elif scope_step <= circle_scope + line_scope_x + line_scope_y / 2: local_scope_pos = scope_step - line_scope_x - line_scope_y / 2 # angle of circle already included circle_pos = local_scope_pos / circle_scope * 2 * math.pi step_x = math.cos( circle_pos) * circle_radius + line_scope_x / 4 step_y = math.sin( circle_pos) * circle_radius - line_scope_y / 4 elif scope_step < circle_scope + line_scope_x + line_scope_y: local_scope_pos = scope_step - circle_scope - line_scope_x - line_scope_y / 2 step_x = x_size / 2 step_y = -line_scope_y / 4 + local_scope_pos else: # error raise "invalid scope_step" kicad_mod.append( Pad(number=1, type=Pad.TYPE_THT, shape=Pad.SHAPE_CIRCLE, at=[step_x, step_y], size=[via_diameter + 0.1, via_diameter + 0.1], drill=via_diameter, layers=['*.Cu', '*.Mask'])) # write file file_handler = KicadFileHandler(kicad_mod) file_handler.writeFile('{name}.kicad_mod'.format(name=name))
def _generatePad(self): if self.chamfer_size[0] >= self.size[0] or self.chamfer_size[ 1] >= self.size[1]: raise ValueError( 'Chamfer size ({}) too large for given pad size ({})'.format( self.chamfer_size, self.size)) is_chamfered = False if self.corner_selection.isAnySelected( ) and self.chamfer_size[0] > 0 and self.chamfer_size[1] > 0: is_chamfered = True radius = self.round_radius_handler.getRoundRadius(min(self.size)) if is_chamfered: outside = Vector2D(self.size.x / 2, self.size.y / 2) inside = [ Vector2D(outside.x, outside.y - self.chamfer_size.y), Vector2D(outside.x - self.chamfer_size.x, outside.y) ] polygon_width = 0 if self.round_radius_handler.roundingRequested(): if self.chamfer_size[0] != self.chamfer_size[1]: raise NotImplementedError( 'Rounded chamfered pads are only supported for 45 degree chamfers.' ' Chamfer {}'.format(self.chamfer_size)) # We prefer the use of rounded rectangle over chamfered pads. r_chamfer = self.chamfer_size[0] + sqrt( 2) * self.chamfer_size[0] / 2 if radius >= r_chamfer: is_chamfered = False elif radius > 0: shortest_sidlength = min( min(self.size - self.chamfer_size), self.chamfer_size[0] * sqrt(2)) if radius > shortest_sidlength / 2: radius = shortest_sidlength / 2 polygon_width = radius * 2 outside -= radius inside[0].y -= radius * (2 / sqrt(2) - 1) inside[0].x -= radius inside[1].x -= radius * (2 / sqrt(2) - 1) inside[1].y -= radius if is_chamfered: points = [] corner_vectors = [ Vector2D(-1, -1), Vector2D(1, -1), Vector2D(1, 1), Vector2D(-1, 1) ] for i in range(4): if self.corner_selection[i]: points.append(corner_vectors[i] * inside[i % 2]) points.append(corner_vectors[i] * inside[(i + 1) % 2]) else: points.append(corner_vectors[i] * outside) primitives = [ Polygon(nodes=points, width=polygon_width, **self.mirror) ] # TODO make size calculation more resilient size = min(self.size.x, self.size.y) - max( self.chamfer_size[0], self.chamfer_size[1]) / sqrt(2) if size <= 0: raise ValueError( 'Anchor pad size calculation failed.' 'Chamfer size ({}) to large for given pad size ({})'. format(self.size, self.chamfer_size)) return Pad(primitives=primitives, at=self.at, shape=Pad.SHAPE_CUSTOM, size=size, **self.padargs) else: return Pad(at=self.at, shape=Pad.SHAPE_ROUNDRECT, size=self.size, round_radius_handler=self.round_radius_handler, **self.padargs)
def create_shielding(name, outer_size, size, attachment_width, attachment_length, attachment_positions, outer_attachment_length): kicad_mod = Footprint(name) # init kicad footprint kicad_mod.setDescription( 'WE-SHC Shielding Cabinet SMD {size}x{size}mm'.format(size=size)) kicad_mod.setTags('Shielding Cabinet') kicad_mod.setAttribute('smd') # set general values kicad_mod.append( Text(type='reference', text='REF**', at=[0, -outer_size / 2. - 1], layer='F.SilkS')) kicad_mod.append( Text(type='value', text=name, at=[0, outer_size / 2. + 1], layer='F.Fab')) # create courtyard kicad_mod.append( RectLine(start=[-outer_size / 2. - 0.25, -outer_size / 2. - 0.25], end=[outer_size / 2. + 0.25, outer_size / 2. + 0.25], layer='F.CrtYd')) # create Fabriaction Layer kicad_mod.append( RectLine(start=[-size / 2., -size / 2.], end=[size / 2., size / 2.], layer='F.Fab')) outer_pointing_pos = outer_size / 2. - attachment_width / 2. general_kwargs = { 'number': 1, 'type': Pad.TYPE_SMT, 'shape': Pad.SHAPE_RECT, 'layers': ['F.Cu', 'F.Mask'] } vertical_kwargs = { 'number': 1, 'type': Pad.TYPE_SMT, 'shape': Pad.SHAPE_RECT, 'size': [attachment_width, attachment_length], 'layers': ['F.Cu', 'F.Mask'] } horizontal_kwargs = { 'number': 1, 'type': Pad.TYPE_SMT, 'shape': Pad.SHAPE_RECT, 'size': [attachment_length, attachment_width], 'layers': ['F.Cu', 'F.Mask'] } # create inner pads for position in attachment_positions: kicad_mod.append( Pad(at=[outer_pointing_pos, position / 2.], **vertical_kwargs)) kicad_mod.append( Pad(at=[outer_pointing_pos, -position / 2.], **vertical_kwargs)) kicad_mod.append( Pad(at=[-outer_pointing_pos, position / 2.], **vertical_kwargs)) kicad_mod.append( Pad(at=[-outer_pointing_pos, -position / 2.], **vertical_kwargs)) kicad_mod.append( Pad(at=[position / 2., outer_pointing_pos], **horizontal_kwargs)) kicad_mod.append( Pad(at=[position / 2., -outer_pointing_pos], **horizontal_kwargs)) kicad_mod.append( Pad(at=[-position / 2., outer_pointing_pos], **horizontal_kwargs)) kicad_mod.append( Pad(at=[-position / 2., -outer_pointing_pos], **horizontal_kwargs)) # create edge pads kicad_mod.append( Pad(at=[outer_pointing_pos, outer_pointing_pos], size=[attachment_width, attachment_width], **general_kwargs)) kicad_mod.append( Pad(at=[outer_pointing_pos, -outer_pointing_pos], size=[attachment_width, attachment_width], **general_kwargs)) kicad_mod.append( Pad(at=[-outer_pointing_pos, outer_pointing_pos], size=[attachment_width, attachment_width], **general_kwargs)) kicad_mod.append( Pad(at=[-outer_pointing_pos, -outer_pointing_pos], size=[attachment_width, attachment_width], **general_kwargs)) inner_edge_pos = outer_size / 2 - attachment_width - ( outer_attachment_length - attachment_width) / 2. inner_edge_length = outer_attachment_length - attachment_width kicad_mod.append( Pad(at=[inner_edge_pos, outer_pointing_pos], size=[inner_edge_length, attachment_width], **general_kwargs)) kicad_mod.append( Pad(at=[inner_edge_pos, -outer_pointing_pos], size=[inner_edge_length, attachment_width], **general_kwargs)) kicad_mod.append( Pad(at=[-inner_edge_pos, outer_pointing_pos], size=[inner_edge_length, attachment_width], **general_kwargs)) kicad_mod.append( Pad(at=[-inner_edge_pos, -outer_pointing_pos], size=[inner_edge_length, attachment_width], **general_kwargs)) kicad_mod.append( Pad(at=[outer_pointing_pos, inner_edge_pos], size=[attachment_width, inner_edge_length], **general_kwargs)) kicad_mod.append( Pad(at=[outer_pointing_pos, -inner_edge_pos], size=[attachment_width, inner_edge_length], **general_kwargs)) kicad_mod.append( Pad(at=[-outer_pointing_pos, inner_edge_pos], size=[attachment_width, inner_edge_length], **general_kwargs)) kicad_mod.append( Pad(at=[-outer_pointing_pos, -inner_edge_pos], size=[attachment_width, inner_edge_length], **general_kwargs)) # write file file_handler = KicadFileHandler(kicad_mod) file_handler.writeFile('{name}.kicad_mod'.format(name=name))
def create_footprint(name, configuration, **kwargs): kicad_mod = Footprint(name) # init kicad footprint datasheet = "" if 'datasheet' in kwargs: datasheet = kwargs['datasheet'] kicad_mod.setDescription(kwargs['description'] + " " + datasheet) kicad_mod.setTags('Capacitor Electrolytic') kicad_mod.setAttribute('smd') # set general values text_offset_y = kwargs['width'] / 2. + configuration['courtyard_offset'][ 'default'] + 0.8 #silkscreen REF** silk_text_size = configuration['references'][0]['size'] silk_text_thickness = silk_text_size[0] * configuration['references'][0][ 'fontwidth'] kicad_mod.append( Text(type='reference', text='REF**', at=[0, -text_offset_y], layer='F.SilkS', size=[silk_text_size[0], silk_text_size[1]], thickness=silk_text_thickness)) #fab value fab_text_size = configuration['values'][0]['size'] fab_text_thickness = fab_text_size[0] * configuration['values'][0][ 'fontwidth'] kicad_mod.append( Text(type='value', text=name, at=[0, text_offset_y], layer='F.Fab', size=[fab_text_size[0], fab_text_size[1]], thickness=fab_text_thickness)) #fab REF** fab_text_size = kwargs['diameter'] / 5. fab_text_size = min(fab_text_size, configuration['references'][1]['size_max'][0]) fab_text_size = max(fab_text_size, configuration['references'][1]['size_min'][0]) fab_text_thickness = fab_text_size * configuration['references'][1][ 'thickness_factor'] kicad_mod.append( Text(type='user', text='%R', at=[0, 0], layer='F.Fab', size=[fab_text_size, fab_text_size], thickness=fab_text_thickness)) # create fabrication layer fab_x = kwargs['length'] / 2. fab_y = kwargs['width'] / 2. if kwargs['pin1_chamfer'] == 'auto': fab_edge = min(fab_x / 2, fab_y / 2, configuration['fab_pin1_marker_length']) else: fab_edge = kwargs['pin1_chamfer'] fab_x_edge = fab_x - fab_edge fab_y_edge = fab_y - fab_edge kicad_mod.append( Line(start=[fab_x, -fab_y], end=[fab_x, fab_y], layer='F.Fab', width=configuration['fab_line_width'])) kicad_mod.append( Line(start=[-fab_x_edge, -fab_y], end=[fab_x, -fab_y], layer='F.Fab', width=configuration['fab_line_width'])) kicad_mod.append( Line(start=[-fab_x_edge, fab_y], end=[fab_x, fab_y], layer='F.Fab', width=configuration['fab_line_width'])) if fab_edge > 0: kicad_mod.append( Line(start=[-fab_x, -fab_y_edge], end=[-fab_x, fab_y_edge], layer='F.Fab', width=configuration['fab_line_width'])) kicad_mod.append( Line(start=[-fab_x, -fab_y_edge], end=[-fab_x_edge, -fab_y], layer='F.Fab', width=configuration['fab_line_width'])) kicad_mod.append( Line(start=[-fab_x, fab_y_edge], end=[-fab_x_edge, fab_y], layer='F.Fab', width=configuration['fab_line_width'])) kicad_mod.append( Circle(center=[0, 0], radius=kwargs['diameter'] / 2., layer='F.Fab', width=configuration['fab_line_width'])) #fab polarity marker fab_pol_size = kwargs['diameter'] / 10. fab_pol_wing = fab_pol_size / 2. fab_pol_distance = kwargs['diameter'] / 2. - fab_pol_wing - configuration[ 'fab_line_width'] fab_pol_pos_y = fab_text_size / 2 + configuration[ 'silk_pad_clearance'] + fab_pol_size fab_pol_pos_x = math.sqrt(fab_pol_distance * fab_pol_distance - fab_pol_pos_y * fab_pol_pos_y) fab_pol_pos_x = -fab_pol_pos_x fab_pol_pos_y = -fab_pol_pos_y kicad_mod.append( Line(start=[fab_pol_pos_x - fab_pol_wing, fab_pol_pos_y], end=[fab_pol_pos_x + fab_pol_wing, fab_pol_pos_y], layer='F.Fab', width=configuration['fab_line_width'])) kicad_mod.append( Line(start=[fab_pol_pos_x, fab_pol_pos_y - fab_pol_wing], end=[fab_pol_pos_x, fab_pol_pos_y + fab_pol_wing], layer='F.Fab', width=configuration['fab_line_width'])) # create silkscreen fab_to_silk_offset = configuration['silk_fab_offset'] silk_x = kwargs['length'] / 2. + fab_to_silk_offset silk_y = kwargs['width'] / 2. + fab_to_silk_offset silk_y_start = kwargs['pad_width'] / 2. + configuration[ 'silk_pad_clearance'] + configuration['silk_line_width'] / 2. silk_45deg_offset = fab_to_silk_offset * math.tan(math.radians(22.5)) silk_x_edge = fab_x - fab_edge + silk_45deg_offset silk_y_edge = fab_y - fab_edge + silk_45deg_offset kicad_mod.append( Line(start=[silk_x, silk_y], end=[silk_x, silk_y_start], layer='F.SilkS', width=configuration['silk_line_width'])) kicad_mod.append( Line(start=[silk_x, -silk_y], end=[silk_x, -silk_y_start], layer='F.SilkS', width=configuration['silk_line_width'])) kicad_mod.append( Line(start=[-silk_x_edge, -silk_y], end=[silk_x, -silk_y], layer='F.SilkS', width=configuration['silk_line_width'])) kicad_mod.append( Line(start=[-silk_x_edge, silk_y], end=[silk_x, silk_y], layer='F.SilkS', width=configuration['silk_line_width'])) if silk_y_edge > silk_y_start: kicad_mod.append( Line(start=[-silk_x, silk_y_edge], end=[-silk_x, silk_y_start], layer='F.SilkS', width=configuration['silk_line_width'])) kicad_mod.append( Line(start=[-silk_x, -silk_y_edge], end=[-silk_x, -silk_y_start], layer='F.SilkS', width=configuration['silk_line_width'])) kicad_mod.append( Line(start=[-silk_x, -silk_y_edge], end=[-silk_x_edge, -silk_y], layer='F.SilkS', width=configuration['silk_line_width'])) kicad_mod.append( Line(start=[-silk_x, silk_y_edge], end=[-silk_x_edge, silk_y], layer='F.SilkS', width=configuration['silk_line_width'])) else: silk_x_cut = silk_x - ( silk_y_start - silk_y_edge ) # because of the 45 degree edge we can user a simple apporach silk_y_edge_cut = silk_y_start kicad_mod.append( Line(start=[-silk_x_cut, -silk_y_edge_cut], end=[-silk_x_edge, -silk_y], layer='F.SilkS', width=configuration['silk_line_width'])) kicad_mod.append( Line(start=[-silk_x_cut, silk_y_edge_cut], end=[-silk_x_edge, silk_y], layer='F.SilkS', width=configuration['silk_line_width'])) #silk polarity marker silk_pol_size = kwargs['diameter'] / 8. silk_pol_wing = silk_pol_size / 2. silk_pol_pos_y = silk_y_start + silk_pol_size silk_pol_pos_x = silk_x + silk_pol_wing + configuration[ 'silk_line_width'] * 2 silk_pol_pos_x = -silk_pol_pos_x silk_pol_pos_y = -silk_pol_pos_y kicad_mod.append( Line(start=[silk_pol_pos_x - silk_pol_wing, silk_pol_pos_y], end=[silk_pol_pos_x + silk_pol_wing, silk_pol_pos_y], layer='F.SilkS', width=configuration['silk_line_width'])) kicad_mod.append( Line(start=[silk_pol_pos_x, silk_pol_pos_y - silk_pol_wing], end=[silk_pol_pos_x, silk_pol_pos_y + silk_pol_wing], layer='F.SilkS', width=configuration['silk_line_width'])) # create courtyard courtyard_offset = configuration['courtyard_offset']['default'] courtyard_x = kwargs['length'] / 2. + courtyard_offset courtyard_y = kwargs['width'] / 2. + courtyard_offset courtyard_pad_x = kwargs['pad_spacing'] / 2. + kwargs[ 'pad_length'] + courtyard_offset courtyard_pad_y = kwargs['pad_width'] / 2. + courtyard_offset courtyard_45deg_offset = courtyard_offset * math.tan(math.radians(22.5)) courtyard_x_edge = fab_x - fab_edge + courtyard_45deg_offset courtyard_y_edge = fab_y - fab_edge + courtyard_45deg_offset courtyard_x_lower_edge = courtyard_x if courtyard_y_edge < courtyard_pad_y: courtyard_x_lower_edge = courtyard_x_lower_edge - courtyard_pad_y + courtyard_y_edge courtyard_y_edge = courtyard_pad_y #rounding courtyard_x = float(format(courtyard_x, ".2f")) courtyard_y = float(format(courtyard_y, ".2f")) courtyard_pad_x = float(format(courtyard_pad_x, ".2f")) courtyard_pad_y = float(format(courtyard_pad_y, ".2f")) courtyard_x_edge = float(format(courtyard_x_edge, ".2f")) courtyard_y_edge = float(format(courtyard_y_edge, ".2f")) courtyard_x_lower_edge = float(format(courtyard_x_lower_edge, ".2f")) # drawing courtyard kicad_mod.append( Line(start=[courtyard_x, -courtyard_y], end=[courtyard_x, -courtyard_pad_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[courtyard_x, -courtyard_pad_y], end=[courtyard_pad_x, -courtyard_pad_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[courtyard_pad_x, -courtyard_pad_y], end=[courtyard_pad_x, courtyard_pad_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[courtyard_pad_x, courtyard_pad_y], end=[courtyard_x, courtyard_pad_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[courtyard_x, courtyard_pad_y], end=[courtyard_x, courtyard_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[-courtyard_x_edge, courtyard_y], end=[courtyard_x, courtyard_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[-courtyard_x_edge, -courtyard_y], end=[courtyard_x, -courtyard_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) if fab_edge > 0: kicad_mod.append( Line(start=[-courtyard_x_lower_edge, courtyard_y_edge], end=[-courtyard_x_edge, courtyard_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[-courtyard_x_lower_edge, -courtyard_y_edge], end=[-courtyard_x_edge, -courtyard_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) if courtyard_y_edge > courtyard_pad_y: kicad_mod.append( Line(start=[-courtyard_x, -courtyard_y_edge], end=[-courtyard_x, -courtyard_pad_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[-courtyard_x, courtyard_pad_y], end=[-courtyard_x, courtyard_y_edge], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[-courtyard_x_lower_edge, -courtyard_pad_y], end=[-courtyard_pad_x, -courtyard_pad_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[-courtyard_pad_x, -courtyard_pad_y], end=[-courtyard_pad_x, courtyard_pad_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[-courtyard_pad_x, courtyard_pad_y], end=[-courtyard_x_lower_edge, courtyard_pad_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) # all pads have this kwargs, so we only write them once pad_kwargs = { 'type': Pad.TYPE_SMT, 'shape': Pad.SHAPE_RECT, 'layers': ['F.Cu', 'F.Mask', 'F.Paste'] } # create pads x_pad_spacing = kwargs['pad_spacing'] / 2. + kwargs['pad_length'] / 2. kicad_mod.append( Pad(number=1, at=[-x_pad_spacing, 0], size=[kwargs['pad_length'], kwargs['pad_width']], **pad_kwargs)) kicad_mod.append( Pad(number=2, at=[x_pad_spacing, 0], size=[kwargs['pad_length'], kwargs['pad_width']], **pad_kwargs)) lib_name = 'Capacitor_SMD' # add model modelname = name.replace("_HandSoldering", "") kicad_mod.append( Model(filename="{model_prefix:s}{lib_name:s}.3dshapes/{name:s}.wrl". format(model_prefix=configuration['3d_model_prefix'], lib_name=lib_name, name=modelname), at=[0, 0, 0], scale=[1, 1, 1], rotate=[0, 0, 0])) # write file output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name) if not os.path.isdir( output_dir ): #returns false if path does not yet exist!! (Does not check path validity) os.makedirs(output_dir) filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=name) file_handler = KicadFileHandler(kicad_mod) file_handler.writeFile(filename)
def generateFootprints(self): fab_line_width = self.configuration.get('fab_line_width', 0.1) silk_line_width = self.configuration.get('silk_line_width', 0.12) for group_name in self.footprint_group_definitions: #print(device_group) footprint_group_data = self.footprint_group_definitions[group_name] device_size_docs = footprint_group_data['size_definitions'] package_size_defintions = {} for device_size_doc in device_size_docs: with open(size_definition_path + device_size_doc, 'r') as size_stream: try: package_size_defintions.update( yaml.safe_load(size_stream)) except yaml.YAMLError as exc: print(exc) for size_name in package_size_defintions: device_size_data = package_size_defintions[size_name] device_dimensions = TwoTerminalSMDchip.deviceDimensions( device_size_data) ipc_reference = footprint_group_data['ipc_reference'] ipc_density = footprint_group_data['ipc_density'] ipc_data_set = self.ipc_defintions[ipc_reference][ipc_density] ipc_round_base = self.ipc_defintions[ipc_reference][ 'round_base'] pad_details, paste_details = self.calcPadDetails( device_dimensions, ipc_data_set, ipc_round_base, footprint_group_data) #print(calc_pad_details()) #print("generate {name}.kicad_mod".format(name=footprint)) suffix = footprint_group_data.get('suffix', '').format( pad_x=pad_details['size'][0], pad_y=pad_details['size'][1]) prefix = footprint_group_data['prefix'] model3d_path_prefix = self.configuration.get( '3d_model_prefix', '${KISYS3DMOD}') suffix_3d = suffix if footprint_group_data.get( 'include_suffix_in_3dpath', 'True') == 'True' else "" code_metric = device_size_data.get('code_metric') code_letter = device_size_data.get('code_letter') code_imperial = device_size_data.get('code_imperial') if 'code_letter' in device_size_data: name_format = self.configuration[ 'fp_name_tantal_format_string'] else: if 'code_metric' in device_size_data: name_format = self.configuration[ 'fp_name_format_string'] else: name_format = self.configuration[ 'fp_name_non_metric_format_string'] fp_name = name_format.format(prefix=prefix, code_imperial=code_imperial, code_metric=code_metric, code_letter=code_letter, suffix=suffix) fp_name_2 = name_format.format(prefix=prefix, code_imperial=code_imperial, code_letter=code_letter, code_metric=code_metric, suffix=suffix_3d) model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format( model3d_path_prefix=model3d_path_prefix, lib_name=footprint_group_data['fp_lib_name'], fp_name=fp_name_2) #print(fp_name) #print(pad_details) kicad_mod = Footprint(fp_name) # init kicad footprint kicad_mod.setDescription( footprint_group_data['description'].format( code_imperial=code_imperial, code_metric=code_metric, code_letter=code_letter, size_info=device_size_data.get('size_info'))) kicad_mod.setTags(footprint_group_data['keywords']) kicad_mod.setAttribute('smd') pad_shape_details = {} pad_shape_details['shape'] = Pad.SHAPE_ROUNDRECT pad_shape_details['radius_ratio'] = configuration.get( 'round_rect_radius_ratio', 0) if 'round_rect_max_radius' in configuration: pad_shape_details['maximum_radius'] = configuration[ 'round_rect_max_radius'] if paste_details is not None: layers_main = ['F.Cu', 'F.Mask'] kicad_mod.append( Pad(number='', type=Pad.TYPE_SMT, layers=['F.Paste'], **merge_dicts(paste_details, pad_shape_details))) paste_details['at'][0] *= (-1) kicad_mod.append( Pad(number='', type=Pad.TYPE_SMT, layers=['F.Paste'], **merge_dicts(paste_details, pad_shape_details))) else: layers_main = Pad.LAYERS_SMT P1 = Pad(number=1, type=Pad.TYPE_SMT, layers=layers_main, **merge_dicts(pad_details, pad_shape_details)) pad_radius = P1.getRoundRadius() kicad_mod.append(P1) pad_details['at'][0] *= (-1) kicad_mod.append( Pad(number=2, type=Pad.TYPE_SMT, layers=layers_main, **merge_dicts(pad_details, pad_shape_details))) fab_outline = self.configuration.get('fab_outline', 'typical') if fab_outline == 'max': outline_size = [ device_dimensions['body_length'].maximum, device_dimensions['body_width'].maximum ] elif fab_outline == 'min': outline_size = [ device_dimensions['body_length'].minimum, device_dimensions['body_width'].minimum ] else: outline_size = [ device_dimensions['body_length'].nominal, device_dimensions['body_width'].nominal ] if footprint_group_data.get('polarization_mark', 'False') == 'True': polararity_marker_size = self.configuration.get( 'fab_polarity_factor', 0.25) polararity_marker_size *= ( outline_size[1] if outline_size[1] < outline_size[0] else outline_size[0]) polarity_marker_thick_line = False polarity_max_size = self.configuration.get( 'fab_polarity_max_size', 1) if polararity_marker_size > polarity_max_size: polararity_marker_size = polarity_max_size polarity_min_size = self.configuration.get( 'fab_polarity_min_size', 0.25) if polararity_marker_size < polarity_min_size: if polararity_marker_size < polarity_min_size * 0.6: polarity_marker_thick_line = True polararity_marker_size = polarity_min_size silk_x_left = -abs(pad_details['at'][0]) - pad_details['size'][0]/2 - \ self.configuration['silk_pad_clearance'] - silk_line_width/2 silk_y_bottom = max( self.configuration['silk_pad_clearance'] + silk_line_width / 2 + pad_details['size'][1] / 2, outline_size[1] / 2 + self.configuration['silk_fab_offset']) if polarity_marker_thick_line: kicad_mod.append( RectLine(start=[ -outline_size[0] / 2, outline_size[1] / 2 ], end=[ outline_size[0] / 2, -outline_size[1] / 2 ], layer='F.Fab', width=fab_line_width)) x = -outline_size[0] / 2 + fab_line_width kicad_mod.append( Line(start=[x, outline_size[1] / 2], end=[x, -outline_size[1] / 2], layer='F.Fab', width=fab_line_width)) x += fab_line_width if x < -fab_line_width / 2: kicad_mod.append( Line(start=[x, outline_size[1] / 2], end=[x, -outline_size[1] / 2], layer='F.Fab', width=fab_line_width)) kicad_mod.append( Circle(center=[silk_x_left - 0.05, 0], radius=0.05, layer="F.SilkS", width=0.1)) else: poly_fab = [{ 'x': outline_size[0] / 2, 'y': -outline_size[1] / 2 }, { 'x': polararity_marker_size - outline_size[0] / 2, 'y': -outline_size[1] / 2 }, { 'x': -outline_size[0] / 2, 'y': polararity_marker_size - outline_size[1] / 2 }, { 'x': -outline_size[0] / 2, 'y': outline_size[1] / 2 }, { 'x': outline_size[0] / 2, 'y': outline_size[1] / 2 }, { 'x': outline_size[0] / 2, 'y': -outline_size[1] / 2 }] kicad_mod.append( PolygoneLine(polygone=poly_fab, layer='F.Fab', width=fab_line_width)) poly_silk = [{ 'x': outline_size[0] / 2, 'y': -silk_y_bottom }, { 'x': silk_x_left, 'y': -silk_y_bottom }, { 'x': silk_x_left, 'y': silk_y_bottom }, { 'x': outline_size[0] / 2, 'y': silk_y_bottom }] kicad_mod.append( PolygoneLine(polygone=poly_silk, layer='F.SilkS', width=silk_line_width)) else: kicad_mod.append( RectLine( start=[-outline_size[0] / 2, outline_size[1] / 2], end=[outline_size[0] / 2, -outline_size[1] / 2], layer='F.Fab', width=fab_line_width)) silk_outline_y = outline_size[1] / 2 + self.configuration[ 'silk_fab_offset'] default_clearance = self.configuration.get( 'silk_pad_clearance', 0.2) silk_point_top_right = nearestSilkPointOnOrthogonalLineSmallClerance( pad_size=pad_details['size'], pad_position=pad_details['at'], pad_radius=pad_radius, fixed_point=Vector2D(0, silk_outline_y), moving_point=Vector2D(outline_size[0]/2, silk_outline_y), silk_pad_offset_default=(silk_line_width/2+default_clearance), silk_pad_offset_reduced=(silk_line_width/2\ +self.configuration.get('silk_clearance_small_parts', default_clearance)), min_lenght=configuration.get('silk_line_lenght_min', 0)/2) if silk_point_top_right: kicad_mod.append( Line(start=[ -silk_point_top_right.x, -silk_point_top_right.y ], end=[ silk_point_top_right.x, -silk_point_top_right.y ], layer='F.SilkS', width=silk_line_width)) kicad_mod.append( Line(start=[ -silk_point_top_right.x, silk_point_top_right.y ], end=silk_point_top_right, layer='F.SilkS', width=silk_line_width)) CrtYd_rect = [None, None] CrtYd_rect[0] = roundToBase(2 * abs(pad_details['at'][0]) + \ pad_details['size'][0] + 2 * ipc_data_set['courtyard'], 0.02) if pad_details['size'][1] > outline_size[1]: CrtYd_rect[1] = pad_details['size'][ 1] + 2 * ipc_data_set['courtyard'] else: CrtYd_rect[ 1] = outline_size[1] + 2 * ipc_data_set['courtyard'] CrtYd_rect[1] = roundToBase(CrtYd_rect[1], 0.02) kicad_mod.append( RectLine(start=[-CrtYd_rect[0] / 2, CrtYd_rect[1] / 2], end=[CrtYd_rect[0] / 2, -CrtYd_rect[1] / 2], layer='F.CrtYd', width=self.configuration['courtyard_line_width'])) ######################### Text Fields ############################### addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges={ 'left': -outline_size[0] / 2, 'right': outline_size[0] / 2, 'top': -outline_size[1] / 2, 'bottom': outline_size[1] / 2 }, courtyard={ 'top': -CrtYd_rect[1] / 2, 'bottom': CrtYd_rect[1] / 2 }, fp_name=fp_name, text_y_inside_position='center') kicad_mod.append(Model(filename=model_name)) output_dir = '{lib_name:s}.pretty/'.format( lib_name=footprint_group_data['fp_lib_name']) if not os.path.isdir( output_dir ): #returns false if path does not yet exist!! (Does not check path validity) os.makedirs(output_dir) filename = '{outdir:s}{fp_name:s}.kicad_mod'.format( outdir=output_dir, fp_name=fp_name) file_handler = KicadFileHandler(kicad_mod) file_handler.writeFile(filename)
def generateFootprint(config, fp_params, fp_id): print('Building footprint for parameter set: {}'.format(fp_id)) pkgWidth = fp_params["pkg_width"] pkgHeight = fp_params["pkg_height"] layoutX = fp_params["layout_x"] layoutY = fp_params["layout_y"] if "row_names" in fp_params: rowNames = fp_params["row_names"] else: rowNames = config['row_names'] if "row_skips" in fp_params: rowSkips = fp_params["row_skips"] else: rowSkips = [] # must be given pitch (equal in X and Y) or a unique pitch in both X and Y if "pitch" in fp_params: if "pitch_x" and "pitch_y" in fp_params: raise KeyError('{}: Either pitch or both pitch_x and pitch_y must be given.'.format(fp_id)) else: pitch_string = str(fp_params["pitch"]) pitch_x = fp_params["pitch"] pitch_y = fp_params["pitch"] else: if "pitch_x" and "pitch_y" in fp_params: pitch_string = str(fp_params["pitch_x"]) + "x" + str(fp_params["pitch_y"]) pitch_x = fp_params["pitch_x"] pitch_y = fp_params["pitch_y"] else: raise KeyError('{}: Either pitch or both pitch_x and pitch_y must be given.'.format(fp_id)) f = Footprint(fp_id) f.setDescription(fp_params["description"]) f.setAttribute("smd") if "mask_margin" in fp_params: f.setMaskMargin(fp_params["mask_margin"]) if "paste_margin" in fp_params: f.setPasteMargin(fp_params["paste_margin"]) if "paste_ratio" in fp_params: f.setPasteMarginRatio(fp_params["paste_ratio"]) s1 = [1.0, 1.0] s2 = [min(1.0, round(pkgWidth / 4.3, 2))] * 2 t1 = 0.15 * s1[0] t2 = 0.15 * s2[0] padShape = Pad.SHAPE_CIRCLE if "pad_shape" in fp_params: if fp_params["pad_shape"] == "rect": padShape = Pad.SHAPE_RECT if fp_params["pad_shape"] == "roundrect": padShape = Pad.SHAPE_ROUNDRECT chamfer = min(config['fab_bevel_size_absolute'], min(pkgWidth, pkgHeight) * config['fab_bevel_size_relative']) silkOffset = config['silk_fab_offset'] crtYdOffset = config['courtyard_offset']['bga'] def crtYdRound(x): # Round away from zero for proper courtyard calculation neg = x < 0 if neg: x = -x x = math.ceil(x * 100) / 100.0 if neg: x = -x return x xCenter = 0.0 xLeftFab = xCenter - pkgWidth / 2.0 xRightFab = xCenter + pkgWidth / 2.0 xChamferFab = xLeftFab + chamfer xPadLeft = xCenter - pitch_x * ((layoutX - 1) / 2.0) xPadRight = xCenter + pitch_x * ((layoutX - 1) / 2.0) xLeftCrtYd = crtYdRound(xCenter - (pkgWidth / 2.0 + crtYdOffset)) xRightCrtYd = crtYdRound(xCenter + (pkgWidth / 2.0 + crtYdOffset)) yCenter = 0.0 yTopFab = yCenter - pkgHeight / 2.0 yBottomFab = yCenter + pkgHeight / 2.0 yChamferFab = yTopFab + chamfer yPadTop = yCenter - pitch_y * ((layoutY - 1) / 2.0) yPadBottom = yCenter + pitch_y * ((layoutY - 1) / 2.0) yTopCrtYd = crtYdRound(yCenter - (pkgHeight / 2.0 + crtYdOffset)) yBottomCrtYd = crtYdRound(yCenter + (pkgHeight / 2.0 + crtYdOffset)) yRef = yTopFab - 1.0 yValue = yBottomFab + 1.0 xLeftSilk = xLeftFab - silkOffset xRightSilk = xRightFab + silkOffset xChamferSilk = xLeftSilk + chamfer yTopSilk = yTopFab - silkOffset yBottomSilk = yBottomFab + silkOffset yChamferSilk = yTopSilk + chamfer wFab = configuration['fab_line_width'] wCrtYd = configuration['courtyard_line_width'] wSilkS = configuration['silk_line_width'] # Text f.append(Text(type="reference", text="REF**", at=[xCenter, yRef], layer="F.SilkS", size=s1, thickness=t1)) f.append(Text(type="value", text=fp_id, at=[xCenter, yValue], layer="F.Fab", size=s1, thickness=t1)) f.append(Text(type="user", text="%R", at=[xCenter, yCenter], layer="F.Fab", size=s2, thickness=t2)) # Fab f.append(PolygoneLine(polygone=[[xRightFab, yBottomFab], [xLeftFab, yBottomFab], [xLeftFab, yChamferFab], [xChamferFab, yTopFab], [xRightFab, yTopFab], [xRightFab, yBottomFab]], layer="F.Fab", width=wFab)) # Courtyard f.append(RectLine(start=[xLeftCrtYd, yTopCrtYd], end=[xRightCrtYd, yBottomCrtYd], layer="F.CrtYd", width=wCrtYd)) # Silk f.append(PolygoneLine(polygone=[[xChamferSilk, yTopSilk], [xRightSilk, yTopSilk], [xRightSilk, yBottomSilk], [xLeftSilk, yBottomSilk], [xLeftSilk, yChamferSilk]], layer="F.SilkS", width=wSilkS)) # Pads balls = layoutX * layoutY if rowSkips == []: for _ in range(layoutY): rowSkips.append([]) for rowNum, row in zip(range(layoutY), rowNames): rowSet = set(range(1, layoutX + 1)) for item in rowSkips[rowNum]: try: # If item is a range, remove that range rowSet -= set(range(*item)) balls -= item[1] - item[0] except TypeError: # If item is an int, remove that int rowSet -= {item} balls -= 1 for col in rowSet: f.append(Pad(number="{}{}".format(row, col), type=Pad.TYPE_SMT, shape=padShape, at=[xPadLeft + (col-1) * pitch_x, yPadTop + rowNum * pitch_y], size=[fp_params["pad_diameter"], fp_params["pad_diameter"]], layers=Pad.LAYERS_SMT, radius_ratio=config['round_rect_radius_ratio'])) # If this looks like a CSP footprint, use the CSP 3dshapes library package_type = 'CSP' if 'BGA' not in fp_id and 'CSP' in fp_id else 'BGA' f.append(Model(filename="{}Package_{}.3dshapes/{}.wrl".format( config['3d_model_prefix'], package_type, fp_id))) f.setTags("{} {} {}".format(package_type, balls, pitch_string)) output_dir = 'Package_{lib_name:s}.pretty/'.format(lib_name=package_type) if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity) os.makedirs(output_dir) filename = '{outdir:s}{fp_id:s}.kicad_mod'.format(outdir=output_dir, fp_id=fp_id) file_handler = KicadFileHandler(f) file_handler.writeFile(filename)
def create_footprint(name, **kwargs): kicad_mod = Footprint(name) # init kicad footprint kicad_mod.setDescription(kwargs['description']) kicad_mod.setTags('Capacitor Electrolytic') kicad_mod.setAttribute('smd') # set general values text_offset_y = kwargs['width'] / 2. + kwargs['courtjard'] + 0.8 kicad_mod.append( Text(type='reference', text='REF**', at=[0, -text_offset_y], layer='F.SilkS')) kicad_mod.append( Text(type='value', text=name, at=[0, text_offset_y], layer='F.Fab')) # create fabrication layer fab_x = kwargs['length'] / 2. fab_y = kwargs['width'] / 2. fab_edge = 1 fab_x_edge = fab_x - fab_edge fab_y_edge = fab_y - fab_edge kicad_mod.append( Line(start=[fab_x, -fab_y], end=[fab_x, fab_y], layer='F.Fab')) kicad_mod.append( Line(start=[-fab_x_edge, -fab_y], end=[fab_x, -fab_y], layer='F.Fab')) kicad_mod.append( Line(start=[-fab_x_edge, fab_y], end=[fab_x, fab_y], layer='F.Fab')) kicad_mod.append( Line(start=[-fab_x, -fab_y_edge], end=[-fab_x, fab_y_edge], layer='F.Fab')) kicad_mod.append( Line(start=[-fab_x, -fab_y_edge], end=[-fab_x_edge, -fab_y], layer='F.Fab')) kicad_mod.append( Line(start=[-fab_x, fab_y_edge], end=[-fab_x_edge, fab_y], layer='F.Fab')) fab_text_x = kwargs['pad_spacing'] / 2. + kwargs['pad_length'] / 4. kicad_mod.append( Text(type='user', text='+', at=[-fab_text_x, 0], layer='F.Fab')) # create silkscreen silk_x = kwargs['length'] / 2. + 0.11 silk_y = kwargs['width'] / 2. + 0.11 silk_y_start = kwargs['pad_width'] / 2. + 0.3 silk_x_edge = fab_x - fab_edge + 0.05 silk_y_edge = fab_y - fab_edge + 0.05 kicad_mod.append( Line(start=[silk_x, silk_y], end=[silk_x, silk_y_start], layer='F.SilkS')) kicad_mod.append( Line(start=[silk_x, -silk_y], end=[silk_x, -silk_y_start], layer='F.SilkS')) kicad_mod.append( Line(start=[-silk_x_edge, -silk_y], end=[silk_x, -silk_y], layer='F.SilkS')) kicad_mod.append( Line(start=[-silk_x_edge, silk_y], end=[silk_x, silk_y], layer='F.SilkS')) if silk_y_edge > silk_y_start: kicad_mod.append( Line(start=[-silk_x, silk_y_edge], end=[-silk_x, silk_y_start], layer='F.SilkS')) kicad_mod.append( Line(start=[-silk_x, -silk_y_edge], end=[-silk_x, -silk_y_start], layer='F.SilkS')) kicad_mod.append( Line(start=[-silk_x, -silk_y_edge], end=[-silk_x_edge, -silk_y], layer='F.SilkS')) kicad_mod.append( Line(start=[-silk_x, silk_y_edge], end=[-silk_x_edge, silk_y], layer='F.SilkS')) else: silk_x_cut = silk_x - ( silk_y_start - silk_y_edge ) # because of the 45 degree edge we can user a simple apporach silk_y_edge_cut = silk_y_start kicad_mod.append( Line(start=[-silk_x_cut, -silk_y_edge_cut], end=[-silk_x_edge, -silk_y], layer='F.SilkS')) kicad_mod.append( Line(start=[-silk_x_cut, silk_y_edge_cut], end=[-silk_x_edge, silk_y], layer='F.SilkS')) silk_cane_x_start = math.cos( math.asin(silk_y_start / (kwargs['diameter'] / 2.))) * (kwargs['diameter'] / 2.) silk_cane_angle = 180 - math.acos( 2 * (silk_cane_x_start / kwargs['diameter'])) * 360. / math.pi # TODO 180 kicad_mod.append( Arc(center=[0, 0], start=[-silk_cane_x_start, -silk_y_start], angle=silk_cane_angle, layer='F.SilkS')) kicad_mod.append( Arc(center=[0, 0], start=[silk_cane_x_start, silk_y_start], angle=silk_cane_angle, layer='F.SilkS')) # create courtyard courtjard_x = kwargs['pad_spacing'] / 2. + kwargs['pad_length'] + kwargs[ 'courtjard'] courtjard_y = kwargs['width'] / 2. + kwargs['courtjard'] kicad_mod.append( RectLine(start=[courtjard_x, courtjard_y], end=[-courtjard_x, -courtjard_y], layer='F.CrtYd')) # '+' sign on silkscreen silk_text_x = courtjard_x - 0.6 silk_text_y = courtjard_y - 0.6 kicad_mod.append( Text(type='user', text='+', at=[-silk_text_x, silk_text_y], layer='F.SilkS')) # all pads have this kwargs, so we only write them once pad_kwargs = { 'type': Pad.TYPE_SMT, 'shape': Pad.SHAPE_RECT, 'layers': ['F.Cu', 'F.Mask', 'F.Paste'] } # create pads x_pad_spacing = kwargs['pad_spacing'] / 2. + kwargs['pad_length'] / 2. kicad_mod.append( Pad(number=1, at=[-x_pad_spacing, 0], size=[kwargs['pad_length'], kwargs['pad_width']], **pad_kwargs)) kicad_mod.append( Pad(number=2, at=[x_pad_spacing, 0], size=[kwargs['pad_length'], kwargs['pad_width']], **pad_kwargs)) # add model kicad_mod.append( Model(filename="example.3dshapes/{name}.wrl".format(name=name), at=[0, 0, 0], scale=[1, 1, 1], rotate=[0, 0, 0])) # write file file_handler = KicadFileHandler(kicad_mod) file_handler.writeFile('{name}.kicad_mod'.format(name=name))
def create_footprint(name, configuration, **kwargs): kicad_mod = Footprint(name) # init kicad footprint datasheet = ", " + kwargs['datasheet'] if 'datasheet' in kwargs else "" description = "SMD capacitor, aluminum electrolytic" tags = 'capacitor electrolytic' if name[:2] == "C_": description += " nonpolar" tags += " nonpolar" if 'extra_description' in kwargs: description += ", " + kwargs['extra_description'] # ensure all provided dimensions are fully toleranced device_dimensions = { 'body_length': TolerancedSize.fromYaml(kwargs, base_name='body_length'), 'body_width': TolerancedSize.fromYaml(kwargs, base_name='body_width'), 'body_height': TolerancedSize.fromYaml(kwargs, base_name='body_height'), 'body_diameter': TolerancedSize.fromYaml(kwargs, base_name='body_diameter') } # for ease of use, capture nominal body and pad sizes body_size = { 'length': device_dimensions['body_length'].nominal, 'width': device_dimensions['body_width'].nominal, 'height': device_dimensions['body_height'].nominal, 'diameter': device_dimensions['body_diameter'].nominal } description += ", " + str(body_size['diameter']) + "x" + str( body_size['height']) + "mm" kicad_mod.setDescription(description + datasheet) kicad_mod.setTags(tags) kicad_mod.setAttribute('smd') # set general values text_offset_y = body_size['width'] / 2.0 + configuration[ 'courtyard_offset']['default'] + 0.8 #silkscreen REF** silk_text_size = configuration['references'][0]['size'] silk_text_thickness = silk_text_size[0] * configuration['references'][0][ 'fontwidth'] kicad_mod.append( Text(type='reference', text='REF**', at=[0, -text_offset_y], layer='F.SilkS', size=[silk_text_size[0], silk_text_size[1]], thickness=silk_text_thickness)) #fab value fab_text_size = configuration['values'][0]['size'] fab_text_thickness = fab_text_size[0] * configuration['values'][0][ 'fontwidth'] kicad_mod.append( Text(type='value', text=name, at=[0, text_offset_y], layer='F.Fab', size=[fab_text_size[0], fab_text_size[1]], thickness=fab_text_thickness)) #fab REF** fab_text_size = body_size['diameter'] / 5.0 fab_text_size = min(fab_text_size, configuration['references'][1]['size_max'][0]) fab_text_size = max(fab_text_size, configuration['references'][1]['size_min'][0]) fab_text_thickness = fab_text_size * configuration['references'][1][ 'thickness_factor'] kicad_mod.append( Text(type='user', text='%R', at=[0, 0], layer='F.Fab', size=[fab_text_size, fab_text_size], thickness=fab_text_thickness)) # create pads # all pads have these properties pad_params = { 'type': Pad.TYPE_SMT, 'layers': Pad.LAYERS_SMT, 'shape': Pad.SHAPE_RECT } # prefer IPC-7351C compliant rounded rectangle pads if not configuration['force_rectangle_pads']: pad_params['shape'] = Pad.SHAPE_ROUNDRECT pad_params['radius_ratio'] = 0.25 pad_params['maximum_radius'] = 0.25 # prefer calculating pads from lead dimensions per IPC # fall back to using pad sizes directly if necessary if ('lead_length' in kwargs) and ('lead_width' in kwargs) and ('lead_spacing' in kwargs): # gather IPC data (unique parameters for >= 10mm tall caps) ipc_density_suffix = '' if body_size['height'] < 10 else '_10mm' ipc_density = configuration['ipc_density'] ipc_data = ipc_defintions['ipc_spec_capae_crystal'][ipc_density + ipc_density_suffix] ipc_round_base = ipc_defintions['ipc_spec_capae_crystal']['round_base'] manf_tol = { 'F': configuration.get('manufacturing_tolerance', 0.1), 'P': configuration.get('placement_tolerance', 0.05) } # # fully tolerance lead dimensions; leads are dimensioned like SOIC so use gullwing calculator device_dimensions['lead_width'] = TolerancedSize.fromYaml( kwargs, base_name='lead_width') device_dimensions['lead_spacing'] = TolerancedSize.fromYaml( kwargs, base_name='lead_spacing') device_dimensions['lead_length'] = TolerancedSize.fromYaml( kwargs, base_name='lead_length') device_dimensions['lead_outside'] = TolerancedSize( maximum=device_dimensions['lead_spacing'].maximum + device_dimensions.get('lead_length').maximum * 2, minimum=device_dimensions['lead_spacing'].minimum + device_dimensions.get('lead_length').minimum * 2) Gmin, Zmax, Xmax = ipc_gull_wing( ipc_data, ipc_round_base, manf_tol, device_dimensions['lead_width'], device_dimensions['lead_outside'], lead_len=device_dimensions.get('lead_length')) pad_params['size'] = [(Zmax - Gmin) / 2.0, Xmax] x_pad_spacing = (Zmax + Gmin) / 4.0 elif ('pad_length' in kwargs) and ('pad_width' in kwargs) and ('pad_spacing' in kwargs): x_pad_spacing = kwargs['pad_spacing'] / 2.0 + kwargs['pad_length'] / 2.0 pad_params['size'] = [kwargs['pad_length'], kwargs['pad_width']] else: raise KeyError( "Provide all three 'pad' or 'lead' properties ('_spacing', '_length', and '_width')" ) kicad_mod.append(Pad(number=1, at=[-x_pad_spacing, 0], **pad_params)) kicad_mod.append(Pad(number=2, at=[x_pad_spacing, 0], **pad_params)) # create fabrication layer fab_x = body_size['length'] / 2.0 fab_y = body_size['width'] / 2.0 if kwargs['pin1_chamfer'] == 'auto': fab_edge = min(fab_x / 2.0, fab_y / 2.0, configuration['fab_pin1_marker_length']) else: fab_edge = kwargs['pin1_chamfer'] fab_x_edge = fab_x - fab_edge fab_y_edge = fab_y - fab_edge kicad_mod.append( Line(start=[fab_x, -fab_y], end=[fab_x, fab_y], layer='F.Fab', width=configuration['fab_line_width'])) kicad_mod.append( Line(start=[-fab_x_edge, -fab_y], end=[fab_x, -fab_y], layer='F.Fab', width=configuration['fab_line_width'])) kicad_mod.append( Line(start=[-fab_x_edge, fab_y], end=[fab_x, fab_y], layer='F.Fab', width=configuration['fab_line_width'])) if fab_edge > 0: kicad_mod.append( Line(start=[-fab_x, -fab_y_edge], end=[-fab_x, fab_y_edge], layer='F.Fab', width=configuration['fab_line_width'])) kicad_mod.append( Line(start=[-fab_x, -fab_y_edge], end=[-fab_x_edge, -fab_y], layer='F.Fab', width=configuration['fab_line_width'])) kicad_mod.append( Line(start=[-fab_x, fab_y_edge], end=[-fab_x_edge, fab_y], layer='F.Fab', width=configuration['fab_line_width'])) kicad_mod.append( Circle(center=[0, 0], radius=body_size['diameter'] / 2.0, layer='F.Fab', width=configuration['fab_line_width'])) #fab polarity marker for polarized caps if name[:2].upper() == "CP": fab_pol_size = body_size['diameter'] / 10.0 fab_pol_wing = fab_pol_size / 2.0 fab_pol_distance = body_size[ 'diameter'] / 2.0 - fab_pol_wing - configuration['fab_line_width'] fab_pol_pos_y = fab_text_size / 2.0 + configuration[ 'silk_pad_clearance'] + fab_pol_size fab_pol_pos_x = math.sqrt(fab_pol_distance * fab_pol_distance - fab_pol_pos_y * fab_pol_pos_y) fab_pol_pos_x = -fab_pol_pos_x fab_pol_pos_y = -fab_pol_pos_y kicad_mod.append( Line(start=[fab_pol_pos_x - fab_pol_wing, fab_pol_pos_y], end=[fab_pol_pos_x + fab_pol_wing, fab_pol_pos_y], layer='F.Fab', width=configuration['fab_line_width'])) kicad_mod.append( Line(start=[fab_pol_pos_x, fab_pol_pos_y - fab_pol_wing], end=[fab_pol_pos_x, fab_pol_pos_y + fab_pol_wing], layer='F.Fab', width=configuration['fab_line_width'])) # create silkscreen fab_to_silk_offset = configuration['silk_fab_offset'] silk_x = body_size['length'] / 2.0 + fab_to_silk_offset silk_y = body_size['width'] / 2.0 + fab_to_silk_offset silk_y_start = pad_params['size'][1] / 2.0 + configuration[ 'silk_pad_clearance'] + configuration['silk_line_width'] / 2.0 silk_45deg_offset = fab_to_silk_offset * math.tan(math.radians(22.5)) silk_x_edge = fab_x - fab_edge + silk_45deg_offset silk_y_edge = fab_y - fab_edge + silk_45deg_offset kicad_mod.append( Line(start=[silk_x, silk_y], end=[silk_x, silk_y_start], layer='F.SilkS', width=configuration['silk_line_width'])) kicad_mod.append( Line(start=[silk_x, -silk_y], end=[silk_x, -silk_y_start], layer='F.SilkS', width=configuration['silk_line_width'])) kicad_mod.append( Line(start=[-silk_x_edge, -silk_y], end=[silk_x, -silk_y], layer='F.SilkS', width=configuration['silk_line_width'])) kicad_mod.append( Line(start=[-silk_x_edge, silk_y], end=[silk_x, silk_y], layer='F.SilkS', width=configuration['silk_line_width'])) if silk_y_edge > silk_y_start: kicad_mod.append( Line(start=[-silk_x, silk_y_edge], end=[-silk_x, silk_y_start], layer='F.SilkS', width=configuration['silk_line_width'])) kicad_mod.append( Line(start=[-silk_x, -silk_y_edge], end=[-silk_x, -silk_y_start], layer='F.SilkS', width=configuration['silk_line_width'])) kicad_mod.append( Line(start=[-silk_x, -silk_y_edge], end=[-silk_x_edge, -silk_y], layer='F.SilkS', width=configuration['silk_line_width'])) kicad_mod.append( Line(start=[-silk_x, silk_y_edge], end=[-silk_x_edge, silk_y], layer='F.SilkS', width=configuration['silk_line_width'])) else: silk_x_cut = silk_x - ( silk_y_start - silk_y_edge ) # because of the 45 degree edge we can user a simple apporach silk_y_edge_cut = silk_y_start kicad_mod.append( Line(start=[-silk_x_cut, -silk_y_edge_cut], end=[-silk_x_edge, -silk_y], layer='F.SilkS', width=configuration['silk_line_width'])) kicad_mod.append( Line(start=[-silk_x_cut, silk_y_edge_cut], end=[-silk_x_edge, silk_y], layer='F.SilkS', width=configuration['silk_line_width'])) #silk polarity marker if name[:2].upper() == "CP": silk_pol_size = body_size['diameter'] / 8.0 silk_pol_wing = silk_pol_size / 2.0 silk_pol_pos_y = silk_y_start + silk_pol_size silk_pol_pos_x = silk_x + silk_pol_wing + configuration[ 'silk_line_width'] * 2 silk_pol_pos_x = -silk_pol_pos_x silk_pol_pos_y = -silk_pol_pos_y kicad_mod.append( Line(start=[silk_pol_pos_x - silk_pol_wing, silk_pol_pos_y], end=[silk_pol_pos_x + silk_pol_wing, silk_pol_pos_y], layer='F.SilkS', width=configuration['silk_line_width'])) kicad_mod.append( Line(start=[silk_pol_pos_x, silk_pol_pos_y - silk_pol_wing], end=[silk_pol_pos_x, silk_pol_pos_y + silk_pol_wing], layer='F.SilkS', width=configuration['silk_line_width'])) # create courtyard courtyard_offset = configuration['courtyard_offset']['default'] courtyard_x = body_size['length'] / 2.0 + courtyard_offset courtyard_y = body_size['width'] / 2.0 + courtyard_offset courtyard_pad_x = x_pad_spacing + pad_params['size'][ 0] / 2.0 + courtyard_offset courtyard_pad_y = pad_params['size'][1] / 2.0 + courtyard_offset courtyard_45deg_offset = courtyard_offset * math.tan(math.radians(22.5)) courtyard_x_edge = fab_x - fab_edge + courtyard_45deg_offset courtyard_y_edge = fab_y - fab_edge + courtyard_45deg_offset courtyard_x_lower_edge = courtyard_x if courtyard_y_edge < courtyard_pad_y: courtyard_x_lower_edge = courtyard_x_lower_edge - courtyard_pad_y + courtyard_y_edge courtyard_y_edge = courtyard_pad_y #rounding courtyard_x = float(format(courtyard_x, ".2f")) courtyard_y = float(format(courtyard_y, ".2f")) courtyard_pad_x = float(format(courtyard_pad_x, ".2f")) courtyard_pad_y = float(format(courtyard_pad_y, ".2f")) courtyard_x_edge = float(format(courtyard_x_edge, ".2f")) courtyard_y_edge = float(format(courtyard_y_edge, ".2f")) courtyard_x_lower_edge = float(format(courtyard_x_lower_edge, ".2f")) # drawing courtyard kicad_mod.append( Line(start=[courtyard_x, -courtyard_y], end=[courtyard_x, -courtyard_pad_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[courtyard_x, -courtyard_pad_y], end=[courtyard_pad_x, -courtyard_pad_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[courtyard_pad_x, -courtyard_pad_y], end=[courtyard_pad_x, courtyard_pad_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[courtyard_pad_x, courtyard_pad_y], end=[courtyard_x, courtyard_pad_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[courtyard_x, courtyard_pad_y], end=[courtyard_x, courtyard_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[-courtyard_x_edge, courtyard_y], end=[courtyard_x, courtyard_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[-courtyard_x_edge, -courtyard_y], end=[courtyard_x, -courtyard_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) if fab_edge > 0: kicad_mod.append( Line(start=[-courtyard_x_lower_edge, courtyard_y_edge], end=[-courtyard_x_edge, courtyard_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[-courtyard_x_lower_edge, -courtyard_y_edge], end=[-courtyard_x_edge, -courtyard_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) if courtyard_y_edge > courtyard_pad_y: kicad_mod.append( Line(start=[-courtyard_x, -courtyard_y_edge], end=[-courtyard_x, -courtyard_pad_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[-courtyard_x, courtyard_pad_y], end=[-courtyard_x, courtyard_y_edge], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[-courtyard_x_lower_edge, -courtyard_pad_y], end=[-courtyard_pad_x, -courtyard_pad_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[-courtyard_pad_x, -courtyard_pad_y], end=[-courtyard_pad_x, courtyard_pad_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) kicad_mod.append( Line(start=[-courtyard_pad_x, courtyard_pad_y], end=[-courtyard_x_lower_edge, courtyard_pad_y], layer='F.CrtYd', width=configuration['courtyard_line_width'])) lib_name = 'Capacitor_SMD' # add model modelname = name.replace("_HandSoldering", "") kicad_mod.append( Model(filename="{model_prefix:s}{lib_name:s}.3dshapes/{name:s}.wrl". format(model_prefix=configuration['3d_model_prefix'], lib_name=lib_name, name=modelname), at=[0, 0, 0], scale=[1, 1, 1], rotate=[0, 0, 0])) # write file output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name) if not os.path.isdir( output_dir ): #returns false if path does not yet exist!! (Does not check path validity) os.makedirs(output_dir) filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=name) file_handler = KicadFileHandler(kicad_mod) file_handler.writeFile(filename)
def generateFootprints(self): fab_line_width = self.configuration.get('fab_line_width', 0.1) silk_line_width = self.configuration.get('silk_line_width', 0.12) for group_name in self.footprint_group_definitions: #print(device_group) footprint_group_data = self.footprint_group_definitions[group_name] device_size_docs = footprint_group_data['size_definitions'] package_size_defintions={} for device_size_doc in device_size_docs: with open(size_definition_path+device_size_doc, 'r') as size_stream: try: package_size_defintions.update(yaml.load(size_stream)) except yaml.YAMLError as exc: print(exc) for size_name in package_size_defintions: device_size_data = package_size_defintions[size_name] ipc_reference = footprint_group_data['ipc_reference'] ipc_density = footprint_group_data['ipc_density'] ipc_data_set = self.ipc_defintions[ipc_reference][ipc_density] ipc_round_base = self.ipc_defintions[ipc_reference]['round_base'] pad_details, paste_details = self.calcPadDetails(device_size_data, ipc_data_set, ipc_round_base, footprint_group_data) #print(calc_pad_details()) #print("generate {name}.kicad_mod".format(name=footprint)) suffix = footprint_group_data.get('suffix', '').format(pad_x=pad_details['size'][0], pad_y=pad_details['size'][1]) prefix = footprint_group_data['prefix'] model3d_path_prefix = self.configuration.get('3d_model_prefix','${KISYS3DMOD}') suffix_3d = suffix if footprint_group_data.get('include_suffix_in_3dpath', 'True') == 'True' else "" code_metric = device_size_data.get('code_metric') code_letter = device_size_data.get('code_letter') code_imperial = device_size_data.get('code_imperial') if 'code_letter' in device_size_data: name_format = self.configuration['fp_name_tantal_format_string'] else: if 'code_metric' in device_size_data: name_format = self.configuration['fp_name_format_string'] else: name_format = self.configuration['fp_name_non_metric_format_string'] fp_name = name_format.format(prefix=prefix, code_imperial=code_imperial, code_metric=code_metric, code_letter=code_letter, suffix=suffix) fp_name_2 = name_format.format(prefix=prefix, code_imperial=code_imperial, code_letter=code_letter, code_metric=code_metric, suffix=suffix_3d) model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format( model3d_path_prefix=model3d_path_prefix, lib_name=footprint_group_data['fp_lib_name'], fp_name=fp_name_2) #print(fp_name) #print(pad_details) kicad_mod = Footprint(fp_name) # init kicad footprint kicad_mod.setDescription(footprint_group_data['description'].format(code_imperial=code_imperial, code_metric=code_metric, code_letter=code_letter, size_info=device_size_data.get('size_info'))) kicad_mod.setTags(footprint_group_data['keywords']) kicad_mod.setAttribute('smd') if paste_details is not None: kicad_mod.append(Pad(number= 1, type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, layers=['F.Cu', 'F.Mask'], **pad_details)) pad_details['at'][0] *= (-1) kicad_mod.append(Pad(number= 2, type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, layers=['F.Cu', 'F.Mask'], **pad_details)) kicad_mod.append(Pad(number= '', type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, layers=['F.Paste'], **paste_details)) paste_details['at'][0] *= (-1) kicad_mod.append(Pad(number= '', type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, layers=['F.Paste'], **paste_details)) else: kicad_mod.append(Pad(number= 1, type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, layers=Pad.LAYERS_SMT, **pad_details)) pad_details['at'][0] *= (-1) kicad_mod.append(Pad(number= 2, type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, layers=Pad.LAYERS_SMT, **pad_details)) fab_outline = self.configuration.get('fab_outline', 'typical') if fab_outline == 'max': outline_size = [device_size_data['body_length_max'], device_size_data['body_width_max']] elif fab_outline == 'min': outline_size = [device_size_data['body_length_min'], device_size_data['body_width_min']] else: outline_size = [device_size_data['body_length'], device_size_data['body_width']] if footprint_group_data.get('polarization_mark', 'False') == 'True': polararity_marker_size = self.configuration.get('fab_polarity_factor', 0.25) polararity_marker_size *= (outline_size[1] if outline_size[1] < outline_size[0] else outline_size[0]) polarity_marker_thick_line = False polarity_max_size = self.configuration.get('fab_polarity_max_size', 1) if polararity_marker_size > polarity_max_size: polararity_marker_size = polarity_max_size polarity_min_size = self.configuration.get('fab_polarity_min_size', 0.25) if polararity_marker_size < polarity_min_size: if polararity_marker_size < polarity_min_size*0.6: polarity_marker_thick_line = True polararity_marker_size = polarity_min_size silk_x_left = -abs(pad_details['at'][0]) - pad_details['size'][0]/2 - \ self.configuration['pad_silk_clearance'] - silk_line_width/2 silk_y_bottom = self.configuration['pad_silk_clearance'] + silk_line_width/2 + \ (outline_size[1] if outline_size[1]> pad_details['size'][1] else pad_details['size'][1])/2 if polarity_marker_thick_line: kicad_mod.append(RectLine(start=[-outline_size[0]/2, outline_size[1]/2], end=[outline_size[0]/2, -outline_size[1]/2], layer='F.Fab', width=fab_line_width)) x = -outline_size[0]/2 + fab_line_width kicad_mod.append(Line(start=[x, outline_size[1]/2], end=[x, -outline_size[1]/2], layer='F.Fab', width=fab_line_width)) x += fab_line_width if x < -fab_line_width/2: kicad_mod.append(Line(start=[x, outline_size[1]/2], end=[x, -outline_size[1]/2], layer='F.Fab', width=fab_line_width)) kicad_mod.append(Circle(center=[silk_x_left-0.05, 0], radius=0.05, layer="F.SilkS", width=0.1)) else: poly_fab= [ {'x':outline_size[0]/2,'y':-outline_size[1]/2}, {'x':polararity_marker_size - outline_size[0]/2,'y':-outline_size[1]/2}, {'x':-outline_size[0]/2,'y':polararity_marker_size-outline_size[1]/2}, {'x':-outline_size[0]/2,'y':outline_size[1]/2}, {'x':outline_size[0]/2,'y':outline_size[1]/2}, {'x':outline_size[0]/2,'y':-outline_size[1]/2} ] kicad_mod.append(PolygoneLine(polygone=poly_fab, layer='F.Fab', width=fab_line_width)) poly_silk = [ {'x':outline_size[0]/2,'y':-silk_y_bottom}, {'x':silk_x_left,'y':-silk_y_bottom}, {'x':silk_x_left,'y':silk_y_bottom}, {'x':outline_size[0]/2,'y':silk_y_bottom} ] kicad_mod.append(PolygoneLine(polygone=poly_silk, layer='F.SilkS', width=silk_line_width)) else: kicad_mod.append(RectLine(start=[-outline_size[0]/2, outline_size[1]/2], end=[outline_size[0]/2, -outline_size[1]/2], layer='F.Fab', width=fab_line_width)) pad_spacing = 2*abs(pad_details['at'][0])-pad_details['size'][0] if pad_spacing > 2*self.configuration['pad_silk_clearance'] + \ self.configuration['silk_line_lenght_min'] + self.configuration['silk_line_width']: silk_outline_x = pad_spacing/2 - silk_line_width - self.configuration['pad_silk_clearance'] silk_outline_y = outline_size[1]/2 + self.configuration['silk_fab_offset'] kicad_mod.append(Line(start=[-silk_outline_x, -silk_outline_y], end=[silk_outline_x, -silk_outline_y], layer='F.SilkS', width=silk_line_width)) kicad_mod.append(Line(start=[-silk_outline_x, silk_outline_y], end=[silk_outline_x, silk_outline_y], layer='F.SilkS', width=silk_line_width)) CrtYd_rect = [None,None] CrtYd_rect[0] = roundToBase(2 * abs(pad_details['at'][0]) + \ pad_details['size'][0] + 2 * ipc_data_set['courtyard'], 0.02) if pad_details['size'][1] > outline_size[1]: CrtYd_rect[1] = pad_details['size'][1] + 2 * ipc_data_set['courtyard'] else: CrtYd_rect[1] = outline_size[1] + 2 * ipc_data_set['courtyard'] CrtYd_rect[1] = roundToBase(CrtYd_rect[1], 0.02) kicad_mod.append(RectLine(start=[-CrtYd_rect[0]/2, CrtYd_rect[1]/2], end=[CrtYd_rect[0]/2, -CrtYd_rect[1]/2], layer='F.CrtYd', width=self.configuration['courtyard_line_width'])) reference_fields = self.configuration['references'] kicad_mod.append(Text(type='reference', text='REF**', **self.getTextFieldDetails(reference_fields[0], outline_size))) for additional_ref in reference_fields[1:]: kicad_mod.append(Text(type='user', text='%R', **self.getTextFieldDetails(additional_ref, outline_size))) value_fields = self.configuration['values'] kicad_mod.append(Text(type='value', text=fp_name, **self.getTextFieldDetails(value_fields[0], outline_size))) for additional_value in value_fields[1:]: kicad_mod.append(Text(type='user', text='%V', **self.getTextFieldDetails(additional_value, outline_size))) kicad_mod.append(Model(filename=model_name)) output_dir = '{lib_name:s}.pretty/'.format(lib_name=footprint_group_data['fp_lib_name']) if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity) os.makedirs(output_dir) filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=fp_name) file_handler = KicadFileHandler(kicad_mod) file_handler.writeFile(filename)