1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.geometry.euclidean.threed.line;
18
19 import org.apache.commons.geometry.core.GeometryTestUtils;
20 import org.apache.commons.geometry.core.Transform;
21 import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
22 import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
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.Vector1D;
26 import org.apache.commons.geometry.euclidean.threed.AffineTransformMatrix3D;
27 import org.apache.commons.geometry.euclidean.threed.Vector3D;
28 import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
29 import org.apache.commons.numbers.angle.PlaneAngleRadians;
30 import org.junit.Assert;
31 import org.junit.Test;
32
33 public class LineConvexSubset3DTest {
34
35 private static final double TEST_EPS = 1e-10;
36
37 private static final DoublePrecisionContext TEST_PRECISION =
38 new EpsilonDoublePrecisionContext(TEST_EPS);
39
40 @Test
41 public void testFromInterval_intervalArg_finite() {
42
43 final DoublePrecisionContext intervalPrecision = new EpsilonDoublePrecisionContext(1e-2);
44 final Interval interval = Interval.of(-1, 2, intervalPrecision);
45
46 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
47
48
49 final Segment3D segment = (Segment3D) Lines3D.subsetFromInterval(line, interval);
50
51
52 final double side = 1.0 / Math.sqrt(3);
53 checkFiniteSegment(segment, Vector3D.of(-side, -side, -side), Vector3D.of(2 * side, 2 * side, 2 * side));
54 }
55
56 @Test
57 public void testFromInterval_intervalArg_full() {
58
59 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
60
61
62 final LineConvexSubset3D span = Lines3D.subsetFromInterval(line, Interval.full());
63
64
65 Assert.assertTrue(span.isInfinite());
66 Assert.assertFalse(span.isFinite());
67
68 GeometryTestUtils.assertNegativeInfinity(span.getSubspaceStart());
69 GeometryTestUtils.assertPositiveInfinity(span.getSubspaceEnd());
70
71 Assert.assertNull(span.getStartPoint());
72 Assert.assertNull(span.getEndPoint());
73
74 Assert.assertSame(Interval.full(), span.getInterval());
75 }
76
77 @Test
78 public void testFromInterval_intervalArg_positiveHalfSpace() {
79
80 final DoublePrecisionContext intervalPrecision = new EpsilonDoublePrecisionContext(1e-2);
81 final Interval interval = Interval.min(-1, intervalPrecision);
82
83 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
84
85
86 final Ray3D ray = (Ray3D) Lines3D.subsetFromInterval(line, interval);
87
88
89 Assert.assertTrue(ray.isInfinite());
90 Assert.assertFalse(ray.isFinite());
91
92 Assert.assertEquals(-1.0, ray.getSubspaceStart(), TEST_EPS);
93 GeometryTestUtils.assertPositiveInfinity(ray.getSubspaceEnd());
94
95 final double side = 1.0 / Math.sqrt(3);
96
97 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(-side, -side, -side), ray.getStartPoint(), TEST_EPS);
98 Assert.assertNull(ray.getEndPoint());
99
100 checkInterval(interval, ray.getInterval());
101 }
102
103 @Test
104 public void testFromInterval_intervalArg_negativeHalfSpace() {
105
106 final DoublePrecisionContext intervalPrecision = new EpsilonDoublePrecisionContext(1e-2);
107 final Interval interval = Interval.max(2, intervalPrecision);
108
109 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
110
111
112 final ReverseRay3D halfLine = (ReverseRay3D) Lines3D.subsetFromInterval(line, interval);
113
114
115 GeometryTestUtils.assertNegativeInfinity(halfLine.getSubspaceStart());
116 Assert.assertEquals(2, halfLine.getSubspaceEnd(), TEST_EPS);
117
118 final double side = 1.0 / Math.sqrt(3);
119
120 Assert.assertNull(halfLine.getStartPoint());
121 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(2 * side, 2 * side, 2 * side), halfLine.getEndPoint(), TEST_EPS);
122
123 checkInterval(interval, halfLine.getInterval());
124 }
125
126 @Test
127 public void testFromInterval_doubleArgs_finite() {
128
129 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
130
131
132 final Segment3D segment = (Segment3D) Lines3D.subsetFromInterval(line, -1, 2);
133
134
135 final double side = 1.0 / Math.sqrt(3);
136 checkFiniteSegment(segment, Vector3D.of(-side, -side, -side), Vector3D.of(2 * side, 2 * side, 2 * side));
137 }
138
139 @Test
140 public void testFromInterval_doubleArgs_full() {
141
142 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
143
144
145 final LineConvexSubset3D span = Lines3D.subsetFromInterval(line, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
146
147
148 GeometryTestUtils.assertNegativeInfinity(span.getSubspaceStart());
149 GeometryTestUtils.assertPositiveInfinity(span.getSubspaceEnd());
150
151 Assert.assertNull(span.getStartPoint());
152 Assert.assertNull(span.getEndPoint());
153 }
154
155 @Test
156 public void testFromInterval_doubleArgs_positiveHalfSpace() {
157
158 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
159
160
161 final Ray3D ray = (Ray3D) Lines3D.subsetFromInterval(line, -1, Double.POSITIVE_INFINITY);
162
163
164 Assert.assertEquals(-1.0, ray.getSubspaceStart(), TEST_EPS);
165 GeometryTestUtils.assertPositiveInfinity(ray.getSubspaceEnd());
166
167 final double side = 1.0 / Math.sqrt(3);
168
169 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(-side, -side, -side), ray.getStartPoint(), TEST_EPS);
170 Assert.assertNull(ray.getEndPoint());
171 }
172
173 @Test
174 public void testFromInterval_doubleArgs_negativeHalfSpace() {
175
176 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
177
178
179 final ReverseRay3D halfLine = (ReverseRay3D) Lines3D.subsetFromInterval(line, 2, Double.NEGATIVE_INFINITY);
180
181
182 GeometryTestUtils.assertNegativeInfinity(halfLine.getSubspaceStart());
183 Assert.assertEquals(2, halfLine.getSubspaceEnd(), TEST_EPS);
184
185 final double side = 1.0 / Math.sqrt(3);
186
187 Assert.assertNull(halfLine.getStartPoint());
188 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(2 * side, 2 * side, 2 * side), halfLine.getEndPoint(), TEST_EPS);
189 }
190
191 @Test
192 public void testFromInterval_doubleArgs_invalidArgs() {
193
194 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
195
196
197 GeometryTestUtils.assertThrows(() -> {
198 Lines3D.subsetFromInterval(line, Double.NaN, 0);
199 }, IllegalArgumentException.class, "Invalid line convex subset interval: NaN, 0.0");
200
201 GeometryTestUtils.assertThrows(() -> {
202 Lines3D.subsetFromInterval(line, 0, Double.NaN);
203 }, IllegalArgumentException.class, "Invalid line convex subset interval: 0.0, NaN");
204
205 GeometryTestUtils.assertThrows(() -> {
206 Lines3D.subsetFromInterval(line, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
207 }, IllegalArgumentException.class, "Invalid line convex subset interval: Infinity, Infinity");
208
209 GeometryTestUtils.assertThrows(() -> {
210 Lines3D.subsetFromInterval(line, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
211 }, IllegalArgumentException.class, "Invalid line convex subset interval: -Infinity, -Infinity");
212 }
213
214 @Test
215 public void testFromInterval_vectorArgs() {
216
217 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
218
219
220 final Segment3D segment = (Segment3D) Lines3D.subsetFromInterval(line, Vector1D.of(-1), Vector1D.of(2));
221
222
223 final double side = 1.0 / Math.sqrt(3);
224 checkFiniteSegment(segment, Vector3D.of(-side, -side, -side), Vector3D.of(2 * side, 2 * side, 2 * side));
225 }
226
227 @Test
228 public void testSpaceSubspaceConversion() {
229
230 final Segment3D segment = Lines3D.segmentFromPoints(Vector3D.ZERO, Vector3D.Unit.PLUS_Y, TEST_PRECISION);
231
232
233 EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(3), segment.toSubspace(Vector3D.of(1, 3, 5)), TEST_EPS);
234 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0, 3, 0), segment.toSpace(Vector1D.of(3)), TEST_EPS);
235 }
236
237 @Test
238 public void testGetSubspaceRegion() {
239
240 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
241 final Interval interval = Interval.full();
242
243 final LineConvexSubset3D subset = Lines3D.subsetFromInterval(line, interval);
244
245
246 Assert.assertSame(interval, subset.getInterval());
247 Assert.assertSame(interval, subset.getSubspaceRegion());
248 }
249
250 @Test
251 public void testTransform_infinite() {
252
253 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.of(1, 0, 0), Vector3D.of(0, 1, -1), TEST_PRECISION);
254 final LineConvexSubset3D subset = Lines3D.subsetFromInterval(line,
255 Interval.min(line.toSubspace(Vector3D.of(1, 0, 0)).getX(), TEST_PRECISION));
256
257 final Transform<Vector3D> transform = AffineTransformMatrix3D.identity()
258 .scale(2, 1, 1)
259 .rotate(QuaternionRotation.fromAxisAngle(Vector3D.Unit.PLUS_Y, PlaneAngleRadians.PI_OVER_TWO));
260
261
262 final LineConvexSubset3D transformed = subset.transform(transform);
263
264
265 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0, 0, -2), transformed.getStartPoint(), TEST_EPS);
266 Assert.assertNull(transformed.getEndPoint());
267 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(-1, 1, 0).normalize(), transformed.getLine().getDirection(), TEST_EPS);
268 }
269
270 private static void checkInterval(final Interval expected, final Interval actual) {
271 Assert.assertEquals(expected.getMin(), actual.getMin(), TEST_EPS);
272 Assert.assertEquals(expected.getMax(), actual.getMax(), TEST_EPS);
273 }
274
275 private static void checkFiniteSegment(final LineConvexSubset3D subset, final Vector3D start, final Vector3D end) {
276 checkFiniteSegment(subset, start, end, TEST_PRECISION);
277 }
278
279 private static void checkFiniteSegment(final LineConvexSubset3D subset, final Vector3D start, final Vector3D end, final DoublePrecisionContext precision) {
280 Assert.assertFalse(subset.isInfinite());
281 Assert.assertTrue(subset.isFinite());
282
283 EuclideanTestUtils.assertCoordinatesEqual(start, subset.getStartPoint(), TEST_EPS);
284 EuclideanTestUtils.assertCoordinatesEqual(end, subset.getEndPoint(), TEST_EPS);
285
286 final Line3D line = subset.getLine();
287
288 Assert.assertEquals(line.toSubspace(subset.getStartPoint()).getX(), subset.getSubspaceStart(), TEST_EPS);
289 Assert.assertEquals(line.toSubspace(subset.getEndPoint()).getX(), subset.getSubspaceEnd(), TEST_EPS);
290
291 Assert.assertSame(precision, line.getPrecision());
292 }
293 }