Example #1
0
    def _placeOutline(self):
        """
        """
        # Place shape
        shape_group = et.SubElement(self._layers['outline']['layer'], 'g')
        shape_group.set('{' + config.cfg['ns']['pcbmode'] + '}type',
                        'module-shapes')
        place.placeShape(self._outline, shape_group)

        # Place a mask for the board's outline. This creates a buffer between
        # the board's edge and pours
        try:
            pour_buffer = self._module['distances']['from-pour-to']['outline']
        except:
            pour_buffer = config.brd['distances']['from-pour-to']['outline']

        for pcb_layer in utils.getSurfaceLayers():
            if utils.checkForPoursInLayer(pcb_layer) is True:
                mask_element = place.placeShape(self._outline,
                                                self._masks[pcb_layer])
                # Override style so that we get the desired effect
                # We stroke the outline with twice the size of the buffer, so
                # we get the actual distance between the outline and board
                style = "fill:none;stroke:#000;stroke-linejoin:round;stroke-width:%s;" % str(
                    pour_buffer * 2)
                mask_element.set('style', style)

                # Also override mask's gerber-lp and set to all clear
                path = self._outline.getOriginalPath().lower()
                segments = path.count('m')
                mask_element.set(
                    '{' + config.cfg['ns']['pcbmode'] + '}gerber-lp',
                    'c' * segments)
Example #2
0
    def _placeOutline(self):
        """
        """
        # Place shape
        shape_group = et.SubElement(self._layers['outline']['layer'], 'g')
        shape_group.set('{'+config.cfg['ns']['pcbmode']+'}type', 'module-shapes')
        place.placeShape(self._outline, shape_group)

        # Place a mask for the board's outline. This creates a buffer between 
        # the board's edge and pours
        try:
            pour_buffer = self._module['distances']['from-pour-to']['outline']
        except:
            pour_buffer = config.brd['distances']['from-pour-to']['outline']

        for pcb_layer in config.stk['layer-names']:
            if utils.checkForPoursInLayer(pcb_layer) is True:
                mask_element = place.placeShape(self._outline, self._masks[pcb_layer])
                # Override style so that we get the desired effect
                # We stroke the outline with twice the size of the buffer, so
                # we get the actual distance between the outline and board
                style = "fill:none;stroke:#000;stroke-linejoin:round;stroke-width:%s;" % str(pour_buffer*2)
                mask_element.set('style', style)

                # Also override mask's gerber-lp and set to all clear
                path = self._outline.getOriginalPath().lower()
                segments = path.count('m')
                mask_element.set('{'+config.cfg['ns']['pcbmode']+'}gerber-lp', 'c'*segments)
Example #3
0
    def _placeLayerIndex(self):
        """
        Adds a drill index
        """

        text_dict = config.stl['layout']['layer-index']['text']
        text_dict['type'] = 'text'

        # Set the height (and width) of the rectangle (square) to the
        # size of the text
        rect_width = utils.parseDimension(text_dict['font-size'])[0]
        rect_height = rect_width
        rect_gap = 0.25

        # Get location, or generate one
        try:
            location = config.brd['layer-index']['location']
        except:
            # If not location is specified, put the drill index at the
            # top right of the board. The 'gap' defines the extra
            # spcae between the top of the largest drill and the
            # board's edge
            gap = 2
            location = [self._width/2+gap, self._height/2-rect_height/2]
        location = utils.toPoint(location)        

        rect_dict = {}
        rect_dict['type'] = 'rect'
        rect_dict['style'] = 'fill'
        rect_dict['width'] = rect_width
        rect_dict['height'] = rect_height

        # Create group for placing index
        for pcb_layer in utils.getSurfaceLayers():
            for sheet in ['copper', 'soldermask', 'silkscreen', 'assembly', 'solderpaste']:
                layer = self._layers[pcb_layer][sheet]['layer']
                transform = "translate(%s,%s)" % (location.x, config.cfg['invert-y']*location.y)
                group = et.SubElement(layer, 'g',
                                      transform=transform)
                group.set('{'+config.cfg['ns']['pcbmode']+'}type', 'layer-index')

                rect_shape = Shape(rect_dict)
                style = Style(rect_dict, sheet)
                rect_shape.setStyle(style)
                place.placeShape(rect_shape, group)

                text_dict['value'] = "%s %s" % (pcb_layer, sheet)
                #text_dict['location'] = [rect_width+rect_gap+text_width, 0]
                text_shape = Shape(text_dict)
                text_width = text_shape.getWidth()
                style = Style(text_dict, sheet)
                text_shape.setStyle(style)
                element = place.placeShape(text_shape, group)
                element.set("transform", "translate(%s,%s)" % (rect_width/2+rect_gap+text_width/2, 0))

                location.y += config.cfg['invert-y']*(rect_height+rect_gap)

            location.y += config.cfg['invert-y']*(rect_height+rect_gap*2)
Example #4
0
    def _placeDocs(self):
        """
        Places documentation blocks on the documentation layer
        """
        try:
            docs_dict = config.brd['documentation']
        except:
            return

        for key in docs_dict:

            location = utils.toPoint(docs_dict[key]['location'])
            docs_dict[key]['location'] = [0, 0]

            shape_group = et.SubElement(self._layers['documentation']['layer'], 'g')
            shape_group.set('{'+config.cfg['ns']['pcbmode']+'}type', 'module-shapes')            
            shape_group.set('{'+config.cfg['ns']['pcbmode']+'}doc-key', key)
            shape_group.set('transform', "translate(%s,%s)" % (location.x, config.cfg['invert-y']*location.y))

            location = docs_dict[key]['location']
            docs_dict[key]['location'] = [0, 0]

            shape = Shape(docs_dict[key])
            style = Style(docs_dict[key], 'documentation')
            shape.setStyle(style)
            element = place.placeShape(shape, shape_group)
Example #5
0
    def _placeDocs(self):
        """
        Places documentation blocks on the documentation layer
        """
        try:
            docs_dict = config.brd['documentation']
        except:
            return

        for key in docs_dict:

            location = utils.toPoint(docs_dict[key]['location'])
            docs_dict[key]['location'] = [0, 0]

            shape_group = et.SubElement(self._layers['documentation']['layer'],
                                        'g')
            shape_group.set('{' + config.cfg['ns']['pcbmode'] + '}type',
                            'module-shapes')
            shape_group.set('{' + config.cfg['ns']['pcbmode'] + '}doc-key',
                            key)
            shape_group.set(
                'transform', "translate(%s,%s)" %
                (location.x, config.cfg['invert-y'] * location.y))

            location = docs_dict[key]['location']
            docs_dict[key]['location'] = [0, 0]

            shape = Shape(docs_dict[key])
            style = Style(docs_dict[key], 'documentation')
            shape.setStyle(style)
            element = place.placeShape(shape, shape_group)
Example #6
0
    def _placeMask(self, svg_layer, shape, kind, original=False, mirror=False):
        """
        Places a mask of a shape of type 'Shape' on SVG layer 'svg_layer'.
        'kind'    : type of shape; used to fetch the correct distance to pour
        'original': use the original path, not the transformed one
        """
        
        # Get the desired distance based on 'kind' 'outline', 'drill',
        # 'pad', 'route' unless 'pour_buffer' is specified
        pour_buffer = shape.getPourBuffer()
        if pour_buffer == None:
            try:
                pour_buffer = self._module_dict['distances']['from-pour-to'][kind]
            except:
                pour_buffer = config.brd['distances']['from-pour-to'][kind]

        style_template = "fill:%s;stroke:#000;stroke-linejoin:round;stroke-width:%s;stroke-linecap:round;"

        style = shape.getStyle()

        if (pour_buffer > 0):
            mask_element = place.placeShape(shape, svg_layer, mirror, original)
            if style.getStyleType() == 'fill':
                mask_element.set('style', style_template % ('#000', pour_buffer*2))
            else:
                # This width provides a distance of 'pour_buffer' from the
                # edge of the trace to a pour
                width = style.getStrokeWidth() + pour_buffer*2
                mask_element.set('style', style_template % ('none', width))        

            path = shape.getOriginalPath().lower()
            segments = path.count('m')
            mask_element.set('{'+config.cfg['ns']['pcbmode']+'}gerber-lp', 'c'*segments)
Example #7
0
    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(
                    "Cannot 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)
                # Get the appropriate style from copper->pours
                style = Style(new_pour_dict,
                              layer_name='copper',
                              sub_item='pours')
                shape.setStyle(style)
            else:
                shape = Shape(pour_dict)
                # Get the appropriate style from copper->pours
                style = Style(pour_dict, layer_name='copper', sub_item='pours')
                shape.setStyle(style)

            # Place on all specified layers
            for layer in layers:
                place.placeShape(shape, shape_group[layer])
Example #8
0
    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("Cannot 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)
                # Get the appropriate style from copper->pours
                style = Style(new_pour_dict, layer_name='copper', sub_item='pours')
                shape.setStyle(style)
            else:
                shape = Shape(pour_dict)
                # Get the appropriate style from copper->pours
                style = Style(pour_dict, layer_name='copper', sub_item='pours')
                shape.setStyle(style)

            # Place on all specified layers
            for layer in layers:
                place.placeShape(shape, shape_group[layer])
Example #9
0
    def _placeMask(self, svg_layer, shape, kind, original=False, mirror=False):
        """
        Places a mask of a shape of type 'Shape' on SVG layer 'svg_layer'.
        'kind'    : type of shape; used to fetch the correct distance to pour
        'original': use the original path, not the transformed one
        """

        # Get the desired distance based on 'kind' 'outline', 'drill',
        # 'pad', 'route' unless 'pour_buffer' is specified
        pour_buffer = shape.getPourBuffer()
        if pour_buffer == None:
            try:
                pour_buffer = self._module_dict['distances']['from-pour-to'][
                    kind]
            except:
                pour_buffer = config.brd['distances']['from-pour-to'][kind]

        style_template = "fill:%s;stroke:#000;stroke-linejoin:round;stroke-width:%s;stroke-linecap:round;"

        style = shape.getStyle()

        if (pour_buffer > 0):
            mask_element = place.placeShape(shape, svg_layer, mirror, original)
            if style.getStyleType() == 'fill':
                mask_element.set('style',
                                 style_template % ('#000', pour_buffer * 2))
            else:
                # This width provides a distance of 'pour_buffer' from the
                # edge of the trace to a pour
                width = style.getStrokeWidth() + pour_buffer * 2
                mask_element.set('style', style_template % ('none', width))

            path = shape.getOriginalPath().lower()
            segments = path.count('m')
            mask_element.set('{' + config.cfg['ns']['pcbmode'] + '}gerber-lp',
                             'c' * segments)
Example #10
0
    def _placeComponents(self, components, component_type, print_refdef=False):
        """
        Places the component on the board.  

        'component_type' is the content of the 'type' fiels of the
        placed group. This is used by the extractor to identify the
        type of component ('component', 'via', 'shape')
        """

        htmlpar = HTMLParser.HTMLParser()

        for component in components:
            shapes_dict = component.getShapes()
            location = component.getLocation()
            rotation = component.getRotation()
            refdef = component.getRefdef()

            if print_refdef == True:
                print refdef,

            # If the component is placed on the bottom layer we need
            # to invert the shapes AND their 'x' coordinate.  This is
            # done using the 'invert' indicator set below
            placement_layer = component.getPlacementLayer()
            if placement_layer == 'bottom':
                invert = True
            else:
                invert = False

            for pcb_layer in config.stk['layer-names']:

                there_are_pours = utils.checkForPoursInLayer(pcb_layer)

                # Copper
                shapes = shapes_dict['conductor'].get(pcb_layer) or []

                if len(shapes) > 0:

                    svg_layer = self._layers[pcb_layer]['conductor']['pads'][
                        '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_type)
                    # Add the reference designator as well if it's a
                    # 'component'
                    if component_type == 'component':
                        shape_group.set(
                            '{' + config.cfg['ns']['pcbmode'] + '}refdef',
                            component.getRefdef())

                    style = utils.dictToStyleText(
                        config.stl['layout']['conductor']['pads']['labels'])
                    label_group = et.SubElement(shape_group, 'g', style=style)

                    for shape in shapes:
                        place.placeShape(shape, shape_group, invert)

                        # Add pin labels
                        # TODO: This isn't perfect, but good enough for now
                        label = shape.getLabel()
                        if label != None:
                            label_location = shape.getLocation()
                            label_rotation = shape.getRotation()
                            label_transform = "rotate(%s)" % label_rotation
                            t = et.SubElement(label_group,
                                              'text',
                                              x=str(((1, -1)[invert]) *
                                                    label_location.x),
                                              y=str(config.cfg['invert-y'] *
                                                    label_location.y),
                                              transform=label_transform)
                            t.text = label

                        if there_are_pours == True:
                            mask_group = et.SubElement(self._masks[pcb_layer],
                                                       'g',
                                                       transform=transform)
                            self._placeMask(mask_group,
                                            shape,
                                            'pad',
                                            original=False,
                                            mirror=invert)

                # Pours
                shapes = shapes_dict['pours'].get(pcb_layer) or []
                try:
                    svg_layer = self._layers[pcb_layer]['conductor']['pours'][
                        'layer']
                    shape_group = et.SubElement(svg_layer,
                                                'g',
                                                mask='url(#mask-%s)' %
                                                pcb_layer)
                except:
                    svg_layer = None

                if len(shapes) > 0 and svg_layer != None:
                    transform = "translate(%s,%s)" % (
                        location[0], config.cfg['invert-y'] * location[1])
                    group = et.SubElement(shape_group,
                                          'g',
                                          transform=transform)
                    group.set('{' + config.cfg['ns']['pcbmode'] + '}type',
                              'pours')
                    for shape in shapes:
                        placed_element = place.placeShape(shape, group, invert)

                # Soldermask
                shapes = shapes_dict['soldermask'].get(pcb_layer) or []
                try:
                    svg_layer = self._layers[pcb_layer]['soldermask']['layer']
                except:
                    svg_layer = None

                if len(shapes) > 0 and svg_layer != None:
                    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'].get(pcb_layer) or []
                try:
                    svg_layer = self._layers[pcb_layer]['solderpaste']['layer']
                except:
                    svg_layer = None

                if len(shapes) > 0 and svg_layer != None:
                    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'].get(pcb_layer) or []
                try:
                    svg_layer = self._layers[pcb_layer]['silkscreen']['layer']
                except:
                    svg_layer = None

                if len(shapes) > 0 and svg_layer != None:
                    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:
                            # Shapes don't need to have silkscreen
                            # reference designators
                            if component_type != 'shape':
                                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'].get(pcb_layer) or []
                try:
                    svg_layer = self._layers[pcb_layer]['assembly']['layer']
                except:
                    svg_layer = None

                if len(shapes) > 0 and svg_layer != None:
                    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'].get(pcb_layer) or []
                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()))

            # Place component origin marker
            svg_layer = self._layers[placement_layer]['placement']['layer']

            # Here pcb_layer may not exist for components that define
            # shapes for internal layers but only surface layers are
            # defined in the stackup
            try:
                group = et.SubElement(svg_layer, 'g', transform=transform)
            except:
                return

            group.set('{' + config.cfg['ns']['pcbmode'] + '}type',
                      component_type)
            group.set('{' + config.cfg['ns']['pcbmode'] + '}footprint',
                      component.getFootprintName())
            if (component_type == 'component') or (component_type == 'shape'):
                group.set('{' + config.cfg['ns']['pcbmode'] + '}refdef',
                          refdef)

            path = svg.placementMarkerPath()
            transform = "translate(%s,%s)" % (
                location[0], config.cfg['invert-y'] * location[1])

            if placement_layer == 'bottom':
                rotation *= -1

            marker_element = et.SubElement(group,
                                           'path',
                                           d=path,
                                           transform="rotate(%s)" % rotation)

            if (component_type == 'component'):
                style = utils.dictToStyleText(
                    config.stl['layout']['placement']['text'])

                t = et.SubElement(group, 'text', x="0", y="-0.17", style=style)
                ts = et.SubElement(t, 'tspan', x="0", dy="0.1")
                ts.text = "%s" % (refdef)
                ts = et.SubElement(t, 'tspan', x="0", dy="0.1")
                ts.text = htmlpar.unescape("%s°" % (rotation))
                ts = et.SubElement(t, 'tspan', x="0", dy="0.1")
                ts.text = "[%.2f,%.2f]" % (location[0], location[1])
            elif (component_type == 'shape'):
                style = utils.dictToStyleText(
                    config.stl['layout']['placement']['text'])

                t = et.SubElement(group, 'text', x="0", y="-0.17", style=style)
                ts = et.SubElement(t, 'tspan', x="0", dy="0.1")
                ts.text = "%s" % (refdef)
                ts = et.SubElement(t, 'tspan', x="0", dy="0.1")
                ts.text = htmlpar.unescape("%s°" % (rotation))
                ts = et.SubElement(t, 'tspan', x="0", dy="0.1")
                ts.text = "[%.2f,%.2f]" % (location[0], location[1])
            elif (component_type == 'via'):
                style = utils.dictToStyleText(
                    config.stl['layout']['placement']['text'])

                t = et.SubElement(group, 'text', x="0", y="-0.11", style=style)
                ts = et.SubElement(t, 'tspan', x="0", dy="0.1")
                ts.text = htmlpar.unescape("%s°" % (rotation))
                ts = et.SubElement(t, 'tspan', x="0", dy="0.1")
                ts.text = "[%.2f,%.2f]" % (location[0], location[1])
            else:
                continue
Example #11
0
    def _placeRouting(self):
        """
        """

        routing = config.rte
        routes = routing.get('routes') or {}
        vias = routing.get('vias')

        # Path effects are used for meandering paths, for example
        path_effects = routes.get('path_effects')

        xpath_expr = "//g[@inkscape:label='%s']//g[@inkscape:label='%s']"
        extra_attributes = [
            'inkscape:connector-curvature', 'inkscape:original-d',
            'inkscape:path-effect'
        ]

        for pcb_layer in utils.getSurfaceLayers():

            # Are there pours in the layer? This makes a difference for whether to place
            # masks
            there_are_pours = utils.checkForPoursInLayer(pcb_layer)

            # Define a group where masks are stored
            mask_group = et.SubElement(self._masks[pcb_layer], 'g')

            # Place defined routes on this SVG layer
            sheet = self._layers[pcb_layer]['copper']['routing']['layer']

            for route_key in (routes.get(pcb_layer) or {}):
                shape_dict = routes[pcb_layer][route_key]
                shape = Shape(shape_dict)
                style = Style(shape_dict, 'copper')
                shape.setStyle(style)

                # Routes are a special case where they are used as-is
                # counting on Inkscapes 'optimised' setting to modify
                # the path such that placement is refleced in
                # it. Therefor we use the original path, not the
                # transformed one as usual
                use_original_path = True
                mirror_path = False
                route_element = place.placeShape(shape, sheet, mirror_path,
                                                 use_original_path)

                route_element.set('style', shape.getStyleString())

                # Set the key as pcbmode:id of the route. This is used
                # when extracting routing to offset the location of a
                # modified route
                route_element.set(
                    '{' + config.cfg['ns']['pcbmode'] + '}%s' % ('id'),
                    route_key)

                # Add a custom buffer definition if it exists
                custom_buffer = shape_dict.get('buffer-to-pour')
                if custom_buffer != None:
                    route_element.set(
                        '{' + config.cfg['namespace']['pcbmode'] +
                        '}%s' % "buffer-to-pour", str(custom_buffer))

                # TODO: can this be done more elegantly, and "general purpose"?
                for extra_attrib in extra_attributes:
                    ea = shape_dict.get(extra_attrib)
                    if ea is not None:
                        route_element.set(
                            '{' + config.cfg['namespace']['inkscape'] + '}%s' %
                            (extra_attrib[extra_attrib.index(':') + 1:], ea))

                # TODO: this needs to eventually go away or be done properly
                pcbmode_params = shape_dict.get('pcbmode')
                if pcbmode_params is not None:
                    route_element.set('pcbmode', pcbmode_params)

                if ((there_are_pours == True) and (custom_buffer != "0")):
                    self._placeMask(self._masks[pcb_layer], shape, 'route',
                                    use_original_path)
Example #12
0
    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):
                        shape_dict['location'][0] *= -1
                        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')
                        self._placeMask(svg_layer=mask_group,
                                        shape=shape,
                                        kind='pad',
                                        original=False,
                                        mirror=mirror)
Example #13
0
    def _placeComponents(self, components, component_type, print_refdef=False):
        """
        """
        for component in components:
            shapes_dict = component.getShapes()
            location = component.getLocation()

            refdef = component.getRefdef()

            if print_refdef == True:
                print refdef,

            # If the component is placed on the bottom layer we need
            # to invert the shapes AND their 'x' coordinate.  This is
            # done using the 'invert' indicator set below
            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',
                                            original=False,
                                            mirror=invert)

                    # Add pin labels

                    # There's a bit of a hack here that won't work in
                    # all possible cases (where pads are placed on
                    # bottom layer in a component that has pins placed
                    # both on the top and on the bottom -- a rare
                    # case). Good enough for now

                    labels = shapes_dict['pin-labels']['top']  #[pcb_layer]
                    if labels != []:
                        style = utils.dictToStyleText(
                            config.stl['layout']['board']['pad-labels'])
                        label_group = et.SubElement(
                            group,
                            'g',
                            transform="rotate(%s)" %
                            (((1, -1)[invert]) * component.getRotation()),
                            style=style)
                        for label in labels:
                            t = et.SubElement(label_group,
                                              'text',
                                              x=str(((1, -1)[invert]) *
                                                    label['location'][0]),
                                              y=str(config.cfg['invert-y'] *
                                                    label['location'][1]))
                            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()))
Example #14
0
    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)
Example #15
0
    def _placeComponents(self, components, component_type, print_refdef=False):
        """
        """
        for component in components:
            shapes_dict = component.getShapes()
            location = component.getLocation()

            refdef = component.getRefdef()

            if print_refdef == True:
                print refdef,

            # If the component is placed on the bottom layer we need
            # to invert the shapes AND their 'x' coordinate.  This is
            # done using the 'invert' indicator set below
            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',
                                            original=False,
                                            mirror=invert)

                    # Add pin labels 

                    # There's a bit of a hack here that won't work in
                    # all possible cases (where pads are placed on
                    # bottom layer in a component that has pins placed
                    # both on the top and on the bottom -- a rare
                    # case). Good enough for now

                    labels = shapes_dict['pin-labels']['top']#[pcb_layer]
                    if labels != []:
                        style = utils.dictToStyleText(config.stl['layout']['board']['pad-labels'])
                        label_group = et.SubElement(group, 'g', 
                                                    transform="rotate(%s)" % (((1,-1)[invert])*component.getRotation()),
                                                    style=style)
                        for label in labels:
                            t = et.SubElement(label_group, 'text',
                                              x=str(((1,-1)[invert])*label['location'][0]),
                                              y=str(config.cfg['invert-y']*label['location'][1]))
                            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)
                        placed_element.set('{'+config.cfg['ns']['pcbmode']+'}diameter',
                                           str(shape.getDiameter()))
Example #16
0
    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)

                # 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()))
Example #17
0
    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(svg_layer=mask_group, 
                                        shape=shape,
                                        kind='pad',
                                        original=False,
                                        mirror=False)
Example #18
0
    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)
Example #19
0
    def _placeRouting(self):
        """
        """

        routing = config.rte
        routes = routing.get('routes') or {}

        # Path effects are used for meandering paths, for example
        path_effects = routes.get('path_effects')
 
        xpath_expr = "//g[@inkscape:label='%s']//g[@inkscape:label='%s']"
        extra_attributes = ['inkscape:connector-curvature', 'inkscape:original-d', 'inkscape:path-effect']
 
        for pcb_layer in config.stk['layer-names']:
 
            # Are there pours in the layer? This makes a difference for whether to place
            # masks
            there_are_pours = utils.checkForPoursInLayer(pcb_layer)

            # Define a group where masks are stored
            mask_group = et.SubElement(self._masks[pcb_layer], 'g')

            # Place defined routes on this SVG layer
            sheet = self._layers[pcb_layer]['conductor']['routing']['layer']

            for route_key in (routes.get(pcb_layer) or {}):
                shape_dict = routes[pcb_layer][route_key]
                shape = Shape(shape_dict)
                style = Style(shape_dict, 'conductor')
                shape.setStyle(style)

                # Routes are a special case where they are used as-is
                # counting on Inkscapes 'optimised' setting to modify
                # the path such that placement is refleced in
                # it. Therefor we use the original path, not the
                # transformed one as usual
                use_original_path = True
                mirror_path = False
                route_element = place.placeShape(shape,
                                                 sheet,
                                                 mirror_path,
                                                 use_original_path)

                route_element.set('style', shape.getStyleString())

                # Set the key as pcbmode:id of the route. This is used
                # when extracting routing to offset the location of a
                # modified route
                route_element.set('{'+config.cfg['ns']['pcbmode']+'}%s' % ('id'),
                                  route_key)

                # Add a custom buffer definition if it exists
                custom_buffer = shape_dict.get('buffer-to-pour')
                if custom_buffer != None:
                    route_element.set('{'+config.cfg['namespace']['pcbmode']+'}%s' % "buffer-to-pour", str(custom_buffer))

                # TODO: can this be done more elegantly, and "general purpose"?
                for extra_attrib in extra_attributes:
                    ea = shape_dict.get(extra_attrib)
                    if ea is not None:
                        route_element.set('{'+config.cfg['namespace']['inkscape']+'}%s' % (extra_attrib[extra_attrib.index(':')+1:], ea))


                # TODO: this needs to eventually go away or be done properly
                pcbmode_params = shape_dict.get('pcbmode')
                if pcbmode_params is not None:
                    route_element.set('pcbmode', pcbmode_params)                

                if ((there_are_pours == True) and (custom_buffer != "0")):
                    self._placeMask(self._masks[pcb_layer], 
                                    shape, 
                                    'route',
                                    use_original_path)
Example #20
0
    def _placeComponents(self, components, component_type, print_refdef=False):
        """
        Places the component on the board.  

        'component_type' is the content of the 'type' fiels of the
        placed group. This is used by the extractor to identify the
        type of component ('component', 'via', 'shape')
        """

        htmlpar = HTMLParser.HTMLParser()

        for component in components:
            shapes_dict = component.getShapes()
            location = component.getLocation()
            rotation = component.getRotation()
            refdef = component.getRefdef()

            if print_refdef == True:
                print refdef,

            # If the component is placed on the bottom layer we need
            # to invert the shapes AND their 'x' coordinate.  This is
            # done using the 'invert' indicator set below
            placement_layer = component.getPlacementLayer()
            if placement_layer == 'bottom':
                invert = True
            else:
                invert = False

            for pcb_layer in config.stk['layer-names']:

                there_are_pours = utils.checkForPoursInLayer(pcb_layer)

                # Copper
                shapes = shapes_dict['conductor'].get(pcb_layer) or []

                if len(shapes) > 0:

                    svg_layer = self._layers[pcb_layer]['conductor']['pads']['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_type)
                    # Add the reference designator as well if it's a
                    # 'component'
                    if component_type == 'component':
                        shape_group.set('{'+config.cfg['ns']['pcbmode']+'}refdef', component.getRefdef())

                    style = utils.dictToStyleText(config.stl['layout']['conductor']['pads']['labels'])
                    label_group = et.SubElement(shape_group, 'g', style=style)

                    for shape in shapes:
                        place.placeShape(shape, shape_group, invert)

                        # Add pin labels
                        # TODO: This isn't perfect, but good enough for now
                        label = shape.getLabel()
                        if label != None:
                            label_location = shape.getLocation()
                            label_rotation = shape.getRotation()
                            label_transform = "rotate(%s)" % label_rotation
                            t = et.SubElement(label_group, 'text',
                                              x=str(((1,-1)[invert])*label_location.x),
                                              y=str(config.cfg['invert-y']*label_location.y),
                                              transform=label_transform)
                            t.text = label


                        if there_are_pours == True:
                            mask_group = et.SubElement(self._masks[pcb_layer], 'g', 
                                                       transform=transform)
                            self._placeMask(mask_group, 
                                            shape,
                                            'pad',
                                            original=False,
                                            mirror=invert)


                # Pours
                shapes = shapes_dict['pours'].get(pcb_layer) or []
                try:
                    svg_layer = self._layers[pcb_layer]['conductor']['pours']['layer']
                    shape_group = et.SubElement(svg_layer, 'g',
                                                mask='url(#mask-%s)' % pcb_layer)
                except:
                    svg_layer = None

                if len(shapes) > 0 and svg_layer != None:
                    transform = "translate(%s,%s)" % (location[0],
                                                      config.cfg['invert-y']*location[1])
                    group = et.SubElement(shape_group, 'g', transform=transform)
                    group.set('{'+config.cfg['ns']['pcbmode']+'}type', 'pours')
                    for shape in shapes:
                        placed_element = place.placeShape(shape, group, invert)




                # Soldermask
                shapes = shapes_dict['soldermask'].get(pcb_layer) or []
                try:
                    svg_layer = self._layers[pcb_layer]['soldermask']['layer']
                except:
                    svg_layer = None

                if len(shapes) > 0 and svg_layer != None:
                    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'].get(pcb_layer) or []
                try:
                    svg_layer = self._layers[pcb_layer]['solderpaste']['layer']
                except:
                    svg_layer = None

                if len(shapes) > 0 and svg_layer != None:
                    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'].get(pcb_layer) or []
                try:
                    svg_layer = self._layers[pcb_layer]['silkscreen']['layer']
                except:
                    svg_layer = None

                if len(shapes) > 0 and svg_layer != None:
                    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:
                            # Shapes don't need to have silkscreen
                            # reference designators
                            if component_type != 'shape':
                                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'].get(pcb_layer) or []
                try:
                    svg_layer = self._layers[pcb_layer]['assembly']['layer']
                except:
                    svg_layer = None

                if len(shapes) > 0 and svg_layer != None: 
                    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'].get(pcb_layer) or []
                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()))


                
            # Place component origin marker
            svg_layer = self._layers[placement_layer]['placement']['layer']

            # Here pcb_layer may not exist for components that define
            # shapes for internal layers but only surface layers are
            # defined in the stackup
            try:
                group = et.SubElement(svg_layer, 'g', transform=transform)
            except:
                return

            group.set('{'+config.cfg['ns']['pcbmode']+'}type', component_type)
            group.set('{'+config.cfg['ns']['pcbmode']+'}footprint', component.getFootprintName())
            if (component_type == 'component') or (component_type == 'shape'):
                group.set('{'+config.cfg['ns']['pcbmode']+'}refdef', refdef)

            path = svg.placementMarkerPath()
            transform = "translate(%s,%s)" % (location[0],
                                              config.cfg['invert-y']*location[1])

            if placement_layer == 'bottom':
                rotation *= -1

            marker_element = et.SubElement(group, 'path',
                                           d=path,
                                           transform="rotate(%s)" % rotation)

            if (component_type == 'component'):
                style = utils.dictToStyleText(config.stl['layout']['placement']['text'])
     
                t = et.SubElement(group, 'text', x="0", y="-0.17", style=style)
                ts = et.SubElement(t, 'tspan', x="0", dy="0.1")
                ts.text = "%s" % (refdef)
                ts = et.SubElement(t, 'tspan', x="0", dy="0.1")
                ts.text = htmlpar.unescape("%s°" % (rotation))
                ts = et.SubElement(t, 'tspan', x="0", dy="0.1")
                ts.text = "[%.2f,%.2f]" % (location[0], location[1])
            elif (component_type == 'shape'):
                style = utils.dictToStyleText(config.stl['layout']['placement']['text'])
     
                t = et.SubElement(group, 'text', x="0", y="-0.17", style=style)
                ts = et.SubElement(t, 'tspan', x="0", dy="0.1")
                ts.text = "%s" % (refdef)
                ts = et.SubElement(t, 'tspan', x="0", dy="0.1")
                ts.text = htmlpar.unescape("%s°" % (rotation))
                ts = et.SubElement(t, 'tspan', x="0", dy="0.1")
                ts.text = "[%.2f,%.2f]" % (location[0], location[1])
            elif (component_type == 'via'):
                style = utils.dictToStyleText(config.stl['layout']['placement']['text'])
     
                t = et.SubElement(group, 'text', x="0", y="-0.11", style=style)
                ts = et.SubElement(t, 'tspan', x="0", dy="0.1")
                ts.text = htmlpar.unescape("%s°" % (rotation))
                ts = et.SubElement(t, 'tspan', x="0", dy="0.1")
                ts.text = "[%.2f,%.2f]" % (location[0], location[1])
            else:
                continue
Example #21
0
    def _placeLayerIndex(self):
        """
        Adds a drill index
        """

        text_dict = config.stl['layout']['layer-index']['text']
        text_dict['type'] = 'text'

        # Set the height (and width) of the rectangle (square) to the
        # size of the text
        rect_width = utils.parseDimension(text_dict['font-size'])[0]
        rect_height = rect_width
        rect_gap = 0.25

        # Get location, or generate one
        try:
            location = config.brd['layer-index']['location']
        except:
            # If not location is specified, put the drill index at the
            # top right of the board. The 'gap' defines the extra
            # spcae between the top of the largest drill and the
            # board's edge
            gap = 2
            location = [
                self._width / 2 + gap, self._height / 2 - rect_height / 2
            ]
        location = utils.toPoint(location)

        rect_dict = {}
        rect_dict['type'] = 'rect'
        rect_dict['style'] = 'fill'
        rect_dict['width'] = rect_width
        rect_dict['height'] = rect_height

        # Create group for placing index
        for pcb_layer in utils.getSurfaceLayers():
            for sheet in [
                    'copper', 'soldermask', 'silkscreen', 'assembly',
                    'solderpaste'
            ]:
                layer = self._layers[pcb_layer][sheet]['layer']
                transform = "translate(%s,%s)" % (
                    location.x, config.cfg['invert-y'] * location.y)
                group = et.SubElement(layer, 'g', transform=transform)
                group.set('{' + config.cfg['ns']['pcbmode'] + '}type',
                          'layer-index')

                rect_shape = Shape(rect_dict)
                style = Style(rect_dict, sheet)
                rect_shape.setStyle(style)
                place.placeShape(rect_shape, group)

                text_dict['value'] = "%s %s" % (pcb_layer, sheet)
                #text_dict['location'] = [rect_width+rect_gap+text_width, 0]
                text_shape = Shape(text_dict)
                text_width = text_shape.getWidth()
                style = Style(text_dict, sheet)
                text_shape.setStyle(style)
                element = place.placeShape(text_shape, group)
                element.set(
                    "transform", "translate(%s,%s)" %
                    (rect_width / 2 + rect_gap + text_width / 2, 0))

                location.y += config.cfg['invert-y'] * (rect_height + rect_gap)

            location.y += config.cfg['invert-y'] * (rect_height + rect_gap * 2)
Example #22
0
    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()))