Commits

saar drimer  committed 801770e

create text for assembly refdef index

  • Participants
  • Parent commits ceabf2b

Comments (0)

Files changed (4)

File pcbmode_config.json

     "build": "build/",
     "styles": "styles/"
   },
+  "refdef_index":
+  {
+    "common":
+    {
+      "AT": "Attenuator",
+      "BR": "Bridge rectifier",
+      "BT": "Battery",
+      "C": "Capacitor",
+      "CN": "Capacitor network",
+      "D": "Diode",
+      "DL": "Delay line",
+      "DS": "Display",
+      "F": "Fuse",
+      "FB": "Ferrite bead",
+      "FD": "Fiducial",
+      "J": "Jack connector",
+      "JP": "Link (Jumper)",
+      "K": "Relay",
+      "L": "Inductor",
+      "LS": "Loudspeaker or buzzer",
+      "M": "Motor",
+      "MK": "Microphone",
+      "MP": "Mechanical part",
+      "P": "Plug connector",
+      "PS": "Power supply",
+      "Q": "Transistor",
+      "R": "Resistor",
+      "RN": "Resistor network",
+      "RT": "Thermistor",
+      "RV": "Varistor",
+      "S": "Switch",
+      "T": "Transformer",
+      "TC": "Thermocouple",
+      "TUN": "Tuner",
+      "TP": "Test point",
+      "U": "Integrated circuit",
+      "V": "Vacuum tube",
+      "VR": "Variable resistor",
+      "X": "Transducer",
+      "Y": "Crystal / oscillator",
+      "Z": "Zener diode"
+    },
+    "pcbmode":
+    {
+      "BJT": "BJT",
+      "C": "Capacitor",
+      "D": "Diode",
+      "F": "Fuse",
+      "FB": "Ferrite bead",
+      "FD": "Fiducial",
+      "FET": "FET",
+      "IC": "Integrated circuit",
+      "J": "Connector",
+      "L": "Inductor",
+      "LED": "LED",
+      "MIC": "Microphone",
+      "PB": "Pushbutton",
+      "POT": "Potentiometer",
+      "R": "Resistor",
+      "REL": "Relay",
+      "SKD": "Schottkey diode",
+      "SW": "Switch",
+      "TP": "Test point",
+      "TVS": "TVS",
+      "ZEN": "Zener diode"
+    }
+  },
   "manufacturers":
   {
     "default":

File utils/board.py

 
 
 
+    
+    def add_refdef_index(cfg):
+        """
+        Adds a reference designator reference table to the specified layer
+        """
+
+        #for layer in utils.get_surface_layers(cfg):
+        #board_svg_layers['assembly']['refdef-index']['layer']
+
+        refdef_index = cfg['pcbmode']['refdef_index']['pcbmode']
+
+        refdef_column_length = 28
+
+        components = cfg['board']['placement']['components']
+        for layer in components:
+            comp_lists = {}
+            for refdef in components[layer]:
+                rd_type, rd_number, rd_extra = utils.parse_refdef(refdef)
+                if rd_type in refdef_index:
+                    if comp_lists.get(rd_type) is None:
+                        comp_lists[rd_type] = {}
+
+                    # categorise by part number or genric description
+                    if components[layer][refdef].get('manufacturer_part_number') is not None:
+                        mpu = components[layer][refdef]['manufacturer_part_number']
+                        if comp_lists[rd_type].get(mpu) is None:
+                           comp_lists[rd_type][mpu] = []
+                        comp_lists[rd_type][mpu].append(refdef)
+                    elif components[layer][refdef].get('generic') is not None:
+                        generic = components[layer][refdef]['generic']
+                        if comp_lists[rd_type].get(generic) is None:
+                           comp_lists[rd_type][generic] = []
+                        comp_lists[rd_type][generic].append(refdef)
+                    else:
+                        if comp_lists[rd_type].get('uncategorised') is None:
+                            comp_lists[rd_type]['uncategorised'] = []
+                        comp_lists[rd_type]['uncategorised'].append(refdef)
+                else:
+                    if comp_lists.get('uncategorised') is None:
+                        comp_lists['uncategorised'] = []
+                    comp_lists['uncategorised'].append(refdef)
+
+            lines = []
+
+            for refdef_type in comp_lists:
+                for comp_value in comp_lists[refdef_type]:
+                    first_line = True
+                    line = ''
+                    # TODO: uberish hack -- need to get on with it
+                    for refdef in comp_lists[refdef_type][comp_value]:
+                        if (len(line) + len(refdef)) >= refdef_column_length:
+                            if first_line is True:
+                                line += '%s ' % (' '*(refdef_column_length-len(line)))
+                                line += '%s' % (comp_value)
+                            first_line = False
+                            lines.append(line)
+                            line = ''
+                        line += '%s ' % refdef
+                    if len(line) < refdef_column_length:
+                        if first_line is True:
+                            line += '%s ' % (' '*(refdef_column_length-len(line)))
+                            line += '%s' % (comp_value)
+                        lines.append(line)
+      
+
+        return
+
+
+
+
+
 
     def import_footprint(footprint, transform, refdef=None):
         """
 
     print "-- processing parts:",
 
-    for pcb_layer in utils.get_surface_layers(cfg):
-        for component_refdef in pcb_components[pcb_layer]:
-            component = pcb_components[pcb_layer][component_refdef]
-            fp_drill_count = place_component(component)
-            # add the count to the total
-            drill_count = utils.add_dict_values(drill_count,
-                                                fp_drill_count)
-
-    print
-
-
-    drills = cfg['board'].get('drills')
-    if drills is not None and drills != {}:
-        print "-- processing drills:",
-        for pcb_layer in utils.get_surface_layers(cfg):
-            for drill_refdef in drills[pcb_layer]:
-                component_refdef = drill_refdef
-                fp_drill_count = place_component(drills[pcb_layer][drill_refdef])
-                # add the count to the total
-                drill_count = utils.add_dict_values(drill_count,
-                                                    fp_drill_count)
-
-    print
-
-
-    print "-- adding routing"
-    filename = os.path.join(cfg['base_dir'],
-                            cfg['board']['files'].get('routing_json') or cfg['board_name'] + '_routing.json')
-    routing = utils.get_json_data_from_file(filename)
-
-    # add routing to copper layers
-    if routing is not None:
-
-        routes = routing.get('routes')
-        vias = routing.get('vias') 
-        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.get_surface_layers(cfg):
-
-            there_are_pours = utils.there_are_pours_in_this_layer(cfg, pcb_layer)
-
-            routing_mask_group = et.SubElement(board_masks[pcb_layer], 'g',
-                                               id="routing_masks")
-            sheet = board_svg_layers[pcb_layer]['copper']['routing']['layer']
-            for route in routes[pcb_layer]:
-                path = routes[pcb_layer][route].get('d')
-                gerber_lp = routes[pcb_layer][route].get('gerber_lp')
-                path_style = routes[pcb_layer][route].get('style') or 'stroke:none;'
-                path_type = routes[pcb_layer][route].get('type')
-                pcbmode_params = routes[pcb_layer][route].get('pcbmode')
-
-                # add shape to copper plane 
-                path_element = et.SubElement(sheet, 'path', d=path)
-                if path_style is not None:
-                    path_element.set('style', path_style)
-                if gerber_lp is not None:
-                    path_element.set('gerber_lp', gerber_lp)
-
-                # add extra attributes if they exist
-                for extra_attrib in extra_attributes:
-                    ea = routes[pcb_layer][route].get(extra_attrib)
-                    if ea is not None:
-                        path_element.set('{'+cfg['namespace']['inkscape']+'}%s' % extra_attrib[extra_attrib.index(':')+1:], ea)
-
-                if path_type is not None:
-                    path_element.set('type', path_type)
-
-                if pcbmode_params is not None:
-                    path_element.set('pcbmode', pcbmode_params)                
-
-                pour_buffer = 0.5
-                try:
-                    pour_buffer = cfg['board']['distances']['buffer_from_pour_to'].get('route') or 0.5
-                except:
-                    pass
-
-                mask_style_template = "fill:%s;stroke:#000;stroke-linejoin:round;stroke-width:%s;stroke-linecap:round;"
-
-                regex = r".*?%s:\s?(?P<s>[^;]*)(?:;|$)"
-                stroke_def = re.match(regex % 'stroke', path_style)
-                if stroke_def is not None:
-                    stroke = stroke_def.group('s')
-
-                stroke_width_def = re.match(regex % 'stroke-width', path_style)    
-                if stroke_width_def is not None:
-                    stroke_width = float(stroke_width_def.group('s'))
-                else:
-                    stroke_width = 0
-
-                if stroke_width > 0:
-                    fill = 'none'
-                else:
-                    fill = re.match(regex % 'fill', path_style)
-                    if fill is not None:
-                        fill = fill.group('s')
-
-                # place mask
-                if path_type not in ['pour_bridge'] and there_are_pours:
-                    mask_element = et.SubElement(routing_mask_group, 'path',
-                                                 #id="%s" % pcb_layer,
-                                                 type="mask_shape",
-                                                 style=mask_style_template % (fill, stroke_width + pour_buffer * 2),
-                                                 d=path)
-     
-                    # set 'gerber_lp' attribute is it's not empty
-                    if gerber_lp is not None:
-                        path_element.set('gerber_lp', gerber_lp)
-                        mask_element.set('gerber_lp', gerber_lp)
-     
-                    # Due to the limitation of the Gerber format, and the method chosen
-                    # for applying masks onto pours, it is not possible to have copper
-                    # pour material inside of paths that have more than a single segment.
-                    # In order to make the apperance in the SVG and Gerbers consistent, 
-                    # each path segment is added with a 'fill'. In the future, when the
-                    # *actual* shape is calculated, it may be possible to avoid this
-                    # hack. On the other hand, one can argue that having pours inside of
-                    # shapes doesn't make sense anyway, because it alters its apperance, 
-                    # and such shapes are stylistic anyway. OK, back to code now...
-                    if gerber_lp is not None:
-                        if len(gerber_lp) > 1:
-                            path_segments = path.split('m')
-                            for path_segment in path_segments[1:]:
-                                mask_element = et.SubElement(routing_mask_group, 'path',
-                                                             #id="%s" % pcb_layer,
-                                                             type="mask_shape",
-                                                             style="fill:#000;stroke:none;",
-                                                             d='m '+path_segment)
-
-        for via in vias.values():
-            
-            via_type = via.get('via_type')
-            # check if via is specified, or 'default' is specified:
-            via_part_name = via_type[len(cfg['via_prefix']):]
-            via_part_name = via_part_name.strip(' ') # remove leading spaces if there any
-
-            # save footprint file
-            # strictly, this is not necessary because these files are not going
-            # to be used. However, it's good for debug.
-            footprint_path = os.path.join(cfg['base_dir'], cfg['pcbmode']['locations']['build'], 'footprints')
-          
-            # check if footprint directory exists; if not, create
-            try:
-                # try to create directory first; this prevents TOCTTOU-type race condition
-                os.makedirs(footprint_path)
-            except OSError:
-                # if the dir exists, pass
-                if os.path.isdir(footprint_path):
-                    pass
-                else:
-                    raise
-           
-            filename_in = os.path.join(cfg['base_dir'], 
-                                       cfg['pcbmode']['locations']['parts'], 
-                                       via_part_name + '.json')
-            filename_out = os.path.join(footprint_path, 
-                                        via_part_name + '.svg')
-
-            # create via footprint
-            via_footprint, fp_width, fp_height, fp_drills = footprint.create_footprint(cfg,
-                                                                                       via_part_name,
-                                                                                       via_type, 
-                                                                                       0, 
-                                                                                       Point, 
-                                                                                       1)
-
-            drill_count = utils.add_dict_values(drill_count, fp_drills)
-
-            location = utils.to_Point(via.get('location') or [0, 0])
-            translate = str(round(location.x, sig_dig))+' '+str(round(-location.y, sig_dig))
-            transform = 'translate('+translate+')'
-            import_footprint(via_footprint, transform)
-
-
-
-        # add path-effect paths to <defs>
-        if path_effects is not None:
-            for path_effect in path_effects.values():
-                effect_element = et.SubElement(board_defs, '{'+cfg['namespace']['inkscape']+'}path-effect')
-                for name, value in path_effect.items():
-                    effect_element.set(name, value)
-
+#    for pcb_layer in utils.get_surface_layers(cfg):
+#        for component_refdef in pcb_components[pcb_layer]:
+#            component = pcb_components[pcb_layer][component_refdef]
+#            fp_drill_count = place_component(component)
+#            # add the count to the total
+#            drill_count = utils.add_dict_values(drill_count,
+#                                                fp_drill_count)
+# 
+#    print
+# 
+# 
+#    drills = cfg['board'].get('drills')
+#    if drills is not None and drills != {}:
+#        print "-- processing drills:",
+#        for pcb_layer in utils.get_surface_layers(cfg):
+#            for drill_refdef in drills[pcb_layer]:
+#                component_refdef = drill_refdef
+#                fp_drill_count = place_component(drills[pcb_layer][drill_refdef])
+#                # add the count to the total
+#                drill_count = utils.add_dict_values(drill_count,
+#                                                    fp_drill_count)
+# 
+#    print
+# 
+# 
+#    print "-- adding routing"
+#    filename = os.path.join(cfg['base_dir'],
+#                            cfg['board']['files'].get('routing_json') or cfg['board_name'] + '_routing.json')
+#    routing = utils.get_json_data_from_file(filename)
+# 
+#    # add routing to copper layers
+#    if routing is not None:
+# 
+#        routes = routing.get('routes')
+#        vias = routing.get('vias') 
+#        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.get_surface_layers(cfg):
+# 
+#            there_are_pours = utils.there_are_pours_in_this_layer(cfg, pcb_layer)
+# 
+#            routing_mask_group = et.SubElement(board_masks[pcb_layer], 'g',
+#                                               id="routing_masks")
+#            sheet = board_svg_layers[pcb_layer]['copper']['routing']['layer']
+#            for route in routes[pcb_layer]:
+#                path = routes[pcb_layer][route].get('d')
+#                gerber_lp = routes[pcb_layer][route].get('gerber_lp')
+#                path_style = routes[pcb_layer][route].get('style') or 'stroke:none;'
+#                path_type = routes[pcb_layer][route].get('type')
+#                pcbmode_params = routes[pcb_layer][route].get('pcbmode')
+# 
+#                # add shape to copper plane 
+#                path_element = et.SubElement(sheet, 'path', d=path)
+#                if path_style is not None:
+#                    path_element.set('style', path_style)
+#                if gerber_lp is not None:
+#                    path_element.set('gerber_lp', gerber_lp)
+# 
+#                # add extra attributes if they exist
+#                for extra_attrib in extra_attributes:
+#                    ea = routes[pcb_layer][route].get(extra_attrib)
+#                    if ea is not None:
+#                        path_element.set('{'+cfg['namespace']['inkscape']+'}%s' % extra_attrib[extra_attrib.index(':')+1:], ea)
+# 
+#                if path_type is not None:
+#                    path_element.set('type', path_type)
+# 
+#                if pcbmode_params is not None:
+#                    path_element.set('pcbmode', pcbmode_params)                
+# 
+#                pour_buffer = 0.5
+#                try:
+#                    pour_buffer = cfg['board']['distances']['buffer_from_pour_to'].get('route') or 0.5
+#                except:
+#                    pass
+# 
+#                mask_style_template = "fill:%s;stroke:#000;stroke-linejoin:round;stroke-width:%s;stroke-linecap:round;"
+# 
+#                regex = r".*?%s:\s?(?P<s>[^;]*)(?:;|$)"
+#                stroke_def = re.match(regex % 'stroke', path_style)
+#                if stroke_def is not None:
+#                    stroke = stroke_def.group('s')
+# 
+#                stroke_width_def = re.match(regex % 'stroke-width', path_style)    
+#                if stroke_width_def is not None:
+#                    stroke_width = float(stroke_width_def.group('s'))
+#                else:
+#                    stroke_width = 0
+# 
+#                if stroke_width > 0:
+#                    fill = 'none'
+#                else:
+#                    fill = re.match(regex % 'fill', path_style)
+#                    if fill is not None:
+#                        fill = fill.group('s')
+# 
+#                # place mask
+#                if path_type not in ['pour_bridge'] and there_are_pours:
+#                    mask_element = et.SubElement(routing_mask_group, 'path',
+#                                                 #id="%s" % pcb_layer,
+#                                                 type="mask_shape",
+#                                                 style=mask_style_template % (fill, stroke_width + pour_buffer * 2),
+#                                                 d=path)
+#     
+#                    # set 'gerber_lp' attribute is it's not empty
+#                    if gerber_lp is not None:
+#                        path_element.set('gerber_lp', gerber_lp)
+#                        mask_element.set('gerber_lp', gerber_lp)
+#     
+#                    # Due to the limitation of the Gerber format, and the method chosen
+#                    # for applying masks onto pours, it is not possible to have copper
+#                    # pour material inside of paths that have more than a single segment.
+#                    # In order to make the apperance in the SVG and Gerbers consistent, 
+#                    # each path segment is added with a 'fill'. In the future, when the
+#                    # *actual* shape is calculated, it may be possible to avoid this
+#                    # hack. On the other hand, one can argue that having pours inside of
+#                    # shapes doesn't make sense anyway, because it alters its apperance, 
+#                    # and such shapes are stylistic anyway. OK, back to code now...
+#                    if gerber_lp is not None:
+#                        if len(gerber_lp) > 1:
+#                            path_segments = path.split('m')
+#                            for path_segment in path_segments[1:]:
+#                                mask_element = et.SubElement(routing_mask_group, 'path',
+#                                                             #id="%s" % pcb_layer,
+#                                                             type="mask_shape",
+#                                                             style="fill:#000;stroke:none;",
+#                                                             d='m '+path_segment)
+# 
+#        for via in vias.values():
+#            
+#            via_type = via.get('via_type')
+#            # check if via is specified, or 'default' is specified:
+#            via_part_name = via_type[len(cfg['via_prefix']):]
+#            via_part_name = via_part_name.strip(' ') # remove leading spaces if there any
+# 
+#            # save footprint file
+#            # strictly, this is not necessary because these files are not going
+#            # to be used. However, it's good for debug.
+#            footprint_path = os.path.join(cfg['base_dir'], cfg['pcbmode']['locations']['build'], 'footprints')
+#          
+#            # check if footprint directory exists; if not, create
+#            try:
+#                # try to create directory first; this prevents TOCTTOU-type race condition
+#                os.makedirs(footprint_path)
+#            except OSError:
+#                # if the dir exists, pass
+#                if os.path.isdir(footprint_path):
+#                    pass
+#                else:
+#                    raise
+#           
+#            filename_in = os.path.join(cfg['base_dir'], 
+#                                       cfg['pcbmode']['locations']['parts'], 
+#                                       via_part_name + '.json')
+#            filename_out = os.path.join(footprint_path, 
+#                                        via_part_name + '.svg')
+# 
+#            # create via footprint
+#            via_footprint, fp_width, fp_height, fp_drills = footprint.create_footprint(cfg,
+#                                                                                       via_part_name,
+#                                                                                       via_type, 
+#                                                                                       0, 
+#                                                                                       Point, 
+#                                                                                       1)
+# 
+#            drill_count = utils.add_dict_values(drill_count, fp_drills)
+# 
+#            location = utils.to_Point(via.get('location') or [0, 0])
+#            translate = str(round(location.x, sig_dig))+' '+str(round(-location.y, sig_dig))
+#            transform = 'translate('+translate+')'
+#            import_footprint(via_footprint, transform)
+# 
+# 
+# 
+#        # add path-effect paths to <defs>
+#        if path_effects is not None:
+#            for path_effect in path_effects.values():
+#                effect_element = et.SubElement(board_defs, '{'+cfg['namespace']['inkscape']+'}path-effect')
+#                for name, value in path_effect.items():
+#                    effect_element.set(name, value)
+# 
 
 
     # add additional shapes
 
     add_measurements(board_svg_layers['dimensions']['measurements']['layer'])    
 
+    add_refdef_index(cfg)
 
     # NOTE: the 'cover' MUST be the last element in the mask definition;
     # that's why it is added here. If it it not the last, every mask element

File utils/svg.py

 
         # instantiate sub-layers for 'copper' PCB layer
         tmp = board_svg_layers[pcb_layer_name]['copper']
-
-
         layer_names = ['pads', 'routing', 'pours']
 
         for layer_name in layer_names:
                                                         style,
                                                         refdef)
 
+        # instantiate sub-layers for 'copper' PCB layer
+        tmp = board_svg_layers[pcb_layer_name]['assembly']
+        layer_names = ['refdef-index']
+
+        for layer_name in layer_names:
+            # define a layer id
+            layer_id = "%s_%s" % (pcb_layer_name, layer_name)
+            if refdef is not None:
+                layer_id += "_%s" % refdef 
+            style = utils.dict_to_style(cfg['layout_style']['assembly']['default'].get(pcb_layer_name))
+            tmp[layer_name] = {}
+            tmp[layer_name]['layer'] = create_svg_layer(cfg, 
+                                                        tmp['layer'], 
+                                                        layer_name,
+                                                        layer_id,
+                                                        None, 
+                                                        style,
+                                                        refdef)
+
 
 
     # create dimentions layer

File utils/utils.py

 
 
 
+
+def parse_refdef(refdef):
+    """
+    Parses a reference designator and returns the refdef categoty,
+    number, and extra characters
+    """
+
+    regex = r'^(?P<t>[a-zA-z\D]+?)(?P<n>\d+)(?P<e>[\-\s].*)?'
+    parse = re.match(regex, refdef)
+
+    t = parse.group('t')
+    n = int(parse.group('n'))
+    e = parse.group('e')
+   
+    return t, n, e
+    
+
+
+
+
+
 def renumber_refdefs(cfg, order):
     """
     Renumber the refdefs in the specified order
     """
 
-    regex = r'^(?P<t>[a-zA-z\D]+?)(?P<n>\d+)(?P<e>[\-\s].*)?'
     components = cfg['board']['placement']['components']
     record_start_values = {}
 
         comp_lists = {}
         for refdef in components[layer]:
 
-            # split the refdef into components
-            parse = re.match(regex, refdef)
+            rd_type, rd_number, rd_extra = parse_refdef(refdef)
 
-            if comp_lists.get(parse.group('t')) is None:
-                comp_lists[parse.group('t')] = []
+            if comp_lists.get(rd_type) is None:
+                comp_lists[rd_type] = []
 
             location = to_Point(components[layer][refdef].get('location') or [0, 0])
             tmp = {}
             tmp['record'] = components[layer][refdef]
-            tmp['type'] = parse.group('t')
-            tmp['number'] = parse.group('n')
-            tmp['extra'] = parse.group('e')
+            tmp['type'] = rd_type
+            tmp['number'] = rd_number
+            tmp['extra'] = rd_extra
             tmp['coord_x'] = location.x
             tmp['coord_y'] = location.y
-            comp_lists[parse.group('t')].append(tmp)
+            comp_lists[rd_type].append(tmp)
 
         # sort list according to desired 'order'
         for comp_type in comp_lists: