def test_bounds_all_elts(self): '''bounds() with all the elements competing''' net = Net('foo') mkbounds(net, 3, 3, -1, -2) self.des.add_net(net) annot = Annotation('foo', 3, 3, 0, True) mkbounds(annot, 3, 3, 3, 5) self.des.design_attributes.add_annotation(annot) libcomp = Component('bar') libcomp.add_symbol(Symbol()) libcomp.symbols[0].add_body(Body()) mkbounds(libcomp.symbols[0].bodies[0], 0, 0, 3, 3) self.des.add_component('foo', libcomp) compinst = ComponentInstance('bar', 'foo', 0) compinst.add_symbol_attribute(SymbolAttribute(3, 0, 0, False)) self.des.add_component_instance(compinst) top_left, btm_right = self.des.bounds() self.assertEqual(top_left.x, -1) self.assertEqual(top_left.y, -2) self.assertEqual(btm_right.x, 6) self.assertEqual(btm_right.y, 5)
def __init__(self, line): parts = line.split() name = parts[1] if name.startswith('~'): name = name[1:] self.component = Component(name) self.component.add_attribute('_prefix', parts[2]) self.num_units = max(int(parts[7]), 1)
def __init__(self, idref): self.component = Component(idref) self.next_pin_number = 0 self.cid2termid = {} # connid -> termid self.termid2pin = {} # termid -> Pin self.terminals = set() self.width = 0.0 self.height = 0.0
def make_component(self, lib, deviceset): """ Construct an openjson component for a deviceset in a library. """ cpt = Component(lib.name + ':' + deviceset.name) for gate in get_subattr(deviceset, 'gates.gate'): symbol = Symbol() cpt.add_symbol(symbol) self.cpt2gate2symbol_index[cpt][gate.name] = len(cpt.symbols) - 1 symbol.add_body(self.make_body_from_symbol(lib, gate.symbol)) return cpt
def parse(self): """ Parses a component from the library, returns a Compenent. """ part = Component(self.filename) part.add_symbol(Symbol()) part.symbols[0].add_body(SBody()) tree = ViewDrawBase.parse(self) for k, v in tree['attr']: part.add_attribute(k, v) for shape in tree['shape'] + sum(tree['lines'], []): part.symbols[0].bodies[0].add_shape(shape) for pin in tree['pin']: part.symbols[0].bodies[0].add_pin(pin) return part
def test_bounds_parts(self): '''test bounds() with just components in the design''' libcomp = Component('bar') libcomp.add_symbol(Symbol()) libcomp.symbols[0].add_body(Body()) mkbounds(libcomp.symbols[0].bodies[0], 0, 0, 10, 10) self.des.add_component('foo', libcomp) for (x, y) in ((1, 3), (3, 2), (5, 3), (3, 7)): compinst = ComponentInstance(str((x, y)), 'foo', 0) compinst.add_symbol_attribute(SymbolAttribute(x, y, 0, False)) self.des.add_component_instance(compinst) top_left, btm_right = self.des.bounds() self.assertEqual(top_left.x, 1) self.assertEqual(top_left.y, 2) self.assertEqual(btm_right.x, 15) self.assertEqual(btm_right.y, 17)
def _convert_library(self, struct): for image in struct.library.image: component = Component(image.image_id) self.design.add_component(image.image_id, component) sym = Symbol() body = Body() component.add_symbol(sym) sym.add_body(body) for pin in image.pin: body.add_pin(Pin(pin.pin_id, self.to_pixels(pin.vertex), self.to_pixels(pin.vertex))) for padstack in struct.library.padstack: if padstack.padstack_id == pin.padstack_id: shapes = [shape.shape for shape in padstack.shape] for shape in self._convert_shapes(shapes, self.to_pixels(pin.vertex)): body.add_shape(shape) break for outline in image.outline: for shape in self._convert_shapes([outline.shape]): body.add_shape(shape)
def _convert_library(self, struct): """ Convert library """ for image in struct.library.image: component = Component(image.image_id) self.design.add_component(image.image_id, component) fpt = Footprint() body = FBody() component.add_footprint(fpt) fpt.add_body(body) for pad in image.pin: body.add_pad(Pad(pad.pad_id, self.to_pixels(pad.vertex), self.to_pixels(pad.vertex))) for padstack in struct.library.padstack: if padstack.padstack_id == pad.padstack_id: shapes = [shape.shape for shape in padstack.shape] for shape in self._convert_shapes(shapes, self.to_pixels(pad.vertex)): body.add_shape(shape) break for outline in image.outline: for shape in self._convert_shapes([outline.shape]): body.add_shape(shape)
def parse_components(self, components): """ Extract a component library. """ for library_id, component in components.items(): name = component.get('name') comp = Component(name) # Get attributes for key, value in component.get('attributes', []).items(): comp.add_attribute(key, value) for symbol_json in component.get('symbols', []): symbol = self.parse_symbol(symbol_json) comp.add_symbol(symbol) for footprint_json in component.get('footprints', []): footprint = self.parse_footprint(footprint_json) comp.add_footprint(footprint) self.design.add_component(library_id, comp)
def _convert_library(self, struct): for image in struct.library.image: component = Component(image.image_id) self.design.add_component(image.image_id, component) sym = Symbol() body = Body() component.add_symbol(sym) sym.add_body(body) for pin in image.pin: body.add_pin( Pin(pin.pin_id, self.to_pixels(pin.vertex), self.to_pixels(pin.vertex))) for padstack in struct.library.padstack: if padstack.padstack_id == pin.padstack_id: shapes = [shape.shape for shape in padstack.shape] for shape in self._convert_shapes( shapes, self.to_pixels(pin.vertex)): body.add_shape(shape) break for outline in image.outline: for shape in self._convert_shapes([outline.shape]): body.add_shape(shape)
def parse_components(self, components): """ Extract a component library. """ for library_id, component in components.items(): name = component.get('name') comp = Component(name) # Get attributes for key, value in component.get('attributes').items(): comp.add_attribute(key, value) for symbol in component.get('symbols'): symb = self.parse_symbol(symbol) comp.add_symbol(symb) self.design.add_component(library_id, comp)
def make_deviceset_component(self, lib, deviceset): """ Construct an openjson component for an eaglexml deviceset in a library.""" cpt = Component(lib.name + ':' + deviceset.name + ':logical') cpt.add_attribute('eaglexml_type', 'logical') cpt.add_attribute('eaglexml_library', lib.name) cpt.add_attribute('eaglexml_deviceset', deviceset.name) symbol = Symbol() cpt.add_symbol(symbol) for i, gate in enumerate(get_subattr(deviceset, 'gates.gate')): body, pin_map, ann_map = self.make_body_from_symbol(lib, gate.symbol) symbol.add_body(body) cpt.add_attribute('eaglexml_symbol_%d' % i, gate.symbol) cpt.add_attribute('eaglexml_gate_%d' % i, gate.name) self.cptgate2body_index[cpt, gate.name] = len(symbol.bodies) - 1 self.cptgate2pin_map[cpt, gate.name] = pin_map self.cptgate2ann_map[cpt, gate.name] = ann_map return cpt
def __init__(self, line): parts = line.split() self.component = Component(parts[1]) self.component.add_attribute('_prefix', parts[2]) self.num_units = max(int(parts[7]), 1)
class ComponentParser(object): """I parse components from Fritzing libraries.""" # The svg files in fritzing libraries are specified in pixels that # are 72dpi. The schematics are in 90dpi. svg_mult = 90.0 / 72.0 def __init__(self, idref): self.component = Component(idref) self.next_pin_number = 0 self.cid2termid = {} # connid -> termid self.termid2pin = {} # termid -> Pin self.terminals = set() self.width = 0.0 self.height = 0.0 def parse_fzp(self, fzp_file): """ Parse the Fritzing component file """ tree = ElementTree(file=fzp_file) try: prefix = tree.find('label').text except AttributeError: pass else: self.component.add_attribute('_prefix', prefix) symbol = Symbol() self.component.add_symbol(symbol) self.body = SBody() symbol.add_body(self.body) self.cid2termid.update(self.parse_terminals(tree)) self.terminals.update(self.cid2termid.values()) layers = tree.find('views/schematicView/layers') if layers is None: self.image = None else: self.image = layers.get('image') def connect_point(self, cid, inst, point): """ Given a connector id, instance id, and a NetPoint, add the appropriate ConnectedComponent to the point """ termid = self.cid2termid.get(cid) pin = self.termid2pin.get(termid) if pin is not None: ccpt = ConnectedComponent(inst.instance_id, pin.pin_number) point.add_connected_component(ccpt) def get_next_pin_number(self): """ Return the next pin number """ nextpn = self.next_pin_number self.next_pin_number += 1 return str(nextpn) def parse_terminals(self, tree): """ Return a dictionary mapping connector id's to terminal id's """ cid2termid = {} for conn in tree.findall('connectors/connector'): plug = conn.find('views/schematicView/p') if plug is None: continue termid = plug.get('terminalId') if termid is None: termid = plug.get('svgId') if termid is not None: cid2termid[conn.get('id')] = termid return cid2termid def parse_svg(self, svg_file): """ Parse the shapes and pins from an svg file """ tree = ElementTree(file=svg_file) viewbox = tree.getroot().get('viewBox') if viewbox != None: self.width, self.height = [float(v) for v in viewbox.split()[-2:]] self.width *= self.svg_mult self.height *= self.svg_mult _iter = tree.getroot().getiterator() for element in _iter: for shape in self.parse_shapes(element): self.body.add_shape(shape) if element.get('id') in self.terminals: pin = get_pin(shape) if pin is not None: pin.pin_number = self.get_next_pin_number() self.termid2pin[element.get('id')] = pin self.body.add_pin(pin) def parse_shapes(self, element): """ Parse a list of shapes from an svg element """ tag = element.tag.rsplit('}', -1)[-1] if tag == 'circle': return self.parse_circle(element) elif tag == 'rect': return self.parse_rect(element) elif tag == 'line': return self.parse_line(element) elif tag == 'path': return self.parse_path(element) elif tag == 'polygon': return self.parse_polygon(element) elif tag == 'polyline': return self.parse_polyline(element) else: return [] def parse_rect(self, rect): """ Parse a rect element """ x, y = (get_x(rect, mult=self.svg_mult), get_y(rect, mult=self.svg_mult)) width, height = (get_length(rect, 'width', self.svg_mult), get_length(rect, 'height', self.svg_mult)) return [Rectangle(x, y, width, height)] def parse_line(self, rect): """ Parse a line element """ return [Line((get_x(rect, 'x1', self.svg_mult), get_y(rect, 'y1', self.svg_mult)), (get_x(rect, 'x2', self.svg_mult), get_y(rect, 'y2', self.svg_mult)))] def parse_path(self, path): """ Parse a path element """ return PathParser(path).parse() def parse_polygon(self, poly): """ Parse a polygon element """ shape = Polygon() for point in poly.get('points', '').split(): if point: x, y = point.split(',') shape.add_point(make_x(x, self.svg_mult), make_y(y, self.svg_mult)) if shape.points: shape.add_point(shape.points[0].x, shape.points[0].y) return [shape] def parse_polyline(self, poly): """ Parse a polyline element """ shapes = [] last_point = None for point in poly.get('points', '').split(): if point: x, y = point.split(',') point = (make_x(x, self.svg_mult), make_y(y, self.svg_mult)) if last_point is not None: shapes.append(Line(last_point, point)) last_point = point return shapes def parse_circle(self, circle): """ Parse a circle element """ return [Circle(get_x(circle, 'cx', self.svg_mult), get_y(circle, 'cy', self.svg_mult), get_length(circle, 'r', self.svg_mult))]
def make_device_component(self, lib, deviceset, device): """ Construct an openjson component for a device in a deviceset. """ cpt = Component(lib.name + ':' + deviceset.name + ':' + device.name) cpt.add_attribute('eaglexml_library', lib.name) cpt.add_attribute('eaglexml_deviceset', deviceset.name) cpt.add_attribute('eaglexml_device', device.name) symbol = Symbol() cpt.add_symbol(symbol) assignment = PinNumberAssignment(device) for i, gate in enumerate(get_subattr(deviceset, 'gates.gate')): body, pin_map, ann_map = self.make_body_from_symbol( lib, gate.symbol, assignment.get_pin_number_lookup(gate.name)) symbol.add_body(body) cpt.add_attribute('eaglexml_symbol_%d' % i, gate.symbol) cpt.add_attribute('eaglexml_gate_%d' % i, gate.name) self.cptgate2body_index[cpt, gate.name] = len(symbol.bodies) - 1 self.cptgate2pin_map[cpt, gate.name] = pin_map self.cptgate2ann_map[cpt, gate.name] = ann_map return cpt
class ComponentParser(object): """I parse components from Fritzing libraries.""" # The svg files in fritzing libraries are specified in pixels that # are 72dpi. The schematics are in 90dpi. svg_mult = 90.0 / 26.0 def __init__(self, idref): self.component = Component(idref) self.next_pin_number = 0 self.cid2termid = {} # connid -> termid self.termid2pin = {} # termid -> Pin self.terminals = set() self.width = 0.0 self.height = 0.0 def parse_fzp(self, fzp_file): """ Parse the Fritzing component file """ tree = ElementTree(file=fzp_file) try: prefix = tree.find('label').text except AttributeError: pass else: self.component.add_attribute('_prefix', prefix) symbol = Symbol() self.component.add_symbol(symbol) self.body = SBody() symbol.add_body(self.body) self.cid2termid.update(self.parse_terminals(tree)) self.terminals.update(self.cid2termid.values()) layers = tree.find('views/schematicView/layers') if layers is None: self.image = None else: self.image = layers.get('image') if self.image == 'schematic/dcpower.svg' : self.image='schematic/dc_powersupply.svg' #print self.image def connect_point(self, cid, inst, point): """ Given a connector id, instance id, and a NetPoint, add the appropriate ConnectedComponent to the point """ termid = self.cid2termid.get(cid) pin = self.termid2pin.get(termid) if pin is not None: ccpt = ConnectedComponent(inst.instance_id, pin.pin_number) point.add_connected_component(ccpt) def get_next_pin_number(self): """ Return the next pin number """ nextpn = self.next_pin_number self.next_pin_number += 1 return str(nextpn) def parse_terminals(self, tree): """ Return a dictionary mapping connector id's to terminal id's """ cid2termid = {} for conn in tree.findall('connectors/connector'): plug = conn.find('views/schematicView/p') if plug is None: continue termid = plug.get('terminalId') if termid is None: termid = plug.get('svgId') if termid is not None: cid2termid[conn.get('id')] = termid return cid2termid def parse_svg(self, svg_file): """ Parse the shapes and pins from an svg file """ tree = ElementTree(file=svg_file) viewbox = tree.getroot().get('viewBox') #self.svg_mult = self.svg_mult*3 if viewbox != None: self.width, self.height = [float(v) for v in viewbox.split()[-2:]] self.width *= self.svg_mult self.height *= self.svg_mult _iter = tree.getroot().getiterator() #print _iter for element in _iter: for shape in self.parse_shapes(element): self.body.add_shape(shape) if element.get('id') in self.terminals: pin = get_pin(shape) if pin is not None: pin.pin_number = self.get_next_pin_number() self.termid2pin[element.get('id')] = pin self.body.add_pin(pin) def parse_shapes(self, element): """ Parse a list of shapes from an svg element """ tag = element.tag.rsplit('}', -1)[-1] #print element if tag == 'circle': return self.parse_circle(element) elif tag == 'rect': return self.parse_rect(element) elif tag == 'line': return self.parse_line(element) elif tag == 'path': return self.parse_path(element) elif tag == 'polygon': return self.parse_polygon(element) elif tag == 'polyline': return self.parse_polyline(element) else: return [] def parse_rect(self, rect): """ Parse a rect element """ x, y = (get_x(rect, mult=self.svg_mult), get_y(rect, mult=self.svg_mult)) width, height = (get_length(rect, 'width', self.svg_mult),get_length(rect, 'height', self.svg_mult)) return [Rectangle(x, y, width, height)] def parse_line(self, rect): """ Parse a line element """ return [Line((get_x(rect, 'x1', self.svg_mult), get_y(rect, 'y1', self.svg_mult)), (get_x(rect, 'x2', self.svg_mult), get_y(rect, 'y2', self.svg_mult)))] def parse_path(self, path): """ Parse a path element """ return PathParser(path).parse() def parse_polygon(self, poly): """ Parse a polygon element """ shape = Polygon() for point in poly.get('points', '').split(): if point: x, y = point.split(',') shape.add_point(make_x(x, self.svg_mult), make_y(y, self.svg_mult)) if shape.points: shape.add_point(shape.points[0].x, shape.points[0].y) return [shape] def parse_polyline(self, poly): """ Parse a polyline element """ shapes = [] last_point = None for point in poly.get('points', '').split(): if point: x, y = point.split(',') point = (make_x(x, self.svg_mult), make_y(y, self.svg_mult)) if last_point is not None: shapes.append(Line(last_point, point)) last_point = point return shapes def parse_circle(self, circle): """ Parse a circle element """ return [Circle(get_x(circle, 'cx', self.svg_mult), get_y(circle, 'cy', self.svg_mult), get_length(circle, 'r', self.svg_mult))]
def test_create_new_component(self): """ Test the creation of a new empty component. """ comp = Component('abc') assert comp.name == 'abc'
def make_deviceset_component(self, lib, deviceset): """ Construct an openjson component for an eaglexml deviceset in a library.""" cpt = Component(lib.name + ':' + deviceset.name + ':logical') cpt.add_attribute('eaglexml_type', 'logical') cpt.add_attribute('eaglexml_library', lib.name) cpt.add_attribute('eaglexml_deviceset', deviceset.name) symbol = Symbol() cpt.add_symbol(symbol) for i, gate in enumerate(get_subattr(deviceset, 'gates.gate')): body, pin_map, ann_map = self.make_body_from_symbol( lib, gate.symbol) symbol.add_body(body) cpt.add_attribute('eaglexml_symbol_%d' % i, gate.symbol) cpt.add_attribute('eaglexml_gate_%d' % i, gate.name) self.cptgate2body_index[cpt, gate.name] = len(symbol.bodies) - 1 self.cptgate2pin_map[cpt, gate.name] = pin_map self.cptgate2ann_map[cpt, gate.name] = ann_map return cpt
class ComponentParser(object): """I parse components from KiCAD libraries.""" # the column positions of the unit and convert fields unit_cols = dict(A=6, C=4, P=2, S=5, T=6, X=9) convert_cols = dict((k, v + 1) for k, v in unit_cols.items()) def __init__(self, line): parts = line.split() self.component = Component(parts[1]) self.component.add_attribute('_prefix', parts[2]) self.num_units = max(int(parts[7]), 1) def build_symbols(self, has_convert): """ Build all Symbols and Bodies for this component. The has_convert argument should be True if there are DeMorgan convert bodies. """ for _ in range(2 if has_convert else 1): symbol = Symbol() for _ in range(self.num_units): symbol.add_body(Body()) self.component.add_symbol(symbol) def iter_bodies(self, unit, convert, has_convert): """ Return an iterator over all the bodies implied by the given unit and convert options. A unit of 0 means all units for the given convert. A convert of 0 means both converts for the given unit. If both are 0 it applies to all bodies.""" if convert == 0 and has_convert: symbol_indices = [0, 1] # both regular and convert elif convert in (0, 1): symbol_indices = [0] # just regular else: symbol_indices = [1] # just convert if unit == 0: body_indices = range(self.num_units) # all bodies else: body_indices = [unit - 1] # one body for symbol_index in symbol_indices: for body_index in body_indices: try: yield self.component.symbols[symbol_index].bodies[ body_index] except IndexError: pass def parse(self, f): """ Parse a DEF block and return the Component """ draw_lines = [] # (unit, convert, prefix, parts) for line in f: parts = line.split() prefix = parts[0] if prefix in ('A', 'C', 'P', 'S', 'T', 'X'): draw_lines.append( (int(parts[self.unit_cols[prefix]]), int(parts[self.convert_cols[prefix]]), prefix, parts)) elif prefix == 'ENDDEF': break has_convert = any(convert == 2 for _, convert, _, _ in draw_lines) self.build_symbols(has_convert) for unit, convert, prefix, parts in draw_lines: method = getattr(self, 'parse_%s_line' % (prefix.lower(), )) for body in self.iter_bodies(unit, convert, has_convert): obj = method(parts) if prefix == 'X': body.add_pin(obj) else: if isinstance(obj, (list, tuple)): [body.add_shape(o) for o in obj] else: body.add_shape(obj) for symbol in self.component.symbols: for body in symbol.bodies: body.pins.sort(key=lambda pin: pin.pin_number) return self.component def parse_a_line(self, parts): """ Parse an A (Arc) line """ x, y, radius, start, end = [int(i) for i in parts[1:6]] # convert tenths of degrees to pi radians start = start / 1800.0 end = end / 1800.0 return Arc(make_length(x), make_length(y), end, start, make_length(radius)) def parse_c_line(self, parts): """ Parse a C (Circle) line """ x, y, radius = [int(i) for i in parts[1:4]] return Circle(make_length(x), make_length(y), make_length(radius)) def parse_p_line(self, parts): """ Parse a P (Polyline) line """ num_points = int(parts[1]) lines = [] last_point = None for i in xrange(num_points): x, y = int(parts[5 + 2 * i]), int(parts[6 + 2 * i]) point = (make_length(x), make_length(y)) if last_point is not None: lines.append(Line(last_point, point)) last_point = point return lines def parse_s_line(self, parts): """ Parse an S (Rectangle) line """ x, y, x2, y2 = [int(i) for i in parts[1:5]] return Rectangle(make_length(x), make_length(y), make_length(x2 - x), make_length(y - y2)) def parse_t_line(self, parts): """ Parse a T (Text) line """ angle, x, y = [int(i) for i in parts[1:4]] angle = angle / 1800.0 text = parts[8].replace('~', ' ') if len(parts) >= 12: align = {'C': 'center', 'L': 'left', 'R': 'right'}.get(parts[11]) else: align = 'left' return Label(make_length(x), make_length(y), text, align, angle) def parse_x_line(self, parts): """ Parse an X (Pin) line """ name, num, direction = parts[1], parts[2], parts[6] p2x, p2y, pinlen = int(parts[3]), int(parts[4]), int(parts[5]) if direction == 'U': # up p1x = p2x p1y = p2y + pinlen label_x = p2x - 20 label_y = p2y + int(pinlen / 2) label_rotation = 1.5 elif direction == 'D': # down p1x = p2x p1y = p2y - pinlen label_x = p2x - 20 label_y = p2y - int(pinlen / 2) label_rotation = 1.5 elif direction == 'L': # left p1x = p2x - pinlen p1y = p2y label_x = p2x - int(pinlen / 2) label_y = p2y + 20 label_rotation = 0 elif direction == 'R': # right p1x = p2x + pinlen p1y = p2y label_x = p2x + int(pinlen / 2) label_y = p2y + 20 label_rotation = 0 else: raise ValueError('unexpected pin direction', direction) if name == '~': label = None else: label = Label(make_length(label_x), make_length(label_y), name, 'center', label_rotation) return Pin(num, (make_length(p1x), make_length(p1y)), (make_length(p2x), make_length(p2y)), label)
class ComponentParser(object): """I parse components from KiCAD libraries.""" # the column positions of the unit and convert fields unit_cols = dict(A=6, C=4, P=2, S=5, T=6, X=9) convert_cols = dict((k, v+1) for k, v in unit_cols.items()) def __init__(self, line): parts = line.split() name = parts[1] if name.startswith('~'): name = name[1:] self.component = Component(name) self.component.add_attribute('_prefix', parts[2]) self.num_units = max(int(parts[7]), 1) def build_symbols(self, has_convert): """ Build all Symbols and Bodies for this component. The has_convert argument should be True if there are DeMorgan convert bodies. """ for _ in range(2 if has_convert else 1): symbol = Symbol() for _ in range(self.num_units): symbol.add_body(SBody()) self.component.add_symbol(symbol) def iter_bodies(self, unit, convert, has_convert): """ Return an iterator over all the bodies implied by the given unit and convert options. A unit of 0 means all units for the given convert. A convert of 0 means both converts for the given unit. If both are 0 it applies to all bodies.""" if convert == 0 and has_convert: symbol_indices = [0, 1] # both regular and convert elif convert in (0, 1): symbol_indices = [0] # just regular else: symbol_indices = [1] # just convert if unit == 0: body_indices = range(self.num_units) # all bodies else: body_indices = [unit-1] # one body for symbol_index in symbol_indices: for body_index in body_indices: try: yield self.component.symbols[symbol_index].bodies[body_index] except IndexError: pass def parse(self, f): """ Parse a DEF block and return the Component """ draw_lines = [] # (unit, convert, prefix, parts) for line in f: parts = line.split() prefix = parts[0] if prefix in ('A', 'C', 'P', 'S', 'T', 'X'): draw_lines.append((int(parts[self.unit_cols[prefix]]), int(parts[self.convert_cols[prefix]]), prefix, parts)) elif prefix == 'ALIAS': self.component.add_attribute('kicad_alias', ' '.join(parts[1:])) elif prefix == 'ENDDEF': break has_convert = any(convert == 2 for _, convert, _, _ in draw_lines) self.build_symbols(has_convert) for unit, convert, prefix, parts in draw_lines: method = getattr(self, 'parse_%s_line' % (prefix.lower(),)) for body in self.iter_bodies(unit, convert, has_convert): obj = method(parts) if prefix == 'X': body.add_pin(obj) else: if isinstance(obj, (list, tuple)): for o in obj: body.add_shape(o) else: body.add_shape(obj) for symbol in self.component.symbols: for body in symbol.bodies: body.pins.sort(key=lambda pin : pin.pin_number) return self.component def parse_a_line(self, parts): """ Parse an A (Arc) line """ x, y, radius, start, end = [int(i) for i in parts[1:6]] # convert tenths of degrees to pi radians start = start / 1800.0 end = end / 1800.0 return Arc(x, y, end, start, radius) def parse_c_line(self, parts): """ Parse a C (Circle) line """ x, y, radius = [int(i) for i in parts[1:4]] return Circle(x, y, radius) def parse_p_line(self, parts): """ Parse a P (Polyline) line """ num_points = int(parts[1]) lines = [] last_point = None for i in xrange(num_points): point = int(parts[5 + 2 * i]), int(parts[6 + 2 * i]) if last_point is not None: lines.append(Line(last_point, point)) last_point = point return lines def parse_s_line(self, parts): """ Parse an S (Rectangle) line """ x, y, x2, y2 = [int(i) for i in parts[1:5]] return Rectangle(x, y, x2 - x, y - y2) def parse_t_line(self, parts): """ Parse a T (Text) line """ angle, x, y = [int(i) for i in parts[1:4]] angle = angle / 1800.0 text = parts[8].replace('~', ' ') if len(parts) >= 12: align = {'C': 'center', 'L': 'left', 'R': 'right'}.get(parts[11]) else: align = 'left' return Label(x, y, text, align=align, rotation=angle) def parse_x_line(self, parts): """ Parse an X (Pin) line """ name, num, direction = parts[1], parts[2], parts[6] p2x, p2y, pinlen = int(parts[3]), int(parts[4]), int(parts[5]) if direction == 'U': # up p1x = p2x p1y = p2y + pinlen label_x = p2x - 20 label_y = p2y + int(pinlen / 2) label_rotation = 1.5 elif direction == 'D': # down p1x = p2x p1y = p2y - pinlen label_x = p2x - 20 label_y = p2y - int(pinlen / 2) label_rotation = 1.5 elif direction == 'L': # left p1x = p2x - pinlen p1y = p2y label_x = p2x - int(pinlen / 2) label_y = p2y + 20 label_rotation = 0 elif direction == 'R': # right p1x = p2x + pinlen p1y = p2y label_x = p2x + int(pinlen / 2) label_y = p2y + 20 label_rotation = 0 else: raise ValueError('unexpected pin direction', direction) if name == '~': label = None else: label = Label(label_x, label_y, name, align='center', rotation=label_rotation) return Pin(num, (p1x, p1y), (p2x, p2y), label)