1 package org.djutils.draw.line;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertTrue;
5 import static org.junit.Assert.fail;
6
7 import org.djutils.draw.DrawRuntimeException;
8 import org.djutils.draw.bounds.Bounds3d;
9 import org.djutils.draw.point.Point3d;
10 import org.junit.Test;
11
12
13
14
15
16
17
18
19
20
21 public class Ray3dTest
22 {
23
24
25
26 @Test
27 public void testConstructors()
28 {
29 verifyRay("Constructor from x, y, phi", new Ray3d(1, 2, 3, 4, 5), 1, 2, 3, 4, 5);
30 verifyRay("Constructor from Point3d, phi", new Ray3d(new Point3d(0.1, 0.2, 0.3), -0.4, -0.5), 0.1, 0.2, 0.3, -0.4,
31 -0.5);
32 verifyRay("Constructor from x, y, z, throughX, throughY, throughZ", new Ray3d(1, 2, 3, 4, 6, 15), 1, 2, 3,
33 Math.atan2(4, 3), Math.atan2(12, 5));
34 verifyRay("Constructor from x, y, z, throughX, throughY, throughZ", new Ray3d(1, 2, 3, 1, 6, 15), 1, 2, 3,
35 Math.atan2(4, 0), Math.atan2(12, 4));
36 verifyRay("Constructor from x, y, z, throughX, throughY, throughZ", new Ray3d(1, 2, 3, 1, 2, 15), 1, 2, 3,
37 Math.atan2(0, 0), Math.atan2(12, 0));
38 verifyRay("Constructor from Point3d, throughX, throughY, throughZ", new Ray3d(new Point3d(1, 2, 3), 4, 6, 15), 1, 2, 3,
39 Math.atan2(4, 3), Math.atan2(12, 5));
40 verifyRay("Constructor from Point3d, throughX, throughY, throughZ", new Ray3d(new Point3d(1, 2, 3), 1, 6, 15), 1, 2, 3,
41 Math.atan2(4, 0), Math.atan2(12, 4));
42 verifyRay("Constructor from Point3d, throughX, throughY, throughZ", new Ray3d(new Point3d(1, 2, 3), 1, 2, 15), 1, 2, 3,
43 Math.atan2(0, 0), Math.atan2(12, 0));
44 verifyRay("Constructor from x, y, z, Point3d", new Ray3d(1, 2, 3, new Point3d(4, 6, 15)), 1, 2, 3, Math.atan2(4, 3),
45 Math.atan2(12, 5));
46 verifyRay("Constructor from x, y, z, Point3d", new Ray3d(1, 2, 3, new Point3d(1, 6, 15)), 1, 2, 3, Math.atan2(4, 0),
47 Math.atan2(12, 4));
48 verifyRay("Constructor from x, y, z, Point3d", new Ray3d(1, 2, 3, new Point3d(1, 2, 15)), 1, 2, 3, Math.atan2(0, 0),
49 Math.atan2(12, 0));
50 verifyRay("Constructor from Point3d, Point3d", new Ray3d(new Point3d(1, 2, 3), new Point3d(4, 6, 15)), 1, 2, 3,
51 Math.atan2(4, 3), Math.atan2(12, 5));
52 verifyRay("Constructor from Point3d, Point3d", new Ray3d(new Point3d(1, 2, 3), new Point3d(1, 6, 15)), 1, 2, 3,
53 Math.atan2(4, 0), Math.atan2(12, 4));
54 verifyRay("Constructor from Point3d, Point3d", new Ray3d(new Point3d(1, 2, 3), new Point3d(1, 2, 15)), 1, 2, 3,
55 Math.atan2(0, 0), Math.atan2(12, 0));
56
57 try
58 {
59 new Ray3d(1, 2, 3, Double.NaN, 0);
60 fail("NaN for phy should have thrown a DrawRuntimeException");
61 }
62 catch (DrawRuntimeException dre)
63 {
64
65 }
66
67 try
68 {
69 new Ray3d(1, 2, 3, 0, Double.NaN);
70 fail("NaN for theta should have thrown a DrawRuntimeException");
71 }
72 catch (DrawRuntimeException dre)
73 {
74
75 }
76
77 try
78 {
79 new Ray3d(null, 1, 2);
80 fail("null for point should have thrown a NullPointerException");
81 }
82 catch (NullPointerException dre)
83 {
84
85 }
86
87 try
88 {
89 new Ray3d(1, 2, 3, 1, 2, 3);
90 fail("Same coordinates for through point should have thrown a DrawRuntimeException");
91 }
92 catch (DrawRuntimeException dre)
93 {
94
95 }
96
97 try
98 {
99 new Ray3d(1, 2, 3, new Point3d(1, 2, 3));
100 fail("Same coordinates for through point should have thrown a DrawRuntimeException");
101 }
102 catch (DrawRuntimeException dre)
103 {
104
105 }
106
107 try
108 {
109 new Ray3d(new Point3d(1, 2, 3), 1, 2, 3);
110 fail("Same coordinates for through point should have thrown a DrawRuntimeException");
111 }
112 catch (DrawRuntimeException dre)
113 {
114
115 }
116
117 try
118 {
119 new Ray3d(1, 2, 3, null);
120 fail("null for through point should have thrown a NullPointerException");
121 }
122 catch (NullPointerException dre)
123 {
124
125 }
126
127 try
128 {
129 new Ray3d(null, new Point3d(4, 5, 6));
130 fail("null for point should have thrown a NullPointerException");
131 }
132 catch (NullPointerException dre)
133 {
134
135 }
136
137 try
138 {
139 new Ray3d(new Point3d(1, 2, 3), null);
140 fail("null for through point should have thrown a NullPointerException");
141 }
142 catch (NullPointerException dre)
143 {
144
145 }
146
147 assertTrue("toString returns something descriptive", new Ray3d(1, 2, 3, 0.2, 0.3).toString().startsWith("Ray3d"));
148 }
149
150
151
152
153
154
155
156
157
158
159
160 private void verifyRay(final String description, final Ray3d ray, final double expectedX, final double expectedY,
161 final double expectedZ, final double expectedPhi, final double expectedTheta)
162 {
163 assertEquals(description + " getX", expectedX, ray.getX(), 0.0001);
164 assertEquals(description + " x", expectedX, ray.x, 0.0001);
165 assertEquals(description + " getY", expectedY, ray.getY(), 0.0001);
166 assertEquals(description + " y", expectedY, ray.y, 0.0001);
167 assertEquals(description + " getZ", expectedZ, ray.getZ(), 0.0001);
168 assertEquals(description + " z", expectedZ, ray.z, 0.0001);
169 assertEquals(description + " getPhi", expectedPhi, ray.getPhi(), 0.0001);
170 assertEquals(description + " phi", expectedPhi, ray.phi, 0.0001);
171 assertEquals(description + " getTheta", expectedTheta, ray.getTheta(), 0.0001);
172 assertEquals(description + " theta", expectedTheta, ray.theta, 0.0001);
173 Point3d startPoint = ray.getEndPoint();
174 assertEquals(description + " getStartPoint x", expectedX, startPoint.x, 0.0001);
175 assertEquals(description + " getStartPoint y", expectedY, startPoint.y, 0.0001);
176 assertEquals(description + " getStartPoint z", expectedZ, startPoint.z, 0.0001);
177 Ray3d negated = ray.neg();
178 assertEquals(description + " neg x", -expectedX, negated.x, 0.0001);
179 assertEquals(description + " neg y", -expectedY, negated.y, 0.0001);
180 assertEquals(description + " neg z", -expectedZ, negated.z, 0.0001);
181 assertEquals(description + " neg phi", expectedPhi + Math.PI, negated.phi, 0.0001);
182 assertEquals(description + " neg theta", expectedTheta + Math.PI, negated.theta, 0.0001);
183 }
184
185
186
187
188 @Test
189 public void boundsTest()
190 {
191
192 Bounds3d b = new Ray3d(1, 2, 3, 0, 0).getBounds();
193
194 assertEquals("Bounds minX", 1, b.getMinX(), 0);
195 assertEquals("Bounds.minY", 2, b.getMinY(), 0);
196 assertEquals("Bounds minZ", 3, b.getMinZ(), 0);
197 assertEquals("Bounds.maxX", Double.POSITIVE_INFINITY, b.getMaxX(), 0);
198 assertEquals("Bounds.maxY", 2, b.getMaxY(), 0);
199 assertEquals("Bounds.maxZ", 3, b.getMinZ(), 0);
200
201
202 b = new Ray3d(1, 2, 3, 0.2, 1.1).getBounds();
203 assertEquals("Bounds minX", 1, b.getMinX(), 0);
204 assertEquals("Bounds.minY", 2, b.getMinY(), 0);
205 assertEquals("Bounds.minZ", 3, b.getMinZ(), 0);
206 assertEquals("Bounds.maxX", Double.POSITIVE_INFINITY, b.getMaxX(), 0);
207 assertEquals("Bounds.maxY", Double.POSITIVE_INFINITY, b.getMaxY(), 0);
208 assertEquals("Bounds.maxZ", Double.POSITIVE_INFINITY, b.getMaxZ(), 0);
209
210
211 b = new Ray3d(1, 2, 3, Math.PI / 2, 0).getBounds();
212 assertEquals("Bounds minX", 1, b.getMinX(), 0);
213 assertEquals("Bounds.minY", 2, b.getMinY(), 0);
214 assertEquals("Bounds minZ", 3, b.getMinZ(), 0);
215 assertEquals("Bounds.maxX", Double.POSITIVE_INFINITY, b.getMaxX(), 0);
216 assertEquals("Bounds.maxY", Double.POSITIVE_INFINITY, b.getMaxY(), 0);
217 assertEquals("Bounds.maxZ", 3, b.getMinZ(), 0);
218
219
220 b = new Ray3d(1, 2, 3, 2, -1).getBounds();
221 assertEquals("Bounds minX", Double.NEGATIVE_INFINITY, b.getMinX(), 0);
222 assertEquals("Bounds.minY", 2, b.getMinY(), 0);
223 assertEquals("Bounds.minZ", Double.NEGATIVE_INFINITY, b.getMinZ(), 0);
224 assertEquals("Bounds.maxX", 1, b.getMaxX(), 0);
225 assertEquals("Bounds.maxY", Double.POSITIVE_INFINITY, b.getMaxY(), 0);
226 assertEquals("Bounds.maxZ", 3, b.getMaxZ(), 0);
227
228
229 b = new Ray3d(1, 2, 3, Math.PI, 0).getBounds();
230 assertEquals("Bounds minX", Double.NEGATIVE_INFINITY, b.getMinX(), 0);
231 assertEquals("Bounds.minY", 2, b.getMinY(), 0);
232 assertEquals("Bounds.maxX", 1, b.getMaxX(), 0);
233 assertEquals("Bounds.maxY", Double.POSITIVE_INFINITY, b.getMaxY(), 0);
234
235
236 b = new Ray3d(1, 2, 3, 4, 0).getBounds();
237 assertEquals("Bounds minX", Double.NEGATIVE_INFINITY, b.getMinX(), 0);
238 assertEquals("Bounds.minY", Double.NEGATIVE_INFINITY, b.getMinY(), 0);
239 assertEquals("Bounds.maxX", 1, b.getMaxX(), 0);
240 assertEquals("Bounds.maxY", 2, b.getMaxY(), 0);
241
242
243 b = new Ray3d(1, 2, 3, -1, 0).getBounds();
244 assertEquals("Bounds minX", 1, b.getMinX(), 0);
245 assertEquals("Bounds.minY", Double.NEGATIVE_INFINITY, b.getMinY(), 0);
246 assertEquals("Bounds.maxX", Double.POSITIVE_INFINITY, b.getMaxX(), 0);
247 assertEquals("Bounds.maxY", 2, b.getMaxY(), 0);
248
249
250 b = new Ray3d(1, 2, 3, -Math.PI / 2, 0).getBounds();
251 assertEquals("Bounds minX", 1, b.getMinX(), 0);
252 assertEquals("Bounds.minY", Double.NEGATIVE_INFINITY, b.getMinY(), 0);
253 assertEquals("Bounds.maxX", Double.POSITIVE_INFINITY, b.getMaxX(), 0);
254 assertEquals("Bounds.maxY", 2, b.getMaxY(), 0);
255
256
257 }
258
259
260
261
262 @Test
263 public void testLocation()
264 {
265 try
266 {
267 new Ray3d(1, 2, 3, 1, 0.5).getLocation(Double.NaN);
268 fail("NaN position should have thrown a DrawRuntimeException");
269 }
270 catch (DrawRuntimeException dre)
271 {
272
273 }
274
275 try
276 {
277 new Ray3d(1, 2, 3, 1, 0.5).getLocation(-1);
278 fail("Negative position should have thrown a DrawRuntimeException");
279 }
280 catch (DrawRuntimeException dre)
281 {
282
283 }
284
285 try
286 {
287 new Ray3d(1, 2, 3, 1, 0.5).getLocation(Double.POSITIVE_INFINITY);
288 fail("Infited position should have thrown a DrawRuntimeException");
289 }
290 catch (DrawRuntimeException dre)
291 {
292
293 }
294
295 try
296 {
297 new Ray3d(1, 2, 3, 1, 0.5).getLocation(Double.NEGATIVE_INFINITY);
298 fail("Infinte position should have thrown a DrawRuntimeException");
299 }
300 catch (DrawRuntimeException dre)
301 {
302
303 }
304
305 for (double phi : new double[] {0, 1, 2, 3, 4, 5, -1, -2, Math.PI})
306 {
307 for (double theta : new double[] {0, 1, 2, 3, 4, 5, -1, -2, Math.PI})
308 {
309 Ray3d ray = new Ray3d(1, 2, 3, phi, theta);
310 for (double position : new double[] {0, 10, 0.1, -2})
311 {
312 Ray3d result = ray.getLocationExtended(position);
313 assertEquals("result is position distance away from base of ray", Math.abs(position), ray.distance(result),
314 0.001);
315 assertEquals("result has same phi as ray", ray.phi, result.phi, 0.00001);
316 assertTrue("Reverse position on result yields ray",
317 ray.epsilonEquals(result.getLocationExtended(-position), 0.0001));
318 if (position > 0)
319 {
320
321 assertEquals("result lies in on ray (phi)", ray.phi, result.phi, 0.0001);
322 assertEquals("result lies on ray (theta)", ray.theta, result.theta, 0.0001);
323 }
324 if (position < 0)
325 {
326 assertEquals("ray lies on result (phi)", result.phi, ray.phi, 0.0001);
327 assertEquals("ray lies on result (theta)", result.theta, ray.theta, 0.0001);
328 }
329 }
330 }
331 }
332 }
333
334
335
336
337 @Test
338 public void testClosestPoint()
339 {
340 Ray3d ray = new Ray3d(1, 2, 3, 0.4, 0.5);
341 try
342 {
343 ray.closestPointOnLine(null);
344 fail("Null for point should have thrown a NullPointerException");
345 }
346 catch (NullPointerException npe)
347 {
348
349 }
350
351 Point3d result = ray.closestPointOnRay(new Point3d(1, 2, 0));
352 assertEquals("result is start point", ray.x, result.x, 0);
353 assertEquals("result is start point", ray.y, result.y, 0);
354 assertEquals("result is start point", ray.z, result.z, 0);
355 result = ray.closestPointOnRay(new Point3d(1, 2, 0));
356 assertEquals("result is start point", ray.x, result.x, 0);
357 assertEquals("result is start point", ray.y, result.y, 0);
358 assertEquals("result is start point", ray.z, result.z, 0);
359 result = ray.closestPointOnRay(new Point3d(0, 2, 3));
360 assertEquals("result is start point", ray.x, result.x, 0);
361 assertEquals("result is start point", ray.y, result.y, 0);
362 assertEquals("result is start point", ray.z, result.z, 0);
363 result = ray.closestPointOnRay(new Point3d(1, 2, 3));
364 assertEquals("result is start point", ray.x, result.x, 0);
365 assertEquals("result is start point", ray.y, result.y, 0);
366 assertEquals("result is start point", ray.z, result.z, 0);
367
368 Point3d projectingPoint = new Point3d(10, 10, 10);
369 result = ray.closestPointOnRay(projectingPoint);
370 double distance = result.distance(ray.getEndPoint());
371 assertTrue("distance from start is > 0", distance > 0);
372
373
374 assertTrue("Point on ray closer than result is further from projectingPoint",
375 ray.getLocation(distance - 0.1).distance(projectingPoint) < distance);
376 assertTrue("Point on ray further than result is further from projectingPoint",
377 ray.getLocation(distance + 0.1).distance(projectingPoint) < distance);
378 }
379
380
381
382
383 @Test
384 public void epsilonEqualsTest()
385 {
386 Ray3d ray = new Ray3d(1, 2, 3, 0.5, -0.5);
387 try
388 {
389 ray.epsilonEquals((Ray3d) null, 1, 1);
390 fail("Null pointer should have thrown a NullPointerException");
391 }
392 catch (NullPointerException npe)
393 {
394
395 }
396
397 try
398 {
399 ray.epsilonEquals(ray, -0.1, 1);
400 fail("Negative epsilonCoordinate should have thrown an IllegalArgumentException");
401 }
402 catch (IllegalArgumentException npe)
403 {
404
405 }
406
407 try
408 {
409 ray.epsilonEquals(ray, 1, -0.1);
410 fail("Negative epsilonDirection should have thrown an IllegalArgumentException");
411 }
412 catch (IllegalArgumentException npe)
413 {
414
415 }
416
417 try
418 {
419 ray.epsilonEquals(ray, Double.NaN, 1);
420 fail("NaN epsilonCoordinate should have thrown an IllegalArgumentException");
421 }
422 catch (IllegalArgumentException npe)
423 {
424
425 }
426
427 try
428 {
429 ray.epsilonEquals(ray, 1, Double.NaN);
430 fail("NaN epsilonDirection should have thrown an IllegalArgumentException");
431 }
432 catch (IllegalArgumentException npe)
433 {
434
435 }
436
437 double[] deltas = new double[] {0.0, -0.125, 0.125, -1, 1};
438 for (double dX : deltas)
439 {
440 for (double dY : deltas)
441 {
442 for (double dZ : deltas)
443 {
444 for (double dPhi : deltas)
445 {
446 for (double dTheta : deltas)
447 {
448 for (double epsilon : new double[] {0, 0.125, 0.5, 0.9, 1.0, 1.1})
449 {
450 Ray3d other = new Ray3d(ray.x + dX, ray.y + dY, ray.z + dZ, ray.phi + dPhi, ray.theta + dTheta);
451
452
453
454 boolean result = ray.epsilonEquals(other, epsilon, Double.POSITIVE_INFINITY);
455 boolean expected =
456 Math.abs(dX) <= epsilon && Math.abs(dY) <= epsilon && Math.abs(dZ) <= epsilon;
457 assertEquals("result of epsilonEquals checking x, y, z", expected, result);
458
459 result = ray.epsilonEquals(other, Double.POSITIVE_INFINITY, epsilon);
460 expected = Math.abs(dPhi) <= epsilon && Math.abs(dTheta) <= epsilon;
461 assertEquals("result of epsilonEquals checking phi and theta", expected, result);
462 }
463 }
464 }
465 }
466 }
467 }
468 }
469
470 }