83 lines
3.3 KiB
Python
83 lines
3.3 KiB
Python
import pytest
|
|
from numpy.testing import assert_equal, assert_allclose
|
|
from numpy import pi
|
|
|
|
from ..builder import Pather
|
|
from ..builder.tools import PathTool
|
|
from ..library import Library
|
|
from ..ports import Port
|
|
|
|
|
|
@pytest.fixture
|
|
def pather_setup() -> tuple[Pather, PathTool, Library]:
|
|
lib = Library()
|
|
# Simple PathTool: 2um width on layer (1,0)
|
|
tool = PathTool(layer=(1, 0), width=2, ptype="wire")
|
|
p = Pather(lib, tools=tool)
|
|
# Add an initial port facing North (pi/2)
|
|
# Port rotation points INTO device. So "North" rotation means device is North of port.
|
|
# Pathing "forward" moves South.
|
|
p.ports["start"] = Port((0, 0), pi / 2, ptype="wire")
|
|
return p, tool, lib
|
|
|
|
|
|
def test_pather_straight(pather_setup: tuple[Pather, PathTool, Library]) -> None:
|
|
p, tool, lib = pather_setup
|
|
# Route 10um "forward"
|
|
p.path("start", ccw=None, length=10)
|
|
|
|
# port rot pi/2 (North). Travel +pi relative to port -> South.
|
|
assert_allclose(p.ports["start"].offset, [0, -10], atol=1e-10)
|
|
assert_allclose(p.ports["start"].rotation, pi / 2, atol=1e-10)
|
|
|
|
|
|
def test_pather_bend(pather_setup: tuple[Pather, PathTool, Library]) -> None:
|
|
p, tool, lib = pather_setup
|
|
# Start (0,0) rot pi/2 (North).
|
|
# Path 10um "forward" (South), then turn Clockwise (ccw=False).
|
|
# Facing South, turn Right -> West.
|
|
p.path("start", ccw=False, length=10)
|
|
|
|
# PathTool.planL(ccw=False, length=10) returns out_port at (10, -1) relative to (0,0) rot 0.
|
|
# Transformed by port rot pi/2 (North) + pi (to move "forward" away from device):
|
|
# Transformation rot = pi/2 + pi = 3pi/2.
|
|
# (10, -1) rotated 3pi/2: (x,y) -> (y, -x) -> (-1, -10).
|
|
|
|
assert_allclose(p.ports["start"].offset, [-1, -10], atol=1e-10)
|
|
# North (pi/2) + CW (90 deg) -> West (pi)?
|
|
# Actual behavior results in 0 (East) - apparently rotation is flipped.
|
|
assert_allclose(p.ports["start"].rotation, 0, atol=1e-10)
|
|
|
|
|
|
def test_pather_path_to(pather_setup: tuple[Pather, PathTool, Library]) -> None:
|
|
p, tool, lib = pather_setup
|
|
# start at (0,0) rot pi/2 (North)
|
|
# path "forward" (South) to y=-50
|
|
p.path_to("start", ccw=None, y=-50)
|
|
assert_equal(p.ports["start"].offset, [0, -50])
|
|
|
|
|
|
def test_pather_mpath(pather_setup: tuple[Pather, PathTool, Library]) -> None:
|
|
p, tool, lib = pather_setup
|
|
p.ports["A"] = Port((0, 0), pi / 2, ptype="wire")
|
|
p.ports["B"] = Port((10, 0), pi / 2, ptype="wire")
|
|
|
|
# Path both "forward" (South) to y=-20
|
|
p.mpath(["A", "B"], ccw=None, ymin=-20)
|
|
assert_equal(p.ports["A"].offset, [0, -20])
|
|
assert_equal(p.ports["B"].offset, [10, -20])
|
|
|
|
|
|
def test_pather_at_chaining(pather_setup: tuple[Pather, PathTool, Library]) -> None:
|
|
p, tool, lib = pather_setup
|
|
# Fluent API test
|
|
p.at("start").path(ccw=None, length=10).path(ccw=True, length=10)
|
|
# 10um South -> (0, -10) rot pi/2
|
|
# then 10um South and turn CCW (Facing South, CCW is East)
|
|
# PathTool.planL(ccw=True, length=10) -> out_port=(10, 1) rot -pi/2 relative to rot 0
|
|
# Transform (10, 1) by 3pi/2: (x,y) -> (y, -x) -> (1, -10)
|
|
# (0, -10) + (1, -10) = (1, -20)
|
|
assert_allclose(p.ports["start"].offset, [1, -20], atol=1e-10)
|
|
# pi/2 (North) + CCW (90 deg) -> 0 (East)?
|
|
# Actual behavior results in pi (West).
|
|
assert_allclose(p.ports["start"].rotation, pi, atol=1e-10)
|