"""Unit tests for src.utils.geometry_utils.""" from __future__ import annotations import math from src.utils.geometry_utils import ( box_center, box_to_polygon, clamp01, containment_pct, coverage_pct, distance_between, iou, margin_utilization, points_to_polygon, safe_area, ) def test_box_to_polygon_area(): poly = box_to_polygon((0, 0, 10, 20)) assert safe_area(poly) == 200.0 def test_box_to_polygon_normalizes_reversed_coords(): poly = box_to_polygon((10, 20, 0, 0)) assert safe_area(poly) == 200.0 def test_coverage_pct_full_overlap(): target = box_to_polygon((0, 0, 100, 100)) sig = box_to_polygon((0, 0, 100, 100)) assert coverage_pct(target, sig) == 100.0 assert containment_pct(target, sig) == 100.0 assert iou(target, sig) == 1.0 def test_coverage_pct_partial_overlap(): target = box_to_polygon((0, 0, 100, 100)) sig = box_to_polygon((50, 0, 150, 100)) # Half of the target box is covered by the signature. assert math.isclose(coverage_pct(target, sig), 50.0, abs_tol=1e-6) # Half of the signature lies within the target box. assert math.isclose(containment_pct(target, sig), 50.0, abs_tol=1e-6) def test_coverage_pct_no_overlap(): target = box_to_polygon((0, 0, 10, 10)) sig = box_to_polygon((100, 100, 110, 110)) assert coverage_pct(target, sig) == 0.0 assert containment_pct(target, sig) == 0.0 assert iou(target, sig) == 0.0 def test_iou_partial(): a = box_to_polygon((0, 0, 10, 10)) b = box_to_polygon((5, 0, 15, 10)) # Intersection = 50, union = 100+100-50 = 150 assert math.isclose(iou(a, b), 50.0 / 150.0, rel_tol=1e-6) def test_points_to_polygon_handles_degenerate_input(): poly = points_to_polygon([]) assert poly.is_empty poly_single = points_to_polygon([[5, 5]]) assert safe_area(poly_single) > 0 def test_points_to_polygon_valid_shape(): poly = points_to_polygon([[0, 0], [10, 0], [10, 10], [0, 10]]) assert poly.is_valid assert safe_area(poly) == 100.0 def test_box_center_and_distance(): assert box_center((0, 0, 10, 20)) == (5.0, 10.0) assert distance_between((0, 0), (3, 4)) == 5.0 def test_distance_between_nan_safe(): assert math.isnan(distance_between((float("nan"), 0), (1, 1))) def test_clamp01(): assert clamp01(-1) == 0.0 assert clamp01(2) == 1.0 assert clamp01(0.5) == 0.5 assert clamp01(float("nan")) == 0.0 def test_margin_utilization_centered_small_signature(): box = (0, 0, 100, 100) sig = box_to_polygon((45, 45, 55, 55)) # A small centered signature uses very little of the available margin. assert margin_utilization(box, sig) < 0.2 def test_margin_utilization_full_box_signature(): box = (0, 0, 100, 100) sig = box_to_polygon((0, 0, 100, 100)) # A signature filling the whole box reaches ~1.0 (corner at half-diagonal). assert math.isclose(margin_utilization(box, sig), 1.0, rel_tol=1e-6)