Files
rpmroute/tests/geometry/test_polyline.py
T
rsp2k a6aa1991a1 Rename to rpmroute
The router began as a port of FreeRouting and has grown its own engine
(negotiated congestion, tree nets, exact checks, axis escapes), and
'freeroute' was one letter from the project it no longer follows. The
package, module and command are now rpmroute; the freeroute command stays
as an alias, and the RPMROUTE / RPMROUTE_ORACLE_JAVA variables fall back
to the old FREEROUTE names. Version 2026.10.07. Routing is unchanged: a
PCBench board routes to a byte-identical session either way.
2026-10-07 14:10:36 -06:00

82 lines
2.7 KiB
Python

"""Tests for Polyline / PolylineShape (the swept trace copper)."""
from __future__ import annotations
from rpmroute.geometry import (
IntBox,
IntPoint,
Polyline,
PolylineShape,
segment_box,
shove_segment,
)
def test_polyline_segments():
pl = Polyline([IntPoint(0, 0), IntPoint(10, 0), IntPoint(10, 10)])
segs = list(pl.segments())
assert len(segs) == 2
assert pl.corner_count() == 3
assert not pl.is_empty()
assert Polyline([IntPoint(0, 0)]).is_empty()
def test_segment_box_horizontal_is_flush_in_x():
box = segment_box(IntPoint(0, 0), IntPoint(100, 0), 10)
# flush in the travel direction (x), offset by half-width in y
assert box == IntBox(0, -10, 100, 10)
def test_segment_box_vertical_is_flush_in_y():
box = segment_box(IntPoint(0, 0), IntPoint(0, 100), 10)
assert box == IntBox(-10, 0, 10, 100)
def test_polyline_shape_tiles_include_corner_squares():
pl = Polyline([IntPoint(0, 0), IntPoint(100, 0), IntPoint(100, 100)])
tiles = PolylineShape(pl, 10).tiles()
# 2 segment boxes + 1 interior-corner square
assert len(tiles) == 3
# the corner square is centred on the turn at (100, 0)
assert IntBox(90, -10, 110, 10) in tiles
def test_polyline_shape_bounding_box():
pl = Polyline([IntPoint(0, 0), IntPoint(100, 0)])
assert PolylineShape(pl, 5).bounding_box() == IntBox(-5, -5, 105, 5)
def test_diagonal_segment_box_is_conservative_bbox():
box = segment_box(IntPoint(0, 0), IntPoint(50, 50), 10)
assert box == IntBox(-10, -10, 60, 60)
# --- shove primitive --------------------------------------------------------
def test_shove_single_segment_inserts_jogs_and_keeps_pads():
# a horizontal pad-to-pad trace shoved up by 30 keeps its endpoints
corners = [IntPoint(0, 0), IntPoint(100, 0)]
out = shove_segment(corners, 0, 0, 30)
assert [(p.x, p.y) for p in out] == [(0, 0), (0, 30), (100, 30), (100, 0)]
assert out[0] == corners[0] and out[-1] == corners[1] # pads fixed
def test_shove_interior_segment_resizes_neighbours():
# the middle horizontal run of a U shoved up 20; verticals resize, pads fixed
corners = [IntPoint(0, 0), IntPoint(0, 50), IntPoint(100, 50), IntPoint(100, 0)]
out = shove_segment(corners, 1, 0, 20)
assert [(p.x, p.y) for p in out] == [(0, 0), (0, 70), (100, 70), (100, 0)]
def test_shove_stays_orthogonal():
corners = [IntPoint(0, 0), IntPoint(0, 40), IntPoint(80, 40), IntPoint(80, 0)]
out = shove_segment(corners, 1, 0, 15)
for a, b in zip(out, out[1:], strict=False):
assert a.x == b.x or a.y == b.y # every segment axis-aligned
def test_shove_out_of_range_is_noop():
corners = [IntPoint(0, 0), IntPoint(100, 0)]
assert shove_segment(corners, 5, 0, 30) == corners