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.GeometryTestUtils;
20  import org.apache.commons.geometry.core.RegionLocation;
21  import org.apache.commons.geometry.core.partitioning.Split;
22  import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
23  import org.apache.commons.geometry.euclidean.oned.Interval;
24  import org.apache.commons.numbers.core.Precision;
25  import org.junit.jupiter.api.Assertions;
26  import org.junit.jupiter.api.Test;
27  
28  class LineSpanningSubsetTest {
29  
30      private static final double TEST_EPS = 1e-10;
31  
32      private static final Precision.DoubleEquivalence TEST_PRECISION =
33              Precision.doubleEquivalenceOfEpsilon(TEST_EPS);
34  
35      @Test
36      void testProperties() {
37          // arrange
38          final Line line = Lines.fromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION);
39  
40          // act
41          final LineSpanningSubset result = new LineSpanningSubset(line);
42  
43          // assert
44          Assertions.assertSame(line, result.getHyperplane());
45          Assertions.assertSame(line, result.getLine());
46  
47          Assertions.assertTrue(result.isFull());
48          Assertions.assertFalse(result.isEmpty());
49          Assertions.assertTrue(result.isInfinite());
50          Assertions.assertFalse(result.isFinite());
51  
52          GeometryTestUtils.assertPositiveInfinity(result.getSize());
53          Assertions.assertNull(result.getCentroid());
54          Assertions.assertNull(result.getBounds());
55  
56          Assertions.assertNull(result.getStartPoint());
57          GeometryTestUtils.assertNegativeInfinity(result.getSubspaceStart());
58          Assertions.assertNull(result.getEndPoint());
59          GeometryTestUtils.assertPositiveInfinity(result.getSubspaceEnd());
60      }
61  
62      @Test
63      void testTransform() {
64          // arrange
65          final AffineTransformMatrix2D t = AffineTransformMatrix2D.createRotation(-0.5 * Math.PI)
66                  .translate(Vector2D.Unit.PLUS_X)
67                  .scale(1, -1);
68  
69          final LineConvexSubset span =
70                  Lines.fromPointAndDirection(Vector2D.of(1, 0), Vector2D.Unit.PLUS_X, TEST_PRECISION).span();
71  
72          // act
73          final LineConvexSubset result = span.transform(t);
74  
75          // assert
76          EuclideanTestUtils.assertCoordinatesEqual(Vector2D.Unit.PLUS_Y, result.getLine().getDirection(), TEST_EPS);
77      }
78  
79      @Test
80      void testReverse() {
81          // arrange
82          final LineConvexSubset span =
83                  Lines.fromPointAndDirection(Vector2D.of(1, 2), Vector2D.Unit.PLUS_X, TEST_PRECISION).span();
84  
85          // act
86          final LineConvexSubset rev = span.reverse();
87  
88          // assert
89          EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, 2), rev.getLine().getOrigin(), TEST_EPS);
90          EuclideanTestUtils.assertCoordinatesEqual(Vector2D.Unit.MINUS_X, rev.getLine().getDirection(), TEST_EPS);
91      }
92  
93      @Test
94      void testClosest() {
95          // arrange
96          final Vector2D p1 = Vector2D.of(0, -1);
97          final Vector2D p2 = Vector2D.of(0, 1);
98          final LineConvexSubset span =
99                  Lines.fromPointAndDirection(p1, p1.directionTo(p2), TEST_PRECISION).span();
100 
101         // act/assert
102         EuclideanTestUtils.assertCoordinatesEqual(p1, span.closest(p1), TEST_EPS);
103         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, -2), span.closest(Vector2D.of(0, -2)), TEST_EPS);
104         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, -2), span.closest(Vector2D.of(2, -2)), TEST_EPS);
105         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, -1), span.closest(Vector2D.of(-1, -1)), TEST_EPS);
106 
107         EuclideanTestUtils.assertCoordinatesEqual(p2, span.closest(p2), TEST_EPS);
108         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, 2), span.closest(Vector2D.of(0, 2)), TEST_EPS);
109         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, 2), span.closest(Vector2D.of(-2, 2)), TEST_EPS);
110         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, 1), span.closest(Vector2D.of(-1, 1)), TEST_EPS);
111 
112         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.ZERO, span.closest(Vector2D.ZERO), TEST_EPS);
113         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, 0.5), span.closest(Vector2D.of(1, 0.5)), TEST_EPS);
114         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, -0.5), span.closest(Vector2D.of(-2, -0.5)), TEST_EPS);
115     }
116 
117     @Test
118     void testClassify() {
119         // arrange
120         final LineConvexSubset span =
121                 Lines.fromPointAndDirection(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X, TEST_PRECISION).span();
122 
123         // act/assert
124         for (double x = -10; x <= 10; x += 1) {
125             EuclideanTestUtils.assertRegionLocation(span, RegionLocation.INSIDE, Vector2D.of(x, 1 + 1e-11));
126 
127             EuclideanTestUtils.assertRegionLocation(span, RegionLocation.OUTSIDE,
128                     Vector2D.of(x, 0), Vector2D.of(x, 2));
129         }
130     }
131 
132     @Test
133     void testSplit() {
134         // --- arrange
135         final Vector2D pt = Vector2D.of(1, 1);
136 
137         final LineConvexSubset span = Lines.fromPointAndDirection(pt, Vector2D.Unit.PLUS_X, TEST_PRECISION).span();
138 
139         // --- act
140         Split<LineConvexSubset> split;
141 
142         // parallel
143         split = span.split(Lines.fromPointAndAngle(Vector2D.of(2, 2), 0, TEST_PRECISION));
144         Assertions.assertNull(split.getMinus());
145         Assertions.assertSame(span, split.getPlus());
146 
147         split = span.split(Lines.fromPointAndAngle(Vector2D.of(2, 2), Math.PI, TEST_PRECISION));
148         Assertions.assertSame(span, split.getMinus());
149         Assertions.assertNull(split.getPlus());
150 
151         // coincident
152         split = span.split(Lines.fromPointAndDirection(pt, Vector2D.Unit.PLUS_X, TEST_PRECISION));
153         Assertions.assertNull(split.getMinus());
154         Assertions.assertNull(split.getPlus());
155 
156         // through point on line
157         checkSplit(span.split(Lines.fromPointAndAngle(pt, 1, TEST_PRECISION)),
158                 null, pt,
159                 pt, null);
160         checkSplit(span.split(Lines.fromPointAndAngle(pt, -1, TEST_PRECISION)),
161                 pt, null,
162                 null, pt);
163     }
164 
165     @Test
166     void testGetInterval() {
167         // arrange
168         final LineConvexSubset span =
169                 Lines.fromPointAndDirection(Vector2D.of(2, -1), Vector2D.Unit.PLUS_X, TEST_PRECISION).span();
170 
171         // act
172         final Interval interval = span.getInterval();
173 
174         // assert
175         GeometryTestUtils.assertNegativeInfinity(interval.getMin());
176         GeometryTestUtils.assertPositiveInfinity(interval.getMax());
177     }
178 
179     @Test
180     void testToString() {
181         // arrange
182         final LineConvexSubset span =
183                 Lines.fromPointAndDirection(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION).span();
184 
185         // act
186         final String str = span.toString();
187 
188         // assert
189         GeometryTestUtils.assertContains("LineSpanningSubset[origin= (0", str);
190         GeometryTestUtils.assertContains(", direction= (1", str);
191     }
192 
193     private static void checkSplit(final Split<LineConvexSubset> split, final Vector2D minusStart, final Vector2D minusEnd,
194                                    final Vector2D plusStart, final Vector2D plusEnd) {
195 
196         final LineConvexSubset minus = split.getMinus();
197         if (minusStart == null && minusEnd == null) {
198             Assertions.assertNull(minus);
199         } else {
200             checkPoint(minusStart, minus.getStartPoint());
201             checkPoint(minusEnd, minus.getEndPoint());
202         }
203 
204 
205         final LineConvexSubset plus = split.getPlus();
206         if (plusStart == null && plusEnd == null) {
207             Assertions.assertNull(plus);
208         } else {
209             checkPoint(plusStart, plus.getStartPoint());
210             checkPoint(plusEnd, plus.getEndPoint());
211         }
212     }
213 
214     private static void checkPoint(final Vector2D expected, final Vector2D pt) {
215         if (expected == null) {
216             Assertions.assertNull(pt);
217         } else {
218             EuclideanTestUtils.assertCoordinatesEqual(expected, pt, TEST_EPS);
219         }
220     }
221 }