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.core.precision.DoublePrecisionContext;
20  import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
21  import org.apache.commons.geometry.euclidean.twod.shape.Parallelogram;
22  import org.junit.Test;
23  
24  public class BoundarySourceLinecaster2DTest {
25  
26      private static final double TEST_EPS = 1e-10;
27  
28      private static final DoublePrecisionContext TEST_PRECISION =
29              new EpsilonDoublePrecisionContext(TEST_EPS);
30  
31      private static final BoundarySource2D UNIT_SQUARE =
32              Parallelogram.axisAligned(Vector2D.ZERO, Vector2D.of(1, 1), TEST_PRECISION);
33  
34      @Test
35      public void testLinecast_line_simple() {
36          // arrange
37          final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
38  
39          // act/assert
40  
41          // no intersections
42          LinecastChecker2D.with(linecaster)
43              .expectNothing()
44              .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0, 4), Vector2D.Unit.MINUS_X, TEST_PRECISION));
45  
46          // through center; two directions
47          LinecastChecker2D.with(linecaster)
48              .expect(Vector2D.of(0, 0.5), Vector2D.Unit.MINUS_X)
49              .and(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
50              .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0.5, 0.5), Vector2D.Unit.PLUS_X, TEST_PRECISION));
51  
52          LinecastChecker2D.with(linecaster)
53              .expect(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
54              .and(Vector2D.of(0, 0.5), Vector2D.Unit.MINUS_X)
55              .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0.5, 0.5), Vector2D.Unit.MINUS_X, TEST_PRECISION));
56      }
57  
58      @Test
59      public void testLinecast_line_alongFace() {
60          // arrange
61          final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
62  
63          // act/assert
64          LinecastChecker2D.with(linecaster)
65              .expect(Vector2D.of(0, 1), Vector2D.Unit.MINUS_X)
66              .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
67              .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0, 1), Vector2D.Unit.PLUS_X, TEST_PRECISION));
68      }
69  
70      @Test
71      public void testLinecast_line_corners() {
72          // arrange
73          final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
74  
75          // act/assert
76  
77          // through single corner vertex
78          LinecastChecker2D.with(linecaster)
79              .expect(Vector2D.of(1, 1), Vector2D.Unit.PLUS_Y)
80              .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
81              .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0, 2), Vector2D.of(1, -1), TEST_PRECISION));
82  
83          // through two corner vertices
84          LinecastChecker2D.with(linecaster)
85              .expect(Vector2D.ZERO, Vector2D.Unit.MINUS_X)
86              .and(Vector2D.ZERO, Vector2D.Unit.MINUS_Y)
87              .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_Y)
88              .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
89              .whenGiven(Lines.fromPointAndDirection(Vector2D.ZERO, Vector2D.of(1, 1), TEST_PRECISION));
90      }
91  
92      @Test
93      public void testLinecast_line_removesDuplicatePoints() {
94          // arrange
95          final BoundarySource2D src = BoundarySource2D.from(
96                      Lines.segmentFromPoints(Vector2D.of(-1, -1), Vector2D.ZERO, TEST_PRECISION),
97                      Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.of(1, 1), TEST_PRECISION)
98                  );
99          final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(src);
100 
101         // act/assert
102         LinecastChecker2D.with(linecaster)
103             .expect(Vector2D.ZERO, Vector2D.Unit.from(1, -1))
104             .whenGiven(Lines.fromPointAndDirection(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION));
105     }
106 
107     @Test
108     public void testLinecast_segment_simple() {
109         // arrange
110         final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
111 
112         // act/assert
113 
114         // no intersections; underlying line does not intersect
115         LinecastChecker2D.with(linecaster)
116             .expectNothing()
117             .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0, 4), Vector2D.Unit.MINUS_X, TEST_PRECISION)
118                     .segment(-10, 10));
119 
120         // no intersections; underlying line does intersect
121         LinecastChecker2D.with(linecaster)
122             .expectNothing()
123             .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0.5, 0.5), Vector2D.Unit.PLUS_X, TEST_PRECISION)
124                     .segment(2, 10));
125 
126         // no boundaries excluded; two directions
127         LinecastChecker2D.with(linecaster)
128             .expect(Vector2D.of(0, 0.5), Vector2D.Unit.MINUS_X)
129             .and(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
130             .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0.5, 0.5), Vector2D.Unit.PLUS_X, TEST_PRECISION)
131                     .segment(-10, 10));
132 
133         LinecastChecker2D.with(linecaster)
134             .expect(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
135             .and(Vector2D.of(0, 0.5), Vector2D.Unit.MINUS_X)
136             .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0.5, 0.5), Vector2D.Unit.MINUS_X, TEST_PRECISION)
137                     .segment(-10, 10));
138     }
139 
140     @Test
141     public void testLinecast_segment_boundaryExcluded() {
142         // arrange
143         final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
144 
145         // act/assert
146         final Vector2D center = Vector2D.of(0.5, 0.5);
147         LinecastChecker2D.with(linecaster)
148             .expect(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
149             .whenGiven(Lines.fromPointAndDirection(center, Vector2D.Unit.PLUS_X, TEST_PRECISION)
150                     .rayFrom(center));
151 
152         LinecastChecker2D.with(linecaster)
153             .expect(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
154             .whenGiven(Lines.fromPointAndDirection(center, Vector2D.Unit.MINUS_X, TEST_PRECISION)
155                     .reverseRayTo(center));
156     }
157 
158     @Test
159     public void testLinecast_segment_startEndPointsOnBoundaries() {
160         // arrange
161         final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
162 
163         // act/assert
164         LinecastChecker2D.with(linecaster)
165             .expect(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
166             .and(Vector2D.of(0, 0.5), Vector2D.Unit.MINUS_X)
167             .whenGiven(Lines.segmentFromPoints(Vector2D.of(1, 0.5), Vector2D.of(0, 0.5), TEST_PRECISION));
168     }
169 
170     @Test
171     public void testLinecast_segment_alongFace() {
172         // arrange
173         final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
174 
175         // act/assert
176 
177         // includes two intersecting boundaries
178         LinecastChecker2D.with(linecaster)
179             .expect(Vector2D.of(0, 1), Vector2D.Unit.MINUS_X)
180             .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
181             .whenGiven(Lines.segmentFromPoints(Vector2D.of(-1, 1), Vector2D.of(2, 1), TEST_PRECISION));
182 
183         // one intersecting boundary
184         LinecastChecker2D.with(linecaster)
185             .expect(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
186             .whenGiven(Lines.segmentFromPoints(Vector2D.of(0.25, 1), Vector2D.of(2, 1), TEST_PRECISION));
187 
188         // no intersecting boundary
189         LinecastChecker2D.with(linecaster)
190             .expectNothing()
191             .whenGiven(Lines.segmentFromPoints(Vector2D.of(0.25, 1), Vector2D.of(0.75, 1), TEST_PRECISION));
192     }
193 
194     @Test
195     public void testLinecast_segment_corners() {
196         // arrange
197         final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
198 
199         // act/assert
200 
201         // through corner
202         LinecastChecker2D.with(linecaster)
203             .expect(Vector2D.of(1, 1), Vector2D.Unit.PLUS_Y)
204             .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
205             .whenGiven(Lines.segmentFromPoints(Vector2D.of(0, 2), Vector2D.of(2, 0), TEST_PRECISION));
206 
207         // starts on corner
208         LinecastChecker2D.with(linecaster)
209             .expect(Vector2D.of(1, 1), Vector2D.Unit.PLUS_Y)
210             .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
211             .whenGiven(Lines.segmentFromPoints(Vector2D.of(1, 1), Vector2D.of(2, 0), TEST_PRECISION));
212 
213         // ends on corner
214         LinecastChecker2D.with(linecaster)
215             .expect(Vector2D.of(1, 1), Vector2D.Unit.PLUS_Y)
216             .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
217             .whenGiven(Lines.segmentFromPoints(Vector2D.of(0, 2), Vector2D.of(1, 1), TEST_PRECISION));
218     }
219 
220     @Test
221     public void testLinecast_segment_removesDuplicatePoints() {
222         // arrange
223         final BoundarySource2D src = BoundarySource2D.from(
224                     Lines.segmentFromPoints(Vector2D.of(-1, -1), Vector2D.ZERO, TEST_PRECISION),
225                     Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.of(1, 1), TEST_PRECISION)
226                 );
227         final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(src);
228 
229         // act/assert
230         LinecastChecker2D.with(linecaster)
231             .expect(Vector2D.ZERO, Vector2D.Unit.from(1, -1))
232             .whenGiven(Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION));
233     }
234 }
235