Skip to content

Commit

Permalink
Switch to identifying modules by index instead of reference
Browse files Browse the repository at this point in the history
Fixes #33, #57
  • Loading branch information
qu1ck committed Nov 18, 2018
1 parent 732470c commit b2b305f
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 49 deletions.
37 changes: 20 additions & 17 deletions InteractiveHtmlBom/generate_interactive_bom.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,11 @@ def skip_component(m, config, extra_data, filter_layer):
return False


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

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

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

Expand Down Expand Up @@ -159,7 +159,7 @@ def natural_sort(l):

group_key = (norm_value, tuple(extras), footprint, attr)
valrefs = part_groups.setdefault(group_key, [value, []])
valrefs[1].append(ref)
valrefs[1].append((ref, i))

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

if '~' not in config.component_sort_order:
config.component_sort_order.append('~')
Expand Down Expand Up @@ -423,10 +423,10 @@ def parse_pad(pad):
return pad_dict


def parse_modules(pcb):
# type: (pcbnew.BOARD) -> dict
modules = {}
for m in pcb.GetModules():
def parse_modules(pcb_modules):
# type: (list) -> list
modules = []
for m in pcb_modules:
ref = m.GetReference()
center = normalize(m.GetCenter())

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

# add module
modules[ref] = {
modules.append({
"ref": ref,
"center": center,
"bbox": bbox,
Expand All @@ -482,7 +482,7 @@ def parse_modules(pcb):
pcbnew.F_Cu: "F",
pcbnew.B_Cu: "B"
}.get(m.GetLayer())
}
})

return modules

Expand Down Expand Up @@ -567,11 +567,14 @@ def main(pcb, config):
"maxx": bbox.GetRight() * 1e-6,
"maxy": bbox.GetBottom() * 1e-6,
}

pcb_modules = list(pcb.GetModules())

pcbdata = {
"edges_bbox": bbox,
"edges": edges,
"silkscreen": parse_silkscreen(pcb),
"modules": parse_modules(pcb),
"modules": parse_modules(pcb_modules),
"metadata": {
"title": title,
"revision": title_block.GetRevision(),
Expand All @@ -580,11 +583,11 @@ def main(pcb, config):
},
"bom": {},
}
pcbdata["bom"]["both"] = generate_bom(pcb, config, extra_fields)
pcbdata["bom"]["both"] = generate_bom(pcb_modules, config, extra_fields)

# build BOM
for layer in (pcbnew.F_Cu, pcbnew.B_Cu):
bom_table = generate_bom(pcb, config, extra_fields, filter_layer=layer)
bom_table = generate_bom(pcb_modules, config, extra_fields, filter_layer=layer)
pcbdata["bom"]["F" if layer == pcbnew.F_Cu else "B"] = bom_table

pcbdata["font_data"] = font_parser.get_parsed_font()
Expand Down
50 changes: 29 additions & 21 deletions InteractiveHtmlBom/ibom.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ var currentSortColumn = null;
var currentSortOrder = null;
var currentHighlightedRowId;
var highlightHandlers = [];
var highlightedRefs = [];
var highlightedModules = [];
var checkboxes = [];
var bomCheckboxes = "";
var highlightpin1 = false;
var storage;
var lastClickedRef;
var lastClicked;

function initStorage(key) {
try {
Expand Down Expand Up @@ -72,17 +72,30 @@ function setHighlightPin1(value) {
}

function getStoredCheckboxRefs(checkbox) {
function convert(ref) {
var intref = parseInt(ref);
if (isNaN(intref)) {
for (var i = 0; i < pcbdata.modules.length; i++) {
if (pcbdata.modules[i].ref == ref) {
return i;
}
}
return -1;
} else {
return intref;
}
}
var existingRefs = readStorage("checkbox_" + checkbox);
if (!existingRefs) {
return new Set();
} else {
return new Set(existingRefs.split(","));
return new Set(existingRefs.split(",").map(r => convert(r)));
}
}

function getCheckboxState(checkbox, references) {
var storedRefsSet = getStoredCheckboxRefs(checkbox);
var currentRefsSet = new Set(references);
var currentRefsSet = new Set(references.map(r => r[1]));
// Get difference of current - stored
var difference = new Set(currentRefsSet);
for (ref of storedRefsSet) {
Expand Down Expand Up @@ -112,12 +125,12 @@ function createCheckboxChangeHandler(checkbox, references) {
if (this.checked) {
// checkbox ticked
for (var ref of references) {
refsSet.add(ref);
refsSet.add(ref[1]);
}
} else {
// checkbox unticked
for (var ref of references) {
refsSet.delete(ref);
refsSet.delete(ref[1]);
}
}
writeStorage("checkbox_" + checkbox, [...refsSet].join(","));
Expand All @@ -134,15 +147,15 @@ function createRowHighlightHandler(rowid, refs) {
}
document.getElementById(rowid).classList.add("highlighted");
currentHighlightedRowId = rowid;
highlightedRefs = refs;
highlightedModules = refs.map(r => r[1]);
drawHighlights();
}
}

function entryMatches(entry) {
// check refs
for (var ref of entry[3]) {
if (ref.toLowerCase().indexOf(filter) >= 0) {
if (ref[0].toLowerCase().indexOf(filter) >= 0) {
return true;
}
}
Expand All @@ -158,12 +171,7 @@ function entryMatches(entry) {
}

function findRefInEntry(entry) {
for (var ref of entry[3]) {
if (ref.toLowerCase() == reflookup) {
return [ref];
}
}
return false;
return entry[3].filter(r => r[0].toLowerCase() == reflookup);
}

function highlightFilter(s) {
Expand Down Expand Up @@ -374,7 +382,7 @@ function populateBomBody() {
var references = bomentry[3];
if (reflookup) {
references = findRefInEntry(bomentry);
if (!references) {
if (references.length == 0) {
continue;
}
}
Expand All @@ -398,7 +406,7 @@ function populateBomBody() {
}
// References
td = document.createElement("TD");
td.innerHTML = highlightFilter(references.join(", "));
td.innerHTML = highlightFilter(references.map(r => r[0]).join(", "));
tr.appendChild(td);
// Extra fields
for (var i in config.extra_fields) {
Expand Down Expand Up @@ -484,12 +492,12 @@ function populateBomTable() {
populateBomBody();
}

function modulesClicked(references) {
var lastClickedIndex = references.indexOf(lastClickedRef);
var ref = references[(lastClickedIndex + 1) % references.length];
function modulesClicked(moduleIndexes) {
var lastClickedIndex = moduleIndexes.indexOf(lastClicked);
var index = moduleIndexes[(lastClickedIndex + 1) % moduleIndexes.length];
for (var handler of highlightHandlers) {
if (handler.refs.indexOf(ref) >= 0) {
lastClickedRef = ref;
if (handler.refs.map(r => r[1]).indexOf(index) >= 0) {
lastClicked = index;
handler.handler();
smoothScrollToRow(currentHighlightedRowId);
break;
Expand Down
22 changes: 11 additions & 11 deletions InteractiveHtmlBom/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,20 +242,20 @@ function drawEdges(canvas, scalefactor) {
}
}

function drawModules(canvas, layer, scalefactor, highlightedRefs) {
function drawModules(canvas, layer, scalefactor, highlightedModules) {
var ctx = canvas.getContext("2d");
ctx.lineWidth = 3 / scalefactor;
var style = getComputedStyle(topmostdiv);
var padcolor = style.getPropertyValue('--pad-color');
var outlinecolor = style.getPropertyValue('--pin1-outline-color');
if (highlightedRefs.length > 0) {
if (highlightedModules.length > 0) {
padcolor = style.getPropertyValue('--pad-color-highlight');
outlinecolor = style.getPropertyValue('--pin1-outline-color-highlight');
}
for (var i in pcbdata.modules) {
for (var i = 0; i < pcbdata.modules.length; i++) {
var mod = pcbdata.modules[i];
var highlight = highlightedRefs.includes(mod.ref);
if (highlightedRefs.length == 0 || highlight) {
var highlight = highlightedModules.includes(i);
if (highlightedModules.length == 0 || highlight) {
drawModule(ctx, layer, scalefactor, mod, padcolor, outlinecolor, highlight);
}
}
Expand Down Expand Up @@ -285,7 +285,7 @@ function clearCanvas(canvas) {
function drawHighlightsOnLayer(canvasdict) {
clearCanvas(canvasdict.highlight);
drawModules(canvasdict.highlight, canvasdict.layer,
canvasdict.transform.s, highlightedRefs);
canvasdict.transform.s, highlightedModules);
}

function drawHighlights() {
Expand Down Expand Up @@ -397,13 +397,13 @@ function resizeAll() {

function bboxScan(layer, x, y) {
var result = [];
for (var i in pcbdata.modules) {
for (var i = 0; i < pcbdata.modules.length; i++) {
var module = pcbdata.modules[i];
if (module.layer == layer) {
var b = module.bbox;
if (b.pos[0] <= x && b.pos[0] + b.size[0] >= x &&
b.pos[1] <= y && b.pos[1] + b.size[1] >= y) {
result.push(module.ref);
result.push(i);
}
}
}
Expand Down Expand Up @@ -434,9 +434,9 @@ function handleMouseClick(e, layerdict) {
}
y = (2 * y / t.zoom - t.y - t.pany) / t.s;
var v = rotateVector([x, y], -boardRotation);
var reflist = bboxScan(layerdict.layer, v[0], v[1]);
if (reflist.length > 0) {
modulesClicked(reflist);
var modules = bboxScan(layerdict.layer, v[0], v[1]);
if (modules.length > 0) {
modulesClicked(modules);
drawHighlights();
}
}
Expand Down

0 comments on commit b2b305f

Please sign in to comment.