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.precision.DoublePrecisionContext;
21 import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
22 import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
23 import org.apache.commons.geometry.euclidean.oned.Interval;
24 import org.apache.commons.geometry.euclidean.threed.AffineTransformMatrix3D;
25 import org.apache.commons.geometry.euclidean.threed.Vector3D;
26 import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
27 import org.junit.Assert;
28 import org.junit.Test;
29
30 public class Ray3DTest {
31
32 private static final double TEST_EPS = 1e-10;
33
34 private static final DoublePrecisionContext TEST_PRECISION =
35 new EpsilonDoublePrecisionContext(TEST_EPS);
36
37 @Test
38 public void testFromPointAndDirection() {
39
40 final Vector3D pt = Vector3D.of(1, 1, 2);
41
42
43 final Ray3D ray = Lines3D.rayFromPointAndDirection(pt, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
44
45
46 Assert.assertTrue(ray.isInfinite());
47 Assert.assertFalse(ray.isFinite());
48
49 EuclideanTestUtils.assertCoordinatesEqual(pt, ray.getStartPoint(), TEST_EPS);
50 Assert.assertNull(ray.getEndPoint());
51
52 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.Unit.PLUS_Z, ray.getDirection(), TEST_EPS);
53
54 Assert.assertEquals(2, ray.getSubspaceStart(), TEST_EPS);
55 GeometryTestUtils.assertPositiveInfinity(ray.getSubspaceEnd());
56
57 GeometryTestUtils.assertPositiveInfinity(ray.getSize());
58
59 Assert.assertNull(ray.getCentroid());
60 Assert.assertNull(ray.getBounds());
61 }
62
63 @Test
64 public void testFromPointAndDirection_invalidArgs() {
65
66 final Vector3D pt = Vector3D.of(0, 2, 4);
67 final Vector3D dir = Vector3D.of(1e-11, 0, 0);
68
69
70 GeometryTestUtils.assertThrows(() -> {
71 Lines3D.rayFromPointAndDirection(pt, dir, TEST_PRECISION);
72 }, IllegalArgumentException.class, "Line direction cannot be zero");
73 }
74
75 @Test
76 public void testFromPoint() {
77
78 final Vector3D pt = Vector3D.of(-2, -1, 2);
79
80 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.of(1, 0, 2), Vector3D.Unit.PLUS_Y, TEST_PRECISION);
81
82
83 final Ray3D ray = Lines3D.rayFromPoint(line, pt);
84
85
86 Assert.assertTrue(ray.isInfinite());
87 Assert.assertFalse(ray.isFinite());
88
89 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, -1, 2), ray.getStartPoint(), TEST_EPS);
90 Assert.assertNull(ray.getEndPoint());
91
92 Assert.assertEquals(-1, ray.getSubspaceStart(), TEST_EPS);
93 GeometryTestUtils.assertPositiveInfinity(ray.getSubspaceEnd());
94
95 GeometryTestUtils.assertPositiveInfinity(ray.getSize());
96
97 Assert.assertNull(ray.getCentroid());
98 Assert.assertNull(ray.getBounds());
99 }
100
101 @Test
102 public void testFromPoint_invalidArgs() {
103
104 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.Unit.PLUS_X, TEST_PRECISION);
105
106
107 GeometryTestUtils.assertThrows(() -> {
108 Lines3D.rayFromPoint(line, Vector3D.NaN);
109 }, IllegalArgumentException.class, "Invalid ray start location: NaN");
110
111 GeometryTestUtils.assertThrows(() -> {
112 Lines3D.rayFromPoint(line, Vector3D.NEGATIVE_INFINITY);
113 }, IllegalArgumentException.class, "Invalid ray start location: NaN");
114
115 GeometryTestUtils.assertThrows(() -> {
116 Lines3D.rayFromPoint(line, Vector3D.POSITIVE_INFINITY);
117 }, IllegalArgumentException.class, "Invalid ray start location: NaN");
118 }
119
120 @Test
121 public void testFromLocation() {
122
123 final Line3D line = Lines3D.fromPointAndDirection(Vector3D.of(-1, 0, 0), Vector3D.Unit.PLUS_Z, TEST_PRECISION);
124
125
126 final Ray3D ray = Lines3D.rayFromLocation(line, -1);
127
128
129 Assert.assertTrue(ray.isInfinite());
130 Assert.assertFalse(ray.isFinite());
131
132 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(-1, 0, -1), ray.getStartPoint(), TEST_EPS);
133 Assert.assertNull(ray.getEndPoint());
134
135 Assert.assertEquals(-1, ray.getSubspaceStart(), TEST_EPS);
136 GeometryTestUtils.assertPositiveInfinity(ray.getSubspaceEnd());
137
138 GeometryTestUtils.assertPositiveInfinity(ray.getSize());
139
140 Assert.assertNull(ray.getCentroid());
141 Assert.assertNull(ray.getBounds());
142 }
143
144 @Test
145 public void testTransform() {
146
147 final AffineTransformMatrix3D t = QuaternionRotation.fromAxisAngle(Vector3D.Unit.PLUS_Y, 0.5 * Math.PI)
148 .toMatrix()
149 .translate(Vector3D.Unit.PLUS_Y);
150
151 final Ray3D ray = Lines3D.rayFromPointAndDirection(Vector3D.of(1, 0, 0), Vector3D.Unit.PLUS_X, TEST_PRECISION);
152
153
154 final Ray3D result = ray.transform(t);
155
156
157 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0, 1, -1), result.getStartPoint(), TEST_EPS);
158 Assert.assertNull(result.getEndPoint());
159
160 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.Unit.MINUS_Z, result.getDirection(), TEST_EPS);
161 }
162
163 @Test
164 public void testTransform_reflection() {
165
166 final AffineTransformMatrix3D t = QuaternionRotation.fromAxisAngle(Vector3D.Unit.PLUS_Y, 0.5 * Math.PI)
167 .toMatrix()
168 .translate(Vector3D.Unit.PLUS_Y)
169 .scale(1, 1, -2);
170
171 final Ray3D ray = Lines3D.rayFromPointAndDirection(Vector3D.of(1, 0, 0), Vector3D.Unit.PLUS_X, TEST_PRECISION);
172
173
174 final Ray3D result = ray.transform(t);
175
176
177 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0, 1, 2), result.getStartPoint(), TEST_EPS);
178 Assert.assertNull(result.getEndPoint());
179
180 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.Unit.PLUS_Z, result.getDirection(), TEST_EPS);
181 }
182
183 @Test
184 public void testContains() {
185
186 final Vector3D p0 = Vector3D.of(1, 1, 1);
187
188 final Vector3D delta = Vector3D.of(1e-12, 1e-12, 1e-12);
189
190 final Ray3D ray = Lines3D.rayFromPointAndDirection(Vector3D.of(1, 1, 1), Vector3D.Unit.PLUS_X, TEST_PRECISION);
191
192
193 Assert.assertFalse(ray.contains(Vector3D.of(2, 2, 2)));
194 Assert.assertFalse(ray.contains(Vector3D.of(0.9, 1, 1)));
195 Assert.assertFalse(ray.contains(Vector3D.of(-1, 1, 1)));
196
197 Assert.assertTrue(ray.contains(p0));
198 Assert.assertTrue(ray.contains(p0.subtract(delta)));
199
200 Assert.assertTrue(ray.contains(Vector3D.of(1000, 1, 1)));
201 }
202
203 @Test
204 public void testGetInterval() {
205
206 final Ray3D ray = Lines3D.rayFromPointAndDirection(Vector3D.of(2, -1, 3), Vector3D.Unit.PLUS_Y, TEST_PRECISION);
207
208
209 final Interval interval = ray.getInterval();
210
211
212 Assert.assertEquals(-1, interval.getMin(), TEST_EPS);
213 GeometryTestUtils.assertPositiveInfinity(interval.getMax());
214
215 Assert.assertSame(ray.getLine().getPrecision(), interval.getMinBoundary().getPrecision());
216 }
217
218 @Test
219 public void testToString() {
220
221 final Ray3D ray = Lines3D.rayFromPointAndDirection(Vector3D.ZERO, Vector3D.Unit.PLUS_X, TEST_PRECISION);
222
223
224 final String str = ray.toString();
225
226
227 GeometryTestUtils.assertContains("Ray3D[startPoint= (0", str);
228 GeometryTestUtils.assertContains(", direction= (1", str);
229 }
230 }