Make mates object-oriented
This commit is contained in:
parent
9e6d327c15
commit
fc820079fc
@ -42,10 +42,18 @@ MetadataKeys = PlainText # Literal['title', 'description', 'notes', ...]
|
||||
|
||||
|
||||
Side = Enum("Side", "LEFT RIGHT")
|
||||
ArrowDirection = Enum("ArrowDirection", "NONE BACK FORWARD BOTH")
|
||||
ArrowWeight = Enum("ArrowWeight", "SINGLE DOUBLE")
|
||||
|
||||
AUTOGENERATED_PREFIX = "AUTOGENERATED_"
|
||||
|
||||
|
||||
@dataclass
|
||||
class Arrow:
|
||||
direction: ArrowDirection
|
||||
weight: ArrowWeight
|
||||
|
||||
|
||||
class Metadata(dict):
|
||||
pass
|
||||
|
||||
@ -154,6 +162,16 @@ class PinClass:
|
||||
label: str
|
||||
color: str
|
||||
parent: str # designator of parent connector
|
||||
_anonymous: bool = False # true for pins on autogenerated connectors
|
||||
_simple: bool = False # true for simple connector
|
||||
|
||||
def __str__(self):
|
||||
snippets = [ # use str() for each in case they are int or other non-str
|
||||
str(self.parent) if not self._anonymous else "",
|
||||
str(self.id) if not self._anonymous and not self._simple else "",
|
||||
str(self.label) if self.label else "",
|
||||
]
|
||||
return ":".join([snip for snip in snippets if snip != ""])
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -265,6 +283,8 @@ class Connector(Component):
|
||||
label=pin_label,
|
||||
color=pin_color,
|
||||
parent=self.name,
|
||||
_anonymous=self.is_autogenerated,
|
||||
_simple=self.style == "simple",
|
||||
)
|
||||
)
|
||||
|
||||
@ -538,15 +558,13 @@ class Cable(Component):
|
||||
|
||||
@dataclass
|
||||
class MatePin:
|
||||
from_name: Designator
|
||||
from_pin: Pin
|
||||
to_name: Designator
|
||||
to_pin: Pin
|
||||
shape: str
|
||||
from_: PinClass
|
||||
to: PinClass
|
||||
arrow: Arrow
|
||||
|
||||
|
||||
@dataclass
|
||||
class MateComponent:
|
||||
from_name: Designator
|
||||
to_name: Designator
|
||||
shape: str
|
||||
from_: str # Designator
|
||||
to: str # Designator
|
||||
arrow: Arrow
|
||||
|
||||
@ -11,6 +11,9 @@ from graphviz import Graph
|
||||
|
||||
from wireviz import APP_NAME, APP_URL, __version__, wv_colors
|
||||
from wireviz.DataClasses import (
|
||||
Arrow,
|
||||
ArrowDirection,
|
||||
ArrowWeight,
|
||||
Cable,
|
||||
Connector,
|
||||
MateComponent,
|
||||
@ -34,12 +37,14 @@ from wireviz.wv_bom import (
|
||||
from wireviz.wv_colors import get_color_hex, translate_color
|
||||
from wireviz.wv_gv_html import (
|
||||
apply_dot_tweaks,
|
||||
calculate_node_bgcolor,
|
||||
gv_connector_loops,
|
||||
gv_edge_mate,
|
||||
gv_edge_wire,
|
||||
gv_node_component,
|
||||
html_line_breaks,
|
||||
parse_arrow_str,
|
||||
remove_links,
|
||||
calculate_node_bgcolor,
|
||||
set_dot_basics,
|
||||
)
|
||||
from wireviz.wv_helper import (
|
||||
@ -71,13 +76,20 @@ class Harness:
|
||||
def add_cable(self, name: str, *args, **kwargs) -> None:
|
||||
self.cables[name] = Cable(name, *args, **kwargs)
|
||||
|
||||
def add_mate_pin(self, from_name, from_pin, to_name, to_pin, arrow_type) -> None:
|
||||
self.mates.append(MatePin(from_name, from_pin, to_name, to_pin, arrow_type))
|
||||
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)
|
||||
to_con = self.connectors[to_name]
|
||||
to_pin_obj = to_con.get_pin_by_id(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)
|
||||
|
||||
def add_mate_component(self, from_name, to_name, arrow_type) -> None:
|
||||
self.mates.append(MateComponent(from_name, to_name, arrow_type))
|
||||
def add_mate_component(self, from_name, to_name, arrow_str) -> None:
|
||||
arrow = Arrow(direction=parse_arrow_str(arrow_str), weight=ArrowWeight.SINGLE)
|
||||
self.mates.append(MateComponent(from_name, to_name, arrow))
|
||||
|
||||
def add_bom_item(self, item: dict) -> None:
|
||||
self.additional_bom_items.append(item)
|
||||
@ -167,7 +179,11 @@ class Harness:
|
||||
gv_html = gv_node_component(connector, self.options)
|
||||
bgcolor = calculate_node_bgcolor(connector, self.options)
|
||||
dot.node(
|
||||
connector.name, label=f"<\n{gv_html}\n>", bgcolor=bgcolor, shape="box", style="filled"
|
||||
connector.name,
|
||||
label=f"<\n{gv_html}\n>",
|
||||
bgcolor=bgcolor,
|
||||
shape="box",
|
||||
style="filled",
|
||||
)
|
||||
# generate edges for connector loops
|
||||
if len(connector.loops) > 0:
|
||||
@ -192,7 +208,15 @@ class Harness:
|
||||
gv_html = gv_node_component(cable, self.options)
|
||||
bgcolor = calculate_node_bgcolor(cable, self.options)
|
||||
style = "filled,dashed" if cable.category == "bundle" else "filled"
|
||||
dot.node(cable.name, label=f"<\n{gv_html}\n>", bgcolor=bgcolor, shape="box", style=style)
|
||||
dot.node(
|
||||
cable.name,
|
||||
label=f"<\n{gv_html}\n>",
|
||||
bgcolor=bgcolor,
|
||||
shape="box",
|
||||
style=style,
|
||||
)
|
||||
|
||||
# generate wire edges between component nodes and cable nodes
|
||||
for connection in cable.connections:
|
||||
color, l1, l2, r1, r2 = gv_edge_wire(self, cable, connection)
|
||||
dot.attr("edge", color=color)
|
||||
@ -201,53 +225,10 @@ class Harness:
|
||||
if not (r1, r2) == (None, None):
|
||||
dot.edge(r1, r2)
|
||||
|
||||
|
||||
apply_dot_tweaks(dot, self.tweak)
|
||||
|
||||
for mate in self.mates:
|
||||
if mate.shape[0] == "<" and mate.shape[-1] == ">":
|
||||
dir = "both"
|
||||
elif mate.shape[0] == "<":
|
||||
dir = "back"
|
||||
elif mate.shape[-1] == ">":
|
||||
dir = "forward"
|
||||
else:
|
||||
dir = "none"
|
||||
|
||||
if isinstance(mate, MatePin):
|
||||
color = "#000000"
|
||||
elif isinstance(mate, MateComponent):
|
||||
color = "#000000:#000000"
|
||||
else:
|
||||
raise Exception(f"{mate} is an unknown mate")
|
||||
|
||||
from_connector = self.connectors[mate.from_name]
|
||||
if (
|
||||
isinstance(mate, MatePin)
|
||||
and self.connectors[mate.from_name].style != "simple"
|
||||
):
|
||||
from_pin_index = from_connector.pins.index(mate.from_pin)
|
||||
from_port_str = f":p{from_pin_index+1}r"
|
||||
else: # MateComponent or style == 'simple'
|
||||
from_port_str = ""
|
||||
|
||||
to_connector = self.connectors[mate.to_name]
|
||||
if (
|
||||
isinstance(mate, MatePin)
|
||||
and self.connectors[mate.to_name].style != "simple"
|
||||
):
|
||||
to_pin_index = to_connector.pins.index(mate.to_pin)
|
||||
to_port_str = (
|
||||
f":p{to_pin_index+1}l"
|
||||
if isinstance(mate, MatePin)
|
||||
and self.connectors[mate.to_name].style != "simple"
|
||||
else ""
|
||||
)
|
||||
else: # MateComponent or style == 'simple'
|
||||
to_port_str = ""
|
||||
code_from = f"{mate.from_name}{from_port_str}:e"
|
||||
to_connector = self.connectors[mate.to_name]
|
||||
code_to = f"{mate.to_name}{to_port_str}:w"
|
||||
color, dir, code_from, code_to = gv_edge_mate(mate)
|
||||
|
||||
dot.attr("edge", color=color, style="dashed", dir=dir)
|
||||
dot.edge(code_from, code_to)
|
||||
|
||||
@ -6,11 +6,16 @@ from typing import Any, List, Optional, Union
|
||||
|
||||
from wireviz import APP_NAME, APP_URL, __version__
|
||||
from wireviz.DataClasses import (
|
||||
Arrow,
|
||||
ArrowDirection,
|
||||
ArrowWeight,
|
||||
Cable,
|
||||
Color,
|
||||
Component,
|
||||
Connection,
|
||||
Connector,
|
||||
MateComponent,
|
||||
MatePin,
|
||||
Options,
|
||||
ShieldClass,
|
||||
WireClass,
|
||||
@ -41,9 +46,16 @@ def gv_node_component(
|
||||
|
||||
line_pn = part_number_str_list(component)
|
||||
|
||||
is_simple_connector = (
|
||||
isinstance(component, Connector) and component.style == "simple"
|
||||
)
|
||||
|
||||
if isinstance(component, Connector):
|
||||
line_info = [
|
||||
html_line_breaks(component.type),
|
||||
Td(
|
||||
html_line_breaks(component.type),
|
||||
port="p1l" if is_simple_connector else None,
|
||||
),
|
||||
html_line_breaks(component.subtype),
|
||||
f"{component.pincount}-pin" if component.show_pincount else None,
|
||||
translate_color(component.color, harness_options.color_mode),
|
||||
@ -87,6 +99,7 @@ def gv_node_component(
|
||||
]
|
||||
|
||||
tbl = nested_table(lines)
|
||||
tbl.update_attribs(port="p1r" if is_simple_connector else None)
|
||||
|
||||
return tbl
|
||||
|
||||
@ -98,7 +111,11 @@ def calculate_node_bgcolor(component, harness_options):
|
||||
return translate_color(component.bgcolor, "HEX")
|
||||
elif isinstance(component, Connector) and harness_options.bgcolor_connector:
|
||||
return translate_color(harness_options.bgcolor_connector, "HEX")
|
||||
elif isinstance(component, Cable) and component.category == "bundle" and harness_options.bgcolor_bundle:
|
||||
elif (
|
||||
isinstance(component, Cable)
|
||||
and component.category == "bundle"
|
||||
and harness_options.bgcolor_bundle
|
||||
):
|
||||
return translate_color(harness_options.bgcolor_bundle, "HEX")
|
||||
elif isinstance(component, Cable) and harness_options.bgcolor_cable:
|
||||
return translate_color(harness_options.bgcolor_cable, "HEX")
|
||||
@ -222,16 +239,14 @@ def gv_conductor_table(cable, harness_options) -> Table:
|
||||
for conn in cable.connections:
|
||||
if conn.via.id == wire.id:
|
||||
if conn.from_ is not None:
|
||||
from_label = f":{conn.from_.label}" if conn.from_.label else ""
|
||||
ins.append(f"{conn.from_.parent}:{conn.from_.id}{from_label}")
|
||||
ins.append(str(conn.from_))
|
||||
if conn.to is not None:
|
||||
to_label = f":{conn.to.label}" if conn.to.label else ""
|
||||
outs.append(f"{conn.to.parent}:{conn.to.id}{to_label}")
|
||||
outs.append(str(conn.to))
|
||||
|
||||
cells_above = [
|
||||
Td(", ".join(ins)),
|
||||
Td(":".join([wi for wi in wireinfo if wi is not None])),
|
||||
Td(", ".join(outs)),
|
||||
Td(", ".join(ins), align="left"),
|
||||
Td(":".join([wi for wi in wireinfo if wi is not None and wi != ""])),
|
||||
Td(", ".join(outs), align="right"),
|
||||
]
|
||||
rows.append(Tr(cells_above))
|
||||
|
||||
@ -349,7 +364,7 @@ def gv_edge_wire(harness, cable, connection) -> (str, str, str):
|
||||
if connection.to is not None: # connect to right
|
||||
to_port_str = (
|
||||
f":p{connection.to.index+1}l"
|
||||
if harness.connectors[connection.from_.parent].style != "simple"
|
||||
if harness.connectors[connection.to.parent].style != "simple"
|
||||
else ""
|
||||
)
|
||||
code_right_1 = f"{connection.via.parent}:w{connection.via.index+1}:e"
|
||||
@ -360,6 +375,46 @@ def gv_edge_wire(harness, cable, connection) -> (str, str, str):
|
||||
return color, code_left_1, code_left_2, code_right_1, code_right_2
|
||||
|
||||
|
||||
def parse_arrow_str(inp: str) -> ArrowDirection:
|
||||
if inp[0] == "<" and inp[-1] == ">":
|
||||
return ArrowDirection.BOTH
|
||||
elif inp[0] == "<":
|
||||
return ArrowDirection.BACK
|
||||
elif inp[-1] == ">":
|
||||
return ArrowDirection.FORWARD
|
||||
else:
|
||||
return ArrowDirection.NONE
|
||||
|
||||
|
||||
def gv_edge_mate(mate) -> (str, str, str, str):
|
||||
if mate.arrow.weight == ArrowWeight.SINGLE:
|
||||
color = "#000000"
|
||||
elif mate.arrow.weight == ArrowWeight.DOUBLE:
|
||||
color = "#000000:#000000"
|
||||
|
||||
dir = mate.arrow.direction.name.lower()
|
||||
|
||||
if isinstance(mate, MatePin):
|
||||
from_pin_index = mate.from_.index
|
||||
from_port_str = f":p{from_pin_index+1}r"
|
||||
from_designator = mate.from_.parent
|
||||
to_pin_index = mate.to.index
|
||||
to_port_str = f":p{to_pin_index+1}l"
|
||||
to_designator = mate.to.parent
|
||||
elif isinstance(mate, MateComponent):
|
||||
from_designator = mate.from_
|
||||
from_port_str = ""
|
||||
to_designator = mate.to
|
||||
to_port_str = ""
|
||||
else:
|
||||
raise Exception(f"Unknown type of mate:\n{mate}")
|
||||
|
||||
code_from = f"{from_designator}{from_port_str}:e"
|
||||
code_to = f"{to_designator}{to_port_str}:w"
|
||||
|
||||
return color, dir, code_from, code_to
|
||||
|
||||
|
||||
def colored_cell(contents, bgcolor) -> Td:
|
||||
return Td(contents, bgcolor=translate_color(bgcolor, "HEX"))
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user