def bodies(self, offset, instance_attributes):
        """ Generated the bodies for the Via with instance attribute overrides. Returns placment attribute and body
            pairs.

        """
        pos = Point(self.x, self.y)

        attached_layers = self.get_attr('attached_layers', '',
                                        instance_attributes).split(',')
        solder_mask_expansion = self.get_int_attr('solder_mask_expansion', 0,
                                                  instance_attributes)
        plating_diameter = self.get_int_attr('plating_diameter', 0,
                                             instance_attributes)
        internal_diameter = self.get_int_attr('internal_diameter', 0,
                                              instance_attributes)
        solder_mask_radius = solder_mask_expansion + (plating_diameter / 2)

        # placment attribute + body pairs making up the generated object
        bodies = []

        top_solder_mask = FBody()
        top_solder_mask.add_shape(Circle(pos.x, pos.y, solder_mask_radius))
        bodies.append((FootprintAttribute(0, 0, 0, False,
                                          'top solder mask'), top_solder_mask))

        bottom_solder_mask = FBody()
        bottom_solder_mask.add_shape(Circle(pos.x, pos.y, solder_mask_radius))
        bodies.append(
            (FootprintAttribute(0, 0, 0, False,
                                'bottom solder mask'), bottom_solder_mask))

        # circle of diameter 'internal_diameter' on the hole layer
        hole = FBody()
        hole.add_shape(Circle(pos.x, pos.y, internal_diameter / 2))
        bodies.append((FootprintAttribute(0, 0, 0, False, 'hole'), hole))

        # circles of diameter 'plating_diameter' on each connection layer
        for layer_name in attached_layers:
            connected_layer = FBody()
            connected_layer.add_shape(
                Circle(pos.x, pos.y, plating_diameter / 2))
            bodies.append((FootprintAttribute(0, 0, 0, False,
                                              layer_name), connected_layer))

        return bodies
    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 _convert_components(self, struct):
        """ Convert component """
        for component in struct.placement.component:
            library_id = component.image_id
            for place in component.place:
                # Outside PCB boundary
                if not place.vertex:
                    continue

                mirror = {90:270, 270:90}
                if place.side == 'back':
                    rotation = place.rotation
                else:
                    rotation = mirror.get(int(place.rotation), place.rotation)
                inst = ComponentInstance(place.component_id, component, library_id, 0)
                v = self.to_pixels(place.vertex)
                symbattr = FootprintAttribute(v[0], v[1], to_piradians(rotation), False)
                inst.add_symbol_attribute(symbattr) 
                self.design.add_component_instance(inst)
    def bodies(self, offset, instance_attributes):
        bodies = []

        attached_layers = self.get_attr('attached_layers', '',
                                        instance_attributes).split(',')
        width = self.get_int_attr('width', 0, instance_attributes)
        height = self.get_int_attr('height', 0, instance_attributes)
        radius = self.get_int_attr('radius', 0, instance_attributes)
        shape_type = self.get_attr('shape', '', instance_attributes)

        pos = Point(self.x, self.y)

        for layer_name in attached_layers:
            layer_name = layer_name
            pad = FBody()
            # invert top/bottom if the footprint is on the bottom of the board
            if offset.side == 'bottom':
                rev_sides = {'top': 'bottom', 'bottom': 'top'}
                layer_name = ' '.join([
                    rev_sides.get(piece, piece)
                    for piece in layer_name.split(' ')
                ])

            if shape_type == 'rectangle':
                pad.add_shape(
                    Rectangle((width / 2), -(height / 2), width, height))
            elif shape_type == 'rounded rectangle':
                pad.add_shape(
                    RoundedRectangle((width / 2), -(height / 2), width, height,
                                     radius))
            elif shape_type == 'circle':
                pad.add_shape(Circle(0, 0, radius))
            else:
                raise ValueError('unexpected shape type for padstack')

            pad.rotate(self.rotation)
            pad.shift(pos.x, pos.y)
            bodies.append((FootprintAttribute(0, 0, 0, False,
                                              layer_name), pad))

        return bodies
    def bodies(self, offset, instance_attributes):
        """ Generated the bodies for the Via with instance attribute overrides. Returns placment attribute and body
            pairs.

        """
        attached_layers = self.get_attr('attached_layers', '',
                                        instance_attributes).split(',')
        internal_diameter = self.get_float_attr('internal_diameter', 0,
                                                instance_attributes)
        plating_shape = self.get_attr('plating_shape', '', instance_attributes)

        # Local vars for use in closures to generate shapes
        # XXX(shamer): The assignment of width and lenght are reversed from the javascript. Not sure why this is.
        plating_width = self.get_float_attr('plating_length', 0,
                                            instance_attributes)
        plating_height = self.get_float_attr('plating_width', 0,
                                             instance_attributes)
        plating_radius = self.get_float_attr('plating_radius', 0,
                                             instance_attributes)
        plating_diameter = self.get_float_attr('plating_diameter', 0,
                                               instance_attributes)

        solder_mask_expansion = self.get_float_attr('solder_mask_expansion', 0,
                                                    instance_attributes)
        #thermal_inner_diameter = self.get_float_attr('thermal_inner_diameter', 0, instance_attributes)
        #thermal_spoke_width = self.get_float_attr('thermal_spoke_width', 0, instance_attributes)
        #antipad_diameter = self.get_float_attr('antipad_diameter', 0, instance_attributes)

        # placment attribute + body pairs making up the generated object
        bodies = []

        pad_pos = Point(self.x, self.y)
        sme_pos = Point(self.x, self.y)

        # Debugging marker for displaying the placment position for generated objects.
        #marker = FBody()
        #marker.add_shape(Circle(pad_pos.x, pad_pos.y, 1000000))
        #bodies.append((FootprintAttribute(0, 0, 0, False, 'top silkscreen'), marker))

        if plating_shape == 'square':
            solder_mask_width = (solder_mask_expansion * 2) + plating_diameter

            create_shape = lambda: Rectangle(
                pad_pos.x, pad_pos.y, plating_diameter, plating_diameter)
            create_solder_mask_expansion = lambda: Rectangle(
                sme_pos.x, sme_pos.y, solder_mask_width, solder_mask_width)

        elif plating_shape == 'circle':
            create_shape = lambda: Circle(pad_pos.x, pad_pos.y,
                                          plating_diameter / 2)

            solder_mask_radius = solder_mask_expansion + (plating_diameter / 2)
            create_solder_mask_expansion = lambda: Circle(
                sme_pos.x, sme_pos.y, solder_mask_radius)

        elif plating_shape == 'rectangle':
            solder_mask_width = (solder_mask_expansion * 2) + plating_width
            solder_mask_height = (solder_mask_expansion * 2) + plating_height

            create_shape = lambda: Rectangle(pad_pos.x, pad_pos.y,
                                             plating_width, plating_height)
            create_solder_mask_expansion = lambda: Rectangle(
                sme_pos.x, sme_pos.y, solder_mask_width, solder_mask_height)

        elif plating_shape == 'rounded rectangle':
            solder_mask_width = (solder_mask_expansion * 2) + plating_width
            solder_mask_height = (solder_mask_expansion * 2) + plating_height

            create_shape = lambda: RoundedRectangle(
                pad_pos.x, pad_pos.y, plating_width, plating_height,
                plating_radius)
            create_solder_mask_expansion = lambda: RoundedRectangle(
                sme_pos.x, sme_pos.y, solder_mask_width, solder_mask_height,
                plating_radius)

        else:
            raise ValueError(
                'unexpected shape for plated through hole "{0}"'.format(
                    plating_shape))

        # cirle of radius 'solder_mask_expansion' + ('plating_diameter' / 2) in the top and bottom silkscreen layers
        solder_mask_radius = solder_mask_expansion + (plating_diameter / 2)
        top_solder_mask = FBody()
        top_solder_mask.add_shape(create_solder_mask_expansion())
        bodies.append((FootprintAttribute(0, 0, 0, False,
                                          'top solder mask'), top_solder_mask))

        bottom_solder_mask = FBody()
        bottom_solder_mask.add_shape(create_solder_mask_expansion())
        bodies.append(
            (FootprintAttribute(0, 0, 0, False,
                                'bottom solder mask'), bottom_solder_mask))

        # circle of diameter 'internal_diameter' on the hole layer
        hole = FBody()
        hole.add_shape(Circle(pad_pos.x, pad_pos.y, internal_diameter / 2))
        bodies.append((FootprintAttribute(0, 0, 0, False, 'hole'), hole))

        # circles of diameter 'plating_diameter' on each connection layer
        for layer_name in attached_layers:
            connected_layer = FBody()
            if layer_name == 'top copper' or layer_name == 'bottom copper':
                connected_layer.add_shape(create_shape())
            else:
                connected_layer.add_shape(
                    Circle(pad_pos.x, pad_pos.y, plating_diameter / 2))
            bodies.append((FootprintAttribute(0, 0, 0, False,
                                              layer_name), connected_layer))

        return bodies