1 package org.djutils.draw.line;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertFalse;
5 import static org.junit.Assert.assertNotEquals;
6 import static org.junit.Assert.assertNull;
7 import static org.junit.Assert.assertTrue;
8 import static org.junit.Assert.fail;
9
10 import java.util.Iterator;
11 import java.util.NoSuchElementException;
12
13 import org.djutils.draw.DrawRuntimeException;
14 import org.djutils.draw.bounds.Bounds3d;
15 import org.djutils.draw.point.OrientedPoint3d;
16 import org.djutils.draw.point.Point3d;
17 import org.junit.Test;
18
19
20
21
22
23
24
25
26
27
28 public class Ray3dTest
29 {
30
31
32
33 @Test
34 public void testConstructors()
35 {
36
37 verifyRay("positive x", new Ray3d(0, 0, 0, 1, 0, 0), 0, 0, 0, 0, Math.PI / 2);
38 verifyRay("positive y", new Ray3d(0, 0, 0, 0, 1, 0), 0, 0, 0, Math.PI / 2, Math.PI / 2);
39 verifyRay("positive z", new Ray3d(0, 0, 0, 0, 0, 1), 0, 0, 0, 0, 0);
40 verifyRay("negative x", new Ray3d(0, 0, 0, -1, 0, 0), 0, 0, 0, Math.PI, Math.PI / 2);
41 verifyRay("negative y", new Ray3d(0, 0, 0, 0, -1, 0), 0, 0, 0, -Math.PI / 2, Math.PI / 2);
42 verifyRay("negative z", new Ray3d(0, 0, 0, 0, 0, -1), 0, 0, 0, 0, Math.PI);
43 verifyRay("Constructor from x, y, phi, theta", new Ray3d(1, 2, 3, 4, 5), 1, 2, 3, 4, 5);
44 verifyRay("Constructor from Point3d, phi, theta", new Ray3d(new Point3d(0.1, 0.2, 0.3), -0.4, -0.5), 0.1, 0.2, 0.3,
45 -0.4, -0.5);
46 verifyRay("Constructor from x, y, z, throughX, throughY, throughZ", new Ray3d(1, 2, 3, 4, 6, 15), 1, 2, 3,
47 Math.atan2(4, 3), Math.atan2(5, 12));
48 verifyRay("Constructor from x, y, z, throughX, throughY, throughZ", new Ray3d(1, 2, 3, 1, 6, 15), 1, 2, 3,
49 Math.atan2(4, 0), Math.atan2(4, 12));
50 verifyRay("Constructor from x, y, z, throughX, throughY, throughZ", new Ray3d(1, 2, 3, 1, 2, 15), 1, 2, 3,
51 Math.atan2(0, 0), Math.atan2(0, 12));
52 verifyRay("Constructor from Point3d, throughX, throughY, throughZ", new Ray3d(new Point3d(1, 2, 3), 4, 6, 15), 1, 2, 3,
53 Math.atan2(4, 3), Math.atan2(5, 12));
54 verifyRay("Constructor from Point3d, throughX, throughY, throughZ", new Ray3d(new Point3d(1, 2, 3), 1, 6, 15), 1, 2, 3,
55 Math.atan2(4, 0), Math.atan2(4, 12));
56 verifyRay("Constructor from Point3d, throughX, throughY, throughZ", new Ray3d(new Point3d(1, 2, 3), 1, 2, 15), 1, 2, 3,
57 Math.atan2(0, 0), Math.atan2(0, 12));
58 verifyRay("Constructor from x, y, z, Point3d", new Ray3d(1, 2, 3, new Point3d(4, 6, 15)), 1, 2, 3, Math.atan2(4, 3),
59 Math.atan2(5, 12));
60 verifyRay("Constructor from x, y, z, Point3d", new Ray3d(1, 2, 3, new Point3d(1, 6, 15)), 1, 2, 3, Math.atan2(4, 0),
61 Math.atan2(4, 12));
62 verifyRay("Constructor from x, y, z, Point3d", new Ray3d(1, 2, 3, new Point3d(1, 2, 15)), 1, 2, 3, Math.atan2(0, 0),
63 Math.atan2(0, 12));
64 verifyRay("Constructor from Point3d, Point3d", new Ray3d(new Point3d(1, 2, 3), new Point3d(4, 6, 15)), 1, 2, 3,
65 Math.atan2(4, 3), Math.atan2(5, 12));
66 verifyRay("Constructor from Point3d, Point3d", new Ray3d(new Point3d(1, 2, 3), new Point3d(1, 6, 15)), 1, 2, 3,
67 Math.atan2(4, 0), Math.atan2(4, 12));
68 verifyRay("Constructor from Point3d, Point3d", new Ray3d(new Point3d(1, 2, 3), new Point3d(1, 2, 15)), 1, 2, 3,
69 Math.atan2(0, 0), Math.atan2(0, 12));
70
71 try
72 {
73 new Ray3d(1, 2, 3, Double.NaN, 0);
74 fail("NaN for phy should have thrown a DrawRuntimeException");
75 }
76 catch (DrawRuntimeException dre)
77 {
78
79 }
80
81 try
82 {
83 new Ray3d(1, 2, 3, 0, Double.NaN);
84 fail("NaN for theta should have thrown a DrawRuntimeException");
85 }
86 catch (DrawRuntimeException dre)
87 {
88
89 }
90
91 try
92 {
93 new Ray3d(null, 1, 2);
94 fail("null for point should have thrown a NullPointerException");
95 }
96 catch (NullPointerException dre)
97 {
98
99 }
100
101 try
102 {
103 new Ray3d(1, 2, 3, 1, 2, 3);
104 fail("Same coordinates for through point should have thrown a DrawRuntimeException");
105 }
106 catch (DrawRuntimeException dre)
107 {
108
109 }
110
111 try
112 {
113 new Ray3d(1, 2, 3, new Point3d(1, 2, 3));
114 fail("Same coordinates for through point should have thrown a DrawRuntimeException");
115 }
116 catch (DrawRuntimeException dre)
117 {
118
119 }
120
121 try
122 {
123 new Ray3d(new Point3d(1, 2, 3), 1, 2, 3);
124 fail("Same coordinates for through point should have thrown a DrawRuntimeException");
125 }
126 catch (DrawRuntimeException dre)
127 {
128
129 }
130
131 try
132 {
133 new Ray3d(1, 2, 3, null);
134 fail("null for through point should have thrown a NullPointerException");
135 }
136 catch (NullPointerException dre)
137 {
138
139 }
140
141 try
142 {
143 new Ray3d(null, new Point3d(4, 5, 6));
144 fail("null for point should have thrown a NullPointerException");
145 }
146 catch (NullPointerException dre)
147 {
148
149 }
150
151 try
152 {
153 new Ray3d(new Point3d(1, 2, 3), null);
154 fail("null for through point should have thrown a NullPointerException");
155 }
156 catch (NullPointerException dre)
157 {
158
159 }
160
161 Ray3d ray = new Ray3d(1, 2, 3, 0.2, 0.3);
162 assertTrue("toString returns something descriptive", ray.toString().startsWith("Ray3d"));
163 assertTrue("toString can suppress the class name", ray.toString().indexOf(ray.toString(true)) > 0);
164 }
165
166
167
168
169
170
171
172
173
174
175
176 private void verifyRay(final String description, final Ray3d ray, final double expectedX, final double expectedY,
177 final double expectedZ, final double expectedPhi, final double expectedTheta)
178 {
179 assertEquals(description + " getX", expectedX, ray.getX(), 0.0001);
180 assertEquals(description + " x", expectedX, ray.x, 0.0001);
181 assertEquals(description + " getY", expectedY, ray.getY(), 0.0001);
182 assertEquals(description + " y", expectedY, ray.y, 0.0001);
183 assertEquals(description + " getZ", expectedZ, ray.getZ(), 0.0001);
184 assertEquals(description + " z", expectedZ, ray.z, 0.0001);
185 assertEquals(description + " getPhi", expectedPhi, ray.getPhi(), 0.0001);
186 assertEquals(description + " phi", expectedPhi, ray.phi, 0.0001);
187 assertEquals(description + " getTheta", expectedTheta, ray.getTheta(), 0.0001);
188 assertEquals(description + " theta", expectedTheta, ray.theta, 0.0001);
189 Point3d startPoint = ray.getEndPoint();
190 assertEquals(description + " getStartPoint x", expectedX, startPoint.x, 0.0001);
191 assertEquals(description + " getStartPoint y", expectedY, startPoint.y, 0.0001);
192 assertEquals(description + " getStartPoint z", expectedZ, startPoint.z, 0.0001);
193 Ray3d negated = ray.neg();
194 assertEquals(description + " neg x", -expectedX, negated.x, 0.0001);
195 assertEquals(description + " neg y", -expectedY, negated.y, 0.0001);
196 assertEquals(description + " neg z", -expectedZ, negated.z, 0.0001);
197 assertEquals(description + " neg phi", expectedPhi + Math.PI, negated.phi, 0.0001);
198 assertEquals(description + " neg theta", expectedTheta + Math.PI, negated.theta, 0.0001);
199 Ray3d flipped = ray.flip();
200 assertEquals(description + " getX", expectedX, flipped.getX(), 0.0001);
201 assertEquals(description + " x", expectedX, flipped.x, 0.0001);
202 assertEquals(description + " getY", expectedY, flipped.getY(), 0.0001);
203 assertEquals(description + " y", expectedY, flipped.y, 0.0001);
204 assertEquals(description + " getZ", expectedZ, flipped.getZ(), 0.0001);
205 assertEquals(description + " z", expectedZ, flipped.z, 0.0001);
206 assertEquals(description + " getPhi", expectedPhi + Math.PI, flipped.getPhi(), 0.0001);
207 assertEquals(description + " phi", expectedPhi + Math.PI, flipped.phi, 0.0001);
208 assertEquals(description + " getTheta", Math.PI - expectedTheta, flipped.getTheta(), 0.0001);
209 assertEquals(description + " theta", Math.PI - expectedTheta, flipped.theta, 0.0001);
210 assertEquals(description + " size", 2, ray.size());
211 Iterator<Point3d> iterator = ray.getPoints();
212
213 assertTrue(iterator.hasNext());
214 Point3d point = iterator.next();
215 assertEquals(description + " iterator first point x", expectedX, point.x, 0.0001);
216 assertEquals(description + " iterator first point y", expectedY, point.y, 0.0001);
217 assertEquals(description + " iterator first point z", expectedZ, point.z, 0.0001);
218 assertTrue(iterator.hasNext());
219 point = iterator.next();
220
221 assertTrue(description + " iterator second point is at infinity",
222 Double.isInfinite(point.x) || Double.isInfinite(point.y) || Double.isInfinite(point.z));
223 assertFalse(iterator.hasNext());
224 try
225 {
226 iterator.next();
227 fail("Should have thrown a NoSuchElementException");
228 }
229 catch (NoSuchElementException nsee)
230 {
231
232 }
233 }
234
235
236
237
238 @Test
239 public void boundsTest()
240 {
241
242
243 verifyBounds(new Ray3d(1, 2, 3, 0, 1).getBounds(), 1, 2, 3, Double.POSITIVE_INFINITY, 2, Double.POSITIVE_INFINITY);
244
245
246
247 verifyBounds(new Ray3d(1, 2, 3, 0, 0).getBounds(), 1, 2, 3, 1, 2, Double.POSITIVE_INFINITY);
248
249
250 verifyBounds(new Ray3d(1, 2, 3, 0.2, 1.1).getBounds(), 1, 2, 3, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY,
251 Double.POSITIVE_INFINITY);
252
253
254 verifyBounds(new Ray3d(1, 2, 3, Math.PI / 2, 1).getBounds(), 1, 2, 3, Double.POSITIVE_INFINITY,
255 Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
256
257
258 verifyBounds(new Ray3d(1, 2, 3, 2, 1).getBounds(), Double.NEGATIVE_INFINITY, 2, 3, 1, Double.POSITIVE_INFINITY,
259 Double.POSITIVE_INFINITY);
260
261
262 verifyBounds(new Ray3d(1, 2, 3, Math.PI, 1).getBounds(), Double.NEGATIVE_INFINITY, 2, 3, 1, Double.POSITIVE_INFINITY,
263 Double.POSITIVE_INFINITY);
264
265
266 verifyBounds(new Ray3d(1, 2, 3, 4, 1).getBounds(), Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, 3, 1, 2,
267 Double.POSITIVE_INFINITY);
268
269
270 verifyBounds(new Ray3d(1, 2, 3, -1, 1).getBounds(), 1, Double.NEGATIVE_INFINITY, 3, Double.POSITIVE_INFINITY, 2,
271 Double.POSITIVE_INFINITY);
272
273
274 verifyBounds(new Ray3d(1, 2, 3, -Math.PI / 2, 1).getBounds(), 1, Double.NEGATIVE_INFINITY, 3, Double.POSITIVE_INFINITY,
275 2, Double.POSITIVE_INFINITY);
276
277
278 verifyBounds(new Ray3d(1, 2, 3, 0.2, 3).getBounds(), 1, 2, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
279 Double.POSITIVE_INFINITY, 3);
280
281
282 verifyBounds(new Ray3d(1, 2, 3, 2, 3).getBounds(), Double.NEGATIVE_INFINITY, 2, Double.NEGATIVE_INFINITY, 1,
283 Double.POSITIVE_INFINITY, 3);
284
285
286 verifyBounds(new Ray3d(1, 2, 3, Math.PI, 3).getBounds(), Double.NEGATIVE_INFINITY, 2, Double.NEGATIVE_INFINITY, 1,
287 Double.POSITIVE_INFINITY, 3);
288
289
290 verifyBounds(new Ray3d(1, 2, 3, 4, 3).getBounds(), Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY,
291 Double.NEGATIVE_INFINITY, 1, 2, 3);
292
293
294 verifyBounds(new Ray3d(1, 2, 3, -1, 3).getBounds(), 1, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY,
295 Double.POSITIVE_INFINITY, 2, 3);
296
297
298 verifyBounds(new Ray3d(1, 2, 3, -Math.PI / 2, 3).getBounds(), 1, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY,
299 Double.POSITIVE_INFINITY, 2, 3);
300
301
302 verifyBounds(new Ray3d(1, 2, 3, 0.2, -1.1).getBounds(), Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, 3, 1, 2,
303 Double.POSITIVE_INFINITY);
304
305
306 verifyBounds(new Ray3d(1, 2, 3, Math.PI / 2, -1).getBounds(), Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, 3, 1,
307 2, Double.POSITIVE_INFINITY);
308
309
310 verifyBounds(new Ray3d(1, 2, 3, 2, -1).getBounds(), 1, Double.NEGATIVE_INFINITY, 3, Double.POSITIVE_INFINITY, 2,
311 Double.POSITIVE_INFINITY);
312
313
314 verifyBounds(new Ray3d(1, 2, 3, Math.PI, -1).getBounds(), 1, Double.NEGATIVE_INFINITY, 3, Double.POSITIVE_INFINITY, 2,
315 Double.POSITIVE_INFINITY);
316
317
318 verifyBounds(new Ray3d(1, 2, 3, 4, -1).getBounds(), 1, 2, 3, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY,
319 Double.POSITIVE_INFINITY);
320
321
322 verifyBounds(new Ray3d(1, 2, 3, -1, -1).getBounds(), Double.NEGATIVE_INFINITY, 2, 3, 1, Double.POSITIVE_INFINITY,
323 Double.POSITIVE_INFINITY);
324
325
326 }
327
328
329
330
331
332
333
334
335
336
337
338 private void verifyBounds(final Bounds3d bounds, final double expectedMinX, final double expectedMinY,
339 final double expectedMinZ, final double expectedMaxX, final double expectedMaxY, final double expectedMaxZ)
340 {
341 assertEquals("Bounds minX", expectedMinX, bounds.getMinX(), 0.0001);
342 assertEquals("Bounds minY", expectedMinY, bounds.getMinY(), 0.0001);
343 assertEquals("Bounds minZ", expectedMinZ, bounds.getMinZ(), 0.0001);
344 assertEquals("Bounds maxX", expectedMaxX, bounds.getMaxX(), 0.0001);
345 assertEquals("Bounds maxY", expectedMaxY, bounds.getMaxY(), 0.0001);
346 assertEquals("Bounds maxZ", expectedMaxZ, bounds.getMaxZ(), 0.0001);
347 }
348
349
350
351
352 @Test
353 public void testLocation()
354 {
355 try
356 {
357 new Ray3d(1, 2, 3, 1, 0.5).getLocation(Double.NaN);
358 fail("NaN position should have thrown a DrawRuntimeException");
359 }
360 catch (DrawRuntimeException dre)
361 {
362
363 }
364
365 try
366 {
367 new Ray3d(1, 2, 3, 1, 0.5).getLocation(-1);
368 fail("Negative position should have thrown a DrawRuntimeException");
369 }
370 catch (DrawRuntimeException dre)
371 {
372
373 }
374
375 try
376 {
377 new Ray3d(1, 2, 3, 1, 0.5).getLocation(Double.POSITIVE_INFINITY);
378 fail("Infited position should have thrown a DrawRuntimeException");
379 }
380 catch (DrawRuntimeException dre)
381 {
382
383 }
384
385 try
386 {
387 new Ray3d(1, 2, 3, 1, 0.5).getLocation(Double.NEGATIVE_INFINITY);
388 fail("Infinte position should have thrown a DrawRuntimeException");
389 }
390 catch (DrawRuntimeException dre)
391 {
392
393 }
394
395 try
396 {
397 new Ray3d(1, 2, 3, 1, 0.5).getLocationExtended(Double.POSITIVE_INFINITY);
398 fail("Infinite position should have thrown a DrawRuntimeException");
399 }
400 catch (DrawRuntimeException dre)
401 {
402
403 }
404
405 try
406 {
407 new Ray3d(1, 2, 3, 1, 0.5).getLocationExtended(Double.NEGATIVE_INFINITY);
408 fail("Infinite position should have thrown a DrawRuntimeException");
409 }
410 catch (DrawRuntimeException dre)
411 {
412
413 }
414
415 try
416 {
417 new Ray3d(1, 2, 3, 1, 0.5).getLocationExtended(Double.NaN);
418 fail("NaN position should have thrown a DrawRuntimeException");
419 }
420 catch (DrawRuntimeException dre)
421 {
422
423 }
424
425 for (double phi : new double[] { 0, 1, 2, 3, 4, 5, -1, -2, Math.PI })
426 {
427 for (double theta : new double[] { 0, 1, 2, 3, 4, 5, -1, -2, Math.PI })
428 {
429 Ray3d ray = new Ray3d(1, 2, 3, phi, theta);
430 for (double position : new double[] { 0, 10, 0.1, -2 })
431 {
432 Ray3d result = ray.getLocationExtended(position);
433 assertEquals("result is position distance away from base of ray", Math.abs(position), ray.distance(result),
434 0.001);
435 assertEquals("result has same phi as ray", ray.phi, result.phi, 0.00001);
436 assertTrue("Reverse position on result yields ray",
437 ray.epsilonEquals(result.getLocationExtended(-position), 0.0001));
438 if (position > 0)
439 {
440
441 assertEquals("result lies in on ray (phi)", ray.phi, result.phi, 0.0001);
442 assertEquals("result lies on ray (theta)", ray.theta, result.theta, 0.0001);
443 }
444 if (position < 0)
445 {
446 assertEquals("ray lies on result (phi)", result.phi, ray.phi, 0.0001);
447 assertEquals("ray lies on result (theta)", result.theta, ray.theta, 0.0001);
448 }
449 }
450 }
451 }
452 }
453
454
455
456
457 @Test
458 public void testClosestPointAndProjectOrthogonal()
459 {
460 Ray3d ray = new Ray3d(1, 2, 3, 0.4, 0.5);
461 try
462 {
463 ray.closestPointOnRay(null);
464 fail("Null for point should have thrown a NullPointerException");
465 }
466 catch (NullPointerException npe)
467 {
468
469 }
470
471 Point3d result = ray.closestPointOnRay(new Point3d(1, 2, 0));
472 assertEquals("result is start point", ray.x, result.x, 0);
473 assertEquals("result is start point", ray.y, result.y, 0);
474 assertEquals("result is start point", ray.z, result.z, 0);
475 result = ray.closestPointOnRay(new Point3d(1, 2, 0));
476 assertEquals("result is start point", ray.x, result.x, 0);
477 assertEquals("result is start point", ray.y, result.y, 0);
478 assertEquals("result is start point", ray.z, result.z, 0);
479 result = ray.closestPointOnRay(new Point3d(0, 2, 3));
480 assertEquals("result is start point", ray.x, result.x, 0);
481 assertEquals("result is start point", ray.y, result.y, 0);
482 assertEquals("result is start point", ray.z, result.z, 0);
483 result = ray.closestPointOnRay(new Point3d(1, 2, 3));
484 assertEquals("result is start point", ray.x, result.x, 0);
485 assertEquals("result is start point", ray.y, result.y, 0);
486 assertEquals("result is start point", ray.z, result.z, 0);
487
488 assertNull("projection misses the ray", ray.projectOrthogonal(new Point3d(1, 0, 3)));
489 assertNull("projection misses the ray", ray.projectOrthogonal(new Point3d(0, 2, 3)));
490 assertNull("projection misses the ray", ray.projectOrthogonal(new Point3d(1, 2, 2)));
491 assertEquals("projection hits start point of ray", new Point3d(1, 2, 3), ray.projectOrthogonal(new Point3d(1, 2, 3)));
492 assertEquals("extended projection returns same point as projection on sufficiently long line segment", 0,
493 new LineSegment3d(ray.getLocationExtended(-100), ray.getLocation(100))
494 .closestPointOnSegment(new Point3d(1, 0, -1))
495 .distance(ray.projectOrthogonalExtended(new Point3d(1, 0, -1))),
496 0.0001);
497
498 Point3d projectingPoint = new Point3d(10, 10, 10);
499 result = ray.closestPointOnRay(projectingPoint);
500 double distance = result.distance(ray.getEndPoint());
501 assertTrue("distance from start is > 0", distance > 0);
502
503
504 assertTrue("Point on ray closer than result is further from projectingPoint",
505 ray.getLocation(distance - 0.1).distance(projectingPoint) < distance);
506 assertTrue("Point on ray further than result is further from projectingPoint",
507 ray.getLocation(distance + 0.1).distance(projectingPoint) < distance);
508 assertEquals("projectOrthogonalExtended returns same result as long as orthogonal projection exists", 0,
509 result.distance(ray.projectOrthogonalExtended(projectingPoint)), 0.0001);
510 }
511
512
513
514
515 @Test
516 public void testProject()
517 {
518 Ray3d ray = new Ray3d(1, 2, 3, 20, 10, 5);
519 assertTrue("projects outside", Double.isNaN(ray.projectOrthogonalFractional(new Point3d(1, 1, 1))));
520 assertTrue("projects before start", ray.projectOrthogonalFractionalExtended(new Point3d(1, 1, 1)) < 0);
521 assertEquals("projects at", -new Point3d(1 - 19 - 19, 2 - 8 - 8, 3 - 2 - 2).distance(ray),
522 ray.projectOrthogonalFractionalExtended(new Point3d(1 - 19 - 19 + 8, 2 - 8 - 8 - 19, 3 - 2 - 2)), 0.0001);
523
524 for (int x = -2; x < 5; x++)
525 {
526 for (int y = -2; y < 5; y++)
527 {
528 for (int z = -2; z < 5; z++)
529 {
530 Point3d point = new Point3d(x, y, z);
531 double fraction = ray.projectOrthogonalFractionalExtended(point);
532 if (fraction < 0)
533 {
534 assertTrue("non extended version yields NaN", Double.isNaN(ray.projectOrthogonalFractional(point)));
535 assertNull("non extended projectOrthogonal yields null", ray.projectOrthogonal(point));
536 }
537 else
538 {
539 assertEquals("non extended version yields same", fraction, ray.projectOrthogonalFractional(point),
540 0.00001);
541 assertEquals("non extended version yields same as extended version", ray.projectOrthogonal(point),
542 ray.projectOrthogonalExtended(point));
543 }
544 Point3d projected = ray.projectOrthogonalExtended(point);
545 assertEquals("projecting projected point yields same", fraction,
546 ray.projectOrthogonalFractionalExtended(projected), 0.00001);
547 }
548 }
549 }
550 }
551
552
553
554
555 @Test
556 public void epsilonEqualsTest()
557 {
558 Ray3d ray = new Ray3d(1, 2, 3, 0.5, -0.5);
559 try
560 {
561 ray.epsilonEquals((Ray3d) null, 1, 1);
562 fail("Null pointer should have thrown a NullPointerException");
563 }
564 catch (NullPointerException npe)
565 {
566
567 }
568
569 try
570 {
571 ray.epsilonEquals(ray, -0.1, 1);
572 fail("Negative epsilonCoordinate should have thrown an IllegalArgumentException");
573 }
574 catch (IllegalArgumentException npe)
575 {
576
577 }
578
579 try
580 {
581 ray.epsilonEquals(ray, 1, -0.1);
582 fail("Negative epsilonDirection should have thrown an IllegalArgumentException");
583 }
584 catch (IllegalArgumentException npe)
585 {
586
587 }
588
589 try
590 {
591 ray.epsilonEquals(ray, Double.NaN, 1);
592 fail("NaN epsilonCoordinate should have thrown an IllegalArgumentException");
593 }
594 catch (IllegalArgumentException npe)
595 {
596
597 }
598
599 try
600 {
601 ray.epsilonEquals(ray, 1, Double.NaN);
602 fail("NaN epsilonDirection should have thrown an IllegalArgumentException");
603 }
604 catch (IllegalArgumentException npe)
605 {
606
607 }
608
609 double[] deltas = new double[] { 0.0, -0.125, 0.125, -1, 1 };
610 for (double dX : deltas)
611 {
612 for (double dY : deltas)
613 {
614 for (double dZ : deltas)
615 {
616 for (double dPhi : deltas)
617 {
618 for (double dTheta : deltas)
619 {
620 for (double epsilon : new double[] { 0, 0.125, 0.5, 0.9, 1.0, 1.1 })
621 {
622 Ray3d other = new Ray3d(ray.x + dX, ray.y + dY, ray.z + dZ, ray.phi + dPhi, ray.theta + dTheta);
623
624
625
626 boolean result = ray.epsilonEquals(other, epsilon, Double.POSITIVE_INFINITY);
627 boolean expected =
628 Math.abs(dX) <= epsilon && Math.abs(dY) <= epsilon && Math.abs(dZ) <= epsilon;
629 assertEquals("result of epsilonEquals checking x, y, z", expected, result);
630
631 result = ray.epsilonEquals(other, Double.POSITIVE_INFINITY, epsilon);
632 expected = Math.abs(dPhi) <= epsilon && Math.abs(dTheta) <= epsilon;
633 assertEquals("result of epsilonEquals checking phi and theta", expected, result);
634
635 other = new Ray3d(ray.x + dX, ray.y + dY, ray.z + dZ, Math.PI + ray.phi + dPhi,
636 Math.PI - ray.theta + dTheta);
637 result = ray.epsilonEquals(other, epsilon, Double.POSITIVE_INFINITY);
638 expected = Math.abs(dX) <= epsilon && Math.abs(dY) <= epsilon && Math.abs(dZ) <= epsilon;
639 assertEquals("result of epsilonEquals checking x, y, z", expected, result);
640
641 result = ray.epsilonEquals(other, Double.POSITIVE_INFINITY, epsilon);
642 expected = Math.abs(dPhi) <= epsilon && Math.abs(dTheta) <= epsilon;
643 assertEquals("result of epsilonEquals checking phi and theta", expected, result);
644 }
645 }
646 }
647 }
648 }
649 }
650 }
651
652
653
654
655 @Test
656 public void equalsAndHashCodeTest()
657 {
658 Ray3d ray = new Ray3d(1, 2, 3, 11, 12, 13);
659 assertEquals("equal to itself", ray, ray);
660 assertNotEquals("not equal to null", ray, null);
661 assertNotEquals("not equal to different object with same parent class", ray, new OrientedPoint3d(1, 2, 3));
662 assertNotEquals("not equal to ray with different phi", ray, new Ray3d(1, 2, 3, 11, 10, 13));
663 assertNotEquals("not equal to ray with different theta", ray, new Ray3d(1, 2, 3, 11, 12, 10));
664 assertNotEquals("not equal to ray with different start x", ray, new Ray3d(2, 2, 3, 12, 12, 13));
665 assertNotEquals("not equal to ray with different start y", ray, new Ray3d(1, 3, 3, 11, 13, 13));
666 assertEquals("equal to ray with same x, y and direction", ray, new Ray3d(1, 2, 3, 21, 22, 23));
667
668 assertNotEquals("hashCode depends on x", ray.hashCode(), new Ray3d(2, 2, 3, 12, 12, 13));
669 assertNotEquals("hashCode depends on y", ray.hashCode(), new Ray3d(1, 3, 3, 11, 13, 13));
670 assertNotEquals("hashCode depends on y", ray.hashCode(), new Ray3d(1, 2, 4, 11, 12, 14));
671 assertNotEquals("hashCode depends on phi", ray.hashCode(), new Ray3d(1, 2, 3, 11, 10, 13));
672 assertNotEquals("hashCode depends on theta", ray.hashCode(), new Ray3d(1, 2, 3, 11, 12, 10));
673 }
674
675 }