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.assertNull;
8 import static org.junit.Assert.assertTrue;
9 import static org.junit.Assert.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.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("Access x", 10.0, p.x, 1E-6);
42 assertEquals("Access y", -20.0, p.y, 1E-6);
43 assertEquals("Dimensions is 2", 2, p.getDimensions());
44
45 assertEquals("Size method returns 1", 1, p.size());
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("x", p.x + 1, p3d.x, 0.00001);
142 assertEquals("y", p.y + 2, p3d.y, 0.00001);
143 assertEquals("z", 3, p3d.z, 0);
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("Bounds min x", p1.x, bounds.getMinX(), 0);
249 assertEquals("Bounds min y", p1.y, bounds.getMinY(), 0);
250 assertEquals("Bounds max x", p1.x, bounds.getMaxX(), 0);
251 assertEquals("Bounds max y", p1.y, bounds.getMaxY(), 0);
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("horizontal line intersection with itself returns null",
347 Point2d.intersectionOfLineSegments(new Point2d(1, 2), new Point2d(4, 2), new Point2d(1, 2), new Point2d(4, 2)));
348 assertNull("vertical line intersection with itself returns null", Point2d.intersectionOfLineSegments(new Point2d(1, 2),
349 new Point2d(1, 10), new Point2d(1, 2), new Point2d(1, 10)));
350 assertEquals("Intersection is at (2,2)", new Point2d(2, 2), Point2d.intersectionOfLineSegments(new Point2d(1, 1),
351 new Point2d(6, 6), new Point2d(4, 2), new Point2d(-2, 2)));
352 assertEquals("Intersection is at (2,2)", new Point2d(2, 2),
353 Point2d.intersectionOfLineSegments(1, 1, 6, 6, 4, 2, -2, 2));
354 assertEquals("Intersection is at (2,2)", new Point2d(2, 2),
355 Point2d.intersectionOfLineSegments(new LineSegment2d(1, 1, 6, 6), new LineSegment2d(4, 2, -2, 2)));
356
357 assertNull("line two passes before start of line one", Point2d.intersectionOfLineSegments(new Point2d(1, 1),
358 new Point2d(5, 5), new Point2d(0, -3), new Point2d(10, 0)));
359 assertNull("line two passes before after end of line one", Point2d.intersectionOfLineSegments(new Point2d(1, 1),
360 new Point2d(5, 5), new Point2d(0, 20), new Point2d(100, 30)));
361 assertNull("line one passes before start of line two", Point2d.intersectionOfLineSegments(new Point2d(1, 1),
362 new Point2d(5, 5), new Point2d(5, 3), new Point2d(10, 2)));
363 assertNull("line one passes after end of line two", Point2d.intersectionOfLineSegments(new Point2d(1, 1),
364 new Point2d(5, 5), new Point2d(-10, 3), new Point2d(0, 2)));
365 assertNull("line two passes before start of line one", Point2d.intersectionOfLineSegments(1, 1, 5, 5, 0, -3, 10, 0));
366 assertNull("line two passes before start of line one",
367 Point2d.intersectionOfLineSegments(new LineSegment2d(1, 15, 5, 5), new LineSegment2d(0, -3, 10, 0)));
368 assertNull("line two passes before after end of line one",
369 Point2d.intersectionOfLineSegments(1, 1, 5, 5, 0, 20, 100, 30));
370 assertNull("line one passes before start of line two", Point2d.intersectionOfLineSegments(1, 1, 5, 5, 5, 3, 10, 2));
371 assertNull("line one passes before start of line two",
372 Point2d.intersectionOfLineSegments(new LineSegment2d(1, 1, 5, 5), new LineSegment2d(5, 3, 10, 2)));
373 assertNull("line one passes after end of line two", Point2d.intersectionOfLineSegments(1, 1, 5, 5, -10, 3, 0, 2));
374 assertNull("line one passes after end of line two",
375 Point2d.intersectionOfLineSegments(new LineSegment2d(1, 1, 5, 5), new LineSegment2d(-10, 3, 0, 2)));
376
377 Point2d line1P1 = new Point2d(1, 2);
378 Point2d line1P2 = new Point2d(3, 2);
379 Point2d line2P1 = new Point2d(2, 0);
380 Point2d line2P2 = new Point2d(2, 4);
381 try
382 {
383 Point2d.intersectionOfLines(null, line1P2, line2P1, line2P2);
384 fail("Null parameter should have thrown a NullPointerException");
385 }
386 catch (NullPointerException npe)
387 {
388
389 }
390
391 try
392 {
393 Point2d.intersectionOfLines(line1P1, null, line2P1, line2P2);
394 fail("Null parameter should have thrown a NullPointerException");
395 }
396 catch (NullPointerException npe)
397 {
398
399 }
400
401 try
402 {
403 Point2d.intersectionOfLines(line1P1, line1P2, null, line2P2);
404 fail("Null parameter should have thrown a NullPointerException");
405 }
406 catch (NullPointerException npe)
407 {
408
409 }
410
411 try
412 {
413 Point2d.intersectionOfLines(line1P1, line1P2, line2P1, null);
414 fail("Null parameter should have thrown a NullPointerException");
415 }
416 catch (NullPointerException npe)
417 {
418
419 }
420
421 try
422 {
423 Point2d.intersectionOfLineSegments(null, line1P2, line2P1, line2P2);
424 fail("Null parameter should have thrown a NullPointerException");
425 }
426 catch (NullPointerException npe)
427 {
428
429 }
430
431 try
432 {
433 Point2d.intersectionOfLineSegments(line1P1, null, line2P1, line2P2);
434 fail("Null parameter should have thrown a NullPointerException");
435 }
436 catch (NullPointerException npe)
437 {
438
439 }
440
441 try
442 {
443 Point2d.intersectionOfLineSegments(line1P1, line1P2, null, line2P2);
444 fail("Null parameter should have thrown a NullPointerException");
445 }
446 catch (NullPointerException npe)
447 {
448
449 }
450
451 try
452 {
453 Point2d.intersectionOfLineSegments(line1P1, line1P2, line2P1, null);
454 fail("Null parameter should have thrown a NullPointerException");
455 }
456 catch (NullPointerException npe)
457 {
458
459 }
460
461 }
462
463
464
465
466 @Test
467 public void testIntersectionOfLines()
468 {
469 assertNull("horizontal line intersection with itself returns null",
470 Point2d.intersectionOfLines(new Point2d(1, 2), new Point2d(4, 2), new Point2d(1, 2), new Point2d(4, 2)));
471 assertNull("horizontal line intersection with itself returns null",
472 Point2d.intersectionOfLines(1, 2, 4, 2, 1, 2, 4, 2));
473 assertNull("vertical line intersection with itself returns null", Point2d.intersectionOfLineSegments(new Point2d(1, 2),
474 new Point2d(1, 10), new Point2d(1, 2), new Point2d(1, 10)));
475 assertNull("vertical line intersection with itself returns null",
476 Point2d.intersectionOfLineSegments(1, 2, 1, 10, 1, 2, 1, 10));
477 assertNull("vertical line intersection with itself returns null",
478 Point2d.intersectionOfLineSegments(new LineSegment2d(1, 2, 1, 10), new LineSegment2d(1, 2, 1, 10)));
479 assertEquals("Intersection is at (2,2)", new Point2d(2, 2),
480 Point2d.intersectionOfLines(new Point2d(1, 1), new Point2d(6, 6), new Point2d(4, 2), new Point2d(-2, 2)));
481
482 assertEquals("line two passes before start of line one", new Point2d(-1.5, -1.5),
483 Point2d.intersectionOfLines(new Point2d(1, 1), new Point2d(5, 5), new Point2d(0, -3), new Point2d(10, -13)));
484 assertEquals("line two passes before after end of line one", new Point2d(20, 20),
485 Point2d.intersectionOfLines(new Point2d(1, 1), new Point2d(5, 5), new Point2d(0, 20), new Point2d(100, 20)));
486 assertEquals("line one passes before start of line two", new Point2d(4, 4),
487 Point2d.intersectionOfLines(new Point2d(1, 1), new Point2d(5, 5), new Point2d(7, 1), new Point2d(10, -2)));
488 assertEquals("line one passes after end of line two", new Point2d(-3.5, -3.5),
489 Point2d.intersectionOfLines(new Point2d(1, 1), new Point2d(5, 5), new Point2d(-10, 3), new Point2d(0, -7)));
490
491 assertEquals("begin of first is on second", new Point2d(1, 1),
492 Point2d.intersectionOfLines(new Point2d(1, 1), new Point2d(2, 1), new Point2d(1, 0), new Point2d(1, 3)));
493 assertEquals("end of first is on second", new Point2d(1, 1),
494 Point2d.intersectionOfLines(new Point2d(-1, 1), new Point2d(1, 1), new Point2d(1, 0), new Point2d(1, 3)));
495 assertEquals("begin of second is on first", new Point2d(1, 1),
496 Point2d.intersectionOfLines(new Point2d(-1, 1), new Point2d(2, 1), new Point2d(1, 1), new Point2d(1, 3)));
497 assertEquals("end of second is on first", new Point2d(1, 1),
498 Point2d.intersectionOfLines(new Point2d(-1, 1), new Point2d(2, 1), new Point2d(1, -1), new Point2d(1, 1)));
499
500 assertTrue("begin of first is just over second", new Point2d(1, 1).epsilonEquals(
501 Point2d.intersectionOfLines(new Point2d(1.001, 1), new Point2d(2, 1), new Point2d(1, 0), new Point2d(1, 3)),
502 0.0001));
503 assertTrue("end of first is just over second", new Point2d(1, 1).epsilonEquals(
504 Point2d.intersectionOfLines(new Point2d(-1, 1), new Point2d(0.999, 1), new Point2d(1, 0), new Point2d(1, 3)),
505 0.0001));
506 assertTrue("begin of second is just over first", new Point2d(1, 1).epsilonEquals(
507 Point2d.intersectionOfLines(new Point2d(-1, 1), new Point2d(2, 1), new Point2d(1, 1.001), new Point2d(1, 3)),
508 0.0001));
509 assertTrue("end of second is just over first", new Point2d(1, 1).epsilonEquals(
510 Point2d.intersectionOfLines(new Point2d(-1, 1), new Point2d(2, 1), new Point2d(1, -1), new Point2d(1, 0.999)),
511 0.0001));
512
513 assertNull("begin of first is just not on second", Point2d.intersectionOfLineSegments(new Point2d(1.001, 1),
514 new Point2d(2, 1), new Point2d(1, 0), new Point2d(1, 3)));
515 assertNull("end of first is just not on second", Point2d.intersectionOfLineSegments(new Point2d(-1, 1),
516 new Point2d(0.999, 1), new Point2d(1, 0), new Point2d(1, 3)));
517 assertNull("begin of second is just not on first", Point2d.intersectionOfLineSegments(new Point2d(-1, 1),
518 new Point2d(2, 1), new Point2d(1, 1.001), new Point2d(1, 3)));
519 assertNull("end of second is just not on first", Point2d.intersectionOfLineSegments(new Point2d(-1, 1),
520 new Point2d(2, 1), new Point2d(1, -1), new Point2d(1, 0.999)));
521 }
522
523
524
525
526
527 @Test
528 public void testClosestPointOnSegmentAndLine() throws DrawRuntimeException
529 {
530 Point2d p1 = new Point2d(-2, 3);
531 for (Point2d p2 : new Point2d[] {new Point2d(7, 4), new Point2d(-3, 6) ,
532 new Point2d(-2, -5) , new Point2d(8, 3) })
533 {
534 PolyLine2d line = new PolyLine2d(p1, p2);
535 for (double x = -10; x <= 10; x += 0.5)
536 {
537 for (double y = -10; y <= 10; y += 0.5)
538 {
539 Point2d p = new Point2d(x, y);
540
541 double fraction = 0.5;
542 double step = 0.25;
543 Point2d approximation = line.getLocationFraction(fraction);
544 double distance = approximation.distance(p);
545
546 for (int iteration = 0; iteration < 10; iteration++)
547 {
548
549 double upFraction = fraction + step;
550 Point2d upApproximation = line.getLocationFraction(upFraction);
551 double upDistance = upApproximation.distance(p);
552 if (upDistance < distance)
553 {
554 distance = upDistance;
555 fraction = upFraction;
556 approximation = upApproximation;
557 }
558 else
559 {
560
561 double downFraction = fraction - step;
562 Point2d downApproximation = line.getLocationFraction(downFraction);
563 double downDistance = downApproximation.distance(p);
564 if (downDistance < distance)
565 {
566 distance = downDistance;
567 fraction = downFraction;
568 approximation = downApproximation;
569 }
570 }
571 step /= 2;
572 }
573 Point2d result = p.closestPointOnSegment(p1, p2);
574 assertEquals("distance should be less than one thousandth of line length", 0,
575 approximation.distance(result), line.getLength() / 1000);
576 assertEquals("zero length line segment should always return start point", p1,
577 p.closestPointOnSegment(p1, p1));
578 result = p.closestPointOnSegment(p1.x, p1.y, p2.x, p2.y);
579 assertEquals("distance should be less than one thousandth of line length", 0,
580 approximation.distance(result), line.getLength() / 1000);
581
582 if (fraction > 0.001 && fraction < 0.999)
583 {
584 result = p.closestPointOnLine(p1, p2);
585 assertEquals("distance should be less than one thousandth of line length", 0,
586 approximation.distance(result), line.getLength() / 1000);
587 result = p.closestPointOnLine(p1, p2);
588 assertEquals("distance should be less than one thousandth of line length", 0,
589 approximation.distance(result), line.getLength() / 1000);
590 result = p.closestPointOnLine(p1.x, p1.y, p2.x, p2.y);
591 assertEquals("distance should be less than one thousandth of line length", 0,
592 approximation.distance(result), line.getLength() / 1000);
593 }
594 else
595 {
596
597 double range = Math.max(Math.max(line.getLength(), p.distance(p1)), p.distance(p2));
598 step = 5.0;
599 fraction = 0.5;
600 distance = range;
601
602 for (int iteration = 0; iteration < 20; iteration++)
603 {
604
605 double upFraction = fraction + step;
606 Point2d upApproximation = line.getLocationFractionExtended(upFraction);
607 double upDistance = upApproximation.distance(p);
608 if (upDistance < distance)
609 {
610 distance = upDistance;
611 fraction = upFraction;
612 approximation = upApproximation;
613 }
614 else
615 {
616
617 double downFraction = fraction - step;
618 Point2d downApproximation = line.getLocationFractionExtended(downFraction);
619 double downDistance = downApproximation.distance(p);
620 if (downDistance < distance)
621 {
622 distance = downDistance;
623 fraction = downFraction;
624 approximation = downApproximation;
625 }
626 }
627 step /= 2;
628 }
629 result = p.closestPointOnLine(p1, p2);
630 assertEquals("distance should be less than one thousandth of range", 0, approximation.distance(result),
631 range / 1000);
632 result = p.closestPointOnLine(p1, p2);
633 assertEquals("distance should be less than one thousandth of range", 0, approximation.distance(result),
634 range / 1000);
635 result = p.closestPointOnLine(p1.x, p1.y, p2.x, p2.y);
636 assertEquals("distance should be less than one thousandth of range", 0, approximation.distance(result),
637 range / 1000);
638 if (fraction < -0.001 || fraction > 1.001)
639 {
640 assertNull("projectOrthogonal should return null", new LineSegment2d(p1, p2).projectOrthogonal(p));
641 assertEquals("projectOrthogonalExtended should return same result as closestPointOnLine", result,
642 new LineSegment2d(p1, p2).projectOrthogonalExtended(p));
643 }
644 }
645 }
646 }
647 }
648
649 try
650 {
651 p1.closestPointOnLine(null, new Point2d(5, 6));
652 fail("null should have thrown a NullPointerException");
653 }
654 catch (NullPointerException npe)
655 {
656
657 }
658
659 try
660 {
661 p1.closestPointOnLine(new Point2d(5, 6), null);
662 fail("null should have thrown a NullPointerException");
663 }
664 catch (NullPointerException npe)
665 {
666
667 }
668
669 try
670 {
671 p1.closestPointOnSegment(Double.NaN, 7, 8, 9);
672 fail("NaN value should have thrown a DrawRuntimeException");
673 }
674 catch (DrawRuntimeException dre)
675 {
676
677 }
678
679 try
680 {
681 p1.closestPointOnSegment(6, Double.NaN, 8, 9);
682 fail("NaN value should have thrown a DrawRuntimeException");
683 }
684 catch (DrawRuntimeException dre)
685 {
686
687 }
688
689 try
690 {
691 p1.closestPointOnSegment(6, 7, Double.NaN, 9);
692 fail("NaN value should have thrown a DrawRuntimeException");
693 }
694 catch (DrawRuntimeException dre)
695 {
696
697 }
698
699 try
700 {
701 p1.closestPointOnSegment(6, 7, 8, Double.NaN);
702 fail("NaN value should have thrown a DrawRuntimeException");
703 }
704 catch (DrawRuntimeException dre)
705 {
706
707 }
708
709 try
710 {
711 p1.closestPointOnLine(Double.NaN, 7, 8, 9);
712 fail("NaN value should have thrown a DrawRuntimeException");
713 }
714 catch (DrawRuntimeException dre)
715 {
716
717 }
718
719 try
720 {
721 p1.closestPointOnLine(6, Double.NaN, 8, 9);
722 fail("NaN value should have thrown a DrawRuntimeException");
723 }
724 catch (DrawRuntimeException dre)
725 {
726
727 }
728
729 try
730 {
731 p1.closestPointOnLine(6, 7, Double.NaN, 9);
732 fail("NaN value should have thrown a DrawRuntimeException");
733 }
734 catch (DrawRuntimeException dre)
735 {
736
737 }
738
739 try
740 {
741 p1.closestPointOnLine(6, 7, 8, Double.NaN);
742 fail("NaN value should have thrown a DrawRuntimeException");
743 }
744 catch (DrawRuntimeException dre)
745 {
746
747 }
748
749 try
750 {
751 p1.closestPointOnLine(6, 7, 6, 7);
752 fail("identical points should have thrown a DrawRuntimeException");
753 }
754 catch (DrawRuntimeException dre)
755 {
756
757 }
758
759 }
760
761
762
763
764 @Test
765 public void circleIntersectionTest()
766 {
767 for (int x1 = -5; x1 <= 5; x1++)
768 {
769 for (int y1 = -5; y1 <= 5; y1++)
770 {
771 Point2d p1 = new Point2d(x1, y1);
772 for (int r1 = 0; r1 < 5; r1++)
773 {
774 for (int x2 = -5; x2 <= 5; x2++)
775 {
776 for (int y2 = -5; y2 <= 5; y2++)
777 {
778 Point2d p2 = new Point2d(x2, y2);
779 double distance = p1.distance(p2);
780 for (int r2 = 0; r2 < 5; r2++)
781 {
782 if (x1 == x2 && y1 == y2 && r1 == r2)
783 {
784 try
785 {
786 Point2d.circleIntersections(p1, r1, p2, r2);
787 fail("Identical circles should have thrown a DrawRuntimeException");
788 }
789 catch (DrawRuntimeException dre)
790 {
791
792 }
793 }
794 else
795 {
796 List<Point2d> result = Point2d.circleIntersections(p1, r1, p2, r2);
797
798
799
800
801
802
803
804 if (distance > r1 + r2 + 0.0001)
805 {
806 if (result.size() > 0)
807 {
808 Point2d.circleIntersections(p1, r1, p2, r2);
809 }
810 assertEquals("There are 0 intersections", 0, result.size());
811 }
812 if (distance < r1 + r2 - 0.0001 && distance > Math.abs(r2 - r1) + 0.0001)
813 {
814 if (result.size() != 2)
815 {
816 Point2d.circleIntersections(p1, r1, p2, r2);
817 }
818 assertEquals("There are 2 intersections", 2, result.size());
819 }
820 for (Point2d p : result)
821 {
822 if (Math.abs(r1 - p.distance(p1)) > 0.1 || Math.abs(r2 - p.distance(p2)) > 0.1)
823 {
824 Point2d.circleIntersections(p1, r1, p2, r2);
825 }
826 assertEquals("result is at r1 from p1", r1, p.distance(p1), 0.0001);
827 assertEquals("result is at r2 from p2", r2, p.distance(p2), 0.0001);
828 }
829 }
830 }
831 }
832 }
833 }
834 }
835 }
836 try
837 {
838 Point2d.circleIntersections(new Point2d(1, 2), -1, new Point2d(3, 4), 2);
839 fail("negative radius should have thrown a DrawRuntimeException");
840 }
841 catch (DrawRuntimeException dre)
842 {
843
844 }
845
846 try
847 {
848 Point2d.circleIntersections(new Point2d(1, 2), 5, new Point2d(3, 4), -2);
849 fail("negative radius should have thrown a DrawRuntimeException");
850 }
851 catch (DrawRuntimeException dre)
852 {
853
854 }
855
856 try
857 {
858 Point2d.circleIntersections(null, 5, new Point2d(3, 4), 2);
859 fail("null for center1 should have thrown a NullPointerException");
860 }
861 catch (NullPointerException npe)
862 {
863
864 }
865
866 try
867 {
868 Point2d.circleIntersections(new Point2d(3, 4), 5, null, 2);
869 fail("null for center1 should have thrown a NullPointerException");
870 }
871 catch (NullPointerException npe)
872 {
873
874 }
875 }
876
877
878
879
880 @Test
881 public void testDirection()
882 {
883 Point2d reference = new Point2d(5, 8);
884 assertEquals("East", 0, reference.directionTo(new Point2d(reference.x + 10, reference.y)), 0);
885 assertEquals("North", Math.PI / 2, reference.directionTo(new Point2d(reference.x, reference.y + 5)), 0.00001);
886 assertEquals("NorthEast", Math.PI / 4, reference.directionTo(new Point2d(reference.x + 2, reference.y + 2)), 0.00001);
887 assertEquals("West", Math.PI, reference.directionTo(new Point2d(reference.x - 1, reference.y)), 0);
888 assertEquals("South", -Math.PI / 2, reference.directionTo(new Point2d(reference.x, reference.y - 0.5)), 0.00001);
889 assertEquals("SouthWst", -3 * Math.PI / 4, reference.directionTo(new Point2d(reference.x - 0.2, reference.y - 0.2)),
890 0.00001);
891 }
892
893 }