From b15658b9264f88ad58146cc4e1f1a74cfdd295ca Mon Sep 17 00:00:00 2001 From: Daniel Rojas Date: Mon, 25 Oct 2021 20:04:24 +0200 Subject: [PATCH] Implement BOM bubbles --- src/wireviz/wireviz.py | 4 +-- src/wireviz/wv_dataclasses.py | 4 +++ src/wireviz/wv_graphviz.py | 26 +++++++++++++----- src/wireviz/wv_harness.py | 50 ++++++++++++++++++++++++++++------- 4 files changed, 66 insertions(+), 18 deletions(-) diff --git a/src/wireviz/wireviz.py b/src/wireviz/wireviz.py index 12314f1..e1bd72f 100755 --- a/src/wireviz/wireviz.py +++ b/src/wireviz/wireviz.py @@ -364,12 +364,12 @@ def parse( # mate two connectors as a whole harness.add_mate_component(from_name, to_name, designator) - # harness population completed ============================================= - if "additional_bom_items" in yaml_data: for line in yaml_data["additional_bom_items"]: harness.add_additional_bom_item(line) + # harness population completed ============================================= + harness.populate_bom() if output_formats: diff --git a/src/wireviz/wv_dataclasses.py b/src/wireviz/wv_dataclasses.py index 7951bbb..00c97f6 100644 --- a/src/wireviz/wv_dataclasses.py +++ b/src/wireviz/wv_dataclasses.py @@ -479,11 +479,14 @@ class WireClass: id: str label: str color: MultiColor + # ... + bom_id: Optional[str] = None # to be filled after harness is built # inheritable from parent cable type: Union[MultilineHypertext, List[MultilineHypertext]] = None subtype: Union[MultilineHypertext, List[MultilineHypertext]] = None gauge: Optional[NumberAndUnit] = None length: Optional[NumberAndUnit] = None + ignore_in_bom: Optional[bool] = False sum_amounts_in_bom: bool = True partnumbers: PartNumberInfo = None @@ -700,6 +703,7 @@ class Cable(TopLevelGraphicalComponent): gauge=self.gauge, length=self.length, sum_amounts_in_bom=self.sum_amounts_in_bom, + ignore_in_bom=self.ignore_in_bom # TODO partnumbers ) diff --git a/src/wireviz/wv_graphviz.py b/src/wireviz/wv_graphviz.py index a6f191d..b0d3a5a 100644 --- a/src/wireviz/wv_graphviz.py +++ b/src/wireviz/wv_graphviz.py @@ -44,6 +44,7 @@ def gv_node_component(component: Component) -> Table: if isinstance(component, Connector): line_info = [ + bom_bubble(component.bom_id), html_line_breaks(component.type), html_line_breaks(component.subtype), f"{component.pincount}-pin" if component.show_pincount else None, @@ -52,6 +53,7 @@ def gv_node_component(component: Component) -> Table: ] elif isinstance(component, Cable): line_info = [ + bom_bubble(component.bom_id) if component.category != "bundle" else None, html_line_breaks(component.type), f"{component.wirecount}x" if component.show_wirecount else None, component.gauge_str_with_equiv, @@ -135,6 +137,15 @@ def calculate_node_bgcolor(component, harness_options): return harness_options.bgcolor_cable.html +def bom_bubble(id) -> Table: + if id is None: + return None + else: + return Table( + Tr(Td(f" {id} ", border=0, cellpadding=0)), border=1, style="rounded" + ) + + def make_list_of_cells(inp) -> List[Td]: # inp may be List, if isinstance(inp, List): @@ -252,14 +263,17 @@ def gv_conductor_table(cable) -> Table: outs.append(str(conn.to)) cells_above = [ - Td(", ".join(ins), align="left"), + Td(" " + ", ".join(ins), align="left"), + # Td(":-)"), + Td(bom_bubble(wire.bom_id)) if cable.category == "bundle" else None, Td(":".join([wi for wi in wireinfo if wi is not None and wi != ""])), - Td(", ".join(outs), align="right"), + Td(", ".join(outs) + " ", align="right"), ] + cells_above = [cell for cell in cells_above if cell is not None] rows.append(Tr(cells_above)) # the wire itself - rows.append(Tr(gv_wire_cell(wire))) + rows.append(Tr(gv_wire_cell(wire, len(cells_above)))) # row below the wire # TODO: PN stuff for bundles @@ -270,7 +284,7 @@ def gv_conductor_table(cable) -> Table: return tbl -def gv_wire_cell(wire: Union[WireClass, ShieldClass]) -> Td: +def gv_wire_cell(wire: Union[WireClass, ShieldClass], colspan: int) -> Td: if wire.color: color_list = ["#000000"] + wire.color.html_padded_list + ["#000000"] else: @@ -282,7 +296,7 @@ def gv_wire_cell(wire: Union[WireClass, ShieldClass]) -> Td: "bgcolor": bgcolor if bgcolor != "" else "#000000", "border": 0, "cellpadding": 0, - "colspan": 3, + "colspan": colspan, "height": 2, } wire_inner_rows.append(Tr(Td("", **wire_inner_cell_attribs))) @@ -291,7 +305,7 @@ def gv_wire_cell(wire: Union[WireClass, ShieldClass]) -> Td: "border": 0, "cellspacing": 0, "cellpadding": 0, - "colspan": 3, + "colspan": colspan, "height": 2 * len(color_list), "port": f"w{wire.index+1}", } diff --git a/src/wireviz/wv_harness.py b/src/wireviz/wv_harness.py index 1f45ae0..15b4580 100644 --- a/src/wireviz/wv_harness.py +++ b/src/wireviz/wv_harness.py @@ -8,7 +8,7 @@ from typing import List from graphviz import Graph import wireviz.wv_colors -from wireviz.wv_bom import BomEntry, print_bom_debug, BomCategory +from wireviz.wv_bom import BomCategory, BomEntry, print_bom_debug from wireviz.wv_dataclasses import ( AUTOGENERATED_PREFIX, AdditionalComponent, @@ -83,24 +83,54 @@ class Harness: self.mates.append(MateComponent(from_name, to_name, arrow)) def populate_bom(self): - for item in self.connectors.values(): - self._add_to_internal_bom(item) - for item in self.cables.values(): - self._add_to_internal_bom(item) - for item in self.additional_bom_items: - self._add_to_internal_bom(item) - + # helper lists + all_toplevel_items = ( + list(self.connectors.values()) + + list(self.cables.values()) + + self.additional_bom_items + ) + all_subitems = [ + subitem + for item in all_toplevel_items + for subitem in item.additional_components + ] + all_bom_relevant_items = ( + list(self.connectors.values()) + + [cable for cable in self.cables.values() if cable.category != "bundle"] + + [ + wire + for cable in self.cables.values() + if cable.category == "bundle" + for wire in cable.wire_objects.values() + ] + + all_subitems + ) + # add items to BOM + for item in all_toplevel_items: + self._add_to_internal_bom(item) # nested subitems are also handled # sort BOM by category first, then alphabetically by description within category self.bom = dict( sorted( self.bom.items(), - key=lambda x: (x[1]["category"], x[0].description) + key=lambda x: ( + x[1]["category"], + x[0].description, + ), # x[0] = key, x[1] = value ) ) - # assign BOM IDs for id, key in enumerate(self.bom.keys(), 1): self.bom[key]["id"] = id + # set BOM IDs within components (for BOM bubbles) + for item in all_bom_relevant_items: + if item.ignore_in_bom: + continue + if not item.bom_hash in self.bom: + print(f"{item}'s hash' not found in BOM dict.") + continue + item.bom_id = self.bom[item.bom_hash]["id"] + + # import pudb; pudb.set_trace() print_bom_debug(self.bom)