From d61bd56f014e99fddb240c8a0e0889d64c761b6d Mon Sep 17 00:00:00 2001 From: qu1ck Date: Tue, 25 Jun 2019 00:13:20 -0700 Subject: [PATCH] Add option to show DNP components in outline mode Fixes #75 --- DATAFORMAT.md | 3 ++ InteractiveHtmlBom/core/ibom.py | 63 ++++++++++++++++++-------------- InteractiveHtmlBom/web/ibom.html | 4 ++ InteractiveHtmlBom/web/ibom.js | 10 +++++ InteractiveHtmlBom/web/render.js | 17 +++++---- InteractiveHtmlBom/web/util.js | 4 +- 6 files changed, 64 insertions(+), 37 deletions(-) diff --git a/DATAFORMAT.md b/DATAFORMAT.md index a445c7cf..94fee6f2 100644 --- a/DATAFORMAT.md +++ b/DATAFORMAT.md @@ -30,6 +30,7 @@ pcbdata = { }, // Describes footprints. // See footprint structure description below. + // index of entry corresponds to component's numeric ID "modules": [ footprint1, footprint2, @@ -48,6 +49,8 @@ pcbdata = { "both": [bomrow1, bomrow2, ...], "F": [bomrow1, bomrow2, ...], "B": [bomrow1, bomrow2, ...], + // numeric IDs of DNP components that are not in BOM + "skipped": [id1, id2, ...] }, // Contains parsed stroke data from newstroke font for // characters used on the pcb. diff --git a/InteractiveHtmlBom/core/ibom.py b/InteractiveHtmlBom/core/ibom.py index b0e70cb8..e83f0833 100644 --- a/InteractiveHtmlBom/core/ibom.py +++ b/InteractiveHtmlBom/core/ibom.py @@ -46,15 +46,11 @@ def warn(self, msg): wx.LogWarning(msg) -log = None # type: Logger +log = None # type: Logger or None -def skip_component(m, config, extra_data, filter_layer): - # type: (Component, Config, dict, str) -> bool - # filter part by layer - if filter_layer is not None and filter_layer != m.layer: - return True - +def skip_component(m, config, extra_data): + # type: (Component, Config, dict) -> bool # skip blacklisted components ref_prefix = re.findall('^[A-Z]*', m.ref)[0] if m.ref in config.component_blacklist: @@ -65,6 +61,10 @@ def skip_component(m, config, extra_data, filter_layer): if config.blacklist_empty_val and m.val in ['', '~']: return True + # skip virtual components if needed + if config.blacklist_virtual and m.attr == 'Virtual': + return True + # skip components with dnp field not empty if config.dnp_field and m.ref in extra_data \ and config.dnp_field in extra_data[m.ref] \ @@ -87,15 +87,14 @@ def skip_component(m, config, extra_data, filter_layer): return False -def generate_bom(pcb_modules, config, extra_data, filter_layer=None): - # type: (list, Config, dict, str) -> list +def generate_bom(pcb_modules, config, extra_data): + # type: (list, Config, dict) -> dict """ Generate BOM from pcb layout. :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 - :return: BOM table (qty, value, footprint, refs) + :return: dict of BOM tables (qty, value, footprint, refs) and dnp components """ def convert(text): @@ -114,18 +113,16 @@ def natural_sort(l): # build grouped part list warning_shown = False + skipped_components = [] part_groups = {} for i, m in enumerate(pcb_modules): - if skip_component(m, config, extra_data, filter_layer): + if skip_component(m, config, extra_data): + skipped_components.append(i) continue # group part refs by value and footprint norm_value = units.componentValue(m.val) - # skip virtual components if needed - if config.blacklist_virtual and m.attr == 'Virtual': - continue - extras = [] if config.extra_fields: if m.ref in extra_data: @@ -134,11 +131,9 @@ def natural_sort(l): else: # Some components are on pcb but not in schematic data. # Show a warning about possibly outdated netlist/xml file. - # Doing it only once when generating full bom is enough. - if filter_layer is None: - log.warn( - 'Component %s is missing from schematic data.' % m.ref) - warning_shown = True + log.warn( + 'Component %s is missing from schematic data.' % m.ref) + warning_shown = True extras = [''] * len(config.extra_fields) group_key = (norm_value, tuple(extras), m.footprint, m.attr) @@ -169,7 +164,23 @@ def sort_func(row): config.component_sort_order.append('~') bom_table = sorted(bom_table, key=sort_func) - return bom_table + result = { + 'both': bom_table, + 'skipped': skipped_components + } + + for layer in ['F', 'B']: + filtered_table = [] + for row in bom_table: + filtered_refs = [ref for ref in row[3] + if pcb_modules[ref[1]].layer == layer] + if filtered_refs: + filtered_table.append((len(filtered_refs), row[1], + row[2], filtered_refs, row[4])) + + result[layer] = sorted(filtered_table, key=sort_func) + + return result def open_file(filename): @@ -274,14 +285,10 @@ def main(parser, config, logger): if not pcbdata or not components: logger.error('Parsing failed.') return - pcbdata["bom"]["both"] = generate_bom(components, config, extra_fields) - # build BOM - for layer in ['F', 'B']: - bom_table = generate_bom(components, config, extra_fields, - filter_layer=layer) - pcbdata["bom"][layer] = bom_table + pcbdata["bom"] = generate_bom(components, config, extra_fields) + # build BOM bom_file = generate_file(pcb_file_dir, pcb_file_name, pcbdata, config) if config.open_browser: diff --git a/InteractiveHtmlBom/web/ibom.html b/InteractiveHtmlBom/web/ibom.html index 8772a922..c1233e27 100644 --- a/InteractiveHtmlBom/web/ibom.html +++ b/InteractiveHtmlBom/web/ibom.html @@ -71,6 +71,10 @@ Values +