1+ from core_geometry .plane import Plane
2+ import numpy as np
3+
4+ def test_plane_from_points_horizontal ():
5+ """
6+ Create a horizontal plane using three points and verify its normal and offset.
7+ """
8+ p1 = [0 , 0 , 0 ]
9+ p2 = [1 , 0 , 0 ]
10+ p3 = [0 , 0 , 1 ]
11+ plane = Plane .from_points (p1 , p2 , p3 )
12+ assert np .allclose (np .abs (plane .normal ), [0 , 1 , 0 ]) or np .allclose (np .abs (plane .normal ), [0 , - 1 , 0 ])
13+ assert np .isclose (plane .offset , 0 )
14+
15+ def test_plane_from_points_inclined ():
16+ """
17+ Create an inclined plane using three points and verify that the signed distance to each point is zero.
18+ """
19+ p1 = [0 , 0 , 0 ]
20+ p2 = [1 , 1 , 0 ]
21+ p3 = [0 , 1 , 1 ]
22+ plane = Plane .from_points (p1 , p2 , p3 )
23+ for p in (p1 , p2 , p3 ):
24+ assert np .isclose (plane .signed_distance_to (p ), 0 )
25+
26+ def test_plane_from_collinear_points_raises ():
27+ """
28+ Attempt to create a plane from three collinear points and expect a ValueError.
29+ """
30+ p1 = [0 , 0 , 0 ]
31+ p2 = [1 , 0 , 0 ]
32+ p3 = [2 , 0 , 0 ]
33+ try :
34+ Plane .from_points (p1 , p2 , p3 )
35+ assert False , "Expected ValueError"
36+ except ValueError :
37+ pass
38+
39+ def test_plane_signed_distance_positive ():
40+ """
41+ Test signed distance to a horizontal plane with points above and below it.
42+ """
43+ plane = Plane ([0 , 1 , 0 ], [0 , 0 , 0 ])
44+ assert np .isclose (plane .signed_distance_to ([0 , 5 , 0 ]), 5 )
45+ assert np .isclose (plane .signed_distance_to ([0 , - 3 , 0 ]), - 3 )
46+
47+ def test_plane_project_points ():
48+ """
49+ Project a point onto a horizontal plane and verify the result.
50+ """
51+ plane = Plane ([0 , 1 , 0 ], [0 , 0 , 0 ])
52+ points = [[1 , 5 , 1 ], [1 , - 3 , 1 ], [1 , 0 , 1 ]]
53+ for point in points :
54+ projected = plane .project_point (point )
55+ assert np .isclose (projected [1 ], 0 )
56+
57+ def test_plane_from_rays_basic ():
58+ """
59+ Create a plane from two rays and verify that the normal is orthogonal to both rays.
60+ """
61+ ray1 = np .array ([1 , 0 , 0 ], dtype = float )
62+ ray2 = np .array ([0 , 0 , 1 ], dtype = float )
63+ origin = [0 , 0 , 0 ]
64+ plane = Plane .from_rays (ray1 , ray2 , origin )
65+ expected_normal = np .cross (ray1 , ray2 )
66+ expected_normal = expected_normal / np .linalg .norm (expected_normal )
67+ assert np .allclose (np .abs (plane .normal ), expected_normal ) or np .allclose (np .abs (plane .normal ), - expected_normal )
68+
69+ def test_plane_from_collinear_rays_raises ():
70+ """
71+ Attempt to create a plane from two collinear rays and expect a ValueError.
72+ """
73+ ray1 = [1 , 0 , 0 ]
74+ ray2 = [2 , 0 , 0 ]
75+ origin = [0 , 0 , 0 ]
76+ try :
77+ Plane .from_rays (ray1 , ray2 , origin )
78+ assert False , "Expected ValueError"
79+ except ValueError :
80+ pass
81+
82+ def test_plane_normalization_enforced ():
83+ # plane = Plane([0, 10, 0], [0, 0, 0])
84+ # assert np.allclose(plane.normal, [0, 1, 0])
85+ # assert np.isclose(plane.offset, 0)
86+ planes = [Plane ([0 , 10 , - 7 ], [0 , 1 , 0 ]),
87+ Plane ([5 , - 10 , 0 ], [2 , 0 , 0 ]),
88+ Plane ([0 , 1 , 10 ], [0 , 0 , - 3 ]),
89+ Plane ([2 , 0 , - 10 ], [1 , 0 , 5 ])]
90+ for plane in planes :
91+ # assert np.linalg.norm(plane.normal) == 1, f"Plane normal not normalized: {plane.normal}"
92+ assert np .isclose (np .linalg .norm (plane .normal ), 1 ), f"Plane normal not normalized: { plane .normal } "
93+
94+ def test_plane_equation ():
95+ p1 = [3 , 4 , 5 ]
96+ p2 = [1 , 0 , 0 ]
97+ p3 = [8 , - 2 , 1 ]
98+ plane = Plane .from_points (p1 , p2 , p3 )
99+ A , B , C = plane .normal
100+ D = plane .offset
101+ # Equation is A*x + B*y + C*z + D = 0
102+ # Launch random rays and verify that the intersection point satisfies the plane equation
103+ # ray_positions, ray_dirs = [np.array(-5, -100, 0)], [np.array([1, 0, -15])], [np.array([0, 1, 0]), np.array([0, 0, 1])]
104+ ray_positions = np .array ([[0 , 0 , 10 ], [0 , 10 , 10 ], [10 , 0 , 10 ], [5 , 5 , - 10 ], [- 10 , - 10 , 10 ]])
105+ ray_dirs = np .array ([[0 , 0 , - 1 ], [0 , - 1 , - 1 ], [- 1 , 0 , - 1 ], [- 0.5 , - 0.5 , 2 ], [1 , 1 , - 1 ]])
106+ intersections = []
107+ for pos , dir in zip (ray_positions , ray_dirs ):
108+ intersection = plane .project_point (pos + dir )
109+ intersections .append (intersection )
110+ assert np .isclose (A * intersection [0 ] + B * intersection [1 ] + C * intersection [2 ] + D , 0 )
111+
112+ if __name__ == "__main__" :
113+ test_plane_from_points_horizontal ()
114+ test_plane_from_points_inclined ()
115+ test_plane_from_collinear_points_raises ()
116+ test_plane_signed_distance_positive ()
117+ test_plane_project_points ()
118+ test_plane_from_rays_basic ()
119+ test_plane_from_collinear_rays_raises ()
120+ test_plane_normalization_enforced ()
121+ test_plane_equation ()
122+ print ("All tests passed!" )
0 commit comments