"""In-memory routing result — the input the SES writer serializes. The maze router (a later stage) populates a :class:`RoutingResult`; the SES writer turns it into the ``(routes (network_out ...))`` scope. Coordinates and widths are in DSN units (the same units the DSN was parsed in); the writer rounds them to integers, matching FreeRouting's ``SesWriter`` which emits integer session coordinates. """ from __future__ import annotations from dataclasses import dataclass, field __all__ = ["RoutedWire", "RoutedVia", "RoutedNet", "RoutingResult"] @dataclass class RoutedWire: """A routed trace segment on one layer. ``coords`` is a flat ``[x1, y1, x2, y2, ...]`` list (DSN units); ``width`` is the full trace width (DSN units). ``fixed`` maps to an emitted ``(type fix)`` marker when set. """ layer: str width: float coords: list[float] fixed: bool = False @dataclass class RoutedVia: """A routed via at ``(x, y)`` (DSN units) using a named padstack.""" padstack: str x: float y: float fixed: bool = False @dataclass class RoutedNet: """The routed wires and vias belonging to one net.""" name: str wires: list[RoutedWire] = field(default_factory=list) vias: list[RoutedVia] = field(default_factory=list) @property def has_items(self) -> bool: return bool(self.wires or self.vias) @dataclass class RoutingResult: """The complete routing output for a board, grouped by net.""" nets: list[RoutedNet] = field(default_factory=list) #: connections the router could not make: (net name, one end, other end, #: the zone both ends sit in or "") -- a zone's fill may join the latter unrouted: list[tuple[str, str, str, str]] = field(default_factory=list) def net(self, name: str, *, create: bool = False) -> RoutedNet | None: """Return the :class:`RoutedNet` with ``name`` (creating it if asked).""" for n in self.nets: if n.name == name: return n if create: n = RoutedNet(name=name) self.nets.append(n) return n return None def add_wire(self, net_name: str, wire: RoutedWire) -> None: self.net(net_name, create=True).wires.append(wire) def add_via(self, net_name: str, via: RoutedVia) -> None: self.net(net_name, create=True).vias.append(via) def routed_nets(self) -> list[RoutedNet]: """Nets that actually carry routed geometry (in insertion order).""" return [n for n in self.nets if n.has_items]