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)) 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 parse_component_instance(self, f): """ Parse a component instance from a $Comp block """ # pylint: disable=R0914 # name & reference prefix, name, reference = f.readline().split() assert prefix == 'L' # unit & convert prefix, unit, convert, _ = f.readline().split(None, 3) unit, convert = int(unit), int(convert) assert prefix == 'U' # position prefix, compx, compy = f.readline().split() assert prefix == 'P' compx, compy = int(compx), int(compy) line = f.readline() rotation = 0 annotations = [] while line.strip() not in ("$EndComp", ''): if line.startswith('F '): parts = line.split('"', 2) value = parts[1].decode('utf-8', errors='replace') parts = parts[2].strip().split() annotations.append( Annotation(value, make_length(int(parts[1]) - compx), -make_length(int(parts[2]) - compy), 0 if parts[0] == 'H' else 1, 'true')) elif line.startswith('\t'): parts = line.strip().split() if len(parts) == 4: rotation = MATRIX2ROTATION.get( tuple(int(i) for i in parts), 0) line = f.readline() inst = ComponentInstance(reference, name, convert - 1) symbattr = SymbolAttribute(make_length(compx), -make_length(compy), rotation) for ann in annotations: symbattr.add_annotation(ann) inst.add_symbol_attribute(symbattr) return inst
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)) 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 test_write_instance(self): """ The write_instance method serializes a component instance correctly. """ inst = ComponentInstance('id', 'libid', 1) inst.add_symbol_attribute(SymbolAttribute(3, 4, 0.5)) writer = KiCAD() buf = StringIO() writer.write_instance(buf, inst) self.assertEqual(buf.getvalue(), '''\ $Comp L libid id U 1 1 00000000 P 33 -44 \t1 33 -44 \t0 1 1 0 $EndComp ''')
def parse_component_instances(self, component_instances): """ Extract the component instances. """ for instance in component_instances: # Get instance_id, library_id and symbol_index instance_id = instance.get('instance_id') library_id = instance.get('library_id') symbol_index = int(instance.get('symbol_index')) # Make the ComponentInstance() inst = ComponentInstance(instance_id, library_id, symbol_index) # Get the SymbolAttributes for symbol_attribute in instance.get('symbol_attributes'): attr = self.parse_symbol_attribute(symbol_attribute) inst.add_symbol_attribute(attr) # Get the Attributes for key, value in instance.get('attributes').items(): inst.add_attribute(key, value) # Add the ComponentInstance self.design.add_component_instance(inst)
def parse_inst(self, args): """ Returns a parsed component instance. """ inst, libname, libnum, x, y, rot, _scale, _b = args.split() # scale is a floating point scaling constant. Also, evil. thisinst = ComponentInstance(inst, self.lookup(libname, libnum), 0) if int(rot) > 3: # part is flipped around y-axis. When applying transforms, flip it # first, then rotate it. rot = str(int(rot) - 4) # flip = True thisinst.add_symbol_attribute(SymbolAttribute(int(x), int(y), float(rot) / 2)) subdata = defaultdict(list) for phrase in self.stream: cmd, _sep, args = phrase.partition(' ') if cmd not in ('|R', 'A', 'C'): self.stream.push(phrase) break k, v = self.parsenode(cmd)(args) subdata[k].append(v) for annot in subdata['annot']: thisinst.symbol_attributes[0].add_annotation(annot) if '=' in annot.value: thisinst.add_attribute(*(annot.value.split('=', 1))) # Turns out C can reference a net before it's been created via # the N command. Really don't like passing stuff inband like this. Ugh. thisinst.conns = subdata['conn'] return ('inst', thisinst)
def parse_component_instance(self, inst): """ Parse a Fritzing non-wire instance into a ComponentInstance """ view = inst.find('views/schematicView') if view is None: return if view.get('layer') == 'breadboardbreadboard': return cpt = self.ensure_component(inst) if cpt is None: return index = inst.get('modelIndex') idref = inst.get('moduleIdRef') title = inst.find('title').text geom = view.find('geometry') xform = geom.find('transform') x, y = float(geom.get('x', 0)), float(geom.get('y', 0)) if xform is None: rotation = 0.0 else: matrix = tuple(int(float(xform.get(key, 0))) for key in ('m11', 'm12', 'm21', 'm22')) x, y = rotate_component(cpt, matrix, x, y) rotation = MATRIX2ROTATION.get(matrix, 0.0) compinst = ComponentInstance(title, idref, 0) compinst.add_symbol_attribute( SymbolAttribute(make_x(x), make_y(y), rotation)) self.component_instances[index] = compinst
def parse_component(self, stream, params): """ Creates a component instance according to the component *params*. If the component is not known in the library, a the component will be created according to its description in the embedded environment ``[]`` or a symbol file. The component is added to the library automatically if necessary. An instance of this component will be created and added to the design. A GEDAError is raised when either the component file is invalid or the referenced symbol file cannot be found in the known directories. Returns a tuple of Component and ComponentInstance objects. """ basename, dummy = os.path.splitext(params['basename']) component_name = basename if params['mirror']: component_name += '_MIRRORED' if component_name in self.design.components.components: component = self.design.components.components[component_name] ## skipping embedded data might be required self.skip_embedded_section(stream) else: ##check if sym file is embedded or referenced if basename.startswith('EMBEDDED'): ## embedded only has to be processed when NOT in symbol lookup if basename not in self.known_symbols: component = self.parse_component_data(stream, params) else: if basename not in self.known_symbols: log.warn("referenced symbol file '%s' unknown" % basename) ## parse optional attached environment before continuing self._parse_environment(stream) return None, None ## requires parsing of referenced symbol file f_in = open(self.known_symbols[basename], "rU") self._check_version(f_in) component = self.parse_component_data(f_in, params) f_in.close() self.design.add_component(component_name, component) ## get all attributes assigned to component instance attributes = self._parse_environment(stream) ## refdes attribute is name of component (mandatory as of gEDA doc) ## examples if gaf repo have components without refdes, use part of ## basename if attributes is not None: instance = ComponentInstance( attributes.get('_refdes', component.name), component.name, 0 ) for key, value in attributes.items(): instance.add_attribute(key, value) else: instance = ComponentInstance( component.name, component.name, 0 ) ## generate a component instance using attributes self.design.add_component_instance(instance) symbol = SymbolAttribute( self.x_to_px(params['x']), self.y_to_px(params['y']), self.conv_angle(params['angle']) ) instance.add_symbol_attribute(symbol) ## add annotation for special attributes for idx, attribute_key in enumerate(['_refdes', 'device']): if attribute_key in component.attributes \ or attribute_key in instance.attributes: symbol.add_annotation( Annotation( '{{%s}}' % attribute_key, 0, 0+idx*10, 0.0, 'true' ) ) return component, instance
def parse(self, filename, library_filename=None): """ Parse a kicad file into a design """ # Rough'n'dirty parsing, assume nothing useful comes before # the description circuit = Design() segments = set() # each wire segment junctions = set() # wire junction point (connects all wires under it) if library_filename is None: library_filename = splitext(filename)[0] + '-cache.lib' if exists(library_filename): self.parse_library(library_filename, circuit) f = open(filename) # Read until the end of the description while f.readline().strip() != "$EndDescr": pass # Now parse wires and components, ignore connections, we get # connectivity from wire segments line = f.readline() while line: element = line.split()[0] # whats next on the list if element == "Wire": # Wire Segment, coords on 2nd line x1, y1, x2, y2 = [int(i) for i in f.readline().split()] if not (x1 == x2 and y1 == y2): # ignore zero-length segments segments.add(((x1, y1), (x2, y2))) elif element == "Connection": # Store these to apply later x, y = [int(i) for i in line.split()[2:4]] junctions.add((x, y)) elif element == "$Comp": # Component Instance # name & reference prefix, name, reference = f.readline().split() assert prefix == 'L' # timestamp prefix, _ = f.readline().split(None, 1) assert prefix == 'U' # position prefix, compx, compy = f.readline().split() assert prefix == 'P' compx, compy = int(compx), int(compy) # TODO(ajray): ignore all the fields for now, probably # could make these annotations while f.readline().strip() not in ("$EndComp", ''): pass # TODO: calculate rotation inst = ComponentInstance(reference, name, 0) inst.add_symbol_attribute(SymbolAttribute(compx, compy, 0)) circuit.add_component_instance(inst) line = f.readline() f.close() segments = self.divide(segments, junctions) circuit.nets = self.calc_nets(segments) return circuit
def parse(self, filename, library_filename=None): """ Parse a kicad file into a design """ # Rough'n'dirty parsing, assume nothing useful comes before # the description circuit = Design() segments = set() # each wire segment junctions = set() # wire junction point (connects all wires under it) if library_filename is None: library_filename = splitext(filename)[0] + "-cache.lib" if exists(library_filename): self.parse_library(library_filename, circuit) f = open(filename) # Read until the end of the description while f.readline().strip() != "$EndDescr": pass # Now parse wires and components, ignore connections, we get # connectivity from wire segments line = f.readline() while line: element = line.split()[0] # whats next on the list if element == "Wire": # Wire Segment, coords on 2nd line x1, y1, x2, y2 = [int(i) for i in f.readline().split()] if not (x1 == x2 and y1 == y2): # ignore zero-length segments segments.add(((x1, y1), (x2, y2))) elif element == "Connection": # Store these to apply later x, y = [int(i) for i in line.split()[2:4]] junctions.add((x, y)) elif element == "$Comp": # Component Instance # name & reference prefix, name, reference = f.readline().split() assert prefix == "L" # timestamp prefix, _ = f.readline().split(None, 1) assert prefix == "U" # position prefix, compx, compy = f.readline().split() assert prefix == "P" compx, compy = int(compx), int(compy) # TODO(ajray): ignore all the fields for now, probably # could make these annotations while f.readline().strip() not in ("$EndComp", ""): pass # TODO: calculate rotation inst = ComponentInstance(reference, name, 0) inst.add_symbol_attribute(SymbolAttribute(compx, compy, 0)) circuit.add_component_instance(inst) line = f.readline() f.close() segments = self.divide(segments, junctions) circuit.nets = self.calc_nets(segments) return circuit