diff --git a/src/wireviz/wv_dataclasses.py b/src/wireviz/wv_dataclasses.py index 46bca0f..bad04fb 100644 --- a/src/wireviz/wv_dataclasses.py +++ b/src/wireviz/wv_dataclasses.py @@ -4,7 +4,7 @@ from collections import namedtuple from dataclasses import dataclass, field from enum import Enum from itertools import zip_longest -from typing import Dict, List, Optional, Tuple, Union +from typing import Any, Dict, List, Optional, Tuple, Union from wireviz.wv_bom import ( BomHash, @@ -273,7 +273,9 @@ class AdditionalComponent(Component): self.qty = self.parse_number_and_unit(self.qty, None) self.amount = self.parse_number_and_unit(self.amount, None) - if isinstance(self.qty_multiplier, float) or isinstance(self.qty_multiplier, int): + if isinstance(self.qty_multiplier, float) or isinstance( + self.qty_multiplier, int + ): pass else: self.qty_multiplier = self.qty_multiplier.upper() @@ -325,9 +327,7 @@ class Connector(TopLevelGraphicalComponent): pins: List[Pin] = field(default_factory=list) # legacy pinlabels: List[Pin] = field(default_factory=list) # legacy pincolors: List[str] = field(default_factory=list) # legacy - pin_objects: List[PinClass] = field( - default_factory=list - ) # new, to replace the lists above + pin_objects: Dict[Any, PinClass] = field(default_factory=dict) # new # rendering option show_pincount: Optional[bool] = None hide_disconnected_pins: bool = False @@ -347,8 +347,11 @@ class Connector(TopLevelGraphicalComponent): ] return ", ".join([str(s) for s in substrs if s is not None and s != ""]) - def should_show_pin(self, pin_name): - return not self.hide_disconnected_pins or self.visible_pins.get(pin_name, False) + def should_show_pin(self, pin_id): + return ( + not self.hide_disconnected_pins + or self.pin_objects[pin_id]._num_connections > 0 + ) @property def unit(self): # for compatibility with BOM hashing @@ -404,16 +407,14 @@ class Connector(TopLevelGraphicalComponent): self.pincolors, ) for pin_index, (pin_id, pin_label, pin_color) in enumerate(pin_tuples): - self.pin_objects.append( - PinClass( - index=pin_index, - id=pin_id, - label=pin_label, - color=MultiColor(pin_color), - parent=self.designator, - _anonymous=self.is_autogenerated, - _simple=self.style == "simple", - ) + self.pin_objects[pin_id] = PinClass( + index=pin_index, + id=pin_id, + label=pin_label, + color=MultiColor(pin_color), + parent=self.designator, + _anonymous=self.is_autogenerated, + _simple=self.style == "simple", ) if self.show_name is None: @@ -433,27 +434,16 @@ class Connector(TopLevelGraphicalComponent): if pin not in self.pins: raise Exception(f'Unknown loop pin "{pin}" for connector "{self.name}"!') # Make sure loop connected pins are not hidden. - self.activate_pin(pin) + # side=None, determine side to show loops during rendering + self.activate_pin(pin, side=None, is_connection=True) for i, item in enumerate(self.additional_components): if isinstance(item, dict): self.additional_components[i] = AdditionalComponent(**item) - def _check_if_unique_id(self, id): - results = [pin for pin in self.pin_objects if pin.id == id] - if len(results) == 0: - raise Exception(f"Pin ID {id} not found in {self.designator}") - if len(results) > 1: - raise Exception(f"Pin ID {id} found more than once in {self.designator}") - return True - - def get_pin_by_id(self, id): - if self._check_if_unique_id(id): - pin = [pin for pin in self.pin_objects if pin.id == id] - return pin[0] - - def activate_pin(self, pin: Pin, side: Side) -> None: - self.visible_pins[pin] = True + def activate_pin(self, pin_id, side: Side = None, is_connection=True) -> None: + if is_connection: + self.pin_objects[pin_id]._num_connections += 1 if side == Side.LEFT: self.ports_left = True elif side == Side.RIGHT: @@ -473,6 +463,7 @@ class Connector(TopLevelGraphicalComponent): # QtyMultiplierCable = Enum( # "QtyMultiplierCable", "ONE WIRECOUNT TERMINATION LENGTH TOTAL_LENGTH" # ) + # def get_qty_multiplier(self, qty_multiplier: Optional[ConnectorMultiplier]) -> int: # # TODO!!! how and when to compute final qty for additional components??? # if not qty_multiplier: @@ -565,9 +556,7 @@ class Cable(TopLevelGraphicalComponent): shield: Union[bool, MultiColor] = False colors: List[str] = field(default_factory=list) # legacy wirelabels: List[Wire] = field(default_factory=list) # legacy - wire_objects: List[WireClass] = field( - default_factory=list - ) # to replace the lists above + wire_objects: Dict[Any, WireClass] = field(default_factory=dict) # new # internal _connections: List[Connection] = field(default_factory=list) # rendering options @@ -704,37 +693,35 @@ class Cable(TopLevelGraphicalComponent): self.wirelabels, ) for wire_index, (wire_color, wire_label) in enumerate(wire_tuples): - self.wire_objects.append( - WireClass( - parent=self.designator, - # wire-specific properties - index=wire_index, # TODO: wire_id - id=wire_index + 1, # TODO: wire_id - label=wire_label, - color=MultiColor(wire_color), - # inheritable from parent cable - type=self.type, - subtype=self.subtype, - gauge=self.gauge, - length=self.length, - sum_amounts_in_bom=self.sum_amounts_in_bom, - # TODO partnumbers - ) + id = wire_index + 1 + self.wire_objects[id] = WireClass( + parent=self.designator, + # wire-specific properties + index=wire_index, # TODO: wire_id + id=id, # TODO: wire_id + label=wire_label, + color=MultiColor(wire_color), + # inheritable from parent cable + type=self.type, + subtype=self.subtype, + gauge=self.gauge, + length=self.length, + sum_amounts_in_bom=self.sum_amounts_in_bom, + # TODO partnumbers ) if self.shield: index_offset = len(self.wire_objects) # TODO: add support for multiple shields - self.wire_objects.append( - ShieldClass( - index=index_offset, - id="s", - label="Shield", - color=MultiColor(self.shield) - if isinstance(self.shield, str) - else MultiColor(None), - parent=self.designator, - ) + id = "s" + self.wire_objects[id] = ShieldClass( + index=index_offset, + id=id, + label="Shield", + color=MultiColor(self.shield) + if isinstance(self.shield, str) + else MultiColor(None), + parent=self.designator, ) if self.show_name is None: @@ -748,24 +735,15 @@ class Cable(TopLevelGraphicalComponent): if isinstance(item, dict): self.additional_components[i] = AdditionalComponent(**item) - def get_wire_by_id(self, id): - wire = [wire for wire in self.wire_objects if wire.id == id] - if len(wire) == 0: - raise Exception(f"Wire ID {id} not found in {self.designator}") - if len(wire) > 1: - raise Exception(f"Wire ID {id} found more than once in {self.designator}") - return wire[0] - def _connect( self, from_pin_obj: [PinClass], via_wire_id: str, to_pin_obj: [PinClass], ) -> None: - via_wire_obj = self.get_wire_by_id(via_wire_id) + via_wire_obj = self.wire_objects[via_wire_id] self._connections.append(Connection(from_pin_obj, via_wire_obj, to_pin_obj)) - # def get_qty_multiplier(self, qty_multiplier: Optional[CableMultiplier]) -> float: # if not qty_multiplier: # return 1 diff --git a/src/wireviz/wv_graphviz.py b/src/wireviz/wv_graphviz.py index 2dcb716..e9b1af8 100644 --- a/src/wireviz/wv_graphviz.py +++ b/src/wireviz/wv_graphviz.py @@ -166,8 +166,8 @@ def nested_table(lines: List[Td]) -> Table: def gv_pin_table(component) -> Table: pin_rows = [] - for pin in component.pin_objects: - if component.should_show_pin(pin.id): # TODO remove True + for pin in component.pin_objects.values(): + if component.should_show_pin(pin.id): pin_rows.append(gv_pin_row(pin, component)) tbl = Table(pin_rows, border=0, cellborder=1, cellpadding=3, cellspacing=0) return tbl @@ -211,7 +211,7 @@ def gv_conductor_table(cable) -> Table: rows.append(Tr(Td(" "))) # spacer row on top inserted_break_inbetween = False - for wire in cable.wire_objects: + for wire in cable.wire_objects.values(): # insert blank space between wires and shields if isinstance(wire, ShieldClass) and not inserted_break_inbetween: diff --git a/src/wireviz/wv_harness.py b/src/wireviz/wv_harness.py index 0ea732a..707d8ba 100644 --- a/src/wireviz/wv_harness.py +++ b/src/wireviz/wv_harness.py @@ -67,14 +67,16 @@ class Harness: def add_mate_pin(self, from_name, from_pin, to_name, to_pin, arrow_str) -> None: from_con = self.connectors[from_name] - from_pin_obj = from_con.get_pin_by_id(from_pin) + from_pin_obj = from_con.pin_objects[from_pin] to_con = self.connectors[to_name] - to_pin_obj = to_con.get_pin_by_id(to_pin) + to_pin_obj = to_con.pin_objects[to_pin] arrow = Arrow(direction=parse_arrow_str(arrow_str), weight=ArrowWeight.SINGLE) self.mates.append(MatePin(from_pin_obj, to_pin_obj, arrow)) - self.connectors[from_name].activate_pin(from_pin, Side.RIGHT) - self.connectors[to_name].activate_pin(to_pin, Side.LEFT) + self.connectors[from_name].activate_pin( + from_pin, Side.RIGHT, is_connection=False + ) + self.connectors[to_name].activate_pin(to_pin, Side.LEFT, is_connection=False) def add_mate_component(self, from_name, to_name, arrow_str) -> None: arrow = Arrow(direction=parse_arrow_str(arrow_str), weight=ArrowWeight.SINGLE) @@ -126,7 +128,7 @@ class Harness: cat = "" if item.category == "bundle": - for subitem in item.wire_objects: + for subitem in item.wire_objects.values(): _add( hash=subitem.bom_hash, qty=item.bom_qty, # should be 1 @@ -225,12 +227,12 @@ class Harness: # perform the actual connection if from_name is not None: from_con = self.connectors[from_name] - from_pin_obj = from_con.get_pin_by_id(from_pin) + from_pin_obj = from_con.pin_objects[from_pin] else: from_pin_obj = None if to_name is not None: to_con = self.connectors[to_name] - to_pin_obj = to_con.get_pin_by_id(to_pin) + to_pin_obj = to_con.pin_objects[to_pin] else: to_pin_obj = None @@ -267,7 +269,7 @@ class Harness: wire_is_multicolor = [ len(wire.color) > 1 for cable in self.cables.values() - for wire in cable.wire_objects + for wire in cable.wire_objects.values() ] if any(wire_is_multicolor): wireviz.wv_colors.padding_amount = 3