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.
132 lines
3.9 KiB
Python
132 lines
3.9 KiB
Python
"""Tests for IntBox.
|
|
|
|
Oracles hand-derived from ``geometry/planar/IntBox.java``. Emphasis on boundary
|
|
containment and degenerate (empty / point / segment) tiles.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from rpmroute.geometry import IntBox, IntPoint, IntVector, RationalPoint
|
|
|
|
|
|
def test_measures():
|
|
b = IntBox(1, 2, 5, 8)
|
|
assert b.width() == 4
|
|
assert b.height() == 6
|
|
assert b.area() == 24
|
|
assert b.circumference() == 20
|
|
assert b.max_width() == 6
|
|
assert b.min_width() == 4
|
|
|
|
|
|
def test_corners_counter_clockwise():
|
|
b = IntBox(0, 0, 4, 3)
|
|
assert b.corners() == [
|
|
IntPoint(0, 0),
|
|
IntPoint(4, 0),
|
|
IntPoint(4, 3),
|
|
IntPoint(0, 3),
|
|
]
|
|
|
|
|
|
def test_dimension_variants():
|
|
assert IntBox(0, 0, 4, 3).dimension() == 2
|
|
assert IntBox(0, 0, 0, 3).dimension() == 1 # vertical segment
|
|
assert IntBox(0, 0, 4, 0).dimension() == 1 # horizontal segment
|
|
assert IntBox(2, 2, 2, 2).dimension() == 0 # single point
|
|
assert IntBox.empty().dimension() == -1
|
|
|
|
|
|
def test_boundary_containment_inclusive_vs_interior():
|
|
b = IntBox(0, 0, 10, 10)
|
|
corner = IntPoint(0, 0)
|
|
edge = IntPoint(0, 5)
|
|
inside = IntPoint(5, 5)
|
|
outside = IntPoint(11, 5)
|
|
# border-inclusive contains
|
|
assert b.contains(corner)
|
|
assert b.contains(edge)
|
|
assert b.contains(inside)
|
|
assert not b.contains(outside)
|
|
# strict interior
|
|
assert not b.contains_inside(corner)
|
|
assert not b.contains_inside(edge)
|
|
assert b.contains_inside(inside)
|
|
|
|
|
|
def test_contains_rational_point_on_border():
|
|
b = IntBox(0, 0, 3, 3)
|
|
# (3, 1.5) sits exactly on the right edge -> contained (inclusive)
|
|
assert b.contains(RationalPoint(6, 3, 2))
|
|
# (3.5, 1.5) just outside
|
|
assert not b.contains(RationalPoint(7, 3, 2))
|
|
|
|
|
|
def test_intersection_overlap_and_touch():
|
|
a = IntBox(0, 0, 10, 10)
|
|
assert a.intersection(IntBox(5, 5, 20, 20)) == IntBox(5, 5, 10, 10)
|
|
# touching along an edge -> 1-dimensional intersection, still non-empty
|
|
touch = a.intersection(IntBox(10, 0, 20, 10))
|
|
assert touch == IntBox(10, 0, 10, 10)
|
|
assert touch.dimension() == 1
|
|
# disjoint -> empty
|
|
assert a.intersection(IntBox(20, 20, 30, 30)).is_empty()
|
|
|
|
|
|
def test_intersects_vs_overlaps_on_touching_edge():
|
|
a = IntBox(0, 0, 10, 10)
|
|
edge_neighbor = IntBox(10, 0, 20, 10)
|
|
assert a.intersects(edge_neighbor) # closed-interval: touching counts
|
|
assert not a.overlaps(edge_neighbor) # open-interval: no 2D overlap
|
|
|
|
|
|
def test_union():
|
|
assert IntBox(0, 0, 2, 2).union(IntBox(5, 5, 8, 8)) == IntBox(0, 0, 8, 8)
|
|
|
|
|
|
def test_offset_expands_and_contracts():
|
|
b = IntBox(0, 0, 10, 10)
|
|
assert b.offset(2) == IntBox(-2, -2, 12, 12)
|
|
assert b.offset(-3) == IntBox(3, 3, 7, 7)
|
|
assert b.offset(0) is b
|
|
assert b.horizontal_offset(2) == IntBox(-2, 0, 12, 10)
|
|
assert b.vertical_offset(2) == IntBox(0, -2, 10, 12)
|
|
|
|
|
|
def test_offset_rounds_half_up():
|
|
b = IntBox(0, 0, 10, 10)
|
|
assert b.offset(2.5) == IntBox(-3, -3, 13, 13) # 2.5 -> 3 (half up)
|
|
|
|
|
|
def test_shrink_collapses_to_center_not_past():
|
|
b = IntBox(0, 0, 10, 10)
|
|
assert b.shrink(3) == IntBox(3, 3, 7, 7)
|
|
# over-shrink collapses to the center line rather than inverting
|
|
collapsed = b.shrink(20)
|
|
assert collapsed == IntBox(5, 5, 5, 5)
|
|
assert collapsed.dimension() == 0
|
|
|
|
|
|
def test_containment_between_boxes():
|
|
outer = IntBox(0, 0, 10, 10)
|
|
inner = IntBox(2, 2, 8, 8)
|
|
assert inner.is_contained_in(outer)
|
|
assert outer.contains_box(inner)
|
|
assert outer.contains_in_interior(inner)
|
|
edge = IntBox(0, 2, 8, 8) # touches left edge
|
|
assert edge.is_contained_in(outer)
|
|
assert not outer.contains_in_interior(edge)
|
|
|
|
|
|
def test_translate_by():
|
|
b = IntBox(0, 0, 4, 4)
|
|
assert b.translate_by(IntVector(3, -2)) == IntBox(3, -2, 7, 2)
|
|
assert b.translate_by(IntVector(0, 0)) is b
|
|
|
|
|
|
def test_empty_box_predicates():
|
|
e = IntBox.empty()
|
|
assert e.is_empty()
|
|
assert e.is_contained_in(IntBox(0, 0, 1, 1))
|
|
assert e.offset(5) is e
|