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.threed.line;
18  
19  import java.util.List;
20  
21  import org.apache.commons.geometry.core.GeometryTestUtils;
22  import org.apache.commons.geometry.core.Transform;
23  import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
24  import org.apache.commons.geometry.euclidean.oned.Interval;
25  import org.apache.commons.geometry.euclidean.oned.RegionBSPTree1D;
26  import org.apache.commons.geometry.euclidean.threed.AffineTransformMatrix3D;
27  import org.apache.commons.geometry.euclidean.threed.Bounds3D;
28  import org.apache.commons.geometry.euclidean.threed.Vector3D;
29  import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
30  import org.apache.commons.numbers.angle.Angle;
31  import org.apache.commons.numbers.core.Precision;
32  import org.junit.jupiter.api.Assertions;
33  import org.junit.jupiter.api.Test;
34  
35  class EmbeddedTreeLineSubset3DTest {
36  
37      private static final double TEST_EPS = 1e-10;
38  
39      private static final Precision.DoubleEquivalence TEST_PRECISION =
40              Precision.doubleEquivalenceOfEpsilon(TEST_EPS);
41  
42      private final Line3D testLine = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 0), TEST_PRECISION);
43  
44      @Test
45      void testCtor_default() {
46          // act
47          final EmbeddedTreeLineSubset3D sub = new EmbeddedTreeLineSubset3D(testLine);
48  
49          // assert
50          Assertions.assertSame(testLine, sub.getLine());
51          Assertions.assertTrue(sub.getSubspaceRegion().isEmpty());
52          Assertions.assertEquals(0, sub.getSize(), TEST_EPS);
53      }
54  
55      @Test
56      void testCtor_true() {
57          // act
58          final EmbeddedTreeLineSubset3D sub = new EmbeddedTreeLineSubset3D(testLine, true);
59  
60          // assert
61          Assertions.assertSame(testLine, sub.getLine());
62          Assertions.assertTrue(sub.getSubspaceRegion().isFull());
63          GeometryTestUtils.assertPositiveInfinity(sub.getSize());
64      }
65  
66      @Test
67      void testCtor_false() {
68          // act
69          final EmbeddedTreeLineSubset3D sub = new EmbeddedTreeLineSubset3D(testLine, false);
70  
71          // assert
72          Assertions.assertSame(testLine, sub.getLine());
73          Assertions.assertTrue(sub.getSubspaceRegion().isEmpty());
74          Assertions.assertEquals(0, sub.getSize(), TEST_EPS);
75      }
76  
77      @Test
78      void testCtor_lineAndRegion() {
79          // arrange
80          final RegionBSPTree1D tree = RegionBSPTree1D.empty();
81  
82          // act
83          final EmbeddedTreeLineSubset3D sub = new EmbeddedTreeLineSubset3D(testLine, tree);
84  
85          // assert
86          Assertions.assertSame(testLine, sub.getLine());
87          Assertions.assertSame(tree, sub.getSubspaceRegion());
88          Assertions.assertEquals(0, sub.getSize(), TEST_EPS);
89      }
90  
91      @Test
92      void testProperties_full() {
93          // arrange
94          final EmbeddedTreeLineSubset3D full = new EmbeddedTreeLineSubset3D(testLine, true);
95  
96          // act/assert
97          Assertions.assertTrue(full.isInfinite());
98          Assertions.assertFalse(full.isFinite());
99  
100         GeometryTestUtils.assertPositiveInfinity(full.getSize());
101         Assertions.assertNull(full.getCentroid());
102         Assertions.assertNull(full.getBounds());
103     }
104 
105     @Test
106     void testProperties_empty() {
107         // arrange
108         final EmbeddedTreeLineSubset3D empty = new EmbeddedTreeLineSubset3D(testLine, false);
109 
110         // act/assert
111         Assertions.assertFalse(empty.isInfinite());
112         Assertions.assertTrue(empty.isFinite());
113 
114         Assertions.assertEquals(0, empty.getSize(), TEST_EPS);
115         Assertions.assertNull(empty.getCentroid());
116         Assertions.assertNull(empty.getBounds());
117     }
118 
119     @Test
120     void testProperties_half() {
121         // arrange
122         final EmbeddedTreeLineSubset3D half = new EmbeddedTreeLineSubset3D(testLine, false);
123         half.getSubspaceRegion().add(Interval.min(1, TEST_PRECISION));
124 
125         // act/assert
126         Assertions.assertTrue(half.isInfinite());
127         Assertions.assertFalse(half.isFinite());
128 
129         GeometryTestUtils.assertPositiveInfinity(half.getSize());
130         Assertions.assertNull(half.getCentroid());
131         Assertions.assertNull(half.getBounds());
132     }
133 
134     @Test
135     void testProperties_finite() {
136         // arrange
137         final Line3D line = Lines3D.fromPointAndDirection(Vector3D.of(0, 0, 1), Vector3D.of(1, 1, 0), TEST_PRECISION);
138         final EmbeddedTreeLineSubset3D sub = new EmbeddedTreeLineSubset3D(line);
139 
140         final double sqrt2 = Math.sqrt(2);
141         sub.getSubspaceRegion().add(Interval.of(0, sqrt2, TEST_PRECISION));
142         sub.getSubspaceRegion().add(Interval.of(-2 * sqrt2, -sqrt2, TEST_PRECISION));
143 
144         // act/assert
145         Assertions.assertFalse(sub.isInfinite());
146         Assertions.assertTrue(sub.isFinite());
147 
148         Assertions.assertEquals(2 * sqrt2, sub.getSize(), TEST_EPS);
149         EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(-0.5, -0.5, 1), sub.getCentroid(), TEST_EPS);
150 
151         final Bounds3D bounds = sub.getBounds();
152         EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(-2, -2, 1), bounds.getMin(), TEST_EPS);
153         EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, 1, 1), bounds.getMax(), TEST_EPS);
154     }
155 
156     @Test
157     void testTransform_full() {
158         // arrange
159         final EmbeddedTreeLineSubset3D sub = new EmbeddedTreeLineSubset3D(testLine, true);
160 
161         final Transform<Vector3D> transform = AffineTransformMatrix3D.identity()
162                 .translate(Vector3D.of(1, 0, 0))
163                 .scale(Vector3D.of(2, 1, 1))
164                 .rotate(QuaternionRotation.fromAxisAngle(Vector3D.Unit.PLUS_Y, Angle.PI_OVER_TWO));
165 
166         // act
167         final EmbeddedTreeLineSubset3D result = sub.transform(transform);
168 
169         // assert
170         final Line3D resultLine = result.getLine();
171 
172         final Vector3D expectedOrigin = Lines3D.fromPoints(Vector3D.of(0, 0, -2), Vector3D.of(0, 1, -4), TEST_PRECISION)
173                 .getOrigin();
174 
175         EuclideanTestUtils.assertCoordinatesEqual(expectedOrigin, resultLine.getOrigin(), TEST_EPS);
176         EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0, 1, -2).normalize(), resultLine.getDirection(), TEST_EPS);
177 
178         Assertions.assertTrue(result.getSubspaceRegion().isFull());
179     }
180 
181     @Test
182     void testTransform_finite() {
183         // arrange
184         final RegionBSPTree1D tree = RegionBSPTree1D.empty();
185         tree.add(Interval.of(
186                 testLine.toSubspace(Vector3D.of(1, 1, 0)).getX(),
187                 testLine.toSubspace(Vector3D.of(2, 2, 0)).getX(), TEST_PRECISION));
188 
189         final EmbeddedTreeLineSubset3D sub = new EmbeddedTreeLineSubset3D(testLine, tree);
190 
191         final Transform<Vector3D> transform = AffineTransformMatrix3D.identity()
192                 .translate(Vector3D.of(1, 0, 0))
193                 .scale(Vector3D.of(2, 1, 1))
194                 .rotate(QuaternionRotation.fromAxisAngle(Vector3D.Unit.PLUS_Y, Angle.PI_OVER_TWO));
195 
196         // act
197         final EmbeddedTreeLineSubset3D result = sub.transform(transform);
198 
199         // assert
200         final Line3D resultLine = result.getLine();
201 
202         final Vector3D expectedOrigin = Lines3D.fromPoints(Vector3D.of(0, 0, -2), Vector3D.of(0, 1, -4), TEST_PRECISION)
203                 .getOrigin();
204 
205         EuclideanTestUtils.assertCoordinatesEqual(expectedOrigin, resultLine.getOrigin(), TEST_EPS);
206         EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0, 1, -2).normalize(), resultLine.getDirection(), TEST_EPS);
207 
208         Assertions.assertFalse(result.getSubspaceRegion().isFull());
209 
210         final List<Interval> intervals = result.getSubspaceRegion().toIntervals();
211         Assertions.assertEquals(1, intervals.size());
212 
213         final Interval resultInterval = intervals.get(0);
214         EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0, 1, -4),
215                 resultLine.toSpace(resultInterval.getMin()), TEST_EPS);
216         EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0, 2, -6),
217                 resultLine.toSpace(resultInterval.getMax()), TEST_EPS);
218     }
219 
220     @Test
221     void testToConvex_full() {
222         // arrange
223         final EmbeddedTreeLineSubset3D sub = new EmbeddedTreeLineSubset3D(testLine, true);
224 
225         // act
226         final List<LineConvexSubset3D> segments = sub.toConvex();
227 
228         // assert
229         Assertions.assertEquals(1, segments.size());
230         Assertions.assertTrue(segments.get(0).getSubspaceRegion().isFull());
231     }
232 
233     @Test
234     void testToConvex_finite() {
235         // arrange
236         final RegionBSPTree1D tree = RegionBSPTree1D.empty();
237         tree.add(Interval.of(
238                 testLine.toSubspace(Vector3D.of(1, 1, 0)).getX(),
239                 testLine.toSubspace(Vector3D.of(2, 2, 0)).getX(), TEST_PRECISION));
240 
241         final EmbeddedTreeLineSubset3D sub = new EmbeddedTreeLineSubset3D(testLine, tree);
242 
243         // act
244         final List<LineConvexSubset3D> segments = sub.toConvex();
245 
246         // assert
247         Assertions.assertEquals(1, segments.size());
248 
249         final LineConvexSubset3D segment = segments.get(0);
250         EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, 1, 0), segment.getStartPoint(), TEST_EPS);
251         EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(2, 2, 0), segment.getEndPoint(), TEST_EPS);
252     }
253 
254     @Test
255     void testToString() {
256         // arrange
257         final EmbeddedTreeLineSubset3D sub = new EmbeddedTreeLineSubset3D(testLine);
258 
259         // act
260         final String str = sub.toString();
261 
262         // assert
263         Assertions.assertTrue(str.contains("EmbeddedTreeLineSubset3D[lineOrigin= "));
264         Assertions.assertTrue(str.contains(", lineDirection= "));
265         Assertions.assertTrue(str.contains(", region= "));
266     }
267 }