Ports the foundational board classes: Unit (mil/inch/mm/um with micrometer scaling), Layer/LayerStructure (the layer stack with name and signal-layer lookups), CoordinateTransform (DSN<->board scaling by the resolution), Net/Nets (connectivity keyed by (name, subnet) and a board- unique net number), and ClearanceMatrix (class x class spacing with a reserved null class and a default class). The per-layer axis of ClearanceMatrix is simplified to a single value per class pair (DSN default clearance rules are layer-independent for the boards we build); the router phase can add the layer dimension. Unit-tested: unit scaling/parsing, layer lookups, transform round-trip, net registration/lookup, and clearance default/append/symmetry.
60 lines
1.6 KiB
Python
60 lines
1.6 KiB
Python
"""``Layer`` and ``LayerStructure`` — the board's layer stack.
|
|
|
|
Ports ``board/Layer.java`` and ``board/LayerStructure.java``. Layer index 0 is
|
|
the component (top) side; ``is_signal`` marks routable copper layers (as opposed
|
|
to power/ground planes).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
|
|
__all__ = ["Layer", "LayerStructure"]
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Layer:
|
|
"""A single board layer."""
|
|
|
|
name: str
|
|
is_signal: bool = True
|
|
|
|
def __str__(self) -> str:
|
|
return self.name
|
|
|
|
|
|
class LayerStructure:
|
|
"""The ordered layer stack, with name/index lookups."""
|
|
|
|
__slots__ = ("arr",)
|
|
|
|
def __init__(self, layers: list[Layer]) -> None:
|
|
self.arr: list[Layer] = list(layers)
|
|
|
|
def __len__(self) -> int:
|
|
return len(self.arr)
|
|
|
|
def get_no(self, layer_or_name) -> int:
|
|
"""Index of a layer (by :class:`Layer` or by name), or -1."""
|
|
if isinstance(layer_or_name, Layer):
|
|
for i, layer in enumerate(self.arr):
|
|
if layer is layer_or_name or layer == layer_or_name:
|
|
return i
|
|
return -1
|
|
for i, layer in enumerate(self.arr):
|
|
if layer.name == layer_or_name:
|
|
return i
|
|
return -1
|
|
|
|
def signal_layer_count(self) -> int:
|
|
return sum(1 for layer in self.arr if layer.is_signal)
|
|
|
|
def get_signal_layer(self, no: int) -> Layer:
|
|
found = 0
|
|
for layer in self.arr:
|
|
if layer.is_signal:
|
|
if found == no:
|
|
return layer
|
|
found += 1
|
|
return self.arr[-1]
|