"""Geometric predicates and constants.""" import math from herding.world.geometry import ( FIELD_X, FIELD_Y, GATE_X, GATE_Y, MAX_SHEEP, PEN_ENTRY, PEN_X, PEN_Y, distance_to_pen_entry, in_field, in_gate_corridor, in_pen, is_penned_position, ) def test_field_dimensions(): assert FIELD_X == (-15.0, 15.0) assert FIELD_Y == (-15.0, 15.0) def test_pen_geometry(): assert PEN_X == (10.0, 13.0) assert PEN_Y == (-22.0, -15.0) assert PEN_ENTRY == (11.5, -15.0) assert GATE_X == PEN_X assert GATE_Y == -15.0 def test_in_pen_strict_interior(): assert in_pen(11.5, -18.0) assert not in_pen(10.0, -18.0) # boundary excluded assert not in_pen(11.5, -15.0) # gate plane excluded assert not in_pen(0.0, 0.0) def test_in_field_with_margin(): assert in_field(0.0, 0.0) assert in_field(14.0, 14.0) assert not in_field(15.5, 0.0) assert in_field(14.4, 0.0, margin=0.5) assert not in_field(14.6, 0.0, margin=0.5) def test_in_gate_corridor(): assert in_gate_corridor(11.5, -18.0) assert in_gate_corridor(10.0, -15.0) assert not in_gate_corridor(11.5, -10.0) assert not in_gate_corridor(5.0, -18.0) def test_is_penned_position_latches_below_gate(): # In the gate column and south of the gate plane → penned. assert is_penned_position(11.5, -15.0) assert is_penned_position(10.5, -18.0) assert is_penned_position(12.5, -22.0) # Above the gate plane → not yet. assert not is_penned_position(11.5, -14.9) # Outside the gate column → not penned even if south. assert not is_penned_position(0.0, -16.0) assert not is_penned_position(14.0, -16.0) def test_is_penned_position_latch_margin(): # Slight tolerance on the gate column. assert is_penned_position(9.9, -15.5) assert is_penned_position(13.1, -15.5) assert not is_penned_position(9.7, -15.5) def test_distance_to_pen_entry(): assert distance_to_pen_entry(*PEN_ENTRY) == 0.0 assert math.isclose(distance_to_pen_entry(11.5, -10.0), 5.0) assert math.isclose(distance_to_pen_entry(0.0, 0.0), math.hypot(11.5, 15.0)) def test_max_sheep_positive_int(): assert isinstance(MAX_SHEEP, int) assert MAX_SHEEP >= 1