def set_symbol_attribute(self, instance, openjson_inst):
        """ Fill out an openjson symbol attribute from an eagle instance
        and an openjson instance. """

        cpt = self.design.components.components[openjson_inst.library_id]

        attr = openjson_inst.symbol_attributes[self.cptgate2body_index[
            cpt, instance.gate]]

        attr.x = self.make_length(instance.x)
        attr.y = self.make_length(instance.y)
        attr.flip = is_mirrored(instance.rot)
        attr.rotation = make_angle(instance.rot or '0')

        if instance.smashed == 'yes':
            annotations = self.iter_instance_annotations(instance)
        else:
            annotations = sorted(
                self.cptgate2ann_map.get((cpt, instance.gate)).items())

        for name, ann in annotations:
            ann = Annotation('', ann.x, ann.y, ann.rotation, ann.visible)
            if name == 'name':
                ann.value = openjson_inst.instance_id
                if len(openjson_inst.symbol_attributes) > 1:
                    ann.value += instance.gate or ''
                attr.add_annotation(ann)
            elif name == 'value' and 'value' in openjson_inst.attributes:
                ann.value = openjson_inst.attributes['value']
                attr.add_annotation(ann)

        self.part2gate2symattr[instance.part][instance.gate] = attr
    def set_symbol_attribute(self, instance, openjson_inst):
        """ Fill out an openjson symbol attribute from an eagle instance
        and an openjson instance. """

        # TODO: handle mirror

        cpt = self.design.components.components[openjson_inst.library_id]

        attr = openjson_inst.symbol_attributes[self.cptgate2body_index[cpt, instance.gate]]

        attr.x = self.make_length(instance.x)
        attr.y = self.make_length(instance.y)
        attr.rotation = self.make_angle(instance.rot or '0')

        if instance.smashed == 'yes':
            annotations = self.iter_instance_annotations(instance)
        else:
            annotations = sorted(self.cptgate2ann_map.get((cpt, instance.gate)).items())

        for name, ann in annotations:
            ann = Annotation('', ann.x, ann.y, ann.rotation, ann.visible)
            if name == 'name':
                ann.value = openjson_inst.instance_id
                attr.add_annotation(ann)
            elif name == 'value' and 'value' in openjson_inst.attributes:
                ann.value = openjson_inst.attributes['value']
                attr.add_annotation(ann)

        self.part2gate2symattr[instance.part][instance.gate] = attr
Example #3
0
 def test_annotation_bounds(self):
     '''Test .bounds()'''
     annot = Annotation('foo', 3, 6, 0, True)
     top_left, bottom_right = annot.bounds()
     # bounds() will give a square with sides 20 units long, centered on the
     # annotation
     self.assertEqual(top_left.x, 3 - 10)
     self.assertEqual(top_left.y, 6 - 10)
     self.assertEqual(bottom_right.x, 3 + 10)
     self.assertEqual(bottom_right.y, 6 + 10)
Example #4
0
    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)
Example #5
0
 def parse_text(self, f, line):
     """ Parse a Text line """
     parts = line.split()
     x, y, rotation = int(parts[2]), int(parts[3]), int(parts[4])
     rotation = rotation / 2.0
     value = f.readline().decode('utf-8', 'replace').strip()
     return Annotation(value, x, -y, rotation, 'true')
Example #6
0
 def parse_annot(self, args):
     """ Returns a parsed annotation. """
     x, y, _font_size, _rot, _anchor, viz, val = args.split(' ', 6)
     # anchor is 1,2,3: bottom,mid,top respectively
     # visibility is 0,1,2,3: invis, vis, name only, val only
     # FIXME use rotation
     subdata = defaultdict(list)
     for phrase in self.stream:
         cmd, _sep, args = phrase.partition(' ')
         if cmd not in ('Q'):
             self.stream.push(phrase)
             break
         # Q cmd is ignored for now anyway, but need to get it out of the way
         k, v = self.parsenode(cmd)(args)
         subdata[k].append(v)
     display = True
     if viz == '1':
         value = val
     elif viz == '2':
         value = val.split('=')[0]
     elif viz == '3':
         value = val.split('=', 1)[-1]
     else:
         value = val
         display = False
     return ('annot', Annotation(value, int(x), int(y), 0, display))
Example #7
0
    def parse(self):
        '''Returns a Design built up from a schematic file that represents one
        sheet of the original schematic'''
        tree = ViewDrawBase.parse(self)
        # tree['lines'] is a [list of [list of lines]]
        tree['shape'].extend(sum(tree['lines'], []))
        ckt = Design()
        # TODO little weak here, a copy instead?
        ckt.components = self.lib

        for net in tree['net']:
            ckt.add_net(net)
        for inst in tree['inst']:
            ckt.add_component_instance(inst)
            # hold on tight, this is ugly
            for (netid, netpt, pinid) in inst.conns:
                net = [n for n in ckt.nets if n.net_id == netid][0]
                comp = ConnectedComponent(inst.instance_id, pinid)
                net.ibpts[netpt - 1].add_connected_component(comp)
            del inst.conns
        for net in ckt.nets:
            del net.ibpts

        for shape in tree['shape']:
            ckt.add_shape(shape)
            if isinstance(shape, Label):
                ann = Annotation(shape.text, shape.x, shape.y, shape._rotation,
                                 True)
                ckt.design_attributes.add_annotation(ann)

        for k, v, annot in tree['attr']:
            ckt.design_attributes.add_attribute(k, v)
            ckt.design_attributes.add_annotation(annot)

        return ckt
Example #8
0
    def make_body_from_symbol(self, lib, symbol_name):
        """ Construct an openjson Body from an eagle symbol in a library. """

        body = Body()

        symbol = [
            s for s in get_subattr(lib, 'symbols.symbol')
            if s.name == symbol_name
        ][0]

        for wire in symbol.wire:
            body.add_shape(
                Line((self.make_length(wire.x1), self.make_length(wire.y1)),
                     (self.make_length(wire.x2), self.make_length(wire.y2))))

        for rect in symbol.rectangle:
            x = self.make_length(rect.x1)
            y = self.make_length(rect.y1)
            width = self.make_length(rect.x2) - x
            height = self.make_length(rect.y2) - y
            body.add_shape(Rectangle(x, y + height, width, height))

        pin_map = {}

        for pin in symbol.pin:
            connect_point = (self.make_length(pin.x), self.make_length(pin.y))
            null_point = self.get_pin_null_point(connect_point, pin.length,
                                                 pin.rot)
            label = self.get_pin_label(pin, null_point)
            pin_map[pin.name] = Pin(pin.name, null_point, connect_point, label)
            body.add_pin(pin_map[pin.name])

        ann_map = {}

        for text in symbol.text:
            x = self.make_length(text.x)
            y = self.make_length(text.y)
            content = '' if text.valueOf_ is None else text.valueOf_
            rotation = self.make_angle('0' if text.rot is None else text.rot)
            if content == '>NAME':
                ann_map['name'] = Annotation(content, x, y, rotation, 'true')
            elif content == '>VALUE':
                ann_map['value'] = Annotation(content, x, y, rotation, 'true')
            else:
                body.add_shape(Label(x, y, content, 'left', rotation))

        return body, pin_map, ann_map
Example #9
0
 def test_create_new_annotation(self):
     """ Test the creation of a new empty annotation. """
     anno = Annotation('abc', 0, 1, 2, False)
     assert anno.value == 'abc'
     assert anno.x == 0
     assert anno.y == 1
     assert anno.rotation == 2
     assert anno.visible != True
Example #10
0
    def test_bounds_annots(self):
        '''Test bounds() with just Annotations added as design attributes'''
        left = Annotation('foo1', 3, 3, 0, True)
        top = Annotation('foo2', 3, 3, 0, True)
        right = Annotation('foo3', 3, 3, 0, True)
        bot = Annotation('foo4', 3, 3, 0, True)
        mkbounds(left, 2, 3, 3, 3)
        mkbounds(top, 3, 2, 3, 3)
        mkbounds(right, 3, 3, 5, 3)
        mkbounds(bot, 3, 3, 3, 6)
        for anno in (left, right, bot, top):
            self.des.design_attributes.add_annotation(anno)

        top_left, btm_right = self.des.bounds()
        self.assertEqual(top_left.x, 2)
        self.assertEqual(top_left.y, 2)
        self.assertEqual(btm_right.x, 5)
        self.assertEqual(btm_right.y, 6)
    def parse_field(self, compx, compy, line):
        """ Parse a field (F) line in a component block """
        parts = line.rsplit('"', 1)
        value = parts[0].split('"', 1)[1].decode('utf-8', 'replace')
        parts = parts[1].strip().split()

        return Annotation(value, make_length(int(parts[1]) - compx),
                          -make_length(int(parts[2]) - compy),
                          0 if parts[0] == 'H' else 1, 'true')
Example #12
0
 def parse_label(self, args):
     """ Returns a parsed label. """
     x, y, _font_size, _rot, _c, _d, _e, _f, text = args.split(' ', 8)
     # treat them as annotations for now, I guess.
     # suspect that c, e are anchor and vis, as in parse_annot
     # According to other research, d is scope (0=local, 1=global) and f
     # might be logic sense (for overbars, 0=normal, 1=inverted)
     # FIXME use rot and vis
     return ('annot', Annotation(text, int(x), int(y), 0, True))
    def test_write_annotation(self):
        """
        The write_annotation method produces the correct string.
        """

        writer = KiCAD()
        buf = StringIO()
        ann = Annotation('test', 1, 2, .5, 'true')
        writer.write_annotation(buf, ann)
        self.assertEqual(buf.getvalue(),
                         'Text Label 11 -22 900 60 ~ 0\ntest\n')
Example #14
0
 def parse_label(self, args):
     """ Returns a parsed label. """
     args = args.split(' ', 8)
     x, y, _font_size, rot, _anchor, _scope, _vis, _sense, text = args
     # treat them as annotations for now, I guess.
     # suspect that anchor and vis are as in parse_annot
     # According to other research, _scope is (0=local, 1=global) and _sense
     # might be logic sense (for overbars, 0=normal, 1=inverted)
     # FIXME use vis
     rot, _flip = self.rot_and_flip(rot)
     return ('annot', Annotation(text, int(x), int(y), rot, True))
    def iter_instance_annotations(self, instance):
        """ Return an iterator over (name, Annotation) for the annotations
        in an eagle instance. """

        for ob in instance.attribute:
            name = ob.name.lower()
            x = self.make_length(ob.x) - self.make_length(instance.x)
            y = self.make_length(ob.y) - self.make_length(instance.y)
            rotation = make_angle('0' if ob.rot is None else ob.rot)
            ann = Annotation(ob.name, x, y, rotation, 'true')
            yield (name, ann)
Example #16
0
 def parse_annotation(self, annotation):
     """ Extract an annotation. """
     value = annotation.get('value')
     x = int(annotation.get('x'))
     y = int(annotation.get('y'))
     rotation = float(annotation.get('rotation'))
     visible = annotation.get('visible')
     if visible is not None and visible.lower() == 'false':
         visible = 'false'
     else:
         visible = 'true'
     return Annotation(value, x, y, rotation, visible)
Example #17
0
 def parse_annot(self, args):
     """ Returns a parsed annotation. """
     x, y, _font_size, rot, _anchor, viz, val = args.split(' ', 6)
     # anchor is 1,2,3: bottom,mid,top respectively
     # visibility is 0,1,2,3: invis, vis, name only, val only
     self.sub_nodes(['Q'])
     # Q cmd is ignored for now anyway, but need to get it out of the way
     display = True
     if viz == '1':
         value = val
     elif viz == '2':
         value = val.split('=')[0]
     elif viz == '3':
         value = val.split('=', 1)[-1]
     else:
         value = val
         display = False
     rot, _flip = self.rot_and_flip(rot)
     return ('annot', Annotation(value, int(x), int(y), rot, display))
Example #18
0
 def parse_annotation(self, annotation):
     """ Extract an annotation. """
     value = annotation.get('value')
     x = int(annotation.get('x'))
     y = int(annotation.get('y'))
     label = self.parse_label(annotation.get('label'))
     layer = annotation.get('layer', 'default')
     rotation = float(annotation.get('rotation'))
     flip_horizontal = annotation.get('flip', False)
     visible = annotation.get('visible')
     if visible is not None and visible.lower() == 'false':
         visible = 'false'
     else:
         visible = 'true'
     return Annotation(value,
                       x,
                       y,
                       rotation,
                       visible,
                       layer=layer,
                       flip_horizontal=flip_horizontal,
                       label=label)
    def make_body_from_symbol(self, lib, symbol_name, pin_number_lookup):
        """ Construct an openjson SBody from an eagle symbol in a library. """

        body = SBody()

        symbol = [
            s for s in get_subattr(lib, 'symbols.symbol')
            if s.name == symbol_name
        ][0]

        for wire in symbol.wire:
            body.add_shape(self.make_shape_for_wire(wire))

        for rect in symbol.rectangle:
            rotation = make_angle('0' if rect.rot is None else rect.rot)
            x1, y1 = rotate_point(
                (self.make_length(rect.x1), self.make_length(rect.y1)),
                rotation)
            x2, y2 = rotate_point(
                (self.make_length(rect.x2), self.make_length(rect.y2)),
                rotation)
            ux, uy = min(x1, x2), max(y1, y2)
            lx, ly = max(x1, x2), min(y1, y2)
            body.add_shape(Rectangle(ux, uy, lx - ux, uy - ly))

        for poly in symbol.polygon:
            map(body.add_shape, self.make_shapes_for_poly(poly))

        for circ in symbol.circle:
            body.add_shape(self.make_shape_for_circle(circ))

        pin_map = {}

        for pin in symbol.pin:
            connect_point = (self.make_length(pin.x), self.make_length(pin.y))
            null_point = self.get_pin_null_point(connect_point, pin.length,
                                                 pin.rot)
            label = self.get_pin_label(pin, null_point)
            pin_map[pin.name] = Pin(pin_number_lookup(pin.name), null_point,
                                    connect_point, label)
            if pin.direction:
                pin_map[pin.name].add_attribute('eaglexml_direction',
                                                pin.direction)
            if pin.visible:
                pin_map[pin.name].add_attribute('eaglexml_visible',
                                                pin.visible)
            body.add_pin(pin_map[pin.name])

        ann_map = {}

        for text in symbol.text:
            x = self.make_length(text.x)
            y = self.make_length(text.y)
            content = '' if text.valueOf_ is None else text.valueOf_
            rotation = make_angle('0' if text.rot is None else text.rot)
            align = 'right' if is_mirrored(text.rot) else 'left'
            if rotation == 0.5:
                rotation = 1.5
            if content.lower() == '>name':
                ann_map['name'] = Annotation(content, x, y, rotation, 'true')
            elif content.lower() == '>value':
                ann_map['value'] = Annotation(content, x, y, rotation, 'true')
            else:
                body.add_shape(
                    Label(x, y, content, align=align, rotation=rotation))

        return body, pin_map, ann_map
Example #20
0
    def calculate_nets(self):
        """ Calculate connected nets from previously stored segments
            and netpoints. The code has been adapted from the kiCAD
            parser since the definition of segments in the schematic
            file are similar. The segments are checked against
            existing nets and added when they touch it. For this
            to work, it is required that intersecting segments are
            divided prior to this method.

            Returns a list of valid nets and its net points.
        """
        nets = []

        # Iterate over the segments, removing segments when added to a net
        while self.segments:
            seg = self.segments.pop()  # pick a point

            net_name = ''
            pt_a, pt_b = seg
            if pt_a.point_id in self.net_names:
                net_name = self.net_names[pt_a.point_id]
            elif pt_b.point_id in self.net_names:
                net_name = self.net_names[pt_b.point_id]

            new_net = net.Net(net_name)
            new_net.connect(seg)
            found = True

            if net_name:
                new_net.attributes['_name'] = net_name

            while found:
                found = set()

                for seg in self.segments:  # iterate over segments
                    if new_net.connected(seg):  # segment touching the net
                        new_net.connect(seg)  # add the segment
                        found.add(seg)

                for seg in found:
                    self.segments.remove(seg)

            nets.append(new_net)

        # check if names are available for calculated nets
        for net_obj in nets:
            for point_id in net_obj.points:
                ## check for stored net names based on pointIDs
                if point_id in self.net_names:
                    net_obj.net_id = self.net_names[point_id]
                    net_obj.attributes['_name'] = self.net_names[point_id]

            if '_name' in net_obj.attributes:
                annotation = Annotation(
                    "{{_name}}",  ## annotation referencing attribute '_name'
                    0,
                    0,
                    self.conv_angle(0.0),
                    self.conv_bool(1),
                )
                net_obj.add_annotation(annotation)

        for net_obj in nets:
            if not net_obj.net_id:
                net_obj.net_id = min(net_obj.points)

        return nets
Example #21
0
    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, _ = os.path.splitext(params['basename'])

        component_name = basename
        if params.get('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)
                    ## create a unknown symbol reference
                    component = self.parse_component_data(
                        StringIO(UNKNOWN_COMPONENT % basename), params)
                    ## parse optional attached environment before continuing
                    self._parse_environment(stream)
                    return None, None

                ## requires parsing of referenced symbol file
                with open(self.known_symbols[basename], "rU") as f_in:
                    self._check_version(f_in)
                    component = self.parse_component_data(f_in, params)

            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'], False))
        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
Example #22
0
 def parse_rev(self, args):
     """ Returns the file revision date, parsed into an annotation. """
     # File revision date. Gahh, ugly.
     return ('annot', Annotation('rev=' + args, 0, 0, 0, False))