예제 #1
0
파일: place.py 프로젝트: Maddimax/pcbmode
def place_path_shape(cfg, shape, layer, layer_name, mirror=False):
    """
    Places a dict path shape definition in the specified layer
    """

    sig_dig = cfg['pcbmode']['significant_digits']

    path = shape.get('value')
    rotation = shape.get('rotate') or 0
    location = shape.get('location')
    scale = shape.get('scale') or 1
    style = shape.get('style')
    stroke_width = shape.get('stroke_width')
    gerber_lp = (shape.get('gerber_lp') or 
                 shape.get('gerber-lp'))

    translate = 'translate(' + str(round(location[0], sig_dig)) + ' ' + str(round(-location[1], sig_dig)) + ')'
    transform = translate

    # convert path to relative commands
    path = svg.absolute_to_relative_path(path)

    # get a path having an origin at the center of the shape
    # defined by the path
    d_width, d_height, path = svg.transform_path(path, True, scale, rotation, Point())

    if mirror is True:
        path = svg.mirror_path_over_axis(path, 'x', 0)

    subelement = et.SubElement(layer, 
                               'path', 
                               transform=transform, 
                               d=path)
    if gerber_lp is not None:
        subelement.set('{'+config.cfg['ns']['pcbmode']+'}gerber-lp', gerber_lp)


    # add the right style
    if style is not None:
        if style == 'outline':
            style = cfg['layout_style'][layer_name].get('outline')
            # if there's a stroke-width definition, then override the default
            if stroke_width is not None:
                style['stroke-width'] = str(stroke_width)
            style = utils.dict_to_style(style)
        elif style == 'fill':
            style = utils.dict_to_style(cfg['layout_style'][layer_name].get('fill'))
        else:
            print "ERROR: unrecognised style"
    else:
        # default to outline
        style = utils.dict_to_style(cfg['layout_style'][layer_name].get('outline'))
 
    if style is not None:
        subelement.set('style', style)

    return
예제 #2
0
 def getStyleString(self):
     return utils.dict_to_style(self._style_dict)
예제 #3
0
파일: module.py 프로젝트: vishnubob/pcbmode
    def _placeDrillIndex(self):
        """
        Adds a drill index
        """

        # Get the drills sheet / SVG layer
        drill_layer = self._layers['drills']['layer']
        ns = {
            'pcbmode': config.cfg['ns']['pcbmode'],
            'svg': config.cfg['ns']['svg']
        }
        drills = drill_layer.findall(".//*[@pcbmode:diameter]", namespaces=ns)

        drills_dict = {}
        largest_drill = 0
        drill_count = 0
        for drill in drills:
            diameter = drill.get('{' + config.cfg['ns']['pcbmode'] +
                                 '}diameter')
            diameter = round(float(diameter), 2)
            if diameter not in drills_dict:
                drills_dict[diameter] = 1
            else:
                drills_dict[diameter] += 1
            if diameter > largest_drill:
                largest_drill = diameter
            drill_count += 1

        # Get location, or generate one
        try:
            location = config.brd['drill-index']['location']
        except:
            # If not location is specified, put the drill index at the
            # bottom left 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, -(self._height / 2 + gap)]
        location = utils.toPoint(location)

        # Create group for placing index
        transform = "translate(%s,%s)" % (location.x,
                                          config.cfg['invert-y'] * location.y)
        group = et.SubElement(drill_layer, 'g', transform=transform)
        group.set('{' + config.cfg['ns']['pcbmode'] + '}type', 'drill-index')

        text_style_dict = config.stl['layout']['drill-index'].get('text')
        text_style = utils.dict_to_style(text_style_dict)

        count_style_dict = config.stl['layout']['drill-index'].get(
            'count-text')
        count_style = utils.dict_to_style(count_style_dict)

        count_style_dict['font-size'] /= 2
        drill_size_style = utils.dict_to_style(count_style_dict)

        if drill_count == 0:
            text = 'No drills'
        elif drill_count == 1:
            text = '1 drill: '
        else:
            text = '%s drills: ' % drill_count
        t = et.SubElement(group, 'text', x=str(0), y=str(0), style=text_style)
        t.text = text

        # "new line"
        location.y = -(largest_drill / 2 + 0.5)
        location.x = largest_drill / 2

        gap = 2

        for diameter in reversed(sorted(drills_dict)):
            path = svg.drillPath(diameter)
            transform = "translate(%s,%s)" % (
                location.x, config.cfg['invert-y'] * location.y)
            element = et.SubElement(group, 'path', d=path, transform=transform)
            element.set("fill-rule", "evenodd")

            t = et.SubElement(group,
                              'text',
                              x=str(location.x),
                              y=str(-location.y),
                              dy="%s" % (config.cfg['invert-y'] * 0.25),
                              style=count_style)
            t.text = str(drills_dict[diameter])

            t = et.SubElement(group,
                              'text',
                              x=str(location.x),
                              y=str(-location.y),
                              dy="%s" % (config.cfg['invert-y'] * -0.5),
                              style=drill_size_style)
            t.text = "%s mm" % diameter

            location.x += max(diameter, 2.5)
예제 #4
0
 def getStyleString(self):
     return utils.dict_to_style(self._style_dict)
예제 #5
0
def placeDrill(drill,
               layer,
               location,
               scale,
               soldermask_layers={},
               mask_groups={}):
    """
    Places the drilling point
    """

    diameter = drill.get('diameter')
    offset = utils.to_Point(drill.get('offset') or [0, 0])
    path = svg.drill_diameter_to_path(diameter)
    mask_path = svg.circle_diameter_to_path(diameter)

    sig_dig = config.cfg['significant-digits']
    transform = 'translate(%s %s)' % (round(
        (location.x + offset.x) * scale,
        sig_dig), round((-location.y - offset.y) * scale, sig_dig))

    drill_element = et.SubElement(layer,
                                  'path',
                                  transform=transform,
                                  d=path,
                                  id='pad_drill',
                                  diameter=str(diameter))

    pour_buffer = 1.0
    try:
        pour_buffer = board_cfg['distances']['buffer_from_pour_to'].get(
            'drill') or 1.0
    except:
        pass

    # add a mask buffer between pour and board outline
    if mask_groups != {}:
        for pcb_layer in surface_layers:
            mask_group = et.SubElement(mask_groups[pcb_layer],
                                       'g',
                                       id="drill_masks")
            pour_mask = et.SubElement(mask_group,
                                      'path',
                                      transform=transform,
                                      style=MASK_STYLE % str(pour_buffer * 2),
                                      gerber_lp="c",
                                      d=mask_path)

    # place the size of the drill; id the drill element has a
    # "show_diameter": "no", then this can be suppressed
    # default to 'yes'
    show_diameter = drill.get('show_diameter') or 'yes'
    if show_diameter.lower() != 'no':
        text = "%s mm" % (str(diameter))
        text_style = config.stl['layout']['drills'].get('text') or None
        if text_style is not None:
            text_style['font-size'] = str(diameter / 10.0) + 'px'
            text_style = utils.dict_to_style(text_style)
            t = et.SubElement(
                layer,
                'text',
                x=str(location.x),
                # TODO: get rid of this hack
                y=str(-location.y - (diameter / 4)),
                style=text_style)
            t.text = text

    # place soldermask unless specified otherwise
    # default is 'yes'
    add_soldermask = drill.get('add_soldermask') or 'yes'
    style = utils.dict_to_style(config.stl['layout']['soldermask'].get('fill'))
    possible_answers = [
        'yes', 'top', 'top only', 'bottom', 'bottom only', 'top and bottom'
    ]
    if (add_soldermask.lower()
            in possible_answers) and (soldermask_layers != {}):
        # TODO: get this into a configuration parameter
        drill_soldermask_scale_factors = drill.get(
            'soldermask_scale_factors') or {
                'top': 1.2,
                'bottom': 1.2
            }
        path_top = svg.circle_diameter_to_path(
            diameter * drill_soldermask_scale_factors['top'])
        path_bottom = svg.circle_diameter_to_path(
            diameter * drill_soldermask_scale_factors['bottom'])

        if add_soldermask.lower() == 'yes' or add_soldermask.lower(
        ) == 'top and bottom':
            drill_element = et.SubElement(soldermask_layers['top'],
                                          'path',
                                          transform=transform,
                                          style=style,
                                          d=path_top)
            drill_element = et.SubElement(soldermask_layers['bottom'],
                                          'path',
                                          transform=transform,
                                          style=style,
                                          d=path_bottom)
        elif add_soldermask.lower() == 'top only' or add_soldermask.lower(
        ) == 'top':
            drill_element = et.SubElement(soldermask_layers['top'],
                                          'path',
                                          transform=transform,
                                          style=style,
                                          d=path_top)
        elif add_soldermask.lower() == 'bottom only' or add_soldermask.lower(
        ) == 'bottom':
            drill_element = et.SubElement(soldermask_layers['bottom'],
                                          'path',
                                          transform=transform,
                                          style=style,
                                          d=path_bottom)
        else:
            print "ERROR: unrecognised drills soldermask option"

    return
예제 #6
0
파일: place.py 프로젝트: epsiro/pcbmode
def placeDrill(drill, 
               layer, 
               location, 
               scale, 
               soldermask_layers={}, 
               mask_groups={}):
    """
    Places the drilling point
    """

    diameter = drill.get('diameter')
    offset = utils.to_Point(drill.get('offset') or [0, 0]) 
    path = svg.drill_diameter_to_path(diameter)
    mask_path = svg.circle_diameter_to_path(diameter)

    sig_dig = config.cfg['significant-digits']
    #translate = str(round((location.x + offset.x)*scale, sig_dig))+' '+str(round((-location.y - offset.y)*scale, sig_dig))
    transform = 'translate(%s %s)' % (round((location.x + offset.x)*scale, sig_dig),
                                      round((-location.y - offset.y)*scale, sig_dig))

    drill_element = et.SubElement(layer, 'path',
                                  transform=transform,
                                  d=path,
                                  id='pad_drill',
                                  diameter=str(diameter))

    pour_buffer = 1.0
    try:
        pour_buffer = board_cfg['distances']['buffer_from_pour_to'].get('drill') or 1.0
    except:
        pass

    # add a mask buffer between pour and board outline
    if mask_groups != {}:
        for pcb_layer in surface_layers:
            mask_group = et.SubElement(mask_groups[pcb_layer], 'g',
                                            id="drill_masks")
            pour_mask = et.SubElement(mask_group, 'path',
                                      transform=transform,
                                      style=MASK_STYLE % str(pour_buffer*2),
                                      gerber_lp="c",
                                      d=mask_path)



    # place the size of the drill; id the drill element has a
    # "show_diameter": "no", then this can be suppressed
    # default to 'yes'
    show_diameter = drill.get('show_diameter') or 'yes'
    if show_diameter.lower() != 'no':
        text = "%s mm" % (str(diameter))
        text_style = config.stl['layout']['drills'].get('text') or None
        if text_style is not None:
            text_style['font-size'] = str(diameter/10.0)+'px'
            text_style = utils.dict_to_style(text_style)
            t = et.SubElement(layer, 'text',
                x=str(location.x),
                # TODO: get rid of this hack
                y=str(-location.y-(diameter/4)),
                style=text_style)
            t.text = text

    # place soldermask unless specified otherwise
    # default is 'yes'
    add_soldermask = drill.get('add_soldermask') or 'yes'
    style = utils.dict_to_style(config.stl['layout']['soldermask'].get('fill'))
    possible_answers = ['yes', 'top', 'top only', 'bottom', 'bottom only', 'top and bottom']
    if (add_soldermask.lower() in possible_answers) and (soldermask_layers != {}):
        # TODO: get this into a configuration parameter
        drill_soldermask_scale_factors = drill.get('soldermask_scale_factors') or {'top':1.2, 'bottom':1.2}
        path_top = svg.circle_diameter_to_path(diameter * drill_soldermask_scale_factors['top'])
        path_bottom = svg.circle_diameter_to_path(diameter * drill_soldermask_scale_factors['bottom'])

        if add_soldermask.lower() == 'yes' or add_soldermask.lower() == 'top and bottom':
            drill_element = et.SubElement(soldermask_layers['top'], 
                                          'path',
                                          transform=transform,
                                          style=style,
                                          d=path_top)
            drill_element = et.SubElement(soldermask_layers['bottom'], 
                                          'path',
                                          transform=transform,
                                          style=style,
                                          d=path_bottom)
        elif add_soldermask.lower() == 'top only' or add_soldermask.lower() == 'top':
            drill_element = et.SubElement(soldermask_layers['top'], 
                                          'path',
                                          transform=transform,
                                          style=style,
                                          d=path_top)
        elif add_soldermask.lower() == 'bottom only' or add_soldermask.lower() == 'bottom':
            drill_element = et.SubElement(soldermask_layers['bottom'], 
                                          'path',
                                          transform=transform,
                                          style=style,
                                          d=path_bottom)
        else:
            print "ERROR: unrecognised drills soldermask option"

    return
예제 #7
0
파일: place.py 프로젝트: Maddimax/pcbmode
def place_text(cfg, text_element, layer, layer_name, mirror=False, additional_rotate=0):
    """
    Places a dict text element in the specified layer
    """

    sig_dig = cfg['pcbmode']['significant_digits']
    text_list = text_element.get('value')

    # Check if text is a string. Text fields used to be only a single line
    # are not a list of lines. So if the input is a string, we need to convert
    # into a single item list.
    # TODO: check if this can be removed after all designs have text input as a list
    if isinstance(text_list, basestring):
        text_list = [text_list]
        
    font = text_element.get('font')
    scale = text_element.get('scale') or text_element.get('scale') or 0.0009
    rotate = text_element.get('rotate') or 0
    rotate += additional_rotate
    location = utils.to_Point(text_element.get('location') or [0, 0])
    offset = utils.to_Point(text_element.get('offset') or [0, 0])
    location += offset
    if mirror is True:
        location.x = -location.x

    add_space = text_element.get('additional_space_between_glyphs') or 0
    style = text_element.get('style')
    gerber_lp = (text_element.get('gerber-lp') or 
                text_element.get('gerber_lp') or '')


    # create a group for the entire string
    string_group = et.SubElement(layer, 'g')
 
    # add the right style
    if style is not None:
        if style == 'outline':
            style = utils.dict_to_style(cfg['layout_style'][layer_name].get('outline'))
        elif style == 'fill':
            style = utils.dict_to_style(cfg['layout_style'][layer_name].get('fill'))
        else:
            print "ERROR: unrecognised style '%s' for text element" % style
    else:
        # default to fill
        style = utils.dict_to_style(cfg['layout_style'][layer_name].get('fill'))
 
    if style is not None:
        string_group.set('style', style)
 
    # place the glyphs' paths 


    line_number = 0

    for text in text_list:

        line_number += 1

        # get the slyphs for the text
        paths, text_width, text_height = glyphs.get_glyphs(cfg,
                                                           text, 
                                                           font, 
                                                           location,
                                                           scale,
                                                           line_number, # line number
                                                           rotate,
                                                           add_space)
     
   
        origin = utils.to_Point(paths[0]['location'])
     
        for path in paths:
     
            # TODO: hack?
            place = utils.to_Point(path['location'])
            d = place - origin
            d.rotate(rotate, Point())
            place = origin + d
     
            if mirror is True:
                path['d'] = svg.mirror_path_over_axis(path['d'], 'x', 0)
                place.x = -place.x
     
            transform = 'translate(%s %s)' % (round(place.x, sig_dig),
                                              round(-place.y, sig_dig))
            
            # add glyph
            subelement = et.SubElement(string_group,
                                       'path', 
                                       transform=transform, 
                                       d=path['d'],
                                       letter=path['symbol'],
                                       gerber_lp=path['gerber-lp'])

    return
예제 #8
0
    def _placeDrillIndex(self):
        """
        Adds a drill index
        """

        # Get the drills sheet / SVG layer
        drill_layer = self._layers['drills']['layer']
        ns = {'pcbmode':config.cfg['ns']['pcbmode'],
              'svg':config.cfg['ns']['svg']}
        drills = drill_layer.findall(".//*[@pcbmode:diameter]", namespaces=ns)

        drills_dict = {}
        largest_drill = 0
        drill_count = 0
        for drill in drills:
            diameter = drill.get('{'+config.cfg['ns']['pcbmode']+'}diameter')
            diameter = round(float(diameter), 2)
            if diameter not in drills_dict:
                drills_dict[diameter] = 1
            else:
                drills_dict[diameter] += 1
            if diameter > largest_drill:
                largest_drill = diameter
            drill_count += 1


        # Get location, or generate one
        try:
            location = config.brd['drill-index']['location']
        except:
            # If not location is specified, put the drill index at the
            # bottom left 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, -(self._height/2+gap)]
        location = utils.toPoint(location)        

        # Create group for placing index
        transform = "translate(%s,%s)" % (location.x, config.cfg['invert-y']*location.y)
        group = et.SubElement(drill_layer, 'g',
                              transform=transform)
        group.set('{'+config.cfg['ns']['pcbmode']+'}type', 'drill-index')
        

        text_style_dict = config.stl['layout']['drill-index'].get('text')
        text_style = utils.dict_to_style(text_style_dict)
 
        count_style_dict = config.stl['layout']['drill-index'].get('count-text')
        count_style = utils.dict_to_style(count_style_dict)        

        count_style_dict['font-size'] /= 2
        drill_size_style = utils.dict_to_style(count_style_dict)

        if drill_count == 0:
            text = 'No drills'
        elif drill_count == 1:
            text = '1 drill: '
        else:
            text = '%s drills: ' % drill_count
        t = et.SubElement(group, 'text',
                          x=str(0),
                          y=str(0),
                          style=text_style)
        t.text = text

        # "new line"
        location.y = -(largest_drill/2 + 0.5)
        location.x = largest_drill/2

        gap = 2

        for diameter in reversed(sorted(drills_dict)):
            path = svg.drillPath(diameter)
            transform = "translate(%s,%s)" % (location.x, config.cfg['invert-y']*location.y)
            element = et.SubElement(group, 'path',
                                    d=path,
                                    transform=transform)
            element.set("fill-rule", "evenodd")

            t = et.SubElement(group, 'text',
                              x=str(location.x),
                              y=str(-location.y),
                              dy="%s" % (config.cfg['invert-y']*0.25),
                              style=count_style)
            t.text = str(drills_dict[diameter])

            t = et.SubElement(group, 'text',
                              x=str(location.x),
                              y=str(-location.y),
                              dy="%s" % (config.cfg['invert-y']*-0.5),
                              style=drill_size_style)
            t.text = "%s mm" % diameter

            location.x += max(diameter, 2.5)