1 package org.djutils.draw.point;
2
3 import static org.junit.jupiter.api.Assertions.assertEquals;
4 import static org.junit.jupiter.api.Assertions.assertFalse;
5 import static org.junit.jupiter.api.Assertions.assertNotEquals;
6 import static org.junit.jupiter.api.Assertions.assertNotNull;
7 import static org.junit.jupiter.api.Assertions.assertNull;
8 import static org.junit.jupiter.api.Assertions.assertTrue;
9 import static org.junit.jupiter.api.Assertions.fail;
10
11 import java.awt.geom.Point2D;
12 import java.util.List;
13
14 import org.djutils.draw.DrawRuntimeException;
15 import org.djutils.draw.bounds.Bounds2d;
16 import org.djutils.draw.line.LineSegment2d;
17 import org.djutils.draw.line.PolyLine2d;
18 import org.djutils.exceptions.Try;
19 import org.junit.jupiter.api.Test;
20
21
22
23
24
25
26
27
28
29
30 public class Point2dTest
31 {
32
33
34
35 @SuppressWarnings("unlikely-arg-type")
36 @Test
37 public void testPoint2dConstruction()
38 {
39 Point2d p = new Point2d(10.0, -20.0);
40 assertNotNull(p);
41 assertEquals(10.0, p.x, 1E-6, "Access x");
42 assertEquals(-20.0, p.y, 1E-6, "Access y");
43 assertEquals(2, p.getDimensions(), "Dimensions is 2");
44
45 assertEquals(1, p.size(), "Size method returns 1");
46
47 try
48 {
49 new Point2d(Double.NaN, 0);
50 fail("NaN should have thrown an IllegalArgumentException");
51 }
52 catch (IllegalArgumentException iae)
53 {
54
55 }
56
57 try
58 {
59 new Point2d(0, Double.NaN);
60 fail("NaN should have thrown an IllegalArgumentException");
61 }
62 catch (IllegalArgumentException iae)
63 {
64
65 }
66
67 double[] p2Arr = new double[] {5.0, 6.0};
68 p = new Point2d(p2Arr);
69 assertEquals(5.0, p.x, 0);
70 assertEquals(6.0, p.y, 0);
71 Point2D.Double p2DD = new Point2D.Double(-0.1, -0.2);
72 p = new Point2d(p2DD);
73 assertEquals(-0.1, p.x, 1E-6);
74 assertEquals(-0.2, p.y, 1E-6);
75 assertEquals(p2DD, p.toPoint2D());
76
77 Try.testFail(new Try.Execution()
78 {
79 @Override
80 public void execute() throws Throwable
81 {
82 new Point2d((Point2D.Double) null);
83 }
84 }, "Should throw NPE", NullPointerException.class);
85
86 Try.testFail(new Try.Execution()
87 {
88 @Override
89 public void execute() throws Throwable
90 {
91 new Point2d(new double[] {});
92 }
93 }, "Should throw IAE", IllegalArgumentException.class);
94
95 Try.testFail(new Try.Execution()
96 {
97 @Override
98 public void execute() throws Throwable
99 {
100 new Point2d(new double[] {1.0});
101 }
102 }, "Should throw IAE", IllegalArgumentException.class);
103
104 Try.testFail(new Try.Execution()
105 {
106 @Override
107 public void execute() throws Throwable
108 {
109 new Point2d(new double[] {1.0, 2.0, 3.0});
110 }
111 }, "Should throw IAE", IllegalArgumentException.class);
112
113 Try.testFail(new Try.Execution()
114 {
115 @Override
116 public void execute() throws Throwable
117 {
118 new Point2d(new Point2D.Double(Double.NaN, 2));
119 }
120 }, "Should throw IAE", IllegalArgumentException.class);
121
122 Try.testFail(new Try.Execution()
123 {
124 @Override
125 public void execute() throws Throwable
126 {
127 new Point2d(new Point2D.Double(1, Double.NaN));
128 }
129 }, "Should throw IAE", IllegalArgumentException.class);
130
131
132 assertTrue(p.equals(p));
133 assertEquals(p.hashCode(), p.hashCode());
134 Point3d p3d = p.translate(1.0, 2.0, 3.0);
135 assertFalse(p.equals(p3d));
136 assertFalse(p.equals(null));
137 assertNotEquals(p3d.hashCode(), p.hashCode());
138 assertEquals(p, p.translate(0.0, 0.0));
139 assertNotEquals(p, p.translate(1.0, 0.0));
140 assertNotEquals(p, p.translate(0.0, 1.0));
141 assertEquals(p.x + 1, p3d.x, 0.00001, "x");
142 assertEquals(p.y + 2, p3d.y, 0.00001, "y");
143 assertEquals(3, p3d.z, 0, "z");
144
145
146 p = new Point2d(10.0, 20.0);
147 assertEquals("Point2d [x=10.000000, y=20.000000]", p.toString());
148 assertEquals("Point2d [x=10.0, y=20.0]", p.toString("%.1f"));
149 assertEquals("[x=10, y=20]", p.toString("%.0f", true));
150
151
152 assertTrue(p.epsilonEquals(p, 0.1));
153 assertTrue(p.epsilonEquals(p, 0.001));
154 assertTrue(p.epsilonEquals(p, 0.0));
155 Point2d p3 = p.translate(0.001, 0.0);
156 assertTrue(p.epsilonEquals(p3, 0.09));
157 assertTrue(p3.epsilonEquals(p, 0.09));
158 assertFalse(p.epsilonEquals(p3, 0.0009));
159 assertFalse(p3.epsilonEquals(p, 0.0009));
160 p3 = p.translate(0.0, 0.001);
161 assertTrue(p.epsilonEquals(p3, 0.09));
162 assertTrue(p3.epsilonEquals(p, 0.09));
163 assertFalse(p.epsilonEquals(p3, 0.0009));
164 assertFalse(p3.epsilonEquals(p, 0.0009));
165 }
166
167
168
169
170 @Test
171 public void testPoint2dOperators()
172 {
173 Point2d p = new Point2d(-0.1, -0.2);
174 assertEquals(0.1, p.abs().x, 1E-6);
175 assertEquals(0.2, p.abs().y, 1E-6);
176 p = p.neg();
177 assertEquals(0.1, p.x, 1E-6);
178 assertEquals(0.2, p.y, 1E-6);
179 p = p.scale(1.0);
180 assertEquals(0.1, p.x, 1E-6);
181 assertEquals(0.2, p.y, 1E-6);
182 p = p.scale(10.0);
183 assertEquals(1.0, p.x, 1E-6);
184 assertEquals(2.0, p.y, 1E-6);
185 p = p.translate(5.0, -1.0);
186 assertEquals(6.0, p.x, 1E-6);
187 assertEquals(1.0, p.y, 1E-6);
188 Point3d p3d = p.translate(1.0, 1.0, 1.0);
189 assertEquals(7.0, p3d.x, 1E-6);
190 assertEquals(2.0, p3d.y, 1E-6);
191 assertEquals(1.0, p3d.z, 1E-6);
192
193 try
194 {
195 p.translate(Double.NaN, 2.0);
196 fail("NaN translation should have thrown an IllegalArgumentException");
197 }
198 catch (IllegalArgumentException iae)
199 {
200
201 }
202
203 try
204 {
205 p.translate(1.0, Double.NaN);
206 fail("NaN translation should have thrown an IllegalArgumentException");
207 }
208 catch (IllegalArgumentException iae)
209 {
210
211 }
212
213
214 Point2d p1 = new Point2d(1.0, 1.0);
215 Point2d p2 = new Point2d(5.0, 5.0);
216 assertEquals(p1, p1.interpolate(p2, 0.0));
217 assertEquals(p2, p2.interpolate(p1, 0.0));
218 assertEquals(p1, p1.interpolate(p1, 0.0));
219 assertEquals(new Point2d(3.0, 3.0), p1.interpolate(p2, 0.5));
220
221
222 assertEquals(Math.sqrt(32.0), p1.distance(p2), 0.001);
223 assertEquals(32.0, p1.distanceSquared(p2), 0.001);
224
225
226
227
228
229
230
231
232
233
234 Point2d pn = p2.normalize();
235 assertEquals(1.0 / Math.sqrt(2.0), pn.x, 0.001);
236 assertEquals(1.0 / Math.sqrt(2.0), pn.y, 0.001);
237
238 Try.testFail(new Try.Execution()
239 {
240 @Override
241 public void execute() throws Throwable
242 {
243 new Point2d(0.0, 0.0).normalize();
244 }
245 }, "Should throw DRtE", DrawRuntimeException.class);
246
247 Bounds2d bounds = p1.getBounds();
248 assertEquals(p1.x, bounds.getMinX(), 0, "Bounds min x");
249 assertEquals(p1.y, bounds.getMinY(), 0, "Bounds min y");
250 assertEquals(p1.x, bounds.getMaxX(), 0, "Bounds max x");
251 assertEquals(p1.y, bounds.getMaxY(), 0, "Bounds max y");
252 }
253
254
255
256
257 @Test
258 public void testPoint2dOperatorsNPE()
259 {
260 final Point2d p1 = new Point2d(1.0, 1.0);
261
262 try
263 {
264 p1.translate(Double.NaN, 2.0);
265 fail("NaN translation should have thrown an IllegalArgumentException");
266 }
267 catch (IllegalArgumentException iae)
268 {
269
270 }
271
272 try
273 {
274 p1.translate(1.0, Double.NaN);
275 fail("NaN translation should have thrown an IllegalArgumentException");
276 }
277 catch (IllegalArgumentException iae)
278 {
279
280 }
281
282 try
283 {
284 p1.translate(Double.NaN, 2.0, 3.0);
285 fail("NaN translation should have thrown an IllegalArgumentException");
286 }
287 catch (IllegalArgumentException iae)
288 {
289
290 }
291
292 try
293 {
294 p1.translate(1.0, Double.NaN, 3.0);
295 fail("NaN translation should have thrown an IllegalArgumentException");
296 }
297 catch (IllegalArgumentException iae)
298 {
299
300 }
301
302 try
303 {
304 p1.translate(1.0, 2.0, Double.NaN);
305 fail("NaN translation should have thrown an IllegalArgumentException");
306 }
307 catch (IllegalArgumentException iae)
308 {
309
310 }
311
312 Try.testFail(new Try.Execution()
313 {
314 @Override
315 public void execute() throws Throwable
316 {
317 p1.interpolate(null, 0.5);
318 }
319 }, "Should throw NPE", NullPointerException.class);
320
321 Try.testFail(new Try.Execution()
322 {
323 @Override
324 public void execute() throws Throwable
325 {
326 p1.distance(null);
327 }
328 }, "Should throw NPE", NullPointerException.class);
329
330 Try.testFail(new Try.Execution()
331 {
332 @Override
333 public void execute() throws Throwable
334 {
335 p1.distanceSquared(null);
336 }
337 }, "Should throw NPE", NullPointerException.class);
338 }
339
340
341
342
343 @Test
344 public void testIntersectionOfLineSegments()
345 {
346 assertNull(
347 Point2d.intersectionOfLineSegments(new Point2d(1, 2), new Point2d(4, 2), new Point2d(1, 2), new Point2d(4, 2)),
348 "horizontal line intersection with itself returns null");
349 assertNull(Point2d.intersectionOfLineSegments(new Point2d(1, 2), new Point2d(1, 10), new Point2d(1, 2),
350 new Point2d(1, 10)), "vertical line intersection with itself returns null");
351 assertEquals(new Point2d(2, 2),
352 Point2d.intersectionOfLineSegments(new Point2d(1, 1), new Point2d(6, 6), new Point2d(4, 2), new Point2d(-2, 2)),
353 "Intersection is at (2,2)");
354 assertEquals(new Point2d(2, 2), Point2d.intersectionOfLineSegments(1, 1, 6, 6, 4, 2, -2, 2),
355 "Intersection is at (2,2)");
356 assertEquals(new Point2d(2, 2),
357 Point2d.intersectionOfLineSegments(new LineSegment2d(1, 1, 6, 6), new LineSegment2d(4, 2, -2, 2)),
358 "Intersection is at (2,2)");
359
360 assertNull(Point2d.intersectionOfLineSegments(new Point2d(1, 1), new Point2d(5, 5), new Point2d(0, -3),
361 new Point2d(10, 0)), "line two passes before start of line one");
362 assertNull(Point2d.intersectionOfLineSegments(new Point2d(1, 1), new Point2d(5, 5), new Point2d(0, 20),
363 new Point2d(100, 30)), "line two passes before after end of line one");
364 assertNull(
365 Point2d.intersectionOfLineSegments(new Point2d(1, 1), new Point2d(5, 5), new Point2d(5, 3), new Point2d(10, 2)),
366 "line one passes before start of line two");
367 assertNull(Point2d.intersectionOfLineSegments(new Point2d(1, 1), new Point2d(5, 5), new Point2d(-10, 3),
368 new Point2d(0, 2)), "line one passes after end of line two");
369 assertNull(Point2d.intersectionOfLineSegments(1, 1, 5, 5, 0, -3, 10, 0), "line two passes before start of line one");
370 assertNull(Point2d.intersectionOfLineSegments(new LineSegment2d(1, 15, 5, 5), new LineSegment2d(0, -3, 10, 0)),
371 "line two passes before start of line one");
372 assertNull(Point2d.intersectionOfLineSegments(1, 1, 5, 5, 0, 20, 100, 30),
373 "line two passes before after end of line one");
374 assertNull(Point2d.intersectionOfLineSegments(1, 1, 5, 5, 5, 3, 10, 2), "line one passes before start of line two");
375 assertNull(Point2d.intersectionOfLineSegments(new LineSegment2d(1, 1, 5, 5), new LineSegment2d(5, 3, 10, 2)),
376 "line one passes before start of line two");
377 assertNull(Point2d.intersectionOfLineSegments(1, 1, 5, 5, -10, 3, 0, 2), "line one passes after end of line two");
378 assertNull(Point2d.intersectionOfLineSegments(new LineSegment2d(1, 1, 5, 5), new LineSegment2d(-10, 3, 0, 2)),
379 "line one passes after end of line two");
380
381 Point2d line1P1 = new Point2d(1, 2);
382 Point2d line1P2 = new Point2d(3, 2);
383 Point2d line2P1 = new Point2d(2, 0);
384 Point2d line2P2 = new Point2d(2, 4);
385 try
386 {
387 Point2d.intersectionOfLines(null, line1P2, line2P1, line2P2);
388 fail("Null parameter should have thrown a NullPointerException");
389 }
390 catch (NullPointerException npe)
391 {
392
393 }
394
395 try
396 {
397 Point2d.intersectionOfLines(line1P1, null, line2P1, line2P2);
398 fail("Null parameter should have thrown a NullPointerException");
399 }
400 catch (NullPointerException npe)
401 {
402
403 }
404
405 try
406 {
407 Point2d.intersectionOfLines(line1P1, line1P2, null, line2P2);
408 fail("Null parameter should have thrown a NullPointerException");
409 }
410 catch (NullPointerException npe)
411 {
412
413 }
414
415 try
416 {
417 Point2d.intersectionOfLines(line1P1, line1P2, line2P1, null);
418 fail("Null parameter should have thrown a NullPointerException");
419 }
420 catch (NullPointerException npe)
421 {
422
423 }
424
425 try
426 {
427 Point2d.intersectionOfLineSegments(null, line1P2, line2P1, line2P2);
428 fail("Null parameter should have thrown a NullPointerException");
429 }
430 catch (NullPointerException npe)
431 {
432
433 }
434
435 try
436 {
437 Point2d.intersectionOfLineSegments(line1P1, null, line2P1, line2P2);
438 fail("Null parameter should have thrown a NullPointerException");
439 }
440 catch (NullPointerException npe)
441 {
442
443 }
444
445 try
446 {
447 Point2d.intersectionOfLineSegments(line1P1, line1P2, null, line2P2);
448 fail("Null parameter should have thrown a NullPointerException");
449 }
450 catch (NullPointerException npe)
451 {
452
453 }
454
455 try
456 {
457 Point2d.intersectionOfLineSegments(line1P1, line1P2, line2P1, null);
458 fail("Null parameter should have thrown a NullPointerException");
459 }
460 catch (NullPointerException npe)
461 {
462
463 }
464
465 }
466
467
468
469
470 @Test
471 public void testIntersectionOfLines()
472 {
473 assertNull(Point2d.intersectionOfLines(new Point2d(1, 2), new Point2d(4, 2), new Point2d(1, 2), new Point2d(4, 2)),
474 "horizontal line intersection with itself returns null");
475 assertNull(Point2d.intersectionOfLines(1, 2, 4, 2, 1, 2, 4, 2),
476 "horizontal line intersection with itself returns null");
477 assertNull(Point2d.intersectionOfLineSegments(new Point2d(1, 2), new Point2d(1, 10), new Point2d(1, 2),
478 new Point2d(1, 10)), "vertical line intersection with itself returns null");
479 assertNull(Point2d.intersectionOfLineSegments(1, 2, 1, 10, 1, 2, 1, 10),
480 "vertical line intersection with itself returns null");
481 assertNull(Point2d.intersectionOfLineSegments(new LineSegment2d(1, 2, 1, 10), new LineSegment2d(1, 2, 1, 10)),
482 "vertical line intersection with itself returns null");
483 assertEquals(new Point2d(2, 2),
484 Point2d.intersectionOfLines(new Point2d(1, 1), new Point2d(6, 6), new Point2d(4, 2), new Point2d(-2, 2)),
485 "Intersection is at (2,2)");
486
487 assertEquals(new Point2d(-1.5, -1.5),
488 Point2d.intersectionOfLines(new Point2d(1, 1), new Point2d(5, 5), new Point2d(0, -3), new Point2d(10, -13)),
489 "line two passes before start of line one");
490 assertEquals(new Point2d(20, 20),
491 Point2d.intersectionOfLines(new Point2d(1, 1), new Point2d(5, 5), new Point2d(0, 20), new Point2d(100, 20)),
492 "line two passes before after end of line one");
493 assertEquals(new Point2d(4, 4),
494 Point2d.intersectionOfLines(new Point2d(1, 1), new Point2d(5, 5), new Point2d(7, 1), new Point2d(10, -2)),
495 "line one passes before start of line two");
496 assertEquals(new Point2d(-3.5, -3.5),
497 Point2d.intersectionOfLines(new Point2d(1, 1), new Point2d(5, 5), new Point2d(-10, 3), new Point2d(0, -7)),
498 "line one passes after end of line two");
499
500 assertEquals(new Point2d(1, 1),
501 Point2d.intersectionOfLines(new Point2d(1, 1), new Point2d(2, 1), new Point2d(1, 0), new Point2d(1, 3)),
502 "begin of first is on second");
503 assertEquals(new Point2d(1, 1),
504 Point2d.intersectionOfLines(new Point2d(-1, 1), new Point2d(1, 1), new Point2d(1, 0), new Point2d(1, 3)),
505 "end of first is on second");
506 assertEquals(new Point2d(1, 1),
507 Point2d.intersectionOfLines(new Point2d(-1, 1), new Point2d(2, 1), new Point2d(1, 1), new Point2d(1, 3)),
508 "begin of second is on first");
509 assertEquals(new Point2d(1, 1),
510 Point2d.intersectionOfLines(new Point2d(-1, 1), new Point2d(2, 1), new Point2d(1, -1), new Point2d(1, 1)),
511 "end of second is on first");
512
513 assertTrue(new Point2d(1, 1).epsilonEquals(
514 Point2d.intersectionOfLines(new Point2d(1.001, 1), new Point2d(2, 1), new Point2d(1, 0), new Point2d(1, 3)),
515 0.0001), "begin of first is just over second");
516 assertTrue(new Point2d(1, 1).epsilonEquals(
517 Point2d.intersectionOfLines(new Point2d(-1, 1), new Point2d(0.999, 1), new Point2d(1, 0), new Point2d(1, 3)),
518 0.0001), "end of first is just over second");
519 assertTrue(new Point2d(1, 1).epsilonEquals(
520 Point2d.intersectionOfLines(new Point2d(-1, 1), new Point2d(2, 1), new Point2d(1, 1.001), new Point2d(1, 3)),
521 0.0001), "begin of second is just over first");
522 assertTrue(new Point2d(1, 1).epsilonEquals(
523 Point2d.intersectionOfLines(new Point2d(-1, 1), new Point2d(2, 1), new Point2d(1, -1), new Point2d(1, 0.999)),
524 0.0001), "end of second is just over first");
525
526 assertNull(Point2d.intersectionOfLineSegments(new Point2d(1.001, 1), new Point2d(2, 1), new Point2d(1, 0),
527 new Point2d(1, 3)), "begin of first is just not on second");
528 assertNull(Point2d.intersectionOfLineSegments(new Point2d(-1, 1), new Point2d(0.999, 1), new Point2d(1, 0),
529 new Point2d(1, 3)), "end of first is just not on second");
530 assertNull(Point2d.intersectionOfLineSegments(new Point2d(-1, 1), new Point2d(2, 1), new Point2d(1, 1.001),
531 new Point2d(1, 3)), "begin of second is just not on first");
532 assertNull(Point2d.intersectionOfLineSegments(new Point2d(-1, 1), new Point2d(2, 1), new Point2d(1, -1),
533 new Point2d(1, 0.999)), "end of second is just not on first");
534 }
535
536
537
538
539
540 @Test
541 public void testClosestPointOnSegmentAndLine() throws DrawRuntimeException
542 {
543 Point2d p1 = new Point2d(-2, 3);
544 for (Point2d p2 : new Point2d[] {new Point2d(7, 4), new Point2d(-3, 6) ,
545 new Point2d(-2, -5) , new Point2d(8, 3) })
546 {
547 PolyLine2d line = new PolyLine2d(p1, p2);
548 for (double x = -10; x <= 10; x += 0.5)
549 {
550 for (double y = -10; y <= 10; y += 0.5)
551 {
552 Point2d p = new Point2d(x, y);
553
554 double fraction = 0.5;
555 double step = 0.25;
556 Point2d approximation = line.getLocationFraction(fraction);
557 double distance = approximation.distance(p);
558
559 for (int iteration = 0; iteration < 10; iteration++)
560 {
561
562 double upFraction = fraction + step;
563 Point2d upApproximation = line.getLocationFraction(upFraction);
564 double upDistance = upApproximation.distance(p);
565 if (upDistance < distance)
566 {
567 distance = upDistance;
568 fraction = upFraction;
569 approximation = upApproximation;
570 }
571 else
572 {
573
574 double downFraction = fraction - step;
575 Point2d downApproximation = line.getLocationFraction(downFraction);
576 double downDistance = downApproximation.distance(p);
577 if (downDistance < distance)
578 {
579 distance = downDistance;
580 fraction = downFraction;
581 approximation = downApproximation;
582 }
583 }
584 step /= 2;
585 }
586 Point2d result = p.closestPointOnSegment(p1, p2);
587 assertEquals(0, approximation.distance(result), line.getLength() / 1000,
588 "distance should be less than one thousandth of line length");
589 assertEquals(p1, p.closestPointOnSegment(p1, p1),
590 "zero length line segment should always return start point");
591 result = p.closestPointOnSegment(p1.x, p1.y, p2.x, p2.y);
592 assertEquals(0, approximation.distance(result), line.getLength() / 1000,
593 "distance should be less than one thousandth of line length");
594
595 if (fraction > 0.001 && fraction < 0.999)
596 {
597 result = p.closestPointOnLine(p1, p2);
598 assertEquals(0, approximation.distance(result), line.getLength() / 1000,
599 "distance should be less than one thousandth of line length");
600 result = p.closestPointOnLine(p1, p2);
601 assertEquals(0, approximation.distance(result), line.getLength() / 1000,
602 "distance should be less than one thousandth of line length");
603 result = p.closestPointOnLine(p1.x, p1.y, p2.x, p2.y);
604 assertEquals(0, approximation.distance(result), line.getLength() / 1000,
605 "distance should be less than one thousandth of line length");
606 }
607 else
608 {
609
610 double range = Math.max(Math.max(line.getLength(), p.distance(p1)), p.distance(p2));
611 step = 5.0;
612 fraction = 0.5;
613 distance = range;
614
615 for (int iteration = 0; iteration < 20; iteration++)
616 {
617
618 double upFraction = fraction + step;
619 Point2d upApproximation = line.getLocationFractionExtended(upFraction);
620 double upDistance = upApproximation.distance(p);
621 if (upDistance < distance)
622 {
623 distance = upDistance;
624 fraction = upFraction;
625 approximation = upApproximation;
626 }
627 else
628 {
629
630 double downFraction = fraction - step;
631 Point2d downApproximation = line.getLocationFractionExtended(downFraction);
632 double downDistance = downApproximation.distance(p);
633 if (downDistance < distance)
634 {
635 distance = downDistance;
636 fraction = downFraction;
637 approximation = downApproximation;
638 }
639 }
640 step /= 2;
641 }
642 result = p.closestPointOnLine(p1, p2);
643 assertEquals(0, approximation.distance(result), range / 1000,
644 "distance should be less than one thousandth of range");
645 result = p.closestPointOnLine(p1, p2);
646 assertEquals(0, approximation.distance(result), range / 1000,
647 "distance should be less than one thousandth of range");
648 result = p.closestPointOnLine(p1.x, p1.y, p2.x, p2.y);
649 assertEquals(0, approximation.distance(result), range / 1000,
650 "distance should be less than one thousandth of range");
651 if (fraction < -0.001 || fraction > 1.001)
652 {
653 assertNull(new LineSegment2d(p1, p2).projectOrthogonal(p), "projectOrthogonal should return null");
654 assertEquals(result, new LineSegment2d(p1, p2).projectOrthogonalExtended(p),
655 "projectOrthogonalExtended should return same result as closestPointOnLine");
656 }
657 }
658 }
659 }
660 }
661
662 try
663 {
664 p1.closestPointOnLine(null, new Point2d(5, 6));
665 fail("null should have thrown a NullPointerException");
666 }
667 catch (NullPointerException npe)
668 {
669
670 }
671
672 try
673 {
674 p1.closestPointOnLine(new Point2d(5, 6), null);
675 fail("null should have thrown a NullPointerException");
676 }
677 catch (NullPointerException npe)
678 {
679
680 }
681
682 try
683 {
684 p1.closestPointOnSegment(Double.NaN, 7, 8, 9);
685 fail("NaN value should have thrown a DrawRuntimeException");
686 }
687 catch (DrawRuntimeException dre)
688 {
689
690 }
691
692 try
693 {
694 p1.closestPointOnSegment(6, Double.NaN, 8, 9);
695 fail("NaN value should have thrown a DrawRuntimeException");
696 }
697 catch (DrawRuntimeException dre)
698 {
699
700 }
701
702 try
703 {
704 p1.closestPointOnSegment(6, 7, Double.NaN, 9);
705 fail("NaN value should have thrown a DrawRuntimeException");
706 }
707 catch (DrawRuntimeException dre)
708 {
709
710 }
711
712 try
713 {
714 p1.closestPointOnSegment(6, 7, 8, Double.NaN);
715 fail("NaN value should have thrown a DrawRuntimeException");
716 }
717 catch (DrawRuntimeException dre)
718 {
719
720 }
721
722 try
723 {
724 p1.closestPointOnLine(Double.NaN, 7, 8, 9);
725 fail("NaN value should have thrown a DrawRuntimeException");
726 }
727 catch (DrawRuntimeException dre)
728 {
729
730 }
731
732 try
733 {
734 p1.closestPointOnLine(6, Double.NaN, 8, 9);
735 fail("NaN value should have thrown a DrawRuntimeException");
736 }
737 catch (DrawRuntimeException dre)
738 {
739
740 }
741
742 try
743 {
744 p1.closestPointOnLine(6, 7, Double.NaN, 9);
745 fail("NaN value should have thrown a DrawRuntimeException");
746 }
747 catch (DrawRuntimeException dre)
748 {
749
750 }
751
752 try
753 {
754 p1.closestPointOnLine(6, 7, 8, Double.NaN);
755 fail("NaN value should have thrown a DrawRuntimeException");
756 }
757 catch (DrawRuntimeException dre)
758 {
759
760 }
761
762 try
763 {
764 p1.closestPointOnLine(6, 7, 6, 7);
765 fail("identical points should have thrown a DrawRuntimeException");
766 }
767 catch (DrawRuntimeException dre)
768 {
769
770 }
771
772 }
773
774
775
776
777 @Test
778 public void circleIntersectionTest()
779 {
780 for (int x1 = -5; x1 <= 5; x1++)
781 {
782 for (int y1 = -5; y1 <= 5; y1++)
783 {
784 Point2d p1 = new Point2d(x1, y1);
785 for (int r1 = 0; r1 < 5; r1++)
786 {
787 for (int x2 = -5; x2 <= 5; x2++)
788 {
789 for (int y2 = -5; y2 <= 5; y2++)
790 {
791 Point2d p2 = new Point2d(x2, y2);
792 double distance = p1.distance(p2);
793 for (int r2 = 0; r2 < 5; r2++)
794 {
795 if (x1 == x2 && y1 == y2 && r1 == r2)
796 {
797 try
798 {
799 Point2d.circleIntersections(p1, r1, p2, r2);
800 fail("Identical circles should have thrown a DrawRuntimeException");
801 }
802 catch (DrawRuntimeException dre)
803 {
804
805 }
806 }
807 else
808 {
809 List<Point2d> result = Point2d.circleIntersections(p1, r1, p2, r2);
810
811
812
813
814
815
816
817 if (distance > r1 + r2 + 0.0001)
818 {
819 if (result.size() > 0)
820 {
821 Point2d.circleIntersections(p1, r1, p2, r2);
822 }
823 assertEquals(0, result.size(), "There are 0 intersections");
824 }
825 if (distance < r1 + r2 - 0.0001 && distance > Math.abs(r2 - r1) + 0.0001)
826 {
827 if (result.size() != 2)
828 {
829 Point2d.circleIntersections(p1, r1, p2, r2);
830 }
831 assertEquals(2, result.size(), "There are 2 intersections");
832 }
833 for (Point2d p : result)
834 {
835 if (Math.abs(r1 - p.distance(p1)) > 0.1 || Math.abs(r2 - p.distance(p2)) > 0.1)
836 {
837 Point2d.circleIntersections(p1, r1, p2, r2);
838 }
839 assertEquals(r1, p.distance(p1), 0.0001, "result is at r1 from p1");
840 assertEquals(r2, p.distance(p2), 0.0001, "result is at r2 from p2");
841 }
842 }
843 }
844 }
845 }
846 }
847 }
848 }
849 try
850 {
851 Point2d.circleIntersections(new Point2d(1, 2), -1, new Point2d(3, 4), 2);
852 fail("negative radius should have thrown a DrawRuntimeException");
853 }
854 catch (DrawRuntimeException dre)
855 {
856
857 }
858
859 try
860 {
861 Point2d.circleIntersections(new Point2d(1, 2), 5, new Point2d(3, 4), -2);
862 fail("negative radius should have thrown a DrawRuntimeException");
863 }
864 catch (DrawRuntimeException dre)
865 {
866
867 }
868
869 try
870 {
871 Point2d.circleIntersections(null, 5, new Point2d(3, 4), 2);
872 fail("null for center1 should have thrown a NullPointerException");
873 }
874 catch (NullPointerException npe)
875 {
876
877 }
878
879 try
880 {
881 Point2d.circleIntersections(new Point2d(3, 4), 5, null, 2);
882 fail("null for center1 should have thrown a NullPointerException");
883 }
884 catch (NullPointerException npe)
885 {
886
887 }
888 }
889
890
891
892
893 @Test
894 public void testDirection()
895 {
896 Point2d reference = new Point2d(5, 8);
897 assertEquals(0, reference.directionTo(new Point2d(reference.x + 10, reference.y)), 0, "East");
898 assertEquals(Math.PI / 2, reference.directionTo(new Point2d(reference.x, reference.y + 5)), 0.00001, "North");
899 assertEquals(Math.PI / 4, reference.directionTo(new Point2d(reference.x + 2, reference.y + 2)), 0.00001, "NorthEast");
900 assertEquals(Math.PI, reference.directionTo(new Point2d(reference.x - 1, reference.y)), 0, "West");
901 assertEquals(-Math.PI / 2, reference.directionTo(new Point2d(reference.x, reference.y - 0.5)), 0.00001, "South");
902 assertEquals(-3 * Math.PI / 4, reference.directionTo(new Point2d(reference.x - 0.2, reference.y - 0.2)), 0.00001,
903 "SouthWst");
904 }
905
906 }