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.euclidean.EuclideanTestUtils;
22 import org.apache.commons.geometry.euclidean.oned.Vector1D;
23 import org.apache.commons.geometry.euclidean.threed.AffineTransformMatrix3D;
24 import org.apache.commons.geometry.euclidean.threed.Vector3D;
25 import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
26 import org.apache.commons.numbers.angle.Angle;
27 import org.apache.commons.numbers.core.Precision;
28 import org.junit.jupiter.api.Assertions;
29 import org.junit.jupiter.api.Test;
30
31 class Line3DTest {
32
33 private static final double TEST_EPS = 1e-10;
34
35 private static final Precision.DoubleEquivalence TEST_PRECISION =
36 Precision.doubleEquivalenceOfEpsilon(TEST_EPS);
37
38 @Test
39 void testFromPointAndDirection() {
40
41 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.of(-1, 1, 0), Vector3D.Unit.PLUS_Y, TEST_PRECISION);
42
43
44 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(-1, 0, 0), line.getOrigin(), TEST_EPS);
45 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.Unit.PLUS_Y, line.getDirection(), TEST_EPS);
46 Assertions.assertSame(TEST_PRECISION, line.getPrecision());
47 }
48
49 @Test
50 void testFromPointAndDirection_normalizesDirection() {
51
52 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
53
54
55 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.ZERO, line.getOrigin(), TEST_EPS);
56
57 final double invSqrt3 = 1.0 / Math.sqrt(3);
58 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(invSqrt3, invSqrt3, invSqrt3), line.getDirection(), TEST_EPS);
59 Assertions.assertSame(TEST_PRECISION, line.getPrecision());
60 }
61
62 @Test
63 void testFromPointAndDirection_illegalDirectionNorm() {
64
65 GeometryTestUtils.assertThrowsWithMessage(() -> {
66 Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.ZERO, TEST_PRECISION);
67 }, IllegalArgumentException.class, "Line direction cannot be zero");
68
69 GeometryTestUtils.assertThrowsWithMessage(() -> {
70 Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1e-12, 1e-12, 1e-12), TEST_PRECISION);
71 }, IllegalArgumentException.class, "Line direction cannot be zero");
72 }
73
74 @Test
75 void testFromPoints() {
76
77 final Line3D line = Lines3D.fromPoints(Vector3D.of(-1, 1, 0), Vector3D.of(-1, 7, 0), TEST_PRECISION);
78
79
80 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(-1, 0, 0), line.getOrigin(), TEST_EPS);
81 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.Unit.PLUS_Y, line.getDirection(), TEST_EPS);
82 Assertions.assertSame(TEST_PRECISION, line.getPrecision());
83 }
84
85 @Test
86 void testFromPoints_pointsTooClose() {
87
88 Assertions.assertThrows(IllegalArgumentException.class, () -> Lines3D.fromPoints(Vector3D.of(1, 1, 1),
89 Vector3D.of(1, 1, 1 + 1e-16), TEST_PRECISION));
90 }
91
92 @Test
93 void testTransform() {
94
95 final Vector3D pt = Vector3D.of(1, 2, 3);
96 final Line3D line = Lines3D.fromPointAndDirection(pt, Vector3D.of(1, 1, 1), TEST_PRECISION);
97
98 final AffineTransformMatrix3D mat = AffineTransformMatrix3D.createRotation(pt,
99 QuaternionRotation.fromAxisAngle(Vector3D.Unit.PLUS_Y, Angle.PI_OVER_TWO));
100
101
102 final Line3D result = line.transform(mat);
103
104
105 Assertions.assertTrue(result.contains(pt));
106 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, 1, -1).normalize(), result.getDirection(), TEST_EPS);
107 }
108
109 @Test
110 void testTransform_reflectionInOneAxis() {
111
112 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.of(1, 0, 0), Vector3D.of(1, 1, 1), TEST_PRECISION);
113
114 final AffineTransformMatrix3D transform = AffineTransformMatrix3D.from(v -> Vector3D.of(v.getX(), v.getY(), -v.getZ()));
115
116
117 final Line3D result = line.transform(transform);
118
119
120 Assertions.assertTrue(result.contains(Vector3D.of(1, 0, 0)));
121 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, 1, -1).normalize(), result.getDirection(), TEST_EPS);
122 }
123
124 @Test
125 void testTransform_reflectionInTwoAxes() {
126
127 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.of(1, 0, 0), Vector3D.of(1, 1, 1), TEST_PRECISION);
128
129 final AffineTransformMatrix3D transform = AffineTransformMatrix3D.from(v -> Vector3D.of(v.getX(), -v.getY(), -v.getZ()));
130
131
132 final Line3D result = line.transform(transform);
133
134
135 Assertions.assertTrue(result.contains(Vector3D.of(1, 0, 0)));
136 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, -1, -1).normalize(), result.getDirection(), TEST_EPS);
137 }
138
139 @Test
140 void testTransform_reflectionInThreeAxes() {
141
142 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.of(1, 0, 0), Vector3D.of(1, 1, 1), TEST_PRECISION);
143
144 final AffineTransformMatrix3D transform = AffineTransformMatrix3D.from(Vector3D::negate);
145
146
147 final Line3D result = line.transform(transform);
148
149
150 Assertions.assertTrue(result.contains(Vector3D.of(-1, 0, 0)));
151 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(-1, -1, -1).normalize(), result.getDirection(), TEST_EPS);
152 }
153
154 @Test
155 void testSubspaceTransform() {
156
157 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.of(0, 0, 1), Vector3D.of(1, 0, 0), TEST_PRECISION);
158
159 final Transform<Vector3D> transform = AffineTransformMatrix3D.identity()
160 .scale(2, 1, 1)
161 .translate(0.5, 1, 0)
162 .rotate(QuaternionRotation.fromAxisAngle(Vector3D.Unit.PLUS_Y, Angle.PI_OVER_TWO));
163
164
165 final Line3D.SubspaceTransform result = line.subspaceTransform(transform);
166
167
168 final Line3D tLine = result.getLine();
169 final Transform<Vector1D> tSub = result.getTransform();
170
171 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, 1, 0), tLine.getOrigin(), TEST_EPS);
172 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0, 0, -1), tLine.getDirection(), TEST_EPS);
173
174 Assertions.assertEquals(0.5, tSub.apply(Vector1D.ZERO).getX(), TEST_EPS);
175 Assertions.assertEquals(4.5, tSub.apply(Vector1D.of(2)).getX(), TEST_EPS);
176 }
177
178 @Test
179 void testAbscissa() {
180
181 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.of(0, 0, -1), Vector3D.of(4, 3, 0), TEST_PRECISION);
182
183
184 Assertions.assertEquals(0.0, line.abscissa(line.getOrigin()), TEST_EPS);
185
186 Assertions.assertEquals(5.0, line.abscissa(Vector3D.of(4, 3, 0)), TEST_EPS);
187 Assertions.assertEquals(5.0, line.abscissa(Vector3D.of(4, 3, 10)), TEST_EPS);
188
189 Assertions.assertEquals(-5.0, line.abscissa(Vector3D.of(-4, -3, 0)), TEST_EPS);
190 Assertions.assertEquals(-5.0, line.abscissa(Vector3D.of(-4, -3, -10)), TEST_EPS);
191 }
192
193 @Test
194 void testToSubspace() {
195
196 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.of(0, 0, -1), Vector3D.of(4, 3, 0), TEST_PRECISION);
197
198
199 Assertions.assertEquals(0.0, line.toSubspace(line.getOrigin()).getX(), TEST_EPS);
200
201 Assertions.assertEquals(5.0, line.toSubspace(Vector3D.of(4, 3, -1)).getX(), TEST_EPS);
202 Assertions.assertEquals(5.0, line.toSubspace(Vector3D.of(4, 3, 10)).getX(), TEST_EPS);
203
204 Assertions.assertEquals(-5.0, line.toSubspace(Vector3D.of(-4, -3, -1)).getX(), TEST_EPS);
205 Assertions.assertEquals(-5.0, line.toSubspace(Vector3D.of(-4, -3, -10)).getX(), TEST_EPS);
206 }
207
208 @Test
209 void testPointAt() {
210
211 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.of(0, 0, -1), Vector3D.of(4, 3, 0), TEST_PRECISION);
212
213
214 EuclideanTestUtils.assertCoordinatesEqual(line.getOrigin(), line.pointAt(0.0), TEST_EPS);
215 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(4, 3, -1), line.pointAt(5.0), TEST_EPS);
216 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(-4, -3, -1), line.pointAt(-5.0), TEST_EPS);
217 }
218
219 @Test
220 void testToSpace() {
221
222 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.of(0, 0, -1), Vector3D.of(4, 3, 0), TEST_PRECISION);
223
224
225 EuclideanTestUtils.assertCoordinatesEqual(line.getOrigin(), line.toSpace(Vector1D.of(0.0)), TEST_EPS);
226 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(4, 3, -1), line.toSpace(Vector1D.of(5.0)), TEST_EPS);
227 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(-4, -3, -1), line.toSpace(Vector1D.of(-5.0)), TEST_EPS);
228 }
229
230 @Test
231 void testContains() {
232 final Vector3D p1 = Vector3D.of(0, 0, 1);
233 final Line3D l = Lines3D.fromPoints(p1, Vector3D.of(0, 0, 2), TEST_PRECISION);
234 Assertions.assertTrue(l.contains(p1));
235 Assertions.assertTrue(l.contains(Vector3D.Sum.of(p1).addScaled(0.3, l.getDirection()).get()));
236 final Vector3D u = l.getDirection().orthogonal();
237 final Vector3D v = l.getDirection().cross(u);
238 for (double alpha = 0; alpha < 2 * Math.PI; alpha += 0.3) {
239 Assertions.assertFalse(l.contains(p1.add(Vector3D.Sum.create().addScaled(Math.cos(alpha), u).addScaled(
240 Math.sin(alpha), v).get())));
241 }
242 }
243
244 @Test
245 void testSimilar() {
246 final Vector3D p1 = Vector3D.of(1.2, 3.4, -5.8);
247 final Vector3D p2 = Vector3D.of(3.4, -5.8, 1.2);
248 final Line3D lA = Lines3D.fromPoints(p1, p2, TEST_PRECISION);
249 final Line3D lB = Lines3D.fromPoints(p2, p1, TEST_PRECISION);
250 Assertions.assertTrue(lA.isSimilarTo(lB));
251 Assertions.assertFalse(lA.isSimilarTo(Lines3D.fromPoints(p1, p1.add(lA.getDirection().orthogonal()), TEST_PRECISION)));
252 }
253
254 @Test
255 void testPointDistance() {
256 final Line3D l = Lines3D.fromPoints(Vector3D.of(0, 1, 1), Vector3D.of(0, 2, 2), TEST_PRECISION);
257 Assertions.assertEquals(Math.sqrt(3.0 / 2.0), l.distance(Vector3D.of(1, 0, 1)), TEST_EPS);
258 Assertions.assertEquals(0, l.distance(Vector3D.of(0, -4, -4)), TEST_EPS);
259 }
260
261 @Test
262 void testLineDistance() {
263 final Line3D l = Lines3D.fromPoints(Vector3D.of(0, 1, 1), Vector3D.of(0, 2, 2), TEST_PRECISION);
264 Assertions.assertEquals(1.0,
265 l.distance(Lines3D.fromPoints(Vector3D.of(1, 0, 1), Vector3D.of(1, 0, 2), TEST_PRECISION)),
266 1.0e-10);
267 Assertions.assertEquals(0.5,
268 l.distance(Lines3D.fromPoints(Vector3D.of(-0.5, 0, 0), Vector3D.of(-0.5, -1, -1), TEST_PRECISION)),
269 1.0e-10);
270 Assertions.assertEquals(0.0,
271 l.distance(l),
272 1.0e-10);
273 Assertions.assertEquals(0.0,
274 l.distance(Lines3D.fromPoints(Vector3D.of(0, -4, -4), Vector3D.of(0, -5, -5), TEST_PRECISION)),
275 1.0e-10);
276 Assertions.assertEquals(0.0,
277 l.distance(Lines3D.fromPoints(Vector3D.of(0, -4, -4), Vector3D.of(0, -3, -4), TEST_PRECISION)),
278 1.0e-10);
279 Assertions.assertEquals(0.0,
280 l.distance(Lines3D.fromPoints(Vector3D.of(0, -4, -4), Vector3D.of(1, -4, -4), TEST_PRECISION)),
281 1.0e-10);
282 Assertions.assertEquals(Math.sqrt(8),
283 l.distance(Lines3D.fromPoints(Vector3D.of(0, -4, 0), Vector3D.of(1, -4, 0), TEST_PRECISION)),
284 1.0e-10);
285 }
286
287 @Test
288 void testClosest() {
289 final Line3D l = Lines3D.fromPoints(Vector3D.of(0, 1, 1), Vector3D.of(0, 2, 2), TEST_PRECISION);
290 Assertions.assertEquals(0.0,
291 l.closest(Lines3D.fromPoints(Vector3D.of(1, 0, 1), Vector3D.of(1, 0, 2), TEST_PRECISION)).distance(Vector3D.of(0, 0, 0)),
292 1.0e-10);
293 Assertions.assertEquals(0.5,
294 l.closest(Lines3D.fromPoints(Vector3D.of(-0.5, 0, 0), Vector3D.of(-0.5, -1, -1), TEST_PRECISION)).distance(Vector3D.of(-0.5, 0, 0)),
295 1.0e-10);
296 Assertions.assertEquals(0.0,
297 l.closest(l).distance(Vector3D.of(0, 0, 0)),
298 1.0e-10);
299 Assertions.assertEquals(0.0,
300 l.closest(Lines3D.fromPoints(Vector3D.of(0, -4, -4), Vector3D.of(0, -5, -5), TEST_PRECISION)).distance(Vector3D.of(0, 0, 0)),
301 1.0e-10);
302 Assertions.assertEquals(0.0,
303 l.closest(Lines3D.fromPoints(Vector3D.of(0, -4, -4), Vector3D.of(0, -3, -4), TEST_PRECISION)).distance(Vector3D.of(0, -4, -4)),
304 1.0e-10);
305 Assertions.assertEquals(0.0,
306 l.closest(Lines3D.fromPoints(Vector3D.of(0, -4, -4), Vector3D.of(1, -4, -4), TEST_PRECISION)).distance(Vector3D.of(0, -4, -4)),
307 1.0e-10);
308 Assertions.assertEquals(0.0,
309 l.closest(Lines3D.fromPoints(Vector3D.of(0, -4, 0), Vector3D.of(1, -4, 0), TEST_PRECISION)).distance(Vector3D.of(0, -2, -2)),
310 1.0e-10);
311 }
312
313 @Test
314 void testIntersection() {
315 final Line3D l = Lines3D.fromPoints(Vector3D.of(0, 1, 1), Vector3D.of(0, 2, 2), TEST_PRECISION);
316 Assertions.assertNull(l.intersection(Lines3D.fromPoints(Vector3D.of(1, 0, 1), Vector3D.of(1, 0, 2), TEST_PRECISION)));
317 Assertions.assertNull(l.intersection(Lines3D.fromPoints(Vector3D.of(-0.5, 0, 0), Vector3D.of(-0.5, -1, -1), TEST_PRECISION)));
318 Assertions.assertEquals(0.0,
319 l.intersection(l).distance(Vector3D.of(0, 0, 0)),
320 1.0e-10);
321 Assertions.assertEquals(0.0,
322 l.intersection(Lines3D.fromPoints(Vector3D.of(0, -4, -4), Vector3D.of(0, -5, -5), TEST_PRECISION)).distance(Vector3D.of(0, 0, 0)),
323 1.0e-10);
324 Assertions.assertEquals(0.0,
325 l.intersection(Lines3D.fromPoints(Vector3D.of(0, -4, -4), Vector3D.of(0, -3, -4), TEST_PRECISION)).distance(Vector3D.of(0, -4, -4)),
326 1.0e-10);
327 Assertions.assertEquals(0.0,
328 l.intersection(Lines3D.fromPoints(Vector3D.of(0, -4, -4), Vector3D.of(1, -4, -4), TEST_PRECISION)).distance(Vector3D.of(0, -4, -4)),
329 1.0e-10);
330 Assertions.assertNull(l.intersection(Lines3D.fromPoints(Vector3D.of(0, -4, 0), Vector3D.of(1, -4, 0), TEST_PRECISION)));
331 }
332
333 @Test
334 void testReverse() {
335
336 final Line3D line = Lines3D.fromPoints(Vector3D.of(1653345.6696423641, 6170370.041579291, 90000),
337 Vector3D.of(1650757.5050732433, 6160710.879908984, 0.9),
338 TEST_PRECISION);
339 final Vector3D expected = line.getDirection().negate();
340
341
342 final Line3D reversed = line.reverse();
343
344
345 EuclideanTestUtils.assertCoordinatesEqual(expected, reversed.getDirection(), TEST_EPS);
346 }
347
348 @Test
349 void testSpan() {
350
351 final Line3D line = Lines3D.fromPoints(Vector3D.ZERO, Vector3D.Unit.PLUS_X, TEST_PRECISION);
352
353
354 final LineConvexSubset3D span = line.span();
355
356
357 Assertions.assertTrue(span.isInfinite());
358 Assertions.assertFalse(span.isFinite());
359
360 Assertions.assertNull(span.getStartPoint());
361 Assertions.assertNull(span.getEndPoint());
362
363 Assertions.assertNull(span.getCentroid());
364 Assertions.assertNull(span.getBounds());
365
366 GeometryTestUtils.assertNegativeInfinity(span.getSubspaceStart());
367 GeometryTestUtils.assertPositiveInfinity(span.getSubspaceEnd());
368
369 GeometryTestUtils.assertPositiveInfinity(span.getSize());
370
371 Assertions.assertSame(line, span.getLine());
372 Assertions.assertTrue(span.getInterval().isFull());
373 }
374
375 @Test
376 void testSpan_contains() {
377
378 final double delta = 1e-12;
379
380 final LineConvexSubset3D span = Lines3D.fromPoints(Vector3D.ZERO, Vector3D.Unit.PLUS_X, TEST_PRECISION).span();
381
382 for (double x = -10; x <= 10; x += 0.5) {
383
384
385 Assertions.assertFalse(span.contains(Vector3D.of(0, 1, 0)));
386 Assertions.assertFalse(span.contains(Vector3D.of(0, 0, 1)));
387
388 Assertions.assertTrue(span.contains(Vector3D.of(x, 0, 0)));
389 Assertions.assertTrue(span.contains(Vector3D.of(x + delta, delta, delta)));
390 }
391 }
392
393 @Test
394 void testSpan_transform() {
395
396 final AffineTransformMatrix3D t = QuaternionRotation.fromAxisAngle(Vector3D.Unit.PLUS_Y, 0.5 * Math.PI)
397 .toMatrix()
398 .translate(Vector3D.Unit.PLUS_Y);
399
400 final LineConvexSubset3D span = Lines3D.fromPointAndDirection(Vector3D.of(1, 0, 0), Vector3D.Unit.PLUS_X, TEST_PRECISION)
401 .span();
402
403
404 final LineConvexSubset3D result = span.transform(t);
405
406
407 Assertions.assertNull(result.getStartPoint());
408 Assertions.assertNull(result.getEndPoint());
409
410 Assertions.assertTrue(result.contains(Vector3D.of(0, 1, -1)));
411 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.Unit.MINUS_Z, result.getLine().getDirection(), TEST_EPS);
412 }
413
414 @Test
415 void testSpan_transform_reflection() {
416
417 final AffineTransformMatrix3D t = QuaternionRotation.fromAxisAngle(Vector3D.Unit.PLUS_Y, 0.5 * Math.PI)
418 .toMatrix()
419 .translate(Vector3D.Unit.PLUS_Y)
420 .scale(1, 1, -2);
421
422 final LineConvexSubset3D span = Lines3D.fromPointAndDirection(Vector3D.of(1, 0, 0),
423 Vector3D.Unit.PLUS_X, TEST_PRECISION).span();
424
425
426 final LineConvexSubset3D result = span.transform(t);
427
428
429 Assertions.assertNull(result.getStartPoint());
430 Assertions.assertNull(result.getEndPoint());
431
432 Assertions.assertTrue(result.contains(Vector3D.of(0, 1, 2)));
433 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.Unit.PLUS_Z, result.getLine().getDirection(), TEST_EPS);
434 }
435
436 @Test
437 void testSpan_toString() {
438
439 final LineConvexSubset3D span = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.Unit.PLUS_X, TEST_PRECISION)
440 .span();
441
442
443 final String str = span.toString();
444
445
446 GeometryTestUtils.assertContains("LineSpanningSubset3D[origin= (0", str);
447 GeometryTestUtils.assertContains(", direction= (1", str);
448 }
449
450 @Test
451 void testSubsetMethods() {
452
453 final Line3D line = Lines3D.fromPoints(Vector3D.of(0, 3, 0), Vector3D.of(1, 3, 0), TEST_PRECISION);
454
455
456 final Segment3D doubleArgResult = line.segment(3, 4);
457 Assertions.assertSame(line, doubleArgResult.getLine());
458 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(3, 3, 0), doubleArgResult.getStartPoint(), TEST_EPS);
459 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(4, 3, 0), doubleArgResult.getEndPoint(), TEST_EPS);
460
461 final Segment3D ptArgResult = line.segment(Vector3D.of(0, 4, 0), Vector3D.of(2, 5, 1));
462 Assertions.assertSame(line, ptArgResult.getLine());
463 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0, 3, 0), ptArgResult.getStartPoint(), TEST_EPS);
464 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(2, 3, 0), ptArgResult.getEndPoint(), TEST_EPS);
465
466 final Ray3D rayDoubleResult = line.rayFrom(2);
467 Assertions.assertSame(line, rayDoubleResult.getLine());
468 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(2, 3, 0), rayDoubleResult.getStartPoint(), TEST_EPS);
469 Assertions.assertNull(rayDoubleResult.getEndPoint());
470
471 final Ray3D rayPtResult = line.rayFrom(Vector3D.of(1, 4, 0));
472 Assertions.assertSame(line, rayPtResult.getLine());
473 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, 3, 0), rayPtResult.getStartPoint(), TEST_EPS);
474 Assertions.assertNull(rayPtResult.getEndPoint());
475
476 final ReverseRay3D toDoubleResult = line.reverseRayTo(-1);
477 Assertions.assertSame(line, toDoubleResult.getLine());
478 Assertions.assertNull(toDoubleResult.getStartPoint());
479 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(-1, 3, 0), toDoubleResult.getEndPoint(), TEST_EPS);
480
481 final ReverseRay3D toPtResult = line.reverseRayTo(Vector3D.of(1, 4, 0));
482 Assertions.assertSame(line, toPtResult.getLine());
483 Assertions.assertNull(toPtResult.getStartPoint());
484 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, 3, 0), toPtResult.getEndPoint(), TEST_EPS);
485 }
486
487 @Test
488 void testEq() {
489
490 final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-3);
491
492 final Vector3D p = Vector3D.of(1, 2, 3);
493 final Vector3D dir = Vector3D.of(1, 0, 0);
494
495 final Line3D a = Lines3D.fromPointAndDirection(p, dir, precision);
496 final Line3D b = Lines3D.fromPointAndDirection(Vector3D.ZERO, dir, precision);
497 final Line3D c = Lines3D.fromPointAndDirection(p, Vector3D.of(1, 1, 0), precision);
498
499 final Line3D d = Lines3D.fromPointAndDirection(p, dir, precision);
500 final Line3D e = Lines3D.fromPointAndDirection(p.add(Vector3D.of(1e-4, 1e-4, 1e-4)), dir, precision);
501 final Line3D f = Lines3D.fromPointAndDirection(p, Vector3D.of(1 + 1e-4, 1e-4, 1e-4), precision);
502
503
504 Assertions.assertTrue(a.eq(a, precision));
505
506 Assertions.assertTrue(a.eq(d, precision));
507 Assertions.assertTrue(d.eq(a, precision));
508
509 Assertions.assertTrue(a.eq(e, precision));
510 Assertions.assertTrue(e.eq(a, precision));
511
512 Assertions.assertTrue(a.eq(f, precision));
513 Assertions.assertTrue(f.eq(a, precision));
514
515 Assertions.assertFalse(a.eq(b, precision));
516 Assertions.assertFalse(a.eq(c, precision));
517 }
518
519 @Test
520 void testHashCode() {
521
522 final Line3D a = Lines3D.fromPointAndDirection(Vector3D.of(1, 2, 3), Vector3D.of(4, 5, 6), TEST_PRECISION);
523 final Line3D b = Lines3D.fromPointAndDirection(Vector3D.of(1, 2, -1), Vector3D.of(4, 5, 6), TEST_PRECISION);
524 final Line3D c = Lines3D.fromPointAndDirection(Vector3D.of(1, 2, 3), Vector3D.of(4, 5, -1), TEST_PRECISION);
525 final Line3D d = Lines3D.fromPointAndDirection(Vector3D.of(1, 2, 3), Vector3D.of(4, 5, 6), Precision.doubleEquivalenceOfEpsilon(TEST_EPS + 1e-3));
526
527 final Line3D e = Lines3D.fromPointAndDirection(Vector3D.of(1, 2, 3), Vector3D.of(4, 5, 6), TEST_PRECISION);
528
529 final int hash = a.hashCode();
530
531
532 Assertions.assertEquals(hash, a.hashCode());
533
534 Assertions.assertNotEquals(hash, b.hashCode());
535 Assertions.assertNotEquals(hash, c.hashCode());
536 Assertions.assertNotEquals(hash, d.hashCode());
537
538 Assertions.assertEquals(hash, e.hashCode());
539 }
540
541 @Test
542 void testEquals() {
543
544 final Line3D a = Lines3D.fromPointAndDirection(Vector3D.of(1, 2, 3), Vector3D.of(4, 5, 6), TEST_PRECISION);
545 final Line3D b = Lines3D.fromPointAndDirection(Vector3D.of(1, 2, -1), Vector3D.of(4, 5, 6), TEST_PRECISION);
546 final Line3D c = Lines3D.fromPointAndDirection(Vector3D.of(1, 2, 3), Vector3D.of(4, 5, -1), TEST_PRECISION);
547 final Line3D d = Lines3D.fromPointAndDirection(Vector3D.of(1, 2, 3), Vector3D.of(4, 5, 6), Precision.doubleEquivalenceOfEpsilon(TEST_EPS + 1e-3));
548
549 final Line3D e = Lines3D.fromPointAndDirection(Vector3D.of(1, 2, 3), Vector3D.of(4, 5, 6), TEST_PRECISION);
550
551
552 GeometryTestUtils.assertSimpleEqualsCases(a);
553
554 Assertions.assertNotEquals(a, b);
555 Assertions.assertNotEquals(a, c);
556 Assertions.assertNotEquals(a, d);
557
558 Assertions.assertEquals(a, e);
559 Assertions.assertEquals(e, a);
560 }
561
562 @Test
563 void testToString() {
564
565 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.Unit.PLUS_X, TEST_PRECISION);
566
567
568 final String str = line.toString();
569
570
571 Assertions.assertTrue(str.contains("Line3D"));
572 Assertions.assertTrue(str.matches(".*origin= \\(0(\\.0)?, 0(\\.0)?, 0(\\.0)?\\).*"));
573 Assertions.assertTrue(str.matches(".*direction= \\(1(\\.0)?, 0(\\.0)?, 0(\\.0)?\\).*"));
574 }
575 }