View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.geometry.euclidean.twod;
18  
19  import org.apache.commons.geometry.euclidean.twod.shape.Parallelogram;
20  import org.apache.commons.numbers.core.Precision;
21  import org.junit.jupiter.api.Test;
22  
23  class BoundarySourceLinecaster2DTest {
24  
25      private static final double TEST_EPS = 1e-10;
26  
27      private static final Precision.DoubleEquivalence TEST_PRECISION =
28              Precision.doubleEquivalenceOfEpsilon(TEST_EPS);
29  
30      private static final BoundarySource2D UNIT_SQUARE =
31              Parallelogram.axisAligned(Vector2D.ZERO, Vector2D.of(1, 1), TEST_PRECISION);
32  
33      @Test
34      void testLinecast_line_simple() {
35          // arrange
36          final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
37  
38          // act/assert
39  
40          // no intersections
41          LinecastChecker2D.with(linecaster)
42              .expectNothing()
43              .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0, 4), Vector2D.Unit.MINUS_X, TEST_PRECISION));
44  
45          // through center; two directions
46          LinecastChecker2D.with(linecaster)
47              .expect(Vector2D.of(0, 0.5), Vector2D.Unit.MINUS_X)
48              .and(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
49              .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0.5, 0.5), Vector2D.Unit.PLUS_X, TEST_PRECISION));
50  
51          LinecastChecker2D.with(linecaster)
52              .expect(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
53              .and(Vector2D.of(0, 0.5), Vector2D.Unit.MINUS_X)
54              .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0.5, 0.5), Vector2D.Unit.MINUS_X, TEST_PRECISION));
55      }
56  
57      @Test
58      void testLinecast_line_alongFace() {
59          // arrange
60          final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
61  
62          // act/assert
63          LinecastChecker2D.with(linecaster)
64              .expect(Vector2D.of(0, 1), Vector2D.Unit.MINUS_X)
65              .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
66              .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0, 1), Vector2D.Unit.PLUS_X, TEST_PRECISION));
67      }
68  
69      @Test
70      void testLinecast_line_corners() {
71          // arrange
72          final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
73  
74          // act/assert
75  
76          // through single corner vertex
77          LinecastChecker2D.with(linecaster)
78              .expect(Vector2D.of(1, 1), Vector2D.Unit.PLUS_Y)
79              .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
80              .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0, 2), Vector2D.of(1, -1), TEST_PRECISION));
81  
82          // through two corner vertices
83          LinecastChecker2D.with(linecaster)
84              .expect(Vector2D.ZERO, Vector2D.Unit.MINUS_X)
85              .and(Vector2D.ZERO, Vector2D.Unit.MINUS_Y)
86              .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_Y)
87              .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
88              .whenGiven(Lines.fromPointAndDirection(Vector2D.ZERO, Vector2D.of(1, 1), TEST_PRECISION));
89      }
90  
91      @Test
92      void testLinecast_line_removesDuplicatePoints() {
93          // arrange
94          final BoundarySource2D src = BoundarySource2D.of(
95                      Lines.segmentFromPoints(Vector2D.of(-1, -1), Vector2D.ZERO, TEST_PRECISION),
96                      Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.of(1, 1), TEST_PRECISION)
97                  );
98          final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(src);
99  
100         // act/assert
101         LinecastChecker2D.with(linecaster)
102             .expect(Vector2D.ZERO, Vector2D.Unit.from(1, -1))
103             .whenGiven(Lines.fromPointAndDirection(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION));
104     }
105 
106     @Test
107     void testLinecast_segment_simple() {
108         // arrange
109         final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
110 
111         // act/assert
112 
113         // no intersections; underlying line does not intersect
114         LinecastChecker2D.with(linecaster)
115             .expectNothing()
116             .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0, 4), Vector2D.Unit.MINUS_X, TEST_PRECISION)
117                     .segment(-10, 10));
118 
119         // no intersections; underlying line does intersect
120         LinecastChecker2D.with(linecaster)
121             .expectNothing()
122             .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0.5, 0.5), Vector2D.Unit.PLUS_X, TEST_PRECISION)
123                     .segment(2, 10));
124 
125         // no boundaries excluded; two directions
126         LinecastChecker2D.with(linecaster)
127             .expect(Vector2D.of(0, 0.5), Vector2D.Unit.MINUS_X)
128             .and(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
129             .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0.5, 0.5), Vector2D.Unit.PLUS_X, TEST_PRECISION)
130                     .segment(-10, 10));
131 
132         LinecastChecker2D.with(linecaster)
133             .expect(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
134             .and(Vector2D.of(0, 0.5), Vector2D.Unit.MINUS_X)
135             .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0.5, 0.5), Vector2D.Unit.MINUS_X, TEST_PRECISION)
136                     .segment(-10, 10));
137     }
138 
139     @Test
140     void testLinecast_segment_boundaryExcluded() {
141         // arrange
142         final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
143 
144         // act/assert
145         final Vector2D center = Vector2D.of(0.5, 0.5);
146         LinecastChecker2D.with(linecaster)
147             .expect(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
148             .whenGiven(Lines.fromPointAndDirection(center, Vector2D.Unit.PLUS_X, TEST_PRECISION)
149                     .rayFrom(center));
150 
151         LinecastChecker2D.with(linecaster)
152             .expect(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
153             .whenGiven(Lines.fromPointAndDirection(center, Vector2D.Unit.MINUS_X, TEST_PRECISION)
154                     .reverseRayTo(center));
155     }
156 
157     @Test
158     void testLinecast_segment_startEndPointsOnBoundaries() {
159         // arrange
160         final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
161 
162         // act/assert
163         LinecastChecker2D.with(linecaster)
164             .expect(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
165             .and(Vector2D.of(0, 0.5), Vector2D.Unit.MINUS_X)
166             .whenGiven(Lines.segmentFromPoints(Vector2D.of(1, 0.5), Vector2D.of(0, 0.5), TEST_PRECISION));
167     }
168 
169     @Test
170     void testLinecast_segment_alongFace() {
171         // arrange
172         final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
173 
174         // act/assert
175 
176         // includes two intersecting boundaries
177         LinecastChecker2D.with(linecaster)
178             .expect(Vector2D.of(0, 1), Vector2D.Unit.MINUS_X)
179             .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
180             .whenGiven(Lines.segmentFromPoints(Vector2D.of(-1, 1), Vector2D.of(2, 1), TEST_PRECISION));
181 
182         // one intersecting boundary
183         LinecastChecker2D.with(linecaster)
184             .expect(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
185             .whenGiven(Lines.segmentFromPoints(Vector2D.of(0.25, 1), Vector2D.of(2, 1), TEST_PRECISION));
186 
187         // no intersecting boundary
188         LinecastChecker2D.with(linecaster)
189             .expectNothing()
190             .whenGiven(Lines.segmentFromPoints(Vector2D.of(0.25, 1), Vector2D.of(0.75, 1), TEST_PRECISION));
191     }
192 
193     @Test
194     void testLinecast_segment_corners() {
195         // arrange
196         final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
197 
198         // act/assert
199 
200         // through corner
201         LinecastChecker2D.with(linecaster)
202             .expect(Vector2D.of(1, 1), Vector2D.Unit.PLUS_Y)
203             .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
204             .whenGiven(Lines.segmentFromPoints(Vector2D.of(0, 2), Vector2D.of(2, 0), TEST_PRECISION));
205 
206         // starts on corner
207         LinecastChecker2D.with(linecaster)
208             .expect(Vector2D.of(1, 1), Vector2D.Unit.PLUS_Y)
209             .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
210             .whenGiven(Lines.segmentFromPoints(Vector2D.of(1, 1), Vector2D.of(2, 0), TEST_PRECISION));
211 
212         // ends on corner
213         LinecastChecker2D.with(linecaster)
214             .expect(Vector2D.of(1, 1), Vector2D.Unit.PLUS_Y)
215             .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
216             .whenGiven(Lines.segmentFromPoints(Vector2D.of(0, 2), Vector2D.of(1, 1), TEST_PRECISION));
217     }
218 
219     @Test
220     void testLinecast_segment_removesDuplicatePoints() {
221         // arrange
222         final BoundarySource2D src = BoundarySource2D.of(
223                     Lines.segmentFromPoints(Vector2D.of(-1, -1), Vector2D.ZERO, TEST_PRECISION),
224                     Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.of(1, 1), TEST_PRECISION)
225                 );
226         final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(src);
227 
228         // act/assert
229         LinecastChecker2D.with(linecaster)
230             .expect(Vector2D.ZERO, Vector2D.Unit.from(1, -1))
231             .whenGiven(Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION));
232     }
233 }
234