<commit_before>#!/usr/bin/python

import os
import datetime
from lxml import etree as et

import config
import messages as msg

import svg
import utils
import place

from shape import Shape
from style import Style
from component import Component



class Module():
    """
    """

    def __init__(self, 
                 module_dict, 
                 routing_dict, 
                 asmodule=False):
        """
        """

        self._module_dict = module_dict
        self._routing_dict = routing_dict

        self._outline = self._getOutline()
        self._width = self._outline.getWidth()
        self._height = self._outline.getHeight()

        # Get dictionary of component definitions
        components_dict = self._module_dict.get('components') or {}
        self._components = self._getComponents(components_dict)

        # Get dictionary of component definitions
        vias_dict = self._routing_dict.get('vias') or {}
        self._vias = self._getComponents(vias_dict)

        sig_dig = config.cfg['significant-digits']
        self._transform = 'translate(%s %s)' % (round(self._width/2, sig_dig),
                                                round(self._height/2, sig_dig))

        # Create the Inkscape SVG document
        self._module = self._getModuleElement()
        svg_doc = et.ElementTree(self._module)

        # Get a dictionary of SVG layers
        self._layers = svg.makeSvgLayers(self._module, self._transform)

        # Add a 'defs' element:
        #   http://www.w3.org/TR/SVG/struct.html#Head
        # This is where masking elements that are used for pours are stored
        defs = et.SubElement(self._module, 'defs')
        self._masks = {}
        for pcb_layer in utils.getSurfaceLayers():
             element = et.SubElement(defs, 'mask',
                                     id="mask-%s" % pcb_layer,
                                     transform=self._transform)
             # This will identify the masks for each PCB layer when
             # the layer is converted to Gerber
             element.set('{'+config.cfg['ns']['pcbmode']+'}pcb-layer', pcb_layer)
             self._masks[pcb_layer] = element

        self._placeOutline()
        self._placeOutlineDimensions()

        msg.subInfo('Placing components:', newline=False)
        self._placeComponents(self._components, 'components', print_refdef=True)
        print

        msg.subInfo('Placing routes')
        self._placeRouting()

        msg.subInfo('Placing vias')
        self._placeComponents(self._vias, 'vias')

        msg.subInfo('Placing shapes')
        self._placeShapes()

        msg.subInfo('Placing pours')
        self._placePours()

        if config.tmp['no-docs'] == False:
            msg.subInfo('Placing documentation')
            self._placeDocs()

        if config.tmp['no-drill-index'] == False:
            msg.subInfo('Placing drill index')
            self._placeDrillIndex()

        if config.tmp['no-layer-index'] == False:
            msg.subInfo('Placing layer index')
            self._placeLayerIndex()


        # This 'cover' "enables" the mask shapes defined in the mask are
        # shown. It *must* be the last element in the mask definition;
        # any mask element after it won't show
        for pcb_layer in utils.getSurfaceLayers():
            if utils.checkForPoursInLayer(pcb_layer) is True:
                mask_cover = et.SubElement(self._masks[pcb_layer], 'rect',
                                           x="%s" % str(-self._width/2), 
                                           y="%s" % str(-self._height/2),
                                           width="%s" % self._width,
                                           height="%s" % self._height,
                                           style="fill:#fff;")
                # This tells the Gerber conversion to ignore this shape
                mask_cover.set('{'+config.cfg['ns']['pcbmode']+'}type', 'mask-cover')

        output_file = os.path.join(config.cfg['base-dir'],
                                   config.cfg['locations']['build'],
                                   config.cfg['name'] + '.svg')
     
        try:
            f = open(output_file, 'wb')
        except IOError as e:
            print "I/O error({0}): {1}".format(e.errno, e.strerror)
     
        f.write(et.tostring(svg_doc, pretty_print=True))
        f.close()





    def _placeOutlineDimensions(self):
        """
        Places outline dimension arrows
        """


        def makeArrow(width, gap):
            """
            Returns a path for an arrow of width 'width' with a center gap of
            width 'gap'
            """
 
            # Length of bar perpendicular to the arrow's shaft
            base_length = 1.8
 
            # Height of arrow's head
            arrow_height = 2.5
 
            # Width of arrow's head
            arrow_base = 1.2
     
            # Create path
            path = "m %s,%s %s,%s m %s,%s %s,%s m %s,%s %s,%s m %s,%s %s,%s m %s,%s m %s,%s %s,%s m %s,%s %s,%s m %s,%s %s,%s m %s,%s %s,%s" % (-gap/2,0, -width/2+gap/2,0, 0,base_length/2, 0,-base_length, arrow_height,(base_length-arrow_base)/2, -arrow_height,arrow_base/2, arrow_height,arrow_base/2, -arrow_height,-arrow_base/2, width/2,0, gap/2,0, width/2-gap/2,0, 0,base_length/2, 0,-base_length, -arrow_height,(base_length-arrow_base)/2, arrow_height,arrow_base/2, -arrow_height,arrow_base/2, arrow_height,-arrow_base/2,) 
            
            return path



 
        # Create text shapes
        shape_dict = {}
        shape_dict['type'] = 'text'
        style_dict = config.stl['layout']['dimensions'].get('text') or {}
        shape_dict['font-family'] = style_dict.get('font-family') or "UbuntuMono-R-webfont"
        shape_dict['font-size'] = style_dict.get('font-size') or "1.5mm"
        shape_dict['line-height'] = style_dict.get('line-height') or "1mm"
        shape_dict['letter-spacing'] = style_dict.get('letter-spacing') or "0mm"

        # Locations
        arrow_gap = 1.5
        width_loc = [0, self._height/2+arrow_gap]
        height_loc = [-(self._width/2+arrow_gap), 0]

        # Width text
        width_text_dict = shape_dict.copy()
        width_text_dict['value'] = "%s mm" % round(self._width,2)
        width_text_dict['location'] = width_loc
        width_text = Shape(width_text_dict)
        style = Style(width_text_dict, 'dimensions')
        width_text.setStyle(style)

        # Height text
        height_text_dict = shape_dict.copy()
        height_text_dict['value'] = "%s mm" % round(self._height,2)
        height_text_dict['rotate'] = -90
        height_text_dict['location'] = height_loc
        height_text = Shape(height_text_dict)
        style = Style(height_text_dict, 'dimensions')
        height_text.setStyle(style)
 
        # Width arrow
        shape_dict = {}
        shape_dict['type'] = 'path'
        shape_dict['value'] = makeArrow(self._width, width_text.getWidth()*1.2)
        shape_dict['location'] = width_loc
        width_arrow = Shape(shape_dict)
        style = Style(shape_dict, 'dimensions')
        width_arrow.setStyle(style)
 
        # Height arrow
        shape_dict = {}
        shape_dict['type'] = 'path'
        shape_dict['value'] = makeArrow(self._height, height_text.getHeight()*1.2)
        shape_dict['rotate'] = -90
        shape_dict['location'] = height_loc
        height_arrow = Shape(shape_dict)
        style = Style(shape_dict, 'dimensions')
        height_arrow.setStyle(style)

        svg_layer = self._layers['dimensions']['layer']
        group = et.SubElement(svg_layer, 'g')
        group.set('{'+config.cfg['ns']['pcbmode']+'}type', 'module-shapes')
        place.placeShape(width_text, group)
        place.placeShape(height_text, group)
        place.placeShape(width_arrow, group)
        place.placeShape(height_arrow, group)
        





    def _placePours(self):
        """
        """

        try:
            pours = self._module_dict['shapes']['pours']
        except:
            return

        shape_group = {}
        for pcb_layer in utils.getSurfaceLayers():
            svg_layer = self._layers[pcb_layer]['copper']['pours']['layer']
            shape_group[pcb_layer] = et.SubElement(svg_layer, 'g',
                                                   mask='url(#mask-%s)' % pcb_layer)

        for pour_dict in pours:
            try:
                pour_type = pour_dict['type']
            except:
                msg.error("Can't find a 'type' for a pour shape. Pours can be any 'shape', or simply 'type':'layer' to cover the entire layer.")

            layers = pour_dict.get('layers') or ['top']

            if pour_type == 'layer':
                # Get the outline shape dict
                new_pour_dict = self._module_dict['outline'].get('shape').copy()
                new_pour_dict['style'] = 'fill'
                shape = Shape(new_pour_dict)
                style = Style(new_pour_dict, 'outline')
                shape.setStyle(style)
            else:
                shape = Shape(pour_dict)
                style = Style(pour_dict, 'outline')
                shape.setStyle(style)

            # Place on all specified layers
            for layer in layers:
                place.placeShape(shape, shape_group[layer])





    def _placeShapes(self):
        """
        """

        mirror = False

        try:
            shapes_dict = self._module_dict['shapes']
        except:
            return


        for sheet in ['copper','soldermask','solderpaste','silkscreen']:
            try:
                shapes = shapes_dict[sheet]
            except KeyError:
                continue

            there_are_pours = {}
            shape_groups = {}
            for pcb_layer in utils.getSurfaceLayers():
                there_are_pours[pcb_layer] = utils.checkForPoursInLayer(pcb_layer)
                shape_groups[pcb_layer] = et.SubElement(self._layers[pcb_layer][sheet]['layer'], 'g')
                shape_groups[pcb_layer].set('{'+config.cfg['ns']['pcbmode']+'}type', 'module-shapes')


            for shape_dict in shapes:

                pcb_layers = shape_dict.get('layers') or ['top']

                for pcb_layer in pcb_layers:

                    # Shapes placed on the bottom layer are not mirrored
                    # unless they are text, in which case, it's the
                    # expected behaviour and so it is mirrored by default
                    # unless otherwise instructed.
                    try:
                        shape_mirror = shape_dict.get['mirror']
                    except:
                        if shape_dict['type'] == 'text':
                            shape_mirror = True
                        else:
                            shape_mirror = False
                        
                    if (pcb_layer == 'bottom') and (shape_mirror != False):
                        mirror = True
                    else:
                        mirror = False
                    shape = Shape(shape_dict)
                    style = Style(shape_dict, sheet)
                    shape.setStyle(style)
                    place.placeShape(shape, shape_groups[pcb_layer], mirror)
     
                    # Place mask for pour if copper shape
                    if (sheet == 'copper') and (there_are_pours[pcb_layer] == True):
                        location = shape.getLocation()
                        transform = "translate(%s,%s)" % (location.x, location.y)
                        mask_group = et.SubElement(self._masks[pcb_layer], 'g')
                                                   #id="routing_masks") 
                                                   #transform=transform)
                        self._placeMask(mask_group, 
                                        shape,
                                        'pad',
                                        False,
                                        mirror)


     
     
     
     
    def _placeComponents(self, components, component_type, print_refdef=False):
        """
        """
        for component in components:
            shapes_dict = component.getShapes()
            location = component.getLocation()

            # If the component is placed on the bottom layer we need
            # to invert the shapes AND their 'x' coordinate.  This is
            # sone using the 'invert' indicator set below
            refdef = component.getRefdef()

            if print_refdef == True:
                print refdef,

            placement_layer = component.getPlacementLayer()
            if placement_layer == 'bottom':
                invert = True
            else:
                invert = False

            for pcb_layer in utils.getSurfaceLayers():

                there_are_pours = utils.checkForPoursInLayer(pcb_layer)

                # Copper
                shapes = shapes_dict['copper'][pcb_layer]
                if len(shapes) > 0:
                    svg_layer = self._layers[pcb_layer]['copper']['pads']['layer']
     
                    transform = "translate(%s,%s)" % (location[0],
                                                      config.cfg['invert-y']*location[1])
                    group = et.SubElement(svg_layer, 'g', 
                                          transform=transform)

                    if component_type == 'components':
                        group.set('{'+config.cfg['ns']['pcbmode']+'}refdef', component.getRefdef())
                    elif component_type == 'vias':
                        group.set('{'+config.cfg['ns']['pcbmode']+'}type', 'via')
                        group.set('{'+config.cfg['ns']['pcbmode']+'}via', component.getFootprintName())
                    else:
                        pass

                    for shape in shapes:
                        place.placeShape(shape, group, invert)
                        if there_are_pours == True:
                            mask_group = et.SubElement(self._masks[pcb_layer], 'g', 
                                                       transform=transform)
                            self._placeMask(mask_group, 
                                            shape,
                                            'pad',
                                            False,
                                            invert)

                    # Add pin labels
                    labels = shapes_dict['pin-labels'][pcb_layer]
                    if labels != []:
                        style = utils.dictToStyleText(config.stl['layout']['board']['pad-labels'])
                        label_group = et.SubElement(group, 'g', 
                                                    transform="rotate(%s)" % component.getRotation(),
                                                    style=style)
                        for label in labels:
                            t = et.SubElement(label_group, 'text',
                                              x=str(label['location'][0]),
                                              # TODO: get rid of this hack
                                              y=str(-label['location'][1]))
                                              #y=str(-pin_location.y + pad_numbers_font_size/3),
                                              #refdef=self._refdef)
                            t.text = label['text']





                # Soldermask
                shapes = shapes_dict['soldermask'][pcb_layer]
                if len(shapes) > 0:
                    svg_layer = self._layers[pcb_layer]['soldermask']['layer']
                    transform = "translate(%s,%s)" % (location[0],
                                                      config.cfg['invert-y']*location[1])
                    group = et.SubElement(svg_layer, 'g', transform=transform)
                    group.set('{'+config.cfg['ns']['pcbmode']+'}type', 'component-shapes')
                    for shape in shapes:
                        placed_element = place.placeShape(shape, group, invert)
     
                    # Solderpaste
                    shapes = shapes_dict['solderpaste'][pcb_layer]
                    svg_layer = self._layers[pcb_layer]['solderpaste']['layer']
                    transform = "translate(%s,%s)" % (location[0],
                                                      config.cfg['invert-y']*location[1])
                    group = et.SubElement(svg_layer, 'g', transform=transform)
                    group.set('{'+config.cfg['ns']['pcbmode']+'}type', 'component-shapes')
                    for shape in shapes:
                        placed_element = place.placeShape(shape, group, invert)


                # Silkscreen
                shapes = shapes_dict['silkscreen'][pcb_layer]
                if len(shapes) > 0:
                    svg_layer = self._layers[pcb_layer]['silkscreen']['layer']
                    transform = "translate(%s,%s)" % (location[0],
                                                      config.cfg['invert-y']*location[1])
                    shape_group = et.SubElement(svg_layer, 'g', transform=transform)
                    shape_group.set('{'+config.cfg['ns']['pcbmode']+'}type', 'component-shapes')
     
                    for shape in shapes:
                        # Refdefs need to be in their own groups so that their
                        # location can later be extracted, hence this...
                        try:
                            is_refdef = getattr(shape, 'is_refdef')
                        except:
                            is_refdef = False

                        if is_refdef == True:
                            refdef_group = et.SubElement(svg_layer, 'g', transform=transform)
                            refdef_group.set('{'+config.cfg['ns']['pcbmode']+'}type', 'refdef')
                            refdef_group.set('{'+config.cfg['ns']['pcbmode']+'}refdef', refdef)
                            placed_element = place.placeShape(shape, refdef_group, invert)
                        else:
                            placed_element = place.placeShape(shape, shape_group, invert)


                # Assembly
                shapes = shapes_dict['assembly'][pcb_layer]
                if len(shapes) > 0: 
                    svg_layer = self._layers[pcb_layer]['assembly']['layer']
                    transform = "translate(%s,%s)" % (location[0],
                                                      config.cfg['invert-y']*location[1])
                    group = et.SubElement(svg_layer, 'g', transform=transform)
                    for shape in shapes:
                        placed_element = place.placeShape(shape, group, invert)

                # Drills
                shapes = shapes_dict['drills'][pcb_layer]
                if len(shapes) > 0:
                    svg_layer = self._layers['drills']['layer']
                    transform = "translate(%s,%s)" % (location[0],
                                                      config.cfg['invert-y']*location[1])
                    group = et.SubElement(svg_layer, 'g', transform=transform)
                    group.set('{'+config.cfg['ns']['pcbmode']+'}type', 'component-shapes')
                    for shape in shapes:
                        placed_element = place.placeShape(shape, group, invert)
                        placed_element.set('{'+config.cfg['ns']['pcbmode']+'}diameter',
                                           str(shape.getDiameter()))






    def _placeRouting(self):
        """
        """

        routing = config.rte
        routes = routing.get('routes') or {}
        vias = routing.get('vias') <commit_msg>Correctly place components on the bottom layer<commit_after>#!/usr/bin/python

import os
import datetime
from lxml import etree as et

import config
import messages as msg

import svg
import utils
import place

from shape import Shape
from style import Style
from component import Component



class Module():
    """
    """

    def __init__(self, 
                 module_dict, 
                 routing_dict, 
                 asmodule=False):
        """
        """

        self._module_dict = module_dict
        self._routing_dict = routing_dict

        self._outline = self._getOutline()
        self._width = self._outline.getWidth()
        self._height = self._outline.getHeight()

        # Get dictionary of component definitions
        components_dict = self._module_dict.get('components') or {}
        self._components = self._getComponents(components_dict)

        # Get dictionary of component definitions
        vias_dict = self._routing_dict.get('vias') or {}
        self._vias = self._getComponents(vias_dict)

        sig_dig = config.cfg['significant-digits']
        self._transform = 'translate(%s %s)' % (round(self._width/2, sig_dig),
                                                round(self._height/2, sig_dig))

        # Create the Inkscape SVG document
        self._module = self._getModuleElement()
        svg_doc = et.ElementTree(self._module)

        # Get a dictionary of SVG layers
        self._layers = svg.makeSvgLayers(self._module, self._transform)

        # Add a 'defs' element:
        #   http://www.w3.org/TR/SVG/struct.html#Head
        # This is where masking elements that are used for pours are stored
        defs = et.SubElement(self._module, 'defs')
        self._masks = {}
        for pcb_layer in utils.getSurfaceLayers():
             element = et.SubElement(defs, 'mask',
                                     id="mask-%s" % pcb_layer,
                                     transform=self._transform)
             # This will identify the masks for each PCB layer when
             # the layer is converted to Gerber
             element.set('{'+config.cfg['ns']['pcbmode']+'}pcb-layer', pcb_layer)
             self._masks[pcb_layer] = element

        self._placeOutline()
        self._placeOutlineDimensions()

        msg.subInfo('Placing components:', newline=False)
        self._placeComponents(self._components, 'components', print_refdef=True)
        print

        msg.subInfo('Placing routes')
        self._placeRouting()

        msg.subInfo('Placing vias')
        self._placeComponents(self._vias, 'vias')

        msg.subInfo('Placing shapes')
        self._placeShapes()

        msg.subInfo('Placing pours')
        self._placePours()

        if config.tmp['no-docs'] == False:
            msg.subInfo('Placing documentation')
            self._placeDocs()

        if config.tmp['no-drill-index'] == False:
            msg.subInfo('Placing drill index')
            self._placeDrillIndex()

        if config.tmp['no-layer-index'] == False:
            msg.subInfo('Placing layer index')
            self._placeLayerIndex()


        # This 'cover' "enables" the mask shapes defined in the mask are
        # shown. It *must* be the last element in the mask definition;
        # any mask element after it won't show
        for pcb_layer in utils.getSurfaceLayers():
            if utils.checkForPoursInLayer(pcb_layer) is True:
                mask_cover = et.SubElement(self._masks[pcb_layer], 'rect',
                                           x="%s" % str(-self._width/2), 
                                           y="%s" % str(-self._height/2),
                                           width="%s" % self._width,
                                           height="%s" % self._height,
                                           style="fill:#fff;")
                # This tells the Gerber conversion to ignore this shape
                mask_cover.set('{'+config.cfg['ns']['pcbmode']+'}type', 'mask-cover')

        output_file = os.path.join(config.cfg['base-dir'],
                                   config.cfg['locations']['build'],
                                   config.cfg['name'] + '.svg')
     
        try:
            f = open(output_file, 'wb')
        except IOError as e:
            print "I/O error({0}): {1}".format(e.errno, e.strerror)
     
        f.write(et.tostring(svg_doc, pretty_print=True))
        f.close()





    def _placeOutlineDimensions(self):
        """
        Places outline dimension arrows
        """


        def makeArrow(width, gap):
            """
            Returns a path for an arrow of width 'width' with a center gap of
            width 'gap'
            """
 
            # Length of bar perpendicular to the arrow's shaft
            base_length = 1.8
 
            # Height of arrow's head
            arrow_height = 2.5
 
            # Width of arrow's head
            arrow_base = 1.2
     
            # Create path
            path = "m %s,%s %s,%s m %s,%s %s,%s m %s,%s %s,%s m %s,%s %s,%s m %s,%s m %s,%s %s,%s m %s,%s %s,%s m %s,%s %s,%s m %s,%s %s,%s" % (-gap/2,0, -width/2+gap/2,0, 0,base_length/2, 0,-base_length, arrow_height,(base_length-arrow_base)/2, -arrow_height,arrow_base/2, arrow_height,arrow_base/2, -arrow_height,-arrow_base/2, width/2,0, gap/2,0, width/2-gap/2,0, 0,base_length/2, 0,-base_length, -arrow_height,(base_length-arrow_base)/2, arrow_height,arrow_base/2, -arrow_height,arrow_base/2, arrow_height,-arrow_base/2,) 
            
            return path



 
        # Create text shapes
        shape_dict = {}
        shape_dict['type'] = 'text'
        style_dict = config.stl['layout']['dimensions'].get('text') or {}
        shape_dict['font-family'] = style_dict.get('font-family') or "UbuntuMono-R-webfont"
        shape_dict['font-size'] = style_dict.get('font-size') or "1.5mm"
        shape_dict['line-height'] = style_dict.get('line-height') or "1mm"
        shape_dict['letter-spacing'] = style_dict.get('letter-spacing') or "0mm"

        # Locations
        arrow_gap = 1.5
        width_loc = [0, self._height/2+arrow_gap]
        height_loc = [-(self._width/2+arrow_gap), 0]

        # Width text
        width_text_dict = shape_dict.copy()
        width_text_dict['value'] = "%s mm" % round(self._width,2)
        width_text_dict['location'] = width_loc
        width_text = Shape(width_text_dict)
        style = Style(width_text_dict, 'dimensions')
        width_text.setStyle(style)

        # Height text
        height_text_dict = shape_dict.copy()
        height_text_dict['value'] = "%s mm" % round(self._height,2)
        height_text_dict['rotate'] = -90
        height_text_dict['location'] = height_loc
        height_text = Shape(height_text_dict)
        style = Style(height_text_dict, 'dimensions')
        height_text.setStyle(style)
 
        # Width arrow
        shape_dict = {}
        shape_dict['type'] = 'path'
        shape_dict['value'] = makeArrow(self._width, width_text.getWidth()*1.2)
        shape_dict['location'] = width_loc
        width_arrow = Shape(shape_dict)
        style = Style(shape_dict, 'dimensions')
        width_arrow.setStyle(style)
 
        # Height arrow
        shape_dict = {}
        shape_dict['type'] = 'path'
        shape_dict['value'] = makeArrow(self._height, height_text.getHeight()*1.2)
        shape_dict['rotate'] = -90
        shape_dict['location'] = height_loc
        height_arrow = Shape(shape_dict)
        style = Style(shape_dict, 'dimensions')
        height_arrow.setStyle(style)

        svg_layer = self._layers['dimensions']['layer']
        group = et.SubElement(svg_layer, 'g')
        group.set('{'+config.cfg['ns']['pcbmode']+'}type', 'module-shapes')
        place.placeShape(width_text, group)
        place.placeShape(height_text, group)
        place.placeShape(width_arrow, group)
        place.placeShape(height_arrow, group)
        





    def _placePours(self):
        """
        """

        try:
            pours = self._module_dict['shapes']['pours']
        except:
            return

        shape_group = {}
        for pcb_layer in utils.getSurfaceLayers():
            svg_layer = self._layers[pcb_layer]['copper']['pours']['layer']
            shape_group[pcb_layer] = et.SubElement(svg_layer, 'g',
                                                   mask='url(#mask-%s)' % pcb_layer)

        for pour_dict in pours:
            try:
                pour_type = pour_dict['type']
            except:
                msg.error("Can't find a 'type' for a pour shape. Pours can be any 'shape', or simply 'type':'layer' to cover the entire layer.")

            layers = pour_dict.get('layers') or ['top']

            if pour_type == 'layer':
                # Get the outline shape dict
                new_pour_dict = self._module_dict['outline'].get('shape').copy()
                new_pour_dict['style'] = 'fill'
                shape = Shape(new_pour_dict)
                style = Style(new_pour_dict, 'outline')
                shape.setStyle(style)
            else:
                shape = Shape(pour_dict)
                style = Style(pour_dict, 'outline')
                shape.setStyle(style)

            # Place on all specified layers
            for layer in layers:
                place.placeShape(shape, shape_group[layer])





    def _placeShapes(self):
        """
        """

        mirror = False

        try:
            shapes_dict = self._module_dict['shapes']
        except:
            return


        for sheet in ['copper','soldermask','solderpaste','silkscreen']:
            try:
                shapes = shapes_dict[sheet]
            except KeyError:
                continue

            there_are_pours = {}
            shape_groups = {}
            for pcb_layer in utils.getSurfaceLayers():
                there_are_pours[pcb_layer] = utils.checkForPoursInLayer(pcb_layer)
                shape_groups[pcb_layer] = et.SubElement(self._layers[pcb_layer][sheet]['layer'], 'g')
                shape_groups[pcb_layer].set('{'+config.cfg['ns']['pcbmode']+'}type', 'module-shapes')


            for shape_dict in shapes:

                pcb_layers = shape_dict.get('layers') or ['top']

                for pcb_layer in pcb_layers:

                    # Shapes placed on the bottom layer are not mirrored
                    # unless they are text, in which case, it's the
                    # expected behaviour and so it is mirrored by default
                    # unless otherwise instructed.
                    try:
                        shape_mirror = shape_dict.get['mirror']
                    except:
                        if shape_dict['type'] == 'text':
                            shape_mirror = True
                        else:
                            shape_mirror = False
                        
                    if (pcb_layer == 'bottom') and (shape_mirror != False):
                        mirror = True
                    else:
                        mirror = False
                    shape = Shape(shape_dict)
                    style = Style(shape_dict, sheet)
                    shape.setStyle(style)
                    place.placeShape(shape, shape_groups[pcb_layer], mirror)
     
                    # Place mask for pour if copper shape
                    if (sheet == 'copper') and (there_are_pours[pcb_layer] == True):
                        location = shape.getLocation()
                        transform = "translate(%s,%s)" % (location.x, location.y)
                        mask_group = et.SubElement(self._masks[pcb_layer], 'g')
                                                   #id="routing_masks") 
                                                   #transform=transform)
                        self._placeMask(mask_group, 
                                        shape,
                                        'pad',
                                        False,
                                        mirror)


     
     
     
     
    def _placeComponents(self, components, component_type, print_refdef=False):
        """
        """
        for component in components:
            shapes_dict = component.getShapes()
            location = component.getLocation()

            # If the component is placed on the bottom layer we need
            # to invert the shapes AND their 'x' coordinate.  This is
            # sone using the 'invert' indicator set below
            refdef = component.getRefdef()

            if print_refdef == True:
                print refdef,

            placement_layer = component.getPlacementLayer()
            if placement_layer == 'bottom':
                invert = True
            else:
                invert = False

            for pcb_layer in utils.getSurfaceLayers():

                there_are_pours = utils.checkForPoursInLayer(pcb_layer)

                # Copper
                shapes = shapes_dict['copper'][pcb_layer]
                if len(shapes) > 0:
                    svg_layer = self._layers[pcb_layer]['copper']['pads']['layer']
     
                    transform = "translate(%s,%s)" % (location[0],
                                                      config.cfg['invert-y']*location[1])
                    group = et.SubElement(svg_layer, 'g', 
                                          transform=transform)

                    if component_type == 'components':
                        group.set('{'+config.cfg['ns']['pcbmode']+'}refdef', component.getRefdef())
                    elif component_type == 'vias':
                        group.set('{'+config.cfg['ns']['pcbmode']+'}type', 'via')
                        group.set('{'+config.cfg['ns']['pcbmode']+'}via', component.getFootprintName())
                    else:
                        pass

                    for shape in shapes:
                        place.placeShape(shape, group)
                        if there_are_pours == True:
                            mask_group = et.SubElement(self._masks[pcb_layer], 'g', 
                                                       transform=transform)
                            self._placeMask(mask_group, 
                                            shape,
                                            'pad')

                    # Add pin labels
                    labels = shapes_dict['pin-labels'][pcb_layer]
                    if labels != []:
                        style = utils.dictToStyleText(config.stl['layout']['board']['pad-labels'])
                        label_group = et.SubElement(group, 'g', 
                                                    transform="rotate(%s)" % component.getRotation(),
                                                    style=style)
                        for label in labels:
                            t = et.SubElement(label_group, 'text',
                                              x=str(label['location'][0]),
                                              # TODO: get rid of this hack
                                              y=str(-label['location'][1]))
                                              #y=str(-pin_location.y + pad_numbers_font_size/3),
                                              #refdef=self._refdef)
                            t.text = label['text']





                # Soldermask
                shapes = shapes_dict['soldermask'][pcb_layer]
                if len(shapes) > 0:
                    svg_layer = self._layers[pcb_layer]['soldermask']['layer']
                    transform = "translate(%s,%s)" % (location[0],
                                                      config.cfg['invert-y']*location[1])
                    group = et.SubElement(svg_layer, 'g', transform=transform)
                    group.set('{'+config.cfg['ns']['pcbmode']+'}type', 'component-shapes')
                    for shape in shapes:
                        placed_element = place.placeShape(shape, group)
     
                    # Solderpaste
                    shapes = shapes_dict['solderpaste'][pcb_layer]
                    svg_layer = self._layers[pcb_layer]['solderpaste']['layer']
                    transform = "translate(%s,%s)" % (location[0],
                                                      config.cfg['invert-y']*location[1])
                    group = et.SubElement(svg_layer, 'g', transform=transform)
                    group.set('{'+config.cfg['ns']['pcbmode']+'}type', 'component-shapes')
                    for shape in shapes:
                        placed_element = place.placeShape(shape, group, invert)


                # Silkscreen
                shapes = shapes_dict['silkscreen'][pcb_layer]
                if len(shapes) > 0:
                    svg_layer = self._layers[pcb_layer]['silkscreen']['layer']
                    transform = "translate(%s,%s)" % (location[0],
                                                      config.cfg['invert-y']*location[1])
                    shape_group = et.SubElement(svg_layer, 'g', transform=transform)
                    shape_group.set('{'+config.cfg['ns']['pcbmode']+'}type', 'component-shapes')
     
                    for shape in shapes:
                        # Refdefs need to be in their own groups so that their
                        # location can later be extracted, hence this...
                        try:
                            is_refdef = getattr(shape, 'is_refdef')
                        except:
                            is_refdef = False

                        if is_refdef == True:
                            refdef_group = et.SubElement(svg_layer, 'g', transform=transform)
                            refdef_group.set('{'+config.cfg['ns']['pcbmode']+'}type', 'refdef')
                            refdef_group.set('{'+config.cfg['ns']['pcbmode']+'}refdef', refdef)
                            placed_element = place.placeShape(shape, refdef_group)
                        else:
                            placed_element = place.placeShape(shape, shape_group)


                # Assembly
                shapes = shapes_dict['assembly'][pcb_layer]
                if len(shapes) > 0: 
                    svg_layer = self._layers[pcb_layer]['assembly']['layer']
                    transform = "translate(%s,%s)" % (location[0],
                                                      config.cfg['invert-y']*location[1])
                    group = et.SubElement(svg_layer, 'g', transform=transform)
                    for shape in shapes:
                        placed_element = place.placeShape(shape, group)

                # Drills
                shapes = shapes_dict['drills'][pcb_layer]
                if len(shapes) > 0:
                    svg_layer = self._layers['drills']['layer']
                    transform = "translate(%s,%s)" % (location[0],
                                                      config.cfg['invert-y']*location[1])
                    group = et.SubElement(svg_layer, 'g', transform=transform)
                    group.set('{'+config.cfg['ns']['pcbmode']+'}type', 'component-shapes')
                    for shape in shapes:
                        placed_element = place.placeShape(shape, group)
                        placed_element.set('{'+config.cfg['ns']['pcbmode']+'}diameter',
                                           str(shape.getDiameter()))






    def _placeRouting(self):
        """
        """

        routing = config.rte
        routes = routing.get('routes') or {}
        vias = routing.get('vias') 
{'fraction_non_alphanumeric': 0.1132104298227745, 'fraction_numerical': 0.004023222652271338, 'mean_word_length': 1.4571732465744853, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 128, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4069882', 'n_tokens_mistral': 10699, 'n_tokens_neox': 10066, 'n_words': 2064}