Ejemplo n.º 1
0
class JSON:
    """ The Open JSON Format Parser
    This is mostly for sanity checks, it reads in the Open JSON format,
    and then outputs it. """

    def __init__(self):
        self.design = Design()


    @staticmethod
    def auto_detect(filename):
        """ Return our confidence that the given file is an openjson file """
        with open(filename, 'r') as f:
            data = f.read()
        confidence = 0
        if 'component_instances' in data:
            confidence += 0.3
        if 'design_attributes' in data:
            confidence += 0.6
        return confidence


    def parse(self, filename):
        """ Parse the openjson file into the core. """
        with open(filename) as f:
            read = json.loads(f.read())

        self.parse_component_instances(read.get('component_instances'))
        self.parse_components(read.get('components'))
        if read.get('shapes') is not None:
            self.parse_sch_shapes(read.get('shapes'))
        self.parse_design_attributes(read.get('design_attributes'))
        self.parse_nets(read.get('nets'))
        self.parse_version(read.get('version'))

        return self.design


    def parse_version(self, version):
        """ Extract the file version. """
        file_version = version.get('file_version')
        exporter = version.get('exporter')
        self.design.set_version(file_version, exporter)


    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_symbol_attribute(self, symbol_attribute):
        """ Extract attributes from a symbol. """
        x = int(symbol_attribute.get('x') or 0)
        y = int(symbol_attribute.get('y') or 0)

        rotation = float(symbol_attribute.get('rotation'))

        # Make SymbolAttribute
        symbol_attr = SymbolAttribute(x, y, rotation)

        # Add Annotations
        for annotation in symbol_attribute.get('annotations'):
            anno = self.parse_annotation(annotation)
            symbol_attr.add_annotation(anno)

        # Return SymbolAttribute to be added to it's ComponentInstance
        return symbol_attr


    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)


    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 parse_sch_shapes(self, shapes):
        """ Extract shapes drawn directly on the schematic. """
        for sh in shapes:
            self.design.add_shape(self.parse_shape(sh))


    def parse_symbol(self, symbol):
        """ Extract a symbol. """
        symb = Symbol()
        for body in symbol.get('bodies'):
            bdy = self.parse_body(body)
            symb.add_body(bdy)
        return symb


    def parse_body(self, body):
        """ Extract a body of a symbol. """
        bdy = Body()
        for pin in body.get('pins'):
            parsed_pin = self.parse_pin(pin)
            bdy.add_pin(parsed_pin)
        for shape in body.get('shapes'):
            parsed_shape = self.parse_shape(shape)
            bdy.add_shape(parsed_shape)
        return bdy


    def parse_pin(self, pin):
        """ Extract a pin of a body. """
        pin_number = pin.get('pin_number')
        p1 = self.parse_point(pin.get('p1'))
        p2 = self.parse_point(pin.get('p2'))
        parsed_pin = Pin(pin_number, p1, p2)
        if pin.get('label') is not None:
            parsed_pin.label = self.parse_label(pin.get('label'))
        parsed_pin.styles = pin.get('styles') or {}
        return parsed_pin

    def parse_point(self, point):
        """ Extract a point. """
        x = int(point.get('x'))
        y = int(point.get('y'))
        return Point(x, y)

    def parse_label(self, label):
        """ Extract a label. """
        x = int(label.get('x'))
        y = int(label.get('y'))
        text = label.get('text')
        align = label.get('align')
        rotation = float(label.get('rotation'))
        parsed_label = Label(x, y, text, align, rotation)
        parsed_label.styles = label.get('styles') or {}
        return parsed_label

    def parse_shape(self, shape):
        """ Extract a shape. """
        # pylint: disable=R0914
        # pylint: disable=R0911

        typ = shape.get('type')
        if 'rectangle' == typ:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            height = int(shape.get('height'))
            width = int(shape.get('width'))
            parsed_shape = Rectangle(x, y, width, height)
        elif 'rounded_rectangle' == typ:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            height = int(shape.get('height'))
            width = int(shape.get('width'))
            radius = int(shape.get('radius'))
            parsed_shape = RoundedRectangle(x, y, width, height, radius)
        elif 'arc' == typ:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            start_angle = float(shape.get('start_angle'))
            end_angle = float(shape.get('end_angle'))
            radius = int(shape.get('radius'))
            parsed_shape = Arc(x, y, start_angle, end_angle, radius)
        elif 'circle' == typ:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            radius = int(shape.get('radius'))
            parsed_shape = Circle(x, y, radius)
        elif 'label' == typ:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            rotation = float(shape.get('rotation'))
            text = shape.get('text')
            align = shape.get('align')
            parsed_shape = Label(x, y, text, align, rotation)
        elif 'line' == typ:
            p1 = self.parse_point(shape.get('p1'))
            p2 = self.parse_point(shape.get('p2'))
            parsed_shape = Line(p1, p2)
        elif 'polygon' == typ:
            parsed_shape = Polygon()
            for point in shape.get('points'):
                parsed_shape.add_point(self.parse_point(point))
        elif 'bezier' == typ:
            control1 = self.parse_point(shape.get('control1'))
            control2 = self.parse_point(shape.get('control2'))
            p1 = self.parse_point(shape.get('p1'))
            p2 = self.parse_point(shape.get('p2'))
            parsed_shape = BezierCurve(control1, control2, p1, p2)

        parsed_shape.styles = shape.get('styles') or {}
        parsed_shape.attributes = shape.get('attributes') or {}
        return parsed_shape

    def parse_design_attributes(self, design_attributes):
        """ Extract design attributes. """
        attrs = DesignAttributes()
        # Get the Annotations
        for annotation in design_attributes.get('annotations'):
            anno = self.parse_annotation(annotation)
            attrs.add_annotation(anno)

        # Get the Attributes
        for key, value in design_attributes.get('attributes').items():
            attrs.add_attribute(key, value)

        # Get the Metadata
        meta = self.parse_metadata(design_attributes.get('metadata'))
        attrs.set_metadata(meta)
        self.design.set_design_attributes(attrs)


    def parse_metadata(self, metadata):
        """ Extract design meta-data. """
        meta = Metadata()
        meta.set_name(metadata.get('name'))
        meta.set_license(metadata.get('license'))
        meta.set_owner(metadata.get('owner'))
        meta.set_updated_timestamp(metadata.get('updated_timestamp'))
        meta.set_design_id(metadata.get('design_id'))
        meta.set_description(metadata.get('description'))
        meta.set_slug(metadata.get('slug'))
        for attached_url in metadata.get('attached_urls'):
            meta.add_attached_url(attached_url)
        return meta


    def parse_nets(self, nets):
        """ Extract nets. """
        for net in nets:
            net_id = net.get('net_id')
            ret_net = Net(net_id)
            # Add Annotations
            for annotation in net.get('annotations'):
                anno = self.parse_annotation(annotation)
                ret_net.add_annotation(anno)
            # Get the Attributes
            for key, value in net.get('attributes').items():
                ret_net.add_attribute(key, value)
            # Get the Points
            for net_point in net.get('points'):
                npnt = self.parse_net_point(net_point)
                ret_net.add_point(npnt)
            self.design.add_net(ret_net)


    def parse_net_point(self, net_point):
        """ Extract a net point. """
        point_id = net_point.get('point_id')
        x = int(net_point.get('x'))
        y = int(net_point.get('y'))
        npnt = NetPoint(point_id, x, y)
        # Get the connected points
        for point in net_point.get('connected_points'):
            npnt.add_connected_point(point)
        # Get the ConnectedComponents
        for connectedcomponent in net_point.get('connected_components'):
            conn_comp = self.parse_connected_component(connectedcomponent)
            npnt.add_connected_component(conn_comp)
        return npnt


    def parse_connected_component(self, connectedcomponent):
        """ Extract a connected component. """
        instance_id = connectedcomponent.get('instance_id')
        pin_number = connectedcomponent.get('pin_number')
        return ConnectedComponent(instance_id, pin_number)
Ejemplo n.º 2
0
class JSON(object):
    """ The Open JSON Format Parser
    This is mostly for sanity checks, it reads in the Open JSON format,
    and then outputs it. """
    def __init__(self):
        self.design = Design()

    @staticmethod
    def auto_detect(filename):
        """ Return our confidence that the given file is an openjson file """
        with open(filename, 'r') as f:
            data = f.read()
        confidence = 0
        if 'component_instances' in data:
            confidence += 0.3
        if 'design_attributes' in data:
            confidence += 0.6
        return confidence

    def parse(self, filename):
        """ Parse the openjson file into the core. """
        log.debug('Starting parse of %s', filename)
        with open(filename) as f:
            read = json.loads(f.read())

        self.parse_components(read.get('components'))
        self.parse_component_instances(read.get('component_instances'))
        if read.get('shapes') is not None:
            self.parse_sch_shapes(read.get('shapes'))
        self.parse_design_attributes(read.get('design_attributes'))
        self.parse_nets(read.get('nets'))
        self.parse_version(read.get('version'))

        # layout aspects
        self.parse_layer_options(read.get('layer_options'))
        self.parse_trace_segments(read.get('trace_segments'))
        self.parse_layout_objects(read.get('gen_objs'))
        self.parse_paths(read.get('paths'))
        self.parse_pours(read.get('pours'))
        self.parse_pcb_text(read.get('text'))

        return self.design

    def parse_version(self, version):
        """ Extract the file version. """
        file_version = version.get('file_version')
        exporter = version.get('exporter')
        self.design.set_version(file_version, exporter)

    def parse_layer_options(self, layer_options_json):
        if layer_options_json is None:
            return None

        for layer_option_json in layer_options_json:
            self.design.layer_options.append(Layer(layer_option_json['name']))

    def parse_trace_segments(self, segments_json):
        if segments_json is None:
            return None

        for segment_json in segments_json:
            p1 = Point(segment_json['p1']['x'], segment_json['p1']['y'])
            p2 = Point(segment_json['p2']['x'], segment_json['p2']['y'])
            segment = Segment(segment_json['layer'], p1, p2,
                              segment_json['width'])
            self.design.trace_segments.append(segment)

    def parse_paths(self, paths_json):
        if paths_json is None:
            return None

        for path_json in paths_json:
            points = [
                Point(point_json['x'], point_json['y'])
                for point_json in path_json['points']
            ]
            width = path_json['width']
            is_closed = path_json['is_closed']
            layer = path_json['layer']
            path = Path(layer, points, width, is_closed)
            self.design.paths.append(path)

    def parse_pours(self, pours_json):
        if pours_json is None:
            return None

        for pour_json in pours_json:
            points = [
                Point(point_json['x'], point_json['y'])
                for point_json in pour_json['points']
            ]

            layer = pour_json['layer']
            subtractive_shapes = []
            if 'subtractive_shapes' in pour_json:
                subtractive_shapes = [
                    self.parse_shape(shape_json)
                    for shape_json in pour_json['subtractive_shapes']
                ]
            if 'readded_shapes' in pour_json:
                readded_shapes = [
                    self.parse_shape(shape_json)
                    for shape_json in pour_json['readded_shapes']
                ]

            pour = Pour(layer, points, subtractive_shapes, readded_shapes)
            self.design.pours.append(pour)

    def parse_pcb_text(self, text_json):
        if text_json is None:
            return None

        for text_instance_json in text_json:
            anno = self.parse_annotation(text_instance_json)
            self.design.pcb_text.append(anno)

    def parse_layout_objects(self, gen_objs_json):
        if gen_objs_json is None:
            return None

        for gen_obj_json in gen_objs_json:
            gen_obj = parse_gen_obj_json(gen_obj_json)
            self.design.layout_objects.append(gen_obj)

    def parse_component_instances(self, component_instances):
        """ Extract the component instances. """

        if component_instances is None:
            return None

        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'))
            footprint_index = int(instance.get('footprint_index'))
            # Make the ComponentInstance()
            inst = ComponentInstance(
                instance_id, self.design.components.components[library_id],
                library_id, symbol_index, footprint_index)

            # Get the SymbolAttributes
            for symbol_attribute in instance.get('symbol_attributes', []):
                attr = self.parse_symbol_attribute(symbol_attribute)
                inst.add_symbol_attribute(attr)

            # TODO(shamer) footprint_pos, fleb and genobj positions are relative to the footprint_pos
            for footprint_attribute in instance.get('footprint_attributes',
                                                    []):
                attr = self.parse_footprint_attribute(footprint_attribute)
                inst.add_footprint_attribute(attr)
            for gen_obj_attribute in instance.get('gen_obj_attributes', []):
                attr = self.parse_gen_obj_attribute(gen_obj_attribute)
                inst.add_gen_obj_attribute(attr)

            footprint_json = instance.get('footprint_pos')
            if footprint_json:
                footprint_pos = self.parse_footprint_pos(footprint_json)
            else:
                footprint_pos = None
            inst.set_footprint_pos(footprint_pos)

            # 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_symbol_attribute(self, symbol_attribute):
        """ Extract attributes from a symbol. """
        x = int(symbol_attribute.get('x') or 0)
        y = int(symbol_attribute.get('y') or 0)

        rotation = float(symbol_attribute.get('rotation'))
        try:
            flip = (symbol_attribute.get('flip').lower() == "true")
        except:
            flip = False

        # Make SymbolAttribute
        symbol_attr = SymbolAttribute(x, y, rotation, flip)

        # Add Annotations
        for annotation in symbol_attribute.get('annotations'):
            anno = self.parse_annotation(annotation)
            symbol_attr.add_annotation(anno)

        # Return SymbolAttribute to be added to its ComponentInstance
        return symbol_attr

    def parse_footprint_attribute(self, footprint_attribute):
        """ Extract attributes from a footprint. """
        x = int(footprint_attribute.get('x') or 0)
        y = int(footprint_attribute.get('y') or 0)

        rotation = float(footprint_attribute.get('rotation'))
        try:
            flip = (footprint_attribute.get('flip').lower() == "true")
        except:
            flip = False

        layer = footprint_attribute.get('layer')

        footprint_attr = FootprintAttribute(x, y, rotation, flip, layer)

        return footprint_attr

    def parse_gen_obj_attribute(self, gen_obj_attribute):
        """ Extract attributes from a gen_obj. """
        x = int(gen_obj_attribute.get('x') or 0)
        y = int(gen_obj_attribute.get('y') or 0)

        rotation = float(gen_obj_attribute.get('rotation'))
        try:
            flip = (gen_obj_attribute.get('flip').lower() == "true")
        except:
            flip = False

        layer = gen_obj_attribute.get('layer')

        gen_obj_attr = GenObjAttribute(x, y, rotation, flip, layer)

        for key, value in gen_obj_attribute.get('attributes').items():
            gen_obj_attr.add_attribute(key, value)

        return gen_obj_attr

    def parse_footprint_pos(self, footprint_pos_json):
        """ Extract footprint pos. """
        x = int(footprint_pos_json.get('x') or 0)
        y = int(footprint_pos_json.get('y') or 0)

        rotation = float(footprint_pos_json.get('rotation', 0))
        flip = footprint_pos_json.get('flip')
        side = footprint_pos_json.get('side')

        return FootprintPos(x, y, rotation, flip, side)

    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 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 parse_sch_shapes(self, shapes):
        """ Extract shapes drawn directly on the schematic. """
        for shape in shapes:
            self.design.add_shape(self.parse_shape(shape))

    def parse_symbol(self, symbol_json):
        """ Extract a symbol. """
        symb = Symbol()
        for body in symbol_json.get('bodies'):
            bdy = self.parse_symbol_body(body)
            symb.add_body(bdy)
        return symb

    def parse_footprint(self, footprint_json):
        """ Extract the bodies for a footprint. """
        footprint = Footprint()
        for body_json in footprint_json.get('bodies'):
            body = self.parse_footprint_body(body_json)
            footprint.add_body(body)
        for gen_obj_json in footprint_json.get('gen_objs'):
            gen_obj = self.parse_gen_obj(gen_obj_json)
            footprint.add_gen_obj(gen_obj)
        return footprint

    def parse_gen_obj(self, gen_obj_json):
        """ Extract the generated object. """
        gen_obj = parse_gen_obj_json(gen_obj_json)
        return gen_obj

    def parse_footprint_body(self, body_json):
        """ Extract a body of a symbol. """
        body = FBody()
        for shape in body_json.get('shapes'):
            parsed_shape = self.parse_shape(shape)
            body.add_shape(parsed_shape)
        body.layer = body_json.get('layer')
        body.rotation = body_json.get('rotation', 0)
        body.flip_horizontal = body_json.get('flip_horizontal', False)
        return body

    def parse_symbol_body(self, body):
        """ Extract a body of a symbol. """
        bdy = SBody()
        for pin in body.get('pins'):
            parsed_pin = self.parse_pin(pin)
            bdy.add_pin(parsed_pin)
        for shape in body.get('shapes'):
            parsed_shape = self.parse_shape(shape)
            bdy.add_shape(parsed_shape)
        return bdy

    def parse_pin(self, pin):
        """ Extract a pin of a body. """
        pin_number = pin.get('pin_number')
        p1 = self.parse_point(pin.get('p1'))
        p2 = self.parse_point(pin.get('p2'))
        parsed_pin = Pin(pin_number, p1, p2)
        if pin.get('label') is not None:
            parsed_pin.label = self.parse_label(pin.get('label'))
        parsed_pin.styles = pin.get('styles') or {}
        return parsed_pin

    def parse_point(self, point):
        """ Extract a point. """
        x = int(point.get('x'))
        y = int(point.get('y'))
        return Point(x, y)

    def parse_label(self, label):
        """ Extract a label. """
        if label is None:
            return None
        x = int(label.get('x'))
        y = int(label.get('y'))
        text = label.get('text')
        font_size = label.get('font_size')
        font_family = label.get('font_family')
        align = label.get('align')
        baseline = label.get('baseline')
        rotation = float(label.get('rotation'))
        parsed_label = Label(x, y, text, font_size, font_family, align,
                             baseline, rotation)
        parsed_label.styles = label.get('styles') or {}
        return parsed_label

    def parse_shape(self, shape):
        """ Extract a shape. """
        # pylint: disable=R0914
        # pylint: disable=R0911

        rotation = shape.get('rotation', 0.0)
        flip_horizontal = shape.get('flip_horizontal', False)

        shape_type = shape.get('type')
        if 'rectangle' == shape_type:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            height = int(shape.get('height'))
            width = int(shape.get('width'))
            parsed_shape = Rectangle(x, y, width, height)
        elif 'rounded_rectangle' == shape_type:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            height = int(shape.get('height'))
            width = int(shape.get('width'))
            radius = int(shape.get('radius'))
            parsed_shape = RoundedRectangle(x, y, width, height, radius)
        elif 'arc' == shape_type:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            start_angle = float(shape.get('start_angle'))
            end_angle = float(shape.get('end_angle'))
            radius = int(shape.get('radius'))
            parsed_shape = Arc(x, y, start_angle, end_angle, radius)
        elif 'circle' == shape_type:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            radius = int(shape.get('radius'))
            parsed_shape = Circle(x, y, radius)
        elif 'label' == shape_type:
            parsed_shape = self.parse_label(shape)
        elif 'line' == shape_type:
            p1 = self.parse_point(shape.get('p1'))
            p2 = self.parse_point(shape.get('p2'))
            parsed_shape = Line(p1, p2)
        elif 'polygon' == shape_type:
            parsed_shape = Polygon()
            for point in shape.get('points'):
                parsed_shape.add_point(self.parse_point(point))
        elif 'bezier' == shape_type:
            control1 = self.parse_point(shape.get('control1'))
            control2 = self.parse_point(shape.get('control2'))
            p1 = self.parse_point(shape.get('p1'))
            p2 = self.parse_point(shape.get('p2'))
            parsed_shape = BezierCurve(control1, control2, p1, p2)
        elif 'rounded_segment' == shape_type:
            p1 = self.parse_point(shape.get('p1'))
            p2 = self.parse_point(shape.get('p2'))
            width = int(shape.get('width'))
            parsed_shape = RoundedSegment(p1, p2, width)

        parsed_shape.rotation = rotation
        parsed_shape.flip_horizontal = flip_horizontal

        parsed_shape.styles = shape.get('styles') or {}
        parsed_shape.attributes = shape.get('attributes') or {}
        return parsed_shape

    def parse_design_attributes(self, design_attributes):
        """ Extract design attributes. """
        attrs = DesignAttributes()
        # Get the Annotations
        for annotation in design_attributes.get('annotations'):
            anno = self.parse_annotation(annotation)
            attrs.add_annotation(anno)

        # Get the Attributes
        for key, value in design_attributes.get('attributes').items():
            attrs.add_attribute(key, value)

        # Get the Metadata
        meta = self.parse_metadata(design_attributes.get('metadata'))
        attrs.set_metadata(meta)
        self.design.set_design_attributes(attrs)

    def parse_metadata(self, metadata):
        """ Extract design meta-data. """
        meta = Metadata()
        meta.set_name(metadata.get('name'))
        meta.set_license(metadata.get('license'))
        meta.set_owner(metadata.get('owner'))
        meta.set_updated_timestamp(metadata.get('updated_timestamp'))
        meta.set_design_id(metadata.get('design_id'))
        meta.set_description(metadata.get('description'))
        meta.set_slug(metadata.get('slug'))
        for attached_url in metadata.get('attached_urls'):
            meta.add_attached_url(attached_url)
        return meta

    def parse_nets(self, nets):
        """ Extract nets. """
        for net in nets:
            net_id = net.get('net_id')
            ret_net = Net(net_id)
            # Add Annotations
            for annotation in net.get('annotations'):
                anno = self.parse_annotation(annotation)
                ret_net.add_annotation(anno)
            # Get the Attributes
            for key, value in net.get('attributes').items():
                ret_net.add_attribute(key, value)
            # Get the Points
            for net_point in net.get('points'):
                npnt = self.parse_net_point(net_point)
                ret_net.add_point(npnt)
            self.design.add_net(ret_net)

    def parse_net_point(self, net_point):
        """ Extract a net point. """
        point_id = net_point.get('point_id')
        x = int(net_point.get('x'))
        y = int(net_point.get('y'))
        npnt = NetPoint(point_id, x, y)
        # Get the connected points
        for point in net_point.get('connected_points'):
            npnt.add_connected_point(point)
        # Get the ConnectedComponents
        for connectedcomponent in net_point.get('connected_components'):
            conn_comp = self.parse_connected_component(connectedcomponent)
            npnt.add_connected_component(conn_comp)
        return npnt

    def parse_connected_component(self, connectedcomponent):
        """ Extract a connected component. """
        instance_id = connectedcomponent.get('instance_id')
        pin_number = connectedcomponent.get('pin_number')
        return ConnectedComponent(instance_id, pin_number)
Ejemplo n.º 3
0
class JSON(object):
    """ The Open JSON Format Parser
    This is mostly for sanity checks, it reads in the Open JSON format,
    and then outputs it. """

    def __init__(self):
        self.design = Design()


    @staticmethod
    def auto_detect(filename):
        """ Return our confidence that the given file is an openjson file """
        with open(filename, 'r') as f:
            data = f.read()
        confidence = 0
        if 'component_instances' in data:
            confidence += 0.3
        if 'design_attributes' in data:
            confidence += 0.6
        return confidence


    def parse(self, filename):
        """ Parse the openjson file into the core. """
        log.debug('Starting parse of %s', filename)
        with open(filename) as f:
            read = json.loads(f.read())

        self.parse_components(read.get('components'))
        self.parse_component_instances(read.get('component_instances'))
        if read.get('shapes') is not None:
            self.parse_sch_shapes(read.get('shapes'))
        self.parse_design_attributes(read.get('design_attributes'))
        self.parse_nets(read.get('nets'))
        self.parse_version(read.get('version'))

        # layout aspects
        self.parse_layer_options(read.get('layer_options'))
        self.parse_trace_segments(read.get('trace_segments'))
        self.parse_layout_objects(read.get('gen_objs'))
        self.parse_paths(read.get('paths'))
        self.parse_pours(read.get('pours'))
        self.parse_pcb_text(read.get('text'))

        return self.design


    def parse_version(self, version):
        """ Extract the file version. """
        file_version = version.get('file_version')
        exporter = version.get('exporter')
        self.design.set_version(file_version, exporter)


    def parse_layer_options(self, layer_options_json):
        if layer_options_json is None:
            return None

        for layer_option_json in layer_options_json:
            self.design.layer_options.append(Layer(layer_option_json['name']))


    def parse_trace_segments(self, segments_json):
        if segments_json is None:
            return None

        for segment_json in segments_json:
            p1 = Point(segment_json['p1']['x'], segment_json['p1']['y'])
            p2 = Point(segment_json['p2']['x'], segment_json['p2']['y'])
            segment = Segment(segment_json['layer'], p1, p2, segment_json['width'])
            self.design.trace_segments.append(segment)


    def parse_paths(self, paths_json):
        if paths_json is None:
            return None

        for path_json in paths_json:
            points = [Point(point_json['x'], point_json['y']) for point_json in path_json['points']]
            width = path_json['width']
            is_closed = path_json['is_closed']
            layer = path_json['layer']
            path = Path(layer, points, width, is_closed)
            self.design.paths.append(path)


    def parse_pours(self, pours_json):
        if pours_json is None:
            return None

        for pour_json in pours_json:
            points = [Point(point_json['x'], point_json['y']) for point_json in pour_json['points']]

            layer = pour_json['layer']
            subtractive_shapes = [];
            if 'subtractive_shapes' in pour_json:
                subtractive_shapes = [self.parse_shape(shape_json) for shape_json in pour_json['subtractive_shapes']]
            if 'readded_shapes' in pour_json:
                readded_shapes = [self.parse_shape(shape_json) for shape_json in pour_json['readded_shapes']]

            pour = Pour(layer, points, subtractive_shapes, readded_shapes)
            self.design.pours.append(pour)


    def parse_pcb_text(self, text_json):
        if text_json is None:
            return None

        for text_instance_json in text_json:
            anno = self.parse_annotation(text_instance_json)
            self.design.pcb_text.append(anno)


    def parse_layout_objects(self, gen_objs_json):
        if gen_objs_json is None:
            return None

        for gen_obj_json in gen_objs_json:
            gen_obj = parse_gen_obj_json(gen_obj_json)
            self.design.layout_objects.append(gen_obj)


    def parse_component_instances(self, component_instances):
        """ Extract the component instances. """

        if component_instances is None:
            return None

        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'))
            footprint_index = int(instance.get('footprint_index'))
            # Make the ComponentInstance()
            inst = ComponentInstance(instance_id, self.design.components.components[library_id], library_id, symbol_index, footprint_index)

            # Get the SymbolAttributes
            for symbol_attribute in instance.get('symbol_attributes', []):
                attr = self.parse_symbol_attribute(symbol_attribute)
                inst.add_symbol_attribute(attr)

            # TODO(shamer) footprint_pos, fleb and genobj positions are relative to the footprint_pos
            for footprint_attribute in instance.get('footprint_attributes', []):
                attr = self.parse_footprint_attribute(footprint_attribute)
                inst.add_footprint_attribute(attr)
            for gen_obj_attribute in instance.get('gen_obj_attributes', []):
                attr = self.parse_gen_obj_attribute(gen_obj_attribute)
                inst.add_gen_obj_attribute(attr)

            footprint_json = instance.get('footprint_pos')
            if footprint_json:
                footprint_pos = self.parse_footprint_pos(footprint_json)
            else:
                footprint_pos = None
            inst.set_footprint_pos(footprint_pos)

            # 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_symbol_attribute(self, symbol_attribute):
        """ Extract attributes from a symbol. """
        x = int(symbol_attribute.get('x') or 0)
        y = int(symbol_attribute.get('y') or 0)

        rotation = float(symbol_attribute.get('rotation'))
        try:
            flip = (symbol_attribute.get('flip').lower() == "true")
        except:
            flip = False

        # Make SymbolAttribute
        symbol_attr = SymbolAttribute(x, y, rotation, flip)

        # Add Annotations
        for annotation in symbol_attribute.get('annotations'):
            anno = self.parse_annotation(annotation)
            symbol_attr.add_annotation(anno)

        # Return SymbolAttribute to be added to its ComponentInstance
        return symbol_attr


    def parse_footprint_attribute(self, footprint_attribute):
        """ Extract attributes from a footprint. """
        x = int(footprint_attribute.get('x') or 0)
        y = int(footprint_attribute.get('y') or 0)

        rotation = float(footprint_attribute.get('rotation'))
        try:
            flip = (footprint_attribute.get('flip').lower() == "true")
        except:
            flip = False

        layer = footprint_attribute.get('layer')

        footprint_attr = FootprintAttribute(x, y, rotation, flip, layer)

        return footprint_attr


    def parse_gen_obj_attribute(self, gen_obj_attribute):
        """ Extract attributes from a gen_obj. """
        x = int(gen_obj_attribute.get('x') or 0)
        y = int(gen_obj_attribute.get('y') or 0)

        rotation = float(gen_obj_attribute.get('rotation'))
        try:
            flip = (gen_obj_attribute.get('flip').lower() == "true")
        except:
            flip = False

        layer = gen_obj_attribute.get('layer')

        gen_obj_attr = GenObjAttribute(x, y, rotation, flip, layer)

        for key, value in gen_obj_attribute.get('attributes').items():
            gen_obj_attr.add_attribute(key, value)

        return gen_obj_attr


    def parse_footprint_pos(self, footprint_pos_json):
        """ Extract footprint pos. """
        x = int(footprint_pos_json.get('x') or 0)
        y = int(footprint_pos_json.get('y') or 0)

        rotation = float(footprint_pos_json.get('rotation', 0))
        flip = footprint_pos_json.get('flip')
        side = footprint_pos_json.get('side')

        return FootprintPos(x, y, rotation, flip, side)


    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 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 parse_sch_shapes(self, shapes):
        """ Extract shapes drawn directly on the schematic. """
        for shape in shapes:
            self.design.add_shape(self.parse_shape(shape))


    def parse_symbol(self, symbol_json):
        """ Extract a symbol. """
        symb = Symbol()
        for body in symbol_json.get('bodies'):
            bdy = self.parse_symbol_body(body)
            symb.add_body(bdy)
        return symb


    def parse_footprint(self, footprint_json):
        """ Extract the bodies for a footprint. """
        footprint = Footprint()
        for body_json in footprint_json.get('bodies'):
            body = self.parse_footprint_body(body_json)
            footprint.add_body(body)
        for gen_obj_json in footprint_json.get('gen_objs'):
            gen_obj = self.parse_gen_obj(gen_obj_json)
            footprint.add_gen_obj(gen_obj)
        return footprint


    def parse_gen_obj(self, gen_obj_json):
        """ Extract the generated object. """
        gen_obj = parse_gen_obj_json(gen_obj_json)
        return gen_obj


    def parse_footprint_body(self, body_json):
        """ Extract a body of a symbol. """
        body = FBody()
        for shape in body_json.get('shapes'):
            parsed_shape = self.parse_shape(shape)
            body.add_shape(parsed_shape)
        body.layer = body_json.get('layer')
        body.rotation = body_json.get('rotation', 0)
        body.flip_horizontal = body_json.get('flip_horizontal', False)
        return body


    def parse_symbol_body(self, body):
        """ Extract a body of a symbol. """
        bdy = SBody()
        pins = body.get('pins')
        if (pins != None):
            for pin in body.get('pins'):
                parsed_pin = self.parse_pin(pin)
                bdy.add_pin(parsed_pin)
        shapes = body.get('shapes')
        if (shapes != None):
            for shape in body.get('shapes'):
                parsed_shape = self.parse_shape(shape)
                bdy.add_shape(parsed_shape)
        return bdy


    def parse_pin(self, pin):
        """ Extract a pin of a body. """
        pin_number = pin.get('pin_number')
        p1 = self.parse_point(pin.get('p1'))
        p2 = self.parse_point(pin.get('p2'))
        parsed_pin = Pin(pin_number, p1, p2)
        if pin.get('label') is not None:
            parsed_pin.label = self.parse_label(pin.get('label'))
        parsed_pin.styles = pin.get('styles') or {}
        return parsed_pin

    def parse_point(self, point):
        """ Extract a point. """
        x = int(point.get('x'))
        y = int(point.get('y'))
        return Point(x, y)

    def parse_label(self, label):
        """ Extract a label. """
        if label is None:
            return None
        x = int(label.get('x'))
        y = int(label.get('y'))
        text = label.get('text')
        font_size = label.get('font_size')
        font_family = label.get('font_family')
        align = label.get('align')
        baseline = label.get('baseline')
        rotation = float(label.get('rotation'))
        parsed_label = Label(x, y, text, font_size, font_family, align, baseline, rotation)
        parsed_label.styles = label.get('styles') or {}
        return parsed_label

    def parse_shape(self, shape):
        """ Extract a shape. """
        # pylint: disable=R0914
        # pylint: disable=R0911

        rotation = shape.get('rotation', 0.0)
        flip_horizontal = shape.get('flip_horizontal', False)

        shape_type = shape.get('type')
        if 'rectangle' == shape_type:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            height = int(shape.get('height'))
            width = int(shape.get('width'))
            parsed_shape = Rectangle(x, y, width, height)
        elif 'rounded_rectangle' == shape_type:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            height = int(shape.get('height'))
            width = int(shape.get('width'))
            radius = int(shape.get('radius'))
            parsed_shape = RoundedRectangle(x, y, width, height, radius)
        elif 'arc' == shape_type:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            start_angle = float(shape.get('start_angle'))
            end_angle = float(shape.get('end_angle'))
            radius = int(shape.get('radius'))
            parsed_shape = Arc(x, y, start_angle, end_angle, radius)
        elif 'circle' == shape_type:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            radius = int(shape.get('radius'))
            parsed_shape = Circle(x, y, radius)
        elif 'label' == shape_type:
            parsed_shape = self.parse_label(shape)
        elif 'line' == shape_type:
            p1 = self.parse_point(shape.get('p1'))
            p2 = self.parse_point(shape.get('p2'))
            parsed_shape = Line(p1, p2)
        elif 'polygon' == shape_type:
            parsed_shape = Polygon()
            for point in shape.get('points'):
                parsed_shape.add_point(self.parse_point(point))
        elif 'bezier' == shape_type:
            control1 = self.parse_point(shape.get('control1'))
            control2 = self.parse_point(shape.get('control2'))
            p1 = self.parse_point(shape.get('p1'))
            p2 = self.parse_point(shape.get('p2'))
            parsed_shape = BezierCurve(control1, control2, p1, p2)
        elif 'rounded_segment' == shape_type:
            p1 = self.parse_point(shape.get('p1'))
            p2 = self.parse_point(shape.get('p2'))
            width = int(shape.get('width'))
            parsed_shape = RoundedSegment(p1, p2, width)

        parsed_shape.rotation = rotation
        parsed_shape.flip_horizontal = flip_horizontal

        parsed_shape.styles = shape.get('styles') or {}
        parsed_shape.attributes = shape.get('attributes') or {}
        return parsed_shape

    def parse_design_attributes(self, design_attributes):
        """ Extract design attributes. """
        attrs = DesignAttributes()
        # Get the Annotations
        for annotation in design_attributes.get('annotations'):
            anno = self.parse_annotation(annotation)
            attrs.add_annotation(anno)

        # Get the Attributes
        for key, value in design_attributes.get('attributes').items():
            attrs.add_attribute(key, value)

        # Get the Metadata
        meta = self.parse_metadata(design_attributes.get('metadata'))
        attrs.set_metadata(meta)
        self.design.set_design_attributes(attrs)


    def parse_metadata(self, metadata):
        """ Extract design meta-data. """
        meta = Metadata()
        meta.set_name(metadata.get('name'))
        meta.set_license(metadata.get('license'))
        meta.set_owner(metadata.get('owner'))
        meta.set_updated_timestamp(metadata.get('updated_timestamp'))
        meta.set_design_id(metadata.get('design_id'))
        meta.set_description(metadata.get('description'))
        meta.set_slug(metadata.get('slug'))
        for attached_url in metadata.get('attached_urls'):
            meta.add_attached_url(attached_url)
        return meta


    def parse_nets(self, nets):
        """ Extract nets. """
        for net in nets:
            net_id = net.get('net_id')
            ret_net = Net(net_id)
            # Add Annotations
            for annotation in net.get('annotations'):
                anno = self.parse_annotation(annotation)
                ret_net.add_annotation(anno)
            # Get the Attributes
            for key, value in net.get('attributes').items():
                ret_net.add_attribute(key, value)
            # Get the Points
            for net_point in net.get('points'):
                npnt = self.parse_net_point(net_point)
                ret_net.add_point(npnt)
            self.design.add_net(ret_net)


    def parse_net_point(self, net_point):
        """ Extract a net point. """
        point_id = net_point.get('point_id')
        x = int(net_point.get('x'))
        y = int(net_point.get('y'))
        npnt = NetPoint(point_id, x, y)
        # Get the connected points
        for point in net_point.get('connected_points'):
            npnt.add_connected_point(point)
        # Get the ConnectedComponents
        comps = net_point.get('connected_components')
        if (comps != None):
            for connectedcomponent in comps:
                conn_comp = self.parse_connected_component(connectedcomponent)
                npnt.add_connected_component(conn_comp)
        return npnt


    def parse_connected_component(self, connectedcomponent):
        """ Extract a connected component. """
        instance_id = connectedcomponent.get('instance_id')
        pin_number = connectedcomponent.get('pin_number')
        return ConnectedComponent(instance_id, pin_number)