[Pather / planner / ports] improve trace_into connection accuracy
This commit is contained in:
parent
e397b3f96e
commit
2b6782c93e
4 changed files with 35 additions and 8 deletions
|
|
@ -32,7 +32,6 @@ from __future__ import annotations
|
||||||
from collections.abc import Iterable, Mapping, Sequence
|
from collections.abc import Iterable, Mapping, Sequence
|
||||||
from dataclasses import dataclass, replace
|
from dataclasses import dataclass, replace
|
||||||
from itertools import combinations
|
from itertools import combinations
|
||||||
from math import cos, sin
|
|
||||||
from typing import Any, Literal
|
from typing import Any, Literal
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
|
|
@ -41,7 +40,7 @@ from numpy.typing import ArrayLike
|
||||||
|
|
||||||
from ...error import BuildError, PortError
|
from ...error import BuildError, PortError
|
||||||
from ...ports import Port
|
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 (
|
from ..tools import (
|
||||||
BendOffer,
|
BendOffer,
|
||||||
PrimitiveKind,
|
PrimitiveKind,
|
||||||
|
|
@ -579,10 +578,11 @@ class Solver:
|
||||||
out_port = step.out_port
|
out_port = step.out_port
|
||||||
if out_port.rotation is None:
|
if out_port.rotation is None:
|
||||||
raise ToolContractError('Primitive endpoints must have rotation')
|
raise ToolContractError('Primitive endpoints must have rotation')
|
||||||
angle_cos = cos(angle)
|
rotation = rotation_matrix_2d(angle)
|
||||||
angle_sin = sin(angle)
|
out_x = float(out_port.x)
|
||||||
x += angle_cos * float(out_port.x) - angle_sin * float(out_port.y)
|
out_y = float(out_port.y)
|
||||||
y += angle_sin * float(out_port.x) + angle_cos * 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
|
angle += out_port.rotation + pi
|
||||||
ptype = out_port.ptype
|
ptype = out_port.ptype
|
||||||
return Port((x, y), rotation=angle - pi, ptype=ptype)
|
return Port((x, y), rotation=angle - pi, ptype=ptype)
|
||||||
|
|
|
||||||
|
|
@ -574,10 +574,10 @@ class PortList(metaclass=ABCMeta):
|
||||||
raise PortError(msg)
|
raise PortError(msg)
|
||||||
|
|
||||||
translations = a_offsets - b_offsets
|
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'
|
msg = 'Port translations do not match:\n'
|
||||||
for nn, (kk, vv) in enumerate(connections.items()):
|
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'
|
msg += f'{kk} | {translations[nn]} | {vv}\n'
|
||||||
raise PortError(msg)
|
raise PortError(msg)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,22 @@ def test_pather_trace_into_shapes() -> None:
|
||||||
assert numpy.isclose(p.pattern.ports['I'].rotation, pi / 2)
|
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:
|
def test_pather_trace_into_refines_output_adapter_route_before_plug() -> None:
|
||||||
class TransitionTool(Tool):
|
class TransitionTool(Tool):
|
||||||
def primitive_offers(
|
def primitive_offers(
|
||||||
|
|
|
||||||
|
|
@ -169,6 +169,17 @@ def test_port_list_plugged() -> None:
|
||||||
assert not pl.ports # Both should be removed
|
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:
|
def test_port_list_plugged_ptype_compatibility_warnings(caplog: pytest.LogCaptureFixture) -> None:
|
||||||
caplog.set_level("WARNING", logger="masque.ports")
|
caplog.set_level("WARNING", logger="masque.ports")
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue