[Pather / planner / ports] improve trace_into connection accuracy

This commit is contained in:
Jan Petykiewicz 2026-07-16 08:35:46 -07:00
commit 2b6782c93e
4 changed files with 35 additions and 8 deletions

View file

@ -32,7 +32,6 @@ from __future__ import annotations
from collections.abc import Iterable, Mapping, Sequence
from dataclasses import dataclass, replace
from itertools import combinations
from math import cos, sin
from typing import Any, Literal
import numpy
@ -41,7 +40,7 @@ from numpy.typing import ArrayLike
from ...error import BuildError, PortError
from ...ports import Port
from ...utils import PTypeMatch, SupportsBool, ptype_match, ptypes_compatible
from ...utils import PTypeMatch, SupportsBool, ptype_match, ptypes_compatible, rotation_matrix_2d
from ..tools import (
BendOffer,
PrimitiveKind,
@ -579,10 +578,11 @@ class Solver:
out_port = step.out_port
if out_port.rotation is None:
raise ToolContractError('Primitive endpoints must have rotation')
angle_cos = cos(angle)
angle_sin = sin(angle)
x += angle_cos * float(out_port.x) - angle_sin * float(out_port.y)
y += angle_sin * float(out_port.x) + angle_cos * float(out_port.y)
rotation = rotation_matrix_2d(angle)
out_x = float(out_port.x)
out_y = float(out_port.y)
x += rotation[0, 0] * out_x + rotation[0, 1] * out_y
y += rotation[1, 0] * out_x + rotation[1, 1] * out_y
angle += out_port.rotation + pi
ptype = out_port.ptype
return Port((x, y), rotation=angle - pi, ptype=ptype)

View file

@ -574,10 +574,10 @@ class PortList(metaclass=ABCMeta):
raise PortError(msg)
translations = a_offsets - b_offsets
if not numpy.allclose(translations, 0):
if not numpy.allclose(a_offsets, b_offsets):
msg = 'Port translations do not match:\n'
for nn, (kk, vv) in enumerate(connections.items()):
if not numpy.allclose(translations[nn], 0):
if not numpy.allclose(a_offsets[nn], b_offsets[nn]):
msg += f'{kk} | {translations[nn]} | {vv}\n'
raise PortError(msg)

View file

@ -113,6 +113,22 @@ def test_pather_trace_into_shapes() -> None:
assert numpy.isclose(p.pattern.ports['I'].rotation, pi / 2)
def test_pather_trace_into_large_composed_manhattan_route_plugs() -> None:
p = Pather(
Library(),
tools=PathTool(layer='M1', width=1000, ptype='wire'),
render='deferred',
)
p.ports['src'] = Port((123.25, 456.75), rotation=0, ptype='wire')
p.ports['dst'] = Port((-99_999_876.75, 20_000_456.75), rotation=0, ptype='wire')
p.trace_into('src', 'dst')
assert 'src' not in p.ports
assert 'dst' not in p.ports
assert [step.kind for step in p._paths['src']] == ['straight', 'bend', 'straight', 'bend', 'plug']
def test_pather_trace_into_refines_output_adapter_route_before_plug() -> None:
class TransitionTool(Tool):
def primitive_offers(

View file

@ -169,6 +169,17 @@ def test_port_list_plugged() -> None:
assert not pl.ports # Both should be removed
def test_port_list_plugged_uses_coordinate_relative_tolerance() -> None:
pattern = Pattern(ports={
"A": Port((10, 10), 0),
"B": Port((10 + 5e-8, 10), pi),
})
pattern.plugged({"A": "B"})
assert not pattern.ports
def test_port_list_plugged_ptype_compatibility_warnings(caplog: pytest.LogCaptureFixture) -> None:
caplog.set_level("WARNING", logger="masque.ports")