[Pather/RenderPather/PathTool] Add updated pather tests
This commit is contained in:
parent
69ac25078c
commit
9d6fb985d8
1 changed files with 183 additions and 0 deletions
183
masque/test/test_pather_api.py
Normal file
183
masque/test/test_pather_api.py
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
import numpy
|
||||
from numpy import pi
|
||||
from masque import Pather, RenderPather, Library, Port
|
||||
from masque.builder.tools import PathTool
|
||||
|
||||
def test_pather_trace_basic() -> None:
|
||||
lib = Library()
|
||||
tool = PathTool(layer='M1', width=1000)
|
||||
p = Pather(lib, tools=tool)
|
||||
|
||||
# Port rotation 0 points in +x (INTO device).
|
||||
# To extend it, we move in -x direction.
|
||||
p.pattern.ports['A'] = Port((0, 0), rotation=0)
|
||||
|
||||
# Trace single port
|
||||
p.at('A').trace(None, 5000)
|
||||
assert numpy.allclose(p.pattern.ports['A'].offset, (-5000, 0))
|
||||
|
||||
# Trace with bend
|
||||
p.at('A').trace(True, 5000) # CCW bend
|
||||
# Port was at (-5000, 0) rot 0.
|
||||
# New wire starts at (-5000, 0) rot 0.
|
||||
# Output port of wire before rotation: (5000, 500) rot -pi/2
|
||||
# Rotate by pi (since dev port rot is 0 and tool port rot is 0):
|
||||
# (-5000, -500) rot pi - pi/2 = pi/2
|
||||
# Add to start: (-10000, -500) rot pi/2
|
||||
assert numpy.allclose(p.pattern.ports['A'].offset, (-10000, -500))
|
||||
assert numpy.isclose(p.pattern.ports['A'].rotation, pi/2)
|
||||
|
||||
def test_pather_trace_to() -> None:
|
||||
lib = Library()
|
||||
tool = PathTool(layer='M1', width=1000)
|
||||
p = Pather(lib, tools=tool)
|
||||
|
||||
p.pattern.ports['A'] = Port((0, 0), rotation=0)
|
||||
|
||||
# Trace to x=-10000
|
||||
p.at('A').trace_to(None, x=-10000)
|
||||
assert numpy.allclose(p.pattern.ports['A'].offset, (-10000, 0))
|
||||
|
||||
# Trace to position=-20000
|
||||
p.at('A').trace_to(None, p=-20000)
|
||||
assert numpy.allclose(p.pattern.ports['A'].offset, (-20000, 0))
|
||||
|
||||
def test_pather_bundle_trace() -> None:
|
||||
lib = Library()
|
||||
tool = PathTool(layer='M1', width=1000)
|
||||
p = Pather(lib, tools=tool)
|
||||
|
||||
p.pattern.ports['A'] = Port((0, 0), rotation=0)
|
||||
p.pattern.ports['B'] = Port((0, 2000), rotation=0)
|
||||
|
||||
# Straight bundle - all should align to same x
|
||||
p.at(['A', 'B']).straight(xmin=-10000)
|
||||
assert numpy.isclose(p.pattern.ports['A'].offset[0], -10000)
|
||||
assert numpy.isclose(p.pattern.ports['B'].offset[0], -10000)
|
||||
|
||||
# Bundle with bend
|
||||
p.at(['A', 'B']).ccw(xmin=-20000, spacing=2000)
|
||||
# Traveling in -x direction. CCW turn turns towards -y.
|
||||
# A is at y=0, B is at y=2000.
|
||||
# Rotation center is at y = -R.
|
||||
# A is closer to center than B. So A is inner, B is outer.
|
||||
# xmin is coordinate of innermost bend (A).
|
||||
assert numpy.isclose(p.pattern.ports['A'].offset[0], -20000)
|
||||
# B's bend is further out (more negative x)
|
||||
assert numpy.isclose(p.pattern.ports['B'].offset[0], -22000)
|
||||
|
||||
def test_pather_each_bound() -> None:
|
||||
lib = Library()
|
||||
tool = PathTool(layer='M1', width=1000)
|
||||
p = Pather(lib, tools=tool)
|
||||
|
||||
p.pattern.ports['A'] = Port((0, 0), rotation=0)
|
||||
p.pattern.ports['B'] = Port((-1000, 2000), rotation=0)
|
||||
|
||||
# Each should move by 5000 (towards -x)
|
||||
p.at(['A', 'B']).trace(None, each=5000)
|
||||
assert numpy.allclose(p.pattern.ports['A'].offset, (-5000, 0))
|
||||
assert numpy.allclose(p.pattern.ports['B'].offset, (-6000, 2000))
|
||||
|
||||
def test_selection_management() -> None:
|
||||
lib = Library()
|
||||
p = Pather(lib)
|
||||
p.pattern.ports['A'] = Port((0, 0), rotation=0)
|
||||
p.pattern.ports['B'] = Port((0, 0), rotation=0)
|
||||
|
||||
pp = p.at('A')
|
||||
assert pp.ports == ['A']
|
||||
|
||||
pp.select('B')
|
||||
assert pp.ports == ['A', 'B']
|
||||
|
||||
pp.deselect('A')
|
||||
assert pp.ports == ['B']
|
||||
|
||||
pp.select(['A'])
|
||||
assert pp.ports == ['B', 'A']
|
||||
|
||||
pp.drop()
|
||||
assert 'A' not in p.pattern.ports
|
||||
assert 'B' not in p.pattern.ports
|
||||
assert pp.ports == []
|
||||
|
||||
def test_mark_fork() -> None:
|
||||
lib = Library()
|
||||
p = Pather(lib)
|
||||
p.pattern.ports['A'] = Port((100, 200), rotation=1)
|
||||
|
||||
pp = p.at('A')
|
||||
pp.mark('B')
|
||||
assert 'B' in p.pattern.ports
|
||||
assert numpy.allclose(p.pattern.ports['B'].offset, (100, 200))
|
||||
assert p.pattern.ports['B'].rotation == 1
|
||||
assert pp.ports == ['A'] # mark keeps current selection
|
||||
|
||||
pp.fork('C')
|
||||
assert 'C' in p.pattern.ports
|
||||
assert pp.ports == ['C'] # fork switches to new name
|
||||
|
||||
def test_rename() -> None:
|
||||
lib = Library()
|
||||
p = Pather(lib)
|
||||
p.pattern.ports['A'] = Port((0, 0), rotation=0)
|
||||
|
||||
p.at('A').rename('B')
|
||||
assert 'A' not in p.pattern.ports
|
||||
assert 'B' in p.pattern.ports
|
||||
|
||||
p.pattern.ports['C'] = Port((0, 0), rotation=0)
|
||||
pp = p.at(['B', 'C'])
|
||||
pp.rename({'B': 'D', 'C': 'E'})
|
||||
assert 'B' not in p.pattern.ports
|
||||
assert 'C' not in p.pattern.ports
|
||||
assert 'D' in p.pattern.ports
|
||||
assert 'E' in p.pattern.ports
|
||||
assert set(pp.ports) == {'D', 'E'}
|
||||
|
||||
def test_renderpather_uturn_fallback() -> None:
|
||||
lib = Library()
|
||||
tool = PathTool(layer='M1', width=1000)
|
||||
rp = RenderPather(lib, tools=tool)
|
||||
rp.pattern.ports['A'] = Port((0, 0), rotation=0)
|
||||
|
||||
# PathTool doesn't implement planU, so it should fall back to two planL calls
|
||||
rp.at('A').uturn(offset=10000, length=5000)
|
||||
|
||||
# Two steps should be added
|
||||
assert len(rp.paths['A']) == 2
|
||||
assert rp.paths['A'][0].opcode == 'L'
|
||||
assert rp.paths['A'][1].opcode == 'L'
|
||||
|
||||
rp.render()
|
||||
assert numpy.isclose(rp.pattern.ports['A'].rotation, pi)
|
||||
|
||||
def test_pather_trace_into() -> None:
|
||||
lib = Library()
|
||||
tool = PathTool(layer='M1', width=1000)
|
||||
p = Pather(lib, tools=tool)
|
||||
|
||||
# 1. Straight connector
|
||||
p.pattern.ports['A'] = Port((0, 0), rotation=0)
|
||||
p.pattern.ports['B'] = Port((-10000, 0), rotation=pi)
|
||||
p.at('A').trace_into('B', plug_destination=False)
|
||||
assert 'B' in p.pattern.ports
|
||||
assert 'A' in p.pattern.ports
|
||||
assert numpy.allclose(p.pattern.ports['A'].offset, (-10000, 0))
|
||||
|
||||
# 2. Single bend
|
||||
p.pattern.ports['C'] = Port((0, 0), rotation=0)
|
||||
p.pattern.ports['D'] = Port((-5000, 5000), rotation=pi/2)
|
||||
p.at('C').trace_into('D', plug_destination=False)
|
||||
assert 'D' in p.pattern.ports
|
||||
assert 'C' in p.pattern.ports
|
||||
assert numpy.allclose(p.pattern.ports['C'].offset, (-5000, 5000))
|
||||
|
||||
# 3. Jog (S-bend)
|
||||
p.pattern.ports['E'] = Port((0, 0), rotation=0)
|
||||
p.pattern.ports['F'] = Port((-10000, 2000), rotation=pi)
|
||||
p.at('E').trace_into('F', plug_destination=False)
|
||||
assert 'F' in p.pattern.ports
|
||||
assert 'E' in p.pattern.ports
|
||||
assert numpy.allclose(p.pattern.ports['E'].offset, (-10000, 2000))
|
||||
Loading…
Add table
Add a link
Reference in a new issue