1 package org.djutils.draw.point;
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.assertNotNull;
7 import static org.junit.Assert.assertTrue;
8 import static org.junit.Assert.fail;
9
10 import java.awt.geom.Point2D;
11
12 import org.djutils.draw.DrawException;
13 import org.djutils.draw.DrawRuntimeException;
14 import org.djutils.draw.bounds.Bounds3d;
15 import org.djutils.draw.line.PolyLine3d;
16 import org.djutils.exceptions.Try;
17 import org.junit.Test;
18
19
20
21
22
23
24
25
26
27
28 public class Point3dTest
29 {
30
31
32
33 @SuppressWarnings("unlikely-arg-type")
34 @Test
35 public void testPoint3dConstruction()
36 {
37 Point3d p = new Point3d(10.0, -20.0, 16.0);
38 assertNotNull(p);
39 assertEquals(10.0, p.x, 0);
40 assertEquals(-20.0, p.y, 0);
41 assertEquals(16.0, p.z, 0);
42
43 assertEquals("size method returns 1", 1, p.size());
44
45 Point2d projection = p.project();
46 assertEquals(10.0, projection.x, 0);
47 assertEquals(-20.0, projection.y, 0);
48
49 try
50 {
51 new Point3d(Double.NaN, 0, 0);
52 fail("NaN should have thrown an IllegalArgumentException");
53 }
54 catch (IllegalArgumentException iae)
55 {
56
57 }
58
59 try
60 {
61 new Point3d(0, Double.NaN, 0);
62 fail("NaN should have thrown an IllegalArgumentException");
63 }
64 catch (IllegalArgumentException iae)
65 {
66
67 }
68
69 try
70 {
71 new Point3d(0, 0, Double.NaN);
72 fail("NaN should have thrown an IllegalArgumentException");
73 }
74 catch (IllegalArgumentException iae)
75 {
76
77 }
78
79 double[] p3Arr = new double[] {5.0, 6.0, 7.0};
80 p = new Point3d(p3Arr);
81 assertEquals(5.0, p.x, 0);
82 assertEquals(6.0, p.y, 0);
83 assertEquals(7.0, p.z, 0);
84 Try.testFail(new Try.Execution()
85 {
86 @Override
87 public void execute() throws Throwable
88 {
89 new Point3d(new double[] {});
90 }
91 }, "Should throw IAE", IllegalArgumentException.class);
92
93 Try.testFail(new Try.Execution()
94 {
95 @Override
96 public void execute() throws Throwable
97 {
98 new Point3d(new double[] {1.0});
99 }
100 }, "Should throw IAE", IllegalArgumentException.class);
101
102 Try.testFail(new Try.Execution()
103 {
104 @Override
105 public void execute() throws Throwable
106 {
107 new Point3d(new double[] {1.0, 2.0});
108 }
109 }, "Should throw IAE", IllegalArgumentException.class);
110
111 Try.testFail(new Try.Execution()
112 {
113 @Override
114 public void execute() throws Throwable
115 {
116 new Point3d(new double[] {1.0, 2.0, 3.0, 4.0});
117 }
118 }, "Should throw IAE", IllegalArgumentException.class);
119
120 Try.testFail(new Try.Execution()
121 {
122 @Override
123 public void execute() throws Throwable
124 {
125 new Point3d((Point2d) null, 0);
126 }
127 }, "Should throw NPE", NullPointerException.class);
128
129 Try.testFail(new Try.Execution()
130 {
131 @Override
132 public void execute() throws Throwable
133 {
134 new Point3d((Point2D.Double) null, 0);
135 }
136 }, "Should throw NPE", NullPointerException.class);
137
138 Try.testFail(new Try.Execution()
139 {
140 @Override
141 public void execute() throws Throwable
142 {
143 new Point3d(new Point2D.Double(Double.NaN, 2), 0);
144 }
145 }, "Should throw IAE", IllegalArgumentException.class);
146
147 Try.testFail(new Try.Execution()
148 {
149 @Override
150 public void execute() throws Throwable
151 {
152 new Point3d(new Point2D.Double(1, Double.NaN), 0);
153 }
154 }, "Should throw IAE", IllegalArgumentException.class);
155
156
157 assertTrue(p.equals(p));
158 assertEquals(p.hashCode(), p.hashCode());
159 Point2d p2d = new Point2d(1.0, 1.0);
160 assertFalse(p.equals(p2d));
161 assertFalse(p.equals(null));
162 assertNotEquals(p2d.hashCode(), p.hashCode());
163 assertEquals("Translating over 0,0,0 returns p", p, p.translate(0.0, 0.0, 0.0));
164 assertNotEquals(p, p.translate(1.0, 0.0, 0.0));
165 assertNotEquals(p, p.translate(0.0, 1.0, 0.0));
166 assertNotEquals(p, p.translate(0.0, 0.0, 1.0));
167
168
169 p = new Point3d(10.0, 20.0, 30.0);
170 assertEquals("(10.000000,20.000000,30.000000)", p.toString());
171 assertEquals("(10.0,20.0,30.0)", p.toString(1));
172 assertEquals("(10,20,30)", p.toString(0));
173 assertEquals("(10,20,30)", p.toString(-1));
174
175
176 assertTrue(p.epsilonEquals(p, 0.1));
177 assertTrue(p.epsilonEquals(p, 0.001));
178 assertTrue(p.epsilonEquals(p, 0.0));
179 Point3d p3 = p.translate(0.001, 0.0, 0.0);
180 assertTrue(p.epsilonEquals(p3, 0.09));
181 assertTrue(p3.epsilonEquals(p, 0.09));
182 assertFalse(p.epsilonEquals(p3, 0.0009));
183 assertFalse(p3.epsilonEquals(p, 0.0009));
184 p3 = p.translate(0.0, 0.001, 0.0);
185 assertTrue(p.epsilonEquals(p3, 0.09));
186 assertTrue(p3.epsilonEquals(p, 0.09));
187 assertFalse(p.epsilonEquals(p3, 0.0009));
188 assertFalse(p3.epsilonEquals(p, 0.0009));
189 p3 = p.translate(0.0, 0.0, 0.001);
190 assertTrue(p.epsilonEquals(p3, 0.09));
191 assertTrue(p3.epsilonEquals(p, 0.09));
192 assertFalse(p.epsilonEquals(p3, 0.0009));
193 assertFalse(p3.epsilonEquals(p, 0.0009));
194
195 p2d = new Point2d(123, 456);
196 p3 = new Point3d(p2d, 789);
197 assertEquals("x", 123, p3.x, 0);
198 assertEquals("y", 456, p3.y, 0);
199 assertEquals("z", 789, p3.z, 0);
200
201 Point2D p2D = new java.awt.geom.Point2D.Double(123, 456);
202 p3 = new Point3d(p2D, 789);
203 assertEquals("x", 123, p3.x, 0);
204 assertEquals("y", 456, p3.y, 0);
205 assertEquals("z", 789, p3.z, 0);
206 }
207
208
209
210
211 @Test
212 public void testPoint3dOperators()
213 {
214 Point3d p = new Point3d(-0.1, -0.2, -0.3);
215 assertEquals(0.1, p.abs().x, 1E-6);
216 assertEquals(0.2, p.abs().y, 1E-6);
217 assertEquals(0.3, p.abs().z, 1E-6);
218 p = p.neg();
219 assertEquals(0.1, p.x, 1E-6);
220 assertEquals(0.2, p.y, 1E-6);
221 assertEquals(0.3, p.z, 1E-6);
222 p = p.scale(1.0);
223 assertEquals(0.1, p.x, 1E-6);
224 assertEquals(0.2, p.y, 1E-6);
225 assertEquals(0.3, p.z, 1E-6);
226 p = p.scale(10.0);
227 assertEquals(1.0, p.x, 1E-6);
228 assertEquals(2.0, p.y, 1E-6);
229 assertEquals(3.0, p.z, 1E-6);
230 p = p.translate(5.0, -1.0, 0.5);
231 assertEquals(6.0, p.x, 1E-6);
232 assertEquals(1.0, p.y, 1E-6);
233 assertEquals(3.5, p.z, 1E-6);
234 Point3d p3d = p.translate(1.0, 1.0, 1.0);
235 assertEquals(7.0, p3d.x, 1E-6);
236 assertEquals(2.0, p3d.y, 1E-6);
237 assertEquals(4.5, p3d.z, 1E-6);
238 p3d = p.translate(6.0, 1.0);
239 assertEquals(12.0, p3d.x, 1E-6);
240 assertEquals(2.0, p3d.y, 1E-6);
241 assertEquals(3.5, p3d.z, 1E-6);
242
243 try
244 {
245 p.translate(Double.NaN, 2.0);
246 fail("NaN translation should have thrown an IllegalArgumentException");
247 }
248 catch (IllegalArgumentException iae)
249 {
250
251 }
252
253 try
254 {
255 p.translate(1.0, Double.NaN);
256 fail("NaN translation should have thrown an IllegalArgumentException");
257 }
258 catch (IllegalArgumentException iae)
259 {
260
261 }
262
263 try
264 {
265 p.translate(Double.NaN, 2.0, 3.0);
266 fail("NaN translation should have thrown an IllegalArgumentException");
267 }
268 catch (IllegalArgumentException iae)
269 {
270
271 }
272
273 try
274 {
275 p.translate(1.0, Double.NaN, 3.0);
276 fail("NaN translation should have thrown an IllegalArgumentException");
277 }
278 catch (IllegalArgumentException iae)
279 {
280
281 }
282
283 try
284 {
285 p.translate(1.0, 2.0, Double.NaN);
286 fail("NaN translation should have thrown an IllegalArgumentException");
287 }
288 catch (IllegalArgumentException iae)
289 {
290
291 }
292
293
294 Point3d p1 = new Point3d(1.0, 1.0, 1.0);
295 Point3d p2 = new Point3d(5.0, 5.0, 5.0);
296 assertEquals("Interpolate at 0.0 returns this", p1, p1.interpolate(p2, 0.0));
297 assertEquals(p2, p2.interpolate(p1, 0.0));
298 assertEquals(p1, p1.interpolate(p1, 0.0));
299 assertEquals(new Point3d(3.0, 3.0, 3.0), p1.interpolate(p2, 0.5));
300
301
302 assertEquals(Math.sqrt(48.0), p1.distance(p2), 0.001);
303 assertEquals(48.0, p1.distanceSquared(p2), 0.001);
304 assertEquals(Math.sqrt(32.0), p1.horizontalDistance(p2), 0.001);
305 assertEquals(32.0, p1.horizontalDistanceSquared(p2), 0.001);
306
307
308 assertEquals(Math.toRadians(45.0), p2.horizontalDirection(), 0.001);
309 assertEquals(Math.toRadians(45.0), p1.horizontalDirection(p2), 0.001);
310 assertEquals(0.0, new Point3d(0.0, 0.0, 0.0).horizontalDirection(), 0.001);
311
312
313 Point3d pn = p2.normalize();
314 assertEquals(1.0 / Math.sqrt(3.0), pn.x, 0.001);
315 assertEquals(1.0 / Math.sqrt(3.0), pn.y, 0.001);
316 assertEquals(1.0 / Math.sqrt(3.0), pn.z, 0.001);
317
318 Try.testFail(new Try.Execution()
319 {
320 @Override
321 public void execute() throws Throwable
322 {
323 new Point3d(0.0, 0.0, 0.0).normalize();
324 }
325 }, "Should throw DRtE", DrawRuntimeException.class);
326
327 assertEquals("size of a Point3d is 1", 1, p1.size());
328 Point2d projection = p1.project();
329 assertEquals("projected x", p1.x, projection.x, 0);
330 assertEquals("projected y", p1.y, projection.y, 0);
331
332 Bounds3d bounds = p1.getBounds();
333 assertEquals("Bounds min x", p1.x, bounds.getMinX(), 0);
334 assertEquals("Bounds min y", p1.y, bounds.getMinY(), 0);
335 assertEquals("Bounds min z", p1.z, bounds.getMinZ(), 0);
336 assertEquals("Bounds max x", p1.x, bounds.getMaxX(), 0);
337 assertEquals("Bounds max y", p1.y, bounds.getMaxY(), 0);
338 assertEquals("Bounds max z", p1.z, bounds.getMaxZ(), 0);
339 }
340
341
342
343
344 @Test
345 public void testPoint3dOperatorsNPE()
346 {
347 final Point3d p1 = new Point3d(1.0, 1.0, 1.0);
348
349 Try.testFail(new Try.Execution()
350 {
351 @Override
352 public void execute() throws Throwable
353 {
354 p1.interpolate(null, 0.5);
355 }
356 }, "Should throw NPE", NullPointerException.class);
357
358 Try.testFail(new Try.Execution()
359 {
360 @Override
361 public void execute() throws Throwable
362 {
363 p1.distance(null);
364 }
365 }, "Should throw NPE", NullPointerException.class);
366
367 Try.testFail(new Try.Execution()
368 {
369 @Override
370 public void execute() throws Throwable
371 {
372 p1.distanceSquared(null);
373 }
374 }, "Should throw NPE", NullPointerException.class);
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395 }
396
397
398
399
400
401 @Test
402 public void testClosestPointOnSegment() throws DrawException
403 {
404 Point3d p1 = new Point3d(-2, 3, 5);
405 for (Point3d p2 : new Point3d[] {new Point3d(7, 4, -5), new Point3d(-3, 6, 5) ,
406 new Point3d(-2, -5, 5) , new Point3d(8, 3, 5), new Point3d(-2, 3, 1) })
407 {
408 PolyLine3d line = new PolyLine3d(p1, p2);
409 for (double x = -10; x <= 10; x += 0.5)
410 {
411 for (double y = -10; y <= 10; y += 0.5)
412 {
413 for (double z = -10; z <= 10; z += 0.5)
414 {
415 Point3d p = new Point3d(x, y, z);
416 Point3d result = p.closestPointOnSegment(p1, p2);
417
418 double fraction = 0.5;
419 double step = 0.25;
420 Point3d approximation = line.getLocationFraction(fraction);
421 double distance = approximation.distance(p);
422
423 for (int iteration = 0; iteration < 10; iteration++)
424 {
425
426 double upFraction = fraction + step;
427 Point3d upApproximation = line.getLocationFraction(upFraction);
428 double upDistance = upApproximation.distance(p);
429 if (upDistance < distance)
430 {
431 distance = upDistance;
432 fraction = upFraction;
433 approximation = upApproximation;
434 }
435 else
436 {
437
438 double downFraction = fraction - step;
439 Point3d downApproximation = line.getLocationFraction(downFraction);
440 double downDistance = downApproximation.distance(p);
441 if (downDistance < distance)
442 {
443 distance = downDistance;
444 fraction = downFraction;
445 approximation = downApproximation;
446 }
447 }
448 step /= 2;
449 }
450 assertEquals("distance should be less than one thousandth of line length", 0,
451 approximation.distance(result), line.getLength() / 1000);
452 assertEquals("zero length line segment should always return start point", p1,
453 p.closestPointOnSegment(p1, p1));
454 }
455 }
456 }
457 }
458 }
459
460 }