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.
103 lines
3.5 KiB
Python
103 lines
3.5 KiB
Python
"""Tests for lines, emphasizing exact intersection.
|
|
|
|
Oracles hand-derived from ``geometry/planar/Line.java``.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from rpmroute.geometry import IntPoint, Line, RationalPoint, Side
|
|
|
|
|
|
def test_side_of_point():
|
|
# Line.side_of reports where the *line* is relative to the point
|
|
# (point.side_of(line).negate() in the source): a point above a +x line has
|
|
# the line on its right.
|
|
line = Line.from_coords(0, 0, 2, 0) # along +x
|
|
assert line.side_of(IntPoint(1, 1)) == Side.ON_THE_RIGHT
|
|
assert line.side_of(IntPoint(1, -1)) == Side.ON_THE_LEFT
|
|
assert line.side_of(IntPoint(5, 0)) == Side.COLLINEAR
|
|
|
|
|
|
def test_integral_intersection_fast_paths():
|
|
# vertical x horizontal
|
|
v = Line.from_coords(3, 0, 3, 9)
|
|
h = Line.from_coords(0, 4, 9, 4)
|
|
assert v.intersection(h) == IntPoint(3, 4)
|
|
# horizontal x right-diagonal (y=x): y=4 -> (4,4)
|
|
diag = Line.from_coords(0, 0, 5, 5)
|
|
assert h.intersection(diag) == IntPoint(4, 4)
|
|
|
|
|
|
def test_general_integral_intersection():
|
|
# y = x/2 and y = 1 -> x = 2
|
|
a = Line.from_coords(0, 0, 2, 1)
|
|
b = Line.from_coords(0, 1, 4, 1)
|
|
assert a.intersection(b) == IntPoint(2, 1)
|
|
|
|
|
|
def test_rational_intersection_exact():
|
|
# y = 2x/3 and y = 1 -> x = 1.5 -> RationalPoint (3,2,2)
|
|
a = Line.from_coords(0, 0, 3, 2)
|
|
b = Line.from_coords(0, 1, 5, 1)
|
|
result = a.intersection(b)
|
|
assert isinstance(result, RationalPoint)
|
|
assert result == RationalPoint(3, 2, 2)
|
|
assert not result.is_infinite()
|
|
# float approximation agrees
|
|
fp = result.to_float()
|
|
assert abs(fp.x - 1.5) < 1e-9 and abs(fp.y - 1.0) < 1e-9
|
|
|
|
|
|
def test_parallel_intersection_is_infinite():
|
|
a = Line.from_coords(0, 0, 1, 0)
|
|
b = Line.from_coords(0, 5, 1, 5)
|
|
result = a.intersection(b)
|
|
assert result.is_infinite()
|
|
assert a.is_parallel(b)
|
|
|
|
|
|
def test_intersection_exact_beyond_double_precision():
|
|
# Two nearly-parallel steep lines crossing at a non-integer point far out.
|
|
# Coordinates chosen so a double determinant would lose bits; int stays exact.
|
|
a = Line.from_coords(0, 0, 1000000, 999999)
|
|
b = Line.from_coords(0, 1, 1000000, 1000000)
|
|
result = a.intersection(b)
|
|
assert isinstance(result, RationalPoint)
|
|
# Verify exactness: the intersection lies on both lines (exact side test).
|
|
assert a.side_of(result) == Side.COLLINEAR
|
|
assert b.side_of(result) == Side.COLLINEAR
|
|
|
|
|
|
def test_intersection_approx_matches_exact():
|
|
a = Line.from_coords(0, 0, 3, 2)
|
|
b = Line.from_coords(0, 1, 5, 1)
|
|
approx = a.intersection_approx(b)
|
|
assert abs(approx.x - 1.5) < 1e-9
|
|
assert abs(approx.y - 1.0) < 1e-9
|
|
|
|
|
|
def test_translate_and_opposite():
|
|
line = Line.from_coords(0, 0, 4, 0)
|
|
assert line.opposite().direction().equals(line.direction()) is False
|
|
from rpmroute.geometry import IntVector
|
|
|
|
moved = line.translate_by(IntVector(0, 5))
|
|
assert moved.side_of(IntPoint(2, 5)) == Side.COLLINEAR
|
|
|
|
|
|
def test_perpendicular_and_parallel_predicates():
|
|
horizontal = Line.from_coords(0, 0, 1, 0)
|
|
vertical = Line.from_coords(0, 0, 0, 1)
|
|
assert horizontal.is_perpendicular(vertical)
|
|
assert not horizontal.is_parallel(vertical)
|
|
assert horizontal.is_parallel(Line.from_coords(3, 7, 10, 7))
|
|
|
|
|
|
def test_line_equality_same_set_same_direction():
|
|
a = Line.from_coords(0, 0, 2, 0)
|
|
b = Line.from_coords(-5, 0, 9, 0) # same line, same direction
|
|
c = Line.from_coords(9, 0, -5, 0) # same set, opposite direction
|
|
assert a == b
|
|
assert a != c
|
|
assert a.is_equal_or_opposite(c)
|