22mod tests {
33 use i_float:: int:: point:: IntPoint ;
44 use i_overlay:: core:: fill_rule:: FillRule ;
5- use i_overlay:: core:: overlay:: { Overlay , ShapeType } ;
5+ use i_overlay:: core:: overlay:: { IntOverlayOptions , Overlay } ;
66 use i_overlay:: core:: overlay_rule:: OverlayRule ;
7+ use i_shape:: int:: area:: Area ;
78
89 // Four boxes that form a shape with a hole, where the exterior
910 // contour and hole contour should share a point at (2,2):
@@ -25,16 +26,17 @@ mod tests {
2526 // The hole is at (1,1)-(2,2). The point (2,2) lies on both the
2627 // exterior contour and the hole contour.
2728 //
28- // Expected exterior contour (6 points):
29+ // Expected exterior contour (6 points, CCW ):
2930 // (0,0) → (3,0) → (3,2) → (2,2) → (2,3) → (0,3)
3031 //
31- // Expected hole contour (4 points):
32+ // Expected hole contour (4 points, CW ):
3233 // (1,1) → (2,1) → (2,2) → (1,2)
3334 //
3435 // BUG: The library currently produces a single merged contour that
3536 // visits (2,2) twice in a figure-8 instead of two separate contours:
3637 // (0,0)→(3,0)→(3,2)→(2,2)→(2,1)→(1,1)→(1,2)→(2,2)→(2,3)→(0,3)
3738
39+ /// Create a CCW rectangle contour from (x1,y1) to (x2,y2).
3840 fn rect ( x1 : i32 , y1 : i32 , x2 : i32 , y2 : i32 ) -> Vec < IntPoint > {
3941 vec ! [
4042 IntPoint :: new( x1, y1) ,
@@ -44,29 +46,44 @@ mod tests {
4446 ]
4547 }
4648
47- fn overlay ( ) -> Overlay {
48- let mut overlay = Overlay :: new ( 16 ) ;
49-
50- overlay. add_contour ( & rect ( 0 , 0 , 3 , 1 ) , ShapeType :: Subject ) ;
51- overlay. add_contour ( & rect ( 0 , 1 , 1 , 2 ) , ShapeType :: Subject ) ;
52- overlay. add_contour ( & rect ( 2 , 1 , 3 , 2 ) , ShapeType :: Subject ) ;
53- overlay. add_contour ( & rect ( 0 , 2 , 2 , 3 ) , ShapeType :: Subject ) ;
49+ fn subject_contours ( ) -> Vec < Vec < IntPoint > > {
50+ vec ! [
51+ rect( 0 , 0 , 3 , 1 ) ,
52+ rect( 0 , 1 , 1 , 2 ) ,
53+ rect( 2 , 1 , 3 , 2 ) ,
54+ rect( 0 , 2 , 2 , 3 ) ,
55+ ]
56+ }
5457
55- overlay
58+ fn overlay ( fill_rule : FillRule ) -> Vec < Vec < Vec < IntPoint > > > {
59+ let contours = subject_contours ( ) ;
60+ let mut overlay = Overlay :: with_contours_custom (
61+ & contours,
62+ & [ ] ,
63+ IntOverlayOptions :: ogc ( ) ,
64+ Default :: default ( ) ,
65+ ) ;
66+ overlay. overlay ( OverlayRule :: Subject , fill_rule)
5667 }
5768
5869 fn contour_contains ( contour : & [ IntPoint ] , point : IntPoint ) -> bool {
5970 contour. iter ( ) . any ( |p| * p == point)
6071 }
6172
6273 #[ test]
63- fn test_shared_point_even_odd ( ) {
64- let mut buffer = Default :: default ( ) ;
74+ fn test_input_winding_order ( ) {
75+ // All input rectangles must be CCW (negative area_two).
76+ for contour in & subject_contours ( ) {
77+ assert ! (
78+ contour. area_two( ) < 0 ,
79+ "input contour must be counter-clockwise, got area_two={}" , contour. area_two( )
80+ ) ;
81+ }
82+ }
6583
66- let result = overlay ( )
67- . build_graph_view ( FillRule :: EvenOdd )
68- . unwrap ( )
69- . extract_shapes ( OverlayRule :: Subject , & mut buffer) ;
84+ #[ test]
85+ fn test_shared_point_even_odd ( ) {
86+ let result = overlay ( FillRule :: EvenOdd ) ;
7087
7188 assert_eq ! ( result. len( ) , 1 , "expected 1 shape" ) ;
7289 assert_eq ! ( result[ 0 ] . len( ) , 2 , "expected 2 contours (exterior + hole)" ) ;
@@ -84,12 +101,7 @@ mod tests {
84101
85102 #[ test]
86103 fn test_shared_point_non_zero ( ) {
87- let mut buffer = Default :: default ( ) ;
88-
89- let result = overlay ( )
90- . build_graph_view ( FillRule :: NonZero )
91- . unwrap ( )
92- . extract_shapes ( OverlayRule :: Subject , & mut buffer) ;
104+ let result = overlay ( FillRule :: NonZero ) ;
93105
94106 assert_eq ! ( result. len( ) , 1 , "expected 1 shape" ) ;
95107 assert_eq ! ( result[ 0 ] . len( ) , 2 , "expected 2 contours (exterior + hole)" ) ;
@@ -107,12 +119,7 @@ mod tests {
107119
108120 #[ test]
109121 fn test_shared_point_positive ( ) {
110- let mut buffer = Default :: default ( ) ;
111-
112- let result = overlay ( )
113- . build_graph_view ( FillRule :: Positive )
114- . unwrap ( )
115- . extract_shapes ( OverlayRule :: Subject , & mut buffer) ;
122+ let result = overlay ( FillRule :: Positive ) ;
116123
117124 assert_eq ! ( result. len( ) , 1 , "expected 1 shape" ) ;
118125 assert_eq ! ( result[ 0 ] . len( ) , 2 , "expected 2 contours (exterior + hole)" ) ;
@@ -130,15 +137,10 @@ mod tests {
130137
131138 #[ test]
132139 fn test_shared_point_negative ( ) {
133- let mut buffer = Default :: default ( ) ;
134-
135- let result = overlay ( )
136- . build_graph_view ( FillRule :: Negative )
137- . unwrap ( )
138- . extract_shapes ( OverlayRule :: Subject , & mut buffer) ;
140+ let result = overlay ( FillRule :: Negative ) ;
139141
140- // All contours are CCW (positive winding), so Negative fill rule
141- // produces no filled regions.
142+ // All input contours are CCW (positive winding), so Negative
143+ // fill rule produces no filled regions.
142144 assert_eq ! ( result. len( ) , 0 , "expected 0 shapes for Negative fill rule" ) ;
143145 }
144146}
0 commit comments