Skip to content

Commit b2b305f

Browse files
committed
Switch to identifying modules by index instead of reference
Fixes #33, #57
1 parent 732470c commit b2b305f

File tree

3 files changed

+60
-49
lines changed

3 files changed

+60
-49
lines changed

InteractiveHtmlBom/generate_interactive_bom.py

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,11 @@ def skip_component(m, config, extra_data, filter_layer):
8787
return False
8888

8989

90-
def generate_bom(pcb, config, extra_data, filter_layer=None):
91-
# type: (pcbnew.BOARD, Config, Dict[str, dict], int) -> list
90+
def generate_bom(pcb_modules, config, extra_data, filter_layer=None):
91+
# type: (list, Config, Dict[str, dict], int) -> list
9292
"""
9393
Generate BOM from pcb layout.
94-
:param pcb: pcbnew BOARD object
94+
:param pcb_modules: list of modules on the pcb
9595
:param config: Config object
9696
:param extra_data: Extra fields data
9797
:param filter_layer: include only parts for given layer
@@ -110,7 +110,7 @@ def natural_sort(l):
110110
Natural sort for strings containing numbers
111111
"""
112112

113-
return sorted(l, key=alphanum_key)
113+
return sorted(l, key=lambda r: (alphanum_key(r[0]), r[1]))
114114

115115
attr_dict = {0: 'Normal',
116116
1: 'Normal+Insert',
@@ -120,7 +120,7 @@ def natural_sort(l):
120120
# build grouped part list
121121
warning_shown = False
122122
part_groups = {}
123-
for m in pcb.GetModules():
123+
for i, m in enumerate(pcb_modules):
124124
if skip_component(m, config, extra_data, filter_layer):
125125
continue
126126

@@ -159,7 +159,7 @@ def natural_sort(l):
159159

160160
group_key = (norm_value, tuple(extras), footprint, attr)
161161
valrefs = part_groups.setdefault(group_key, [value, []])
162-
valrefs[1].append(ref)
162+
valrefs[1].append((ref, i))
163163

164164
if warning_shown:
165165
logwarn('Netlist/xml file is likely out of date.')
@@ -174,12 +174,12 @@ def natural_sort(l):
174174
# sort table by reference prefix, footprint and quantity
175175
def sort_func(row):
176176
qty, _, fp, rf, extras = row
177-
prefix = re.findall('^[A-Z]*', rf[0])[0]
177+
prefix = re.findall('^[A-Z]*', rf[0][0])[0]
178178
if prefix in config.component_sort_order:
179179
ref_ord = config.component_sort_order.index(prefix)
180180
else:
181181
ref_ord = config.component_sort_order.index('~')
182-
return ref_ord, extras, fp, -qty, alphanum_key(rf[0])
182+
return ref_ord, extras, fp, -qty, alphanum_key(rf[0][0])
183183

184184
if '~' not in config.component_sort_order:
185185
config.component_sort_order.append('~')
@@ -423,10 +423,10 @@ def parse_pad(pad):
423423
return pad_dict
424424

425425

426-
def parse_modules(pcb):
427-
# type: (pcbnew.BOARD) -> dict
428-
modules = {}
429-
for m in pcb.GetModules():
426+
def parse_modules(pcb_modules):
427+
# type: (list) -> list
428+
modules = []
429+
for m in pcb_modules:
430430
ref = m.GetReference()
431431
center = normalize(m.GetCenter())
432432

@@ -472,7 +472,7 @@ def parse_modules(pcb):
472472
pads = [p[1] for p in pads]
473473

474474
# add module
475-
modules[ref] = {
475+
modules.append({
476476
"ref": ref,
477477
"center": center,
478478
"bbox": bbox,
@@ -482,7 +482,7 @@ def parse_modules(pcb):
482482
pcbnew.F_Cu: "F",
483483
pcbnew.B_Cu: "B"
484484
}.get(m.GetLayer())
485-
}
485+
})
486486

487487
return modules
488488

@@ -567,11 +567,14 @@ def main(pcb, config):
567567
"maxx": bbox.GetRight() * 1e-6,
568568
"maxy": bbox.GetBottom() * 1e-6,
569569
}
570+
571+
pcb_modules = list(pcb.GetModules())
572+
570573
pcbdata = {
571574
"edges_bbox": bbox,
572575
"edges": edges,
573576
"silkscreen": parse_silkscreen(pcb),
574-
"modules": parse_modules(pcb),
577+
"modules": parse_modules(pcb_modules),
575578
"metadata": {
576579
"title": title,
577580
"revision": title_block.GetRevision(),
@@ -580,11 +583,11 @@ def main(pcb, config):
580583
},
581584
"bom": {},
582585
}
583-
pcbdata["bom"]["both"] = generate_bom(pcb, config, extra_fields)
586+
pcbdata["bom"]["both"] = generate_bom(pcb_modules, config, extra_fields)
584587

585588
# build BOM
586589
for layer in (pcbnew.F_Cu, pcbnew.B_Cu):
587-
bom_table = generate_bom(pcb, config, extra_fields, filter_layer=layer)
590+
bom_table = generate_bom(pcb_modules, config, extra_fields, filter_layer=layer)
588591
pcbdata["bom"]["F" if layer == pcbnew.F_Cu else "B"] = bom_table
589592

590593
pcbdata["font_data"] = font_parser.get_parsed_font()

InteractiveHtmlBom/ibom.js

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ var currentSortColumn = null;
1111
var currentSortOrder = null;
1212
var currentHighlightedRowId;
1313
var highlightHandlers = [];
14-
var highlightedRefs = [];
14+
var highlightedModules = [];
1515
var checkboxes = [];
1616
var bomCheckboxes = "";
1717
var highlightpin1 = false;
1818
var storage;
19-
var lastClickedRef;
19+
var lastClicked;
2020

2121
function initStorage(key) {
2222
try {
@@ -72,17 +72,30 @@ function setHighlightPin1(value) {
7272
}
7373

7474
function getStoredCheckboxRefs(checkbox) {
75+
function convert(ref) {
76+
var intref = parseInt(ref);
77+
if (isNaN(intref)) {
78+
for (var i = 0; i < pcbdata.modules.length; i++) {
79+
if (pcbdata.modules[i].ref == ref) {
80+
return i;
81+
}
82+
}
83+
return -1;
84+
} else {
85+
return intref;
86+
}
87+
}
7588
var existingRefs = readStorage("checkbox_" + checkbox);
7689
if (!existingRefs) {
7790
return new Set();
7891
} else {
79-
return new Set(existingRefs.split(","));
92+
return new Set(existingRefs.split(",").map(r => convert(r)));
8093
}
8194
}
8295

8396
function getCheckboxState(checkbox, references) {
8497
var storedRefsSet = getStoredCheckboxRefs(checkbox);
85-
var currentRefsSet = new Set(references);
98+
var currentRefsSet = new Set(references.map(r => r[1]));
8699
// Get difference of current - stored
87100
var difference = new Set(currentRefsSet);
88101
for (ref of storedRefsSet) {
@@ -112,12 +125,12 @@ function createCheckboxChangeHandler(checkbox, references) {
112125
if (this.checked) {
113126
// checkbox ticked
114127
for (var ref of references) {
115-
refsSet.add(ref);
128+
refsSet.add(ref[1]);
116129
}
117130
} else {
118131
// checkbox unticked
119132
for (var ref of references) {
120-
refsSet.delete(ref);
133+
refsSet.delete(ref[1]);
121134
}
122135
}
123136
writeStorage("checkbox_" + checkbox, [...refsSet].join(","));
@@ -134,15 +147,15 @@ function createRowHighlightHandler(rowid, refs) {
134147
}
135148
document.getElementById(rowid).classList.add("highlighted");
136149
currentHighlightedRowId = rowid;
137-
highlightedRefs = refs;
150+
highlightedModules = refs.map(r => r[1]);
138151
drawHighlights();
139152
}
140153
}
141154

142155
function entryMatches(entry) {
143156
// check refs
144157
for (var ref of entry[3]) {
145-
if (ref.toLowerCase().indexOf(filter) >= 0) {
158+
if (ref[0].toLowerCase().indexOf(filter) >= 0) {
146159
return true;
147160
}
148161
}
@@ -158,12 +171,7 @@ function entryMatches(entry) {
158171
}
159172

160173
function findRefInEntry(entry) {
161-
for (var ref of entry[3]) {
162-
if (ref.toLowerCase() == reflookup) {
163-
return [ref];
164-
}
165-
}
166-
return false;
174+
return entry[3].filter(r => r[0].toLowerCase() == reflookup);
167175
}
168176

169177
function highlightFilter(s) {
@@ -374,7 +382,7 @@ function populateBomBody() {
374382
var references = bomentry[3];
375383
if (reflookup) {
376384
references = findRefInEntry(bomentry);
377-
if (!references) {
385+
if (references.length == 0) {
378386
continue;
379387
}
380388
}
@@ -398,7 +406,7 @@ function populateBomBody() {
398406
}
399407
// References
400408
td = document.createElement("TD");
401-
td.innerHTML = highlightFilter(references.join(", "));
409+
td.innerHTML = highlightFilter(references.map(r => r[0]).join(", "));
402410
tr.appendChild(td);
403411
// Extra fields
404412
for (var i in config.extra_fields) {
@@ -484,12 +492,12 @@ function populateBomTable() {
484492
populateBomBody();
485493
}
486494

487-
function modulesClicked(references) {
488-
var lastClickedIndex = references.indexOf(lastClickedRef);
489-
var ref = references[(lastClickedIndex + 1) % references.length];
495+
function modulesClicked(moduleIndexes) {
496+
var lastClickedIndex = moduleIndexes.indexOf(lastClicked);
497+
var index = moduleIndexes[(lastClickedIndex + 1) % moduleIndexes.length];
490498
for (var handler of highlightHandlers) {
491-
if (handler.refs.indexOf(ref) >= 0) {
492-
lastClickedRef = ref;
499+
if (handler.refs.map(r => r[1]).indexOf(index) >= 0) {
500+
lastClicked = index;
493501
handler.handler();
494502
smoothScrollToRow(currentHighlightedRowId);
495503
break;

InteractiveHtmlBom/render.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -242,20 +242,20 @@ function drawEdges(canvas, scalefactor) {
242242
}
243243
}
244244

245-
function drawModules(canvas, layer, scalefactor, highlightedRefs) {
245+
function drawModules(canvas, layer, scalefactor, highlightedModules) {
246246
var ctx = canvas.getContext("2d");
247247
ctx.lineWidth = 3 / scalefactor;
248248
var style = getComputedStyle(topmostdiv);
249249
var padcolor = style.getPropertyValue('--pad-color');
250250
var outlinecolor = style.getPropertyValue('--pin1-outline-color');
251-
if (highlightedRefs.length > 0) {
251+
if (highlightedModules.length > 0) {
252252
padcolor = style.getPropertyValue('--pad-color-highlight');
253253
outlinecolor = style.getPropertyValue('--pin1-outline-color-highlight');
254254
}
255-
for (var i in pcbdata.modules) {
255+
for (var i = 0; i < pcbdata.modules.length; i++) {
256256
var mod = pcbdata.modules[i];
257-
var highlight = highlightedRefs.includes(mod.ref);
258-
if (highlightedRefs.length == 0 || highlight) {
257+
var highlight = highlightedModules.includes(i);
258+
if (highlightedModules.length == 0 || highlight) {
259259
drawModule(ctx, layer, scalefactor, mod, padcolor, outlinecolor, highlight);
260260
}
261261
}
@@ -285,7 +285,7 @@ function clearCanvas(canvas) {
285285
function drawHighlightsOnLayer(canvasdict) {
286286
clearCanvas(canvasdict.highlight);
287287
drawModules(canvasdict.highlight, canvasdict.layer,
288-
canvasdict.transform.s, highlightedRefs);
288+
canvasdict.transform.s, highlightedModules);
289289
}
290290

291291
function drawHighlights() {
@@ -397,13 +397,13 @@ function resizeAll() {
397397

398398
function bboxScan(layer, x, y) {
399399
var result = [];
400-
for (var i in pcbdata.modules) {
400+
for (var i = 0; i < pcbdata.modules.length; i++) {
401401
var module = pcbdata.modules[i];
402402
if (module.layer == layer) {
403403
var b = module.bbox;
404404
if (b.pos[0] <= x && b.pos[0] + b.size[0] >= x &&
405405
b.pos[1] <= y && b.pos[1] + b.size[1] >= y) {
406-
result.push(module.ref);
406+
result.push(i);
407407
}
408408
}
409409
}
@@ -434,9 +434,9 @@ function handleMouseClick(e, layerdict) {
434434
}
435435
y = (2 * y / t.zoom - t.y - t.pany) / t.s;
436436
var v = rotateVector([x, y], -boardRotation);
437-
var reflist = bboxScan(layerdict.layer, v[0], v[1]);
438-
if (reflist.length > 0) {
439-
modulesClicked(reflist);
437+
var modules = bboxScan(layerdict.layer, v[0], v[1]);
438+
if (modules.length > 0) {
439+
modulesClicked(modules);
440440
drawHighlights();
441441
}
442442
}

0 commit comments

Comments
 (0)