Files
rpmroute/tests/geometry/test_line.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

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)