Skip to content

Commit ec985b3

Browse files
committed
Add options to include tracks and netlist data
Issue #113
1 parent a335f79 commit ec985b3

File tree

9 files changed

+296
-36
lines changed

9 files changed

+296
-36
lines changed

InteractiveHtmlBom/core/config.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ class Config:
6363
component_blacklist = []
6464
blacklist_virtual = True
6565
blacklist_empty_val = False
66+
include_tracks = False
67+
include_nets = False
6668

6769
# Extra fields section
6870
netlist_file = None
@@ -113,6 +115,8 @@ def __init__(self):
113115
'blacklist_virtual', self.blacklist_virtual)
114116
self.blacklist_empty_val = f.ReadBool(
115117
'blacklist_empty_val', self.blacklist_empty_val)
118+
self.include_tracks = f.ReadBool('include_tracks', self.include_tracks)
119+
self.include_nets = f.ReadBool('include_nets', self.include_nets)
116120

117121
f.SetPath('/extra_fields')
118122
self.extra_fields = self._split(f.Read(
@@ -159,6 +163,8 @@ def save(self):
159163
','.join(self.component_blacklist))
160164
f.WriteBool('blacklist_virtual', self.blacklist_virtual)
161165
f.WriteBool('blacklist_empty_val', self.blacklist_empty_val)
166+
f.WriteBool('include_tracks', self.include_tracks)
167+
f.WriteBool('include_nets', self.include_nets)
162168

163169
f.SetPath('/extra_fields')
164170
f.Write('extra_fields', ','.join(self.extra_fields))
@@ -196,6 +202,8 @@ def set_from_dialog(self, dlg):
196202
dlg.general.blacklistVirtualCheckbox.IsChecked()
197203
self.blacklist_empty_val = \
198204
dlg.general.blacklistEmptyValCheckbox.IsChecked()
205+
self.include_tracks = dlg.general.includeTracksCheckbox.IsChecked()
206+
self.include_nets = dlg.general.includeNetsCheckbox.IsChecked()
199207

200208
# Extra fields
201209
self.netlist_file = dlg.extra.netlistFilePicker.Path
@@ -241,6 +249,8 @@ def transfer_to_dialog(self, dlg):
241249
dlg.general.blacklistBox.SetItems(self.component_blacklist)
242250
dlg.general.blacklistVirtualCheckbox.Value = self.blacklist_virtual
243251
dlg.general.blacklistEmptyValCheckbox.Value = self.blacklist_empty_val
252+
dlg.general.includeTracksCheckbox.Value = self.include_tracks
253+
dlg.general.includeNetsCheckbox.Value = self.include_nets
244254

245255
# Extra fields
246256
dlg.extra.netlistFilePicker.SetInitialDirectory(
@@ -308,6 +318,11 @@ def add_options(self, parser, file_name_format_hint):
308318
'relative to pcb file directory.')
309319
parser.add_argument('--name-format', default=self.bom_name_format,
310320
help=file_name_format_hint.replace('%', '%%'))
321+
parser.add_argument('--include-tracks', action='store_true',
322+
help='Include track/zone information in output. '
323+
'F.Cu and B.Cu layers only.')
324+
parser.add_argument('--include-nets', action='store_true',
325+
help='Include netlist information in output.')
311326
parser.add_argument('--sort-order',
312327
help='Default sort order for components. '
313328
'Must contain "~" once.',
@@ -370,6 +385,8 @@ def set_from_args(self, args):
370385
self.component_blacklist = self._split(args.blacklist)
371386
self.blacklist_virtual = not args.no_blacklist_virtual
372387
self.blacklist_empty_val = args.blacklist_empty_val
388+
self.include_tracks = args.include_tracks
389+
self.include_nets = args.include_nets
373390

374391
# Extra
375392
self.netlist_file = args.netlist_file

InteractiveHtmlBom/dialog/dialog_base.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,17 @@ def __init__( self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = wx.
234234

235235
bSizer32.Add( sbSizer6, 0, wx.ALL|wx.EXPAND, 5 )
236236

237+
sbSizer9 = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, u"Additional pcb data" ), wx.HORIZONTAL )
238+
239+
self.includeTracksCheckbox = wx.CheckBox( sbSizer9.GetStaticBox(), wx.ID_ANY, u"Include tracks/zones", wx.DefaultPosition, wx.DefaultSize, 0 )
240+
sbSizer9.Add( self.includeTracksCheckbox, 1, wx.ALL, 5 )
241+
242+
self.includeNetsCheckbox = wx.CheckBox( sbSizer9.GetStaticBox(), wx.ID_ANY, u"Include nets", wx.DefaultPosition, wx.DefaultSize, 0 )
243+
sbSizer9.Add( self.includeNetsCheckbox, 1, wx.ALL, 5 )
244+
245+
246+
bSizer32.Add( sbSizer9, 0, wx.ALL|wx.EXPAND, 5 )
247+
237248
sortingSizer = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, u"Component sort order" ), wx.VERTICAL )
238249

239250
bSizer4 = wx.BoxSizer( wx.HORIZONTAL )

InteractiveHtmlBom/ecad/__init__.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
import os
22

33

4-
def get_parser_by_extension(file_name, logger):
4+
def get_parser_by_extension(file_name, config, logger):
55
ext = os.path.splitext(file_name)[1]
66
if ext == '.kicad_pcb':
7-
return get_kicad_parser(file_name, logger)
7+
return get_kicad_parser(file_name, config, logger)
88
elif ext == '.json':
9-
return get_easyeda_parser(file_name, logger)
9+
return get_easyeda_parser(file_name, config, logger)
1010
else:
1111
return None
1212

1313

14-
def get_kicad_parser(file_name, logger, board=None):
14+
def get_kicad_parser(file_name, config, logger, board=None):
1515
from .kicad import PcbnewParser
16-
return PcbnewParser(file_name, logger, board)
16+
return PcbnewParser(file_name, config, logger, board)
1717

1818

19-
def get_easyeda_parser(file_name, logger):
19+
def get_easyeda_parser(file_name, config, logger):
2020
from .easyeda import EasyEdaParser
21-
return EasyEdaParser(file_name, logger)
21+
return EasyEdaParser(file_name, config, logger)

InteractiveHtmlBom/ecad/common.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55

66
class EcadParser(object):
77

8-
def __init__(self, file_name, logger):
8+
def __init__(self, file_name, config, logger):
99
"""
1010
:param file_name: path to file that should be parsed.
11+
:param config: Config instance
1112
:param logger: logging object.
1213
"""
1314
self.file_name = file_name
15+
self.config = config
1416
self.logger = logger
1517
self.extra_data_func = lambda f, b: ([], {})
1618

InteractiveHtmlBom/ecad/kicad.py

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212

1313
class PcbnewParser(EcadParser):
1414

15-
def __init__(self, file_name, logger, board=None):
16-
super(PcbnewParser, self).__init__(file_name, logger)
15+
def __init__(self, file_name, config, logger, board=None):
16+
super(PcbnewParser, self).__init__(file_name, config, logger)
1717
self.board = board
1818
if self.board is None:
1919
self.board = pcbnew.LoadBoard(self.file_name) # type: pcbnew.BOARD
@@ -273,6 +273,8 @@ def parse_pad(self, pad):
273273
pad_dict["type"] = "smd"
274274
if hasattr(pad, "GetOffset"):
275275
pad_dict["offset"] = self.normalize(pad.GetOffset())
276+
if self.config.include_nets:
277+
pad_dict["net"] = pad.GetNetname()
276278

277279
return pad_dict
278280

@@ -354,12 +356,14 @@ def parse_tracks(self, tracks):
354356
result[l].append(track_dict)
355357
else:
356358
if track.GetLayer() in [pcbnew.F_Cu, pcbnew.B_Cu]:
357-
result[track.GetLayer()].append({
359+
track_dict = {
358360
"start": self.normalize(track.GetStart()),
359361
"end": self.normalize(track.GetEnd()),
360362
"width": track.GetWidth() * 1e-6,
361-
"net": track.GetNetname(),
362-
})
363+
}
364+
if self.config.include_nets:
365+
track_dict["net"] = track.GetNetname()
366+
result[track.GetLayer()].append(track_dict)
363367

364368
return {
365369
'F': result.get(pcbnew.F_Cu),
@@ -368,20 +372,30 @@ def parse_tracks(self, tracks):
368372

369373
def parse_zones(self, zones):
370374
result = {pcbnew.F_Cu: [], pcbnew.B_Cu: []}
371-
for zone in zones:
375+
for zone in zones: # type: (pcbnew.ZONE_CONTAINER)
372376
if not zone.IsFilled() or zone.GetIsKeepout():
373377
continue
374378
if zone.GetLayer() in [pcbnew.F_Cu, pcbnew.B_Cu]:
375-
result[zone.GetLayer()].append({
379+
zone_dict = {
376380
"polygons": self.parse_poly_set(zone.GetFilledPolysList()),
377-
"net": zone.GetNetname(),
378-
})
381+
}
382+
if self.config.include_nets:
383+
zone_dict["net"] = zone.GetNetname()
384+
result[zone.GetLayer()].append(zone_dict)
379385

380386
return {
381387
'F': result.get(pcbnew.F_Cu),
382388
'B': result.get(pcbnew.B_Cu)
383389
}
384390

391+
@staticmethod
392+
def parse_netlist(net_info):
393+
# type: (pcbnew.NETINFO_LIST) -> list
394+
nets = net_info.NetsByName().asdict().keys()
395+
nets = [str(s) for s in nets]
396+
nets.sort()
397+
return nets
398+
385399
@staticmethod
386400
def module_to_component(module):
387401
# type: (pcbnew.MODULE) -> Component
@@ -452,8 +466,11 @@ def parse(self):
452466
"bom": {},
453467
"font_data": self.font_parser.get_parsed_font()
454468
}
455-
pcbdata["tracks"] = self.parse_tracks(self.board.GetTracks())
456-
pcbdata["zones"] = self.parse_zones(self.board.Zones())
469+
if self.config.include_tracks:
470+
pcbdata["tracks"] = self.parse_tracks(self.board.GetTracks())
471+
pcbdata["zones"] = self.parse_zones(self.board.Zones())
472+
if self.config.include_nets:
473+
pcbdata["nets"] = self.parse_netlist(self.board.GetNetInfo())
457474
components = [self.module_to_component(m) for m in pcb_modules]
458475

459476
return pcbdata, components
@@ -485,5 +502,5 @@ def Run(self):
485502
logger.error('Please save the board file before generating BOM.')
486503
return
487504

488-
parser = PcbnewParser(pcb_file_name, logger, board)
505+
parser = PcbnewParser(pcb_file_name, config, logger, board)
489506
ibom.run_with_dialog(parser, config, logger)

InteractiveHtmlBom/generate_interactive_bom.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def to_utf(s):
4444
exit(1)
4545
print("Loading %s" % args.file)
4646
logger = ibom.Logger(cli=True)
47-
parser = get_parser_by_extension(os.path.abspath(args.file), logger)
47+
parser = get_parser_by_extension(os.path.abspath(args.file), config, logger)
4848
if args.show_dialog:
4949
ibom.run_with_dialog(parser, config, logger)
5050
else:

InteractiveHtmlBom/web/ibom.html

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,16 @@
7171
<input id="valuesCheckbox" type="checkbox" checked onchange="valuesVisible(this.checked)">
7272
Values
7373
</label>
74-
<label class="menu-label" style="width: calc(50% - 18px)">
75-
<input id="tracksCheckbox" type="checkbox" checked onchange="tracksVisible(this.checked)">
76-
Tracks
77-
</label><!-- This comment eats space! All of it!
78-
--><label class="menu-label" style="width: calc(50% - 17px); border-left: 0;">
79-
<input id="zonesCheckbox" type="checkbox" checked onchange="zonesVisible(this.checked)">
80-
Zones
81-
</label>
74+
<div id="tracksAndZonesCheckboxes">
75+
<label class="menu-label" style="width: calc(50% - 18px)">
76+
<input id="tracksCheckbox" type="checkbox" checked onchange="tracksVisible(this.checked)">
77+
Tracks
78+
</label><!-- This comment eats space! All of it!
79+
--><label class="menu-label" style="width: calc(50% - 17px); border-left: 0;">
80+
<input id="zonesCheckbox" type="checkbox" checked onchange="zonesVisible(this.checked)">
81+
Zones
82+
</label>
83+
</div>
8284
<label class="menu-label">
8385
<input id="dnpOutlineCheckbox" type="checkbox" checked onchange="dnpOutline(this.checked)">
8486
DNP components outlined

InteractiveHtmlBom/web/ibom.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -865,13 +865,19 @@ function initDefaults() {
865865
document.getElementById("valuesCheckbox").checked = b;
866866
valuesVisible(b);
867867

868-
b = getStorageBooleanOrDefault("tracksVisible", true);
869-
document.getElementById("tracksCheckbox").checked = b;
870-
tracksVisible(b);
871-
872-
b = getStorageBooleanOrDefault("zonesVisible", true);
873-
document.getElementById("zonesCheckbox").checked = b;
874-
zonesVisible(b);
868+
if ("tracks" in pcbdata) {
869+
b = getStorageBooleanOrDefault("tracksVisible", true);
870+
document.getElementById("tracksCheckbox").checked = b;
871+
tracksVisible(b);
872+
873+
b = getStorageBooleanOrDefault("zonesVisible", true);
874+
document.getElementById("zonesCheckbox").checked = b;
875+
zonesVisible(b);
876+
} else {
877+
document.getElementById("tracksAndZonesCheckboxes").style.display = "none";
878+
tracksVisible(false);
879+
zonesVisible(false);
880+
}
875881

876882
b = getStorageBooleanOrDefault("dnpOutline", false);
877883
document.getElementById("dnpOutlineCheckbox").checked = b;

0 commit comments

Comments
 (0)