View Javadoc
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  
13  import org.djutils.draw.DrawRuntimeException;
14  import org.djutils.draw.bounds.Bounds3d;
15  import org.djutils.draw.line.LineSegment3d;
16  import org.djutils.draw.line.PolyLine3d;
17  import org.djutils.exceptions.Try;
18  import org.junit.jupiter.api.Test;
19  
20  /**
21   * Point3dTest.java.
22   * <p>
23   * Copyright (c) 2020-2025 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
24   * BSD-style license. See <a href="https://djutils.org/docs/current/djutils/licenses.html">DJUTILS License</a>.
25   * </p>
26   * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
27   * @author <a href="https://github.com/peter-knoppers">Peter Knoppers</a>
28   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
29   */
30  public class Point3dTest
31  {
32      /**
33       * Test the Point3d construction methods.
34       */
35      @SuppressWarnings("unlikely-arg-type")
36      @Test
37      public void testPoint3dConstruction()
38      {
39          Point3d p = new Point3d(10.0, -20.0, 16.0);
40          assertNotNull(p);
41          assertEquals(10.0, p.x, 0, "Access x");
42          assertEquals(-20.0, p.y, 0, "Access y");
43          assertEquals(16.0, p.z, 0, "Access z");
44          assertEquals(3, p.getDimensions(), "Dimensions is 3");
45  
46          assertEquals(1, p.size(), "Size method returns 1");
47  
48          Point2d projection = p.project();
49          assertEquals(10.0, projection.x, 0);
50          assertEquals(-20.0, projection.y, 0);
51  
52          try
53          {
54              new Point3d(Double.NaN, 0, 0);
55              fail("NaN should have thrown an ArithmeticException");
56          }
57          catch (ArithmeticException e)
58          {
59              // Ignore expected exception
60          }
61  
62          try
63          {
64              new Point3d(0, Double.NaN, 0);
65              fail("NaN should have thrown an ArithmeticException");
66          }
67          catch (ArithmeticException e)
68          {
69              // Ignore expected exception
70          }
71  
72          try
73          {
74              new Point3d(0, 0, Double.NaN);
75              fail("NaN should have thrown an ArithmeticException");
76          }
77          catch (ArithmeticException e)
78          {
79              // Ignore expected exception
80          }
81  
82          double[] p3Arr = new double[] {5.0, 6.0, 7.0};
83          p = new Point3d(p3Arr);
84          assertEquals(5.0, p.x, 0);
85          assertEquals(6.0, p.y, 0);
86          assertEquals(7.0, p.z, 0);
87          Try.testFail(new Try.Execution()
88          {
89              @Override
90              public void execute() throws Throwable
91              {
92                  new Point3d(new double[] {});
93              }
94          }, "Should throw IAE", IllegalArgumentException.class);
95  
96          Try.testFail(new Try.Execution()
97          {
98              @Override
99              public void execute() throws Throwable
100             {
101                 new Point3d(new double[] {1.0});
102             }
103         }, "Should throw IAE", IllegalArgumentException.class);
104 
105         Try.testFail(new Try.Execution()
106         {
107             @Override
108             public void execute() throws Throwable
109             {
110                 new Point3d(new double[] {1.0, 2.0});
111             }
112         }, "Should throw IAE", IllegalArgumentException.class);
113 
114         Try.testFail(new Try.Execution()
115         {
116             @Override
117             public void execute() throws Throwable
118             {
119                 new Point3d(new double[] {1.0, 2.0, 3.0, 4.0});
120             }
121         }, "Should throw IAE", IllegalArgumentException.class);
122 
123         Try.testFail(new Try.Execution()
124         {
125             @Override
126             public void execute() throws Throwable
127             {
128                 new Point3d((Point2d) null, 0);
129             }
130         }, "Should throw NPE", NullPointerException.class);
131 
132         Try.testFail(new Try.Execution()
133         {
134             @Override
135             public void execute() throws Throwable
136             {
137                 new Point3d((Point2D.Double) null, 0);
138             }
139         }, "Should throw NPE", NullPointerException.class);
140 
141         Try.testFail(new Try.Execution()
142         {
143             @Override
144             public void execute() throws Throwable
145             {
146                 new Point3d(new Point2D.Double(Double.NaN, 2), 0);
147             }
148         }, "Should throw ArithmeticException", ArithmeticException.class);
149 
150         Try.testFail(new Try.Execution()
151         {
152             @Override
153             public void execute() throws Throwable
154             {
155                 new Point3d(new Point2D.Double(1, Double.NaN), 0);
156             }
157         }, "Should throw ArithmeticException", ArithmeticException.class);
158 
159         // equals and hashCode
160         assertTrue(p.equals(p));
161         assertEquals(p.hashCode(), p.hashCode());
162         Point2d p2d = new Point2d(1.0, 1.0);
163         assertFalse(p.equals(p2d));
164         assertFalse(p.equals(null));
165         assertNotEquals(p2d.hashCode(), p.hashCode());
166         assertEquals(p, p.translate(0.0, 0.0, 0.0), "Translating over 0,0,0 returns p");
167         assertNotEquals(p, p.translate(1.0, 0.0, 0.0));
168         assertNotEquals(p, p.translate(0.0, 1.0, 0.0));
169         assertNotEquals(p, p.translate(0.0, 0.0, 1.0));
170 
171         // toString
172         p = new Point3d(10.0, 20.0, 30.0);
173         assertEquals("Point3d [x=10.000000, y=20.000000, z=30.000000]", p.toString());
174         assertEquals("Point3d [x=10.0, y=20.0, z=30.0]", p.toString("%.1f"));
175         assertEquals("[x=10, y=20, z=30]", p.toString("%.0f", true));
176 
177         // epsilonEquals
178         assertTrue(p.epsilonEquals(p, 0.1));
179         assertTrue(p.epsilonEquals(p, 0.001));
180         assertTrue(p.epsilonEquals(p, 0.0));
181         Point3d p3 = p.translate(0.001, 0.0, 0.0);
182         assertTrue(p.epsilonEquals(p3, 0.09));
183         assertTrue(p3.epsilonEquals(p, 0.09));
184         assertFalse(p.epsilonEquals(p3, 0.0009));
185         assertFalse(p3.epsilonEquals(p, 0.0009));
186         p3 = p.translate(0.0, 0.001, 0.0);
187         assertTrue(p.epsilonEquals(p3, 0.09));
188         assertTrue(p3.epsilonEquals(p, 0.09));
189         assertFalse(p.epsilonEquals(p3, 0.0009));
190         assertFalse(p3.epsilonEquals(p, 0.0009));
191         p3 = p.translate(0.0, 0.0, 0.001);
192         assertTrue(p.epsilonEquals(p3, 0.09));
193         assertTrue(p3.epsilonEquals(p, 0.09));
194         assertFalse(p.epsilonEquals(p3, 0.0009));
195         assertFalse(p3.epsilonEquals(p, 0.0009));
196 
197         p2d = new Point2d(123, 456);
198         p3 = new Point3d(p2d, 789);
199         assertEquals(123, p3.x, 0, "x");
200         assertEquals(456, p3.y, 0, "y");
201         assertEquals(789, p3.z, 0, "z");
202 
203         Point2D p2D = new java.awt.geom.Point2D.Double(123, 456);
204         p3 = new Point3d(p2D, 789);
205         assertEquals(123, p3.x, 0, "x");
206         assertEquals(456, p3.y, 0, "y");
207         assertEquals(789, p3.z, 0, "z");
208     }
209 
210     /**
211      * Test the Point3d operators.
212      */
213     @Test
214     public void testPoint3dOperators()
215     {
216         Point3d p = new Point3d(-0.1, -0.2, -0.3);
217         assertEquals(0.1, p.abs().x, 1E-6);
218         assertEquals(0.2, p.abs().y, 1E-6);
219         assertEquals(0.3, p.abs().z, 1E-6);
220         p = p.neg();
221         assertEquals(0.1, p.x, 1E-6);
222         assertEquals(0.2, p.y, 1E-6);
223         assertEquals(0.3, p.z, 1E-6);
224         p = p.scale(1.0);
225         assertEquals(0.1, p.x, 1E-6);
226         assertEquals(0.2, p.y, 1E-6);
227         assertEquals(0.3, p.z, 1E-6);
228         p = p.scale(10.0);
229         assertEquals(1.0, p.x, 1E-6);
230         assertEquals(2.0, p.y, 1E-6);
231         assertEquals(3.0, p.z, 1E-6);
232         p = p.translate(5.0, -1.0, 0.5);
233         assertEquals(6.0, p.x, 1E-6);
234         assertEquals(1.0, p.y, 1E-6);
235         assertEquals(3.5, p.z, 1E-6);
236         Point3d p3d = p.translate(1.0, 1.0, 1.0);
237         assertEquals(7.0, p3d.x, 1E-6);
238         assertEquals(2.0, p3d.y, 1E-6);
239         assertEquals(4.5, p3d.z, 1E-6);
240         p3d = p.translate(6.0, 1.0);
241         assertEquals(12.0, p3d.x, 1E-6);
242         assertEquals(2.0, p3d.y, 1E-6);
243         assertEquals(3.5, p3d.z, 1E-6);
244 
245         try
246         {
247             p.translate(Double.NaN, 2.0);
248             fail("NaN translation should have thrown an ArithmeticException");
249         }
250         catch (ArithmeticException e)
251         {
252             // Ignore expected exception
253         }
254 
255         try
256         {
257             p.translate(1.0, Double.NaN);
258             fail("NaN translation should have thrown an ArithmeticException");
259         }
260         catch (ArithmeticException e)
261         {
262             // Ignore expected exception
263         }
264 
265         try
266         {
267             p.translate(Double.NaN, 2.0, 3.0);
268             fail("NaN translation should have thrown an ArithmeticException");
269         }
270         catch (ArithmeticException e)
271         {
272             // Ignore expected exception
273         }
274 
275         try
276         {
277             p.translate(1.0, Double.NaN, 3.0);
278             fail("NaN translation should have thrown an ArithmeticException");
279         }
280         catch (ArithmeticException e)
281         {
282             // Ignore expected exception
283         }
284 
285         try
286         {
287             p.translate(1.0, 2.0, Double.NaN);
288             fail("NaN translation should have thrown an ArithmeticException");
289         }
290         catch (ArithmeticException e)
291         {
292             // Ignore expected exception
293         }
294 
295         // interpolate
296         Point3d p1 = new Point3d(1.0, 1.0, 1.0);
297         Point3d p2 = new Point3d(5.0, 5.0, 5.0);
298         assertEquals(p1, p1.interpolate(p2, 0.0), "Interpolate at 0.0 returns this");
299         assertEquals(p2, p2.interpolate(p1, 0.0));
300         assertEquals(p1, p1.interpolate(p1, 0.0));
301         assertEquals(new Point3d(3.0, 3.0, 3.0), p1.interpolate(p2, 0.5));
302 
303         // distance
304         assertEquals(Math.sqrt(48.0), p1.distance(p2), 0.001);
305         assertEquals(48.0, p1.distanceSquared(p2), 0.001);
306         assertEquals(Math.sqrt(32.0), p1.horizontalDistance(p2), 0.001);
307         assertEquals(32.0, p1.horizontalDistanceSquared(p2), 0.001);
308 
309         // direction
310         assertEquals(Math.toRadians(45.0), p2.horizontalDirection(), 0.001);
311         assertEquals(Math.toRadians(45.0), p1.horizontalDirection(p2), 0.001);
312         assertEquals(0.0, new Point3d(0.0, 0.0, 0.0).horizontalDirection(), 0.001);
313         assertEquals(Math.atan2(Math.sqrt(2.0), 1), p1.verticalDirection(p2), 0.001);
314         assertEquals(Math.PI / 2, p1.verticalDirection(new Point3d(2.0, 2.0, 1.0)), 0.01);
315         assertEquals(0, p1.verticalDirection(new Point3d(1.0, 1.0, 2.0)), 0.01);
316 
317         // normalize
318         Point3d pn = p2.normalize();
319         assertEquals(1.0 / Math.sqrt(3.0), pn.x, 0.001);
320         assertEquals(1.0 / Math.sqrt(3.0), pn.y, 0.001);
321         assertEquals(1.0 / Math.sqrt(3.0), pn.z, 0.001);
322 
323         Try.testFail(new Try.Execution()
324         {
325             @Override
326             public void execute() throws Throwable
327             {
328                 new Point3d(0.0, 0.0, 0.0).normalize();
329             }
330         }, "Should throw DRtE", DrawRuntimeException.class);
331 
332         assertEquals(1, p1.size(), "size of a Point3d is 1");
333         Point2d projection = p1.project();
334         assertEquals(p1.x, projection.x, 0, "projected x");
335         assertEquals(p1.y, projection.y, 0, "projected y");
336 
337         Bounds3d bounds = p1.getBounds();
338         assertEquals(p1.x, bounds.getMinX(), 0, "Bounds min x");
339         assertEquals(p1.y, bounds.getMinY(), 0, "Bounds min y");
340         assertEquals(p1.z, bounds.getMinZ(), 0, "Bounds min z");
341         assertEquals(p1.x, bounds.getMaxX(), 0, "Bounds max x");
342         assertEquals(p1.y, bounds.getMaxY(), 0, "Bounds max y");
343         assertEquals(p1.z, bounds.getMaxZ(), 0, "Bounds max z");
344     }
345 
346     /**
347      * Test the Point3d operators for NPE.
348      */
349     @Test
350     public void testPoint3dOperatorsNPE()
351     {
352         final Point3d p1 = new Point3d(1.0, 1.0, 1.0);
353 
354         Try.testFail(new Try.Execution()
355         {
356             @Override
357             public void execute() throws Throwable
358             {
359                 p1.interpolate(null, 0.5);
360             }
361         }, "Should throw NPE", NullPointerException.class);
362 
363         Try.testFail(new Try.Execution()
364         {
365             @Override
366             public void execute() throws Throwable
367             {
368                 p1.distance(null);
369             }
370         }, "Should throw NPE", NullPointerException.class);
371 
372         Try.testFail(new Try.Execution()
373         {
374             @Override
375             public void execute() throws Throwable
376             {
377                 p1.distanceSquared(null);
378             }
379         }, "Should throw NPE", NullPointerException.class);
380 
381         // FIXME
382         // Try.testFail(new Try.Execution()
383         // {
384         // @Override
385         // public void execute() throws Throwable
386         // {
387         // p1.horizontalDistance((Point2d) null);
388         // }
389         // }, "Should throw NPE", NullPointerException.class);
390         //
391         // Try.testFail(new Try.Execution()
392         // {
393         // @Override
394         // public void execute() throws Throwable
395         // {
396         // p1.horizontalDistanceSquared((Point3d) null);
397         // }
398         // }, "Should throw NPE", NullPointerException.class);
399 
400     }
401 
402     /**
403      * Test the closestPointOnSegment and the closestPointOnLine methods.
404      * @throws DrawRuntimeException if that happens uncaught; this test has failed
405      */
406     @Test
407     public void testClosestPointOnSegmentAndLine() throws DrawRuntimeException
408     {
409         Point3d p1 = new Point3d(-2, 3, 5);
410         for (Point3d p2 : new Point3d[] {new Point3d(7, 4, -5)/* angled */, new Point3d(-3, 6, 5) /* also angled */,
411                 new Point3d(-2, -5, 5) /* vertical */, new Point3d(8, 3, 5)/* horizontal */, new Point3d(-2, 3, 1)/* z */ })
412         {
413             PolyLine3d line = new PolyLine3d(p1, p2);
414             for (double x = -10; x <= 10; x += 0.5)
415             {
416                 for (double y = -10; y <= 10; y += 0.5)
417                 {
418                     for (double z = -10; z <= 10; z += 0.5)
419                     {
420                         Point3d p = new Point3d(x, y, z);
421                         // Figure out the correct result using a totally different method (binary search over the line segment)
422                         double fraction = 0.5;
423                         double step = 0.25;
424                         Point3d approximation = line.getLocationFraction(fraction);
425                         double distance = approximation.distance(p);
426                         // 10 iterations should get us to within one thousandth
427                         for (int iteration = 0; iteration < 10; iteration++)
428                         {
429                             // Try stepping up
430                             double upFraction = fraction + step;
431                             Point3d upApproximation = line.getLocationFraction(upFraction);
432                             double upDistance = upApproximation.distance(p);
433                             if (upDistance < distance)
434                             {
435                                 distance = upDistance;
436                                 fraction = upFraction;
437                                 approximation = upApproximation;
438                             }
439                             else
440                             {
441                                 // Try stepping down
442                                 double downFraction = fraction - step;
443                                 Point3d downApproximation = line.getLocationFraction(downFraction);
444                                 double downDistance = downApproximation.distance(p);
445                                 if (downDistance < distance)
446                                 {
447                                     distance = downDistance;
448                                     fraction = downFraction;
449                                     approximation = downApproximation;
450                                 }
451                             }
452                             step /= 2;
453                         }
454                         Point3d result = p.closestPointOnSegment(p1, p2);
455                         assertEquals(0, approximation.distance(result), line.getLength() / 1000,
456                                 "distance should be less than one thousandth of line length");
457                         assertEquals(p1, p.closestPointOnSegment(p1, p1),
458                                 "zero length line segment should always return start point");
459                         result = p.closestPointOnSegment(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
460                         assertEquals(0, approximation.distance(result), line.getLength() / 1000,
461                                 "distance should be less than one thousandth of line length");
462 
463                         if (fraction > 0.001 && fraction < 0.999)
464                         {
465                             result = p.closestPointOnLine(p1, p2);
466                             assertEquals(0, approximation.distance(result), line.getLength() / 1000,
467                                     "distance should be less than one thousandth of line length");
468                             result = p.closestPointOnLine(p1, p2);
469                             assertEquals(0, approximation.distance(result), line.getLength() / 1000,
470                                     "distance should be less than one thousandth of line length");
471                             result = p.closestPointOnLine(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
472                             assertEquals(0, approximation.distance(result), line.getLength() / 1000,
473                                     "distance should be less than one thousandth of line length");
474                         }
475                         else
476                         {
477                             // extrapolating
478                             double range = Math.max(Math.max(line.getLength(), p.distance(p1)), p.distance(p2));
479                             step = 5.0;
480                             fraction = 0.5;
481                             distance = range;
482                             // 10 iterations should get us to within one thousandth
483                             for (int iteration = 0; iteration < 20; iteration++)
484                             {
485                                 // Try stepping up
486                                 double upFraction = fraction + step;
487                                 Point3d upApproximation = line.getLocationFractionExtended(upFraction);
488                                 double upDistance = upApproximation.distance(p);
489                                 if (upDistance < distance)
490                                 {
491                                     distance = upDistance;
492                                     fraction = upFraction;
493                                     approximation = upApproximation;
494                                 }
495                                 else
496                                 {
497                                     // Try stepping down
498                                     double downFraction = fraction - step;
499                                     Point3d downApproximation = line.getLocationFractionExtended(downFraction);
500                                     double downDistance = downApproximation.distance(p);
501                                     if (downDistance < distance)
502                                     {
503                                         distance = downDistance;
504                                         fraction = downFraction;
505                                         approximation = downApproximation;
506                                     }
507                                 }
508                                 step /= 2;
509                             }
510                             result = p.closestPointOnLine(p1, p2);
511                             assertEquals(0, approximation.distance(result), range / 1000,
512                                     "distance should be less than one thousandth of range");
513                             result = p.closestPointOnLine(p1, p2);
514                             assertEquals(0, approximation.distance(result), range / 1000,
515                                     "distance should be less than one thousandth of range");
516                             result = p.closestPointOnLine(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
517                             assertEquals(0, approximation.distance(result), range / 1000,
518                                     "distance should be less than one thousandth of range");
519                             if (fraction < -0.001 || fraction > 1.001)
520                             {
521                                 assertNull(new LineSegment3d(p1, p2).projectOrthogonal(p),
522                                         "projectOrthogonal should return null");
523                                 assertEquals(result, new LineSegment3d(p1, p2).projectOrthogonalExtended(p),
524                                         "projectOrthogonalExtended should return same result as closestPointOnLine");
525                             }
526                         }
527                     }
528                 }
529             }
530         }
531 
532         try
533         {
534             p1.closestPointOnLine(null, new Point3d(5, 6, 7));
535             fail("null should have thrown a NullPointerException");
536         }
537         catch (NullPointerException e)
538         {
539             // Ignore expected exception
540         }
541 
542         try
543         {
544             p1.closestPointOnLine(new Point3d(5, 6, 7), null);
545             fail("null should have thrown a NullPointerException");
546         }
547         catch (NullPointerException e)
548         {
549             // Ignore expected exception
550         }
551 
552         try
553         {
554             p1.closestPointOnSegment(Double.NaN, 7, 8, 9, 10, 11);
555             fail("NaN value should have thrown an ArithmeticException");
556         }
557         catch (ArithmeticException e)
558         {
559             // Ignore expected exception
560         }
561 
562         try
563         {
564             p1.closestPointOnSegment(6, Double.NaN, 8, 9, 10, 11);
565             fail("NaN value should have thrown an ArithmeticException");
566         }
567         catch (ArithmeticException e)
568         {
569             // Ignore expected exception
570         }
571 
572         try
573         {
574             p1.closestPointOnSegment(6, 7, Double.NaN, 9, 10, 11);
575             fail("NaN value should have thrown an ArithmeticException");
576         }
577         catch (ArithmeticException e)
578         {
579             // Ignore expected exception
580         }
581 
582         try
583         {
584             p1.closestPointOnSegment(6, 7, 8, Double.NaN, 10, 11);
585             fail("NaN value should have thrown an ArithmeticException");
586         }
587         catch (ArithmeticException e)
588         {
589             // Ignore expected exception
590         }
591 
592         try
593         {
594             p1.closestPointOnSegment(6, 7, 8, 9, Double.NaN, 11);
595             fail("NaN value should have thrown an ArithmeticException");
596         }
597         catch (ArithmeticException e)
598         {
599             // Ignore expected exception
600         }
601 
602         try
603         {
604             p1.closestPointOnSegment(6, 7, 8, 9, 10, Double.NaN);
605             fail("NaN value should have thrown an ArithmeticException");
606         }
607         catch (ArithmeticException e)
608         {
609             // Ignore expected exception
610         }
611 
612         try
613         {
614             p1.closestPointOnLine(Double.NaN, 7, 8, 9, 10, 11);
615             fail("NaN value should have thrown an ArithmeticException");
616         }
617         catch (ArithmeticException e)
618         {
619             // Ignore expected exception
620         }
621 
622         try
623         {
624             p1.closestPointOnLine(6, Double.NaN, 8, 9, 10, 11);
625             fail("NaN value should have thrown an ArithmeticException");
626         }
627         catch (ArithmeticException dere)
628         {
629             // Ignore expected exception
630         }
631 
632         try
633         {
634             p1.closestPointOnLine(6, 7, Double.NaN, 9, 10, 11);
635             fail("NaN value should have thrown an ArithmeticException");
636         }
637         catch (ArithmeticException e)
638         {
639             // Ignore expected exception
640         }
641 
642         try
643         {
644             p1.closestPointOnLine(6, 7, 8, Double.NaN, 10, 11);
645             fail("NaN value should have thrown an ArithmeticException");
646         }
647         catch (ArithmeticException e)
648         {
649             // Ignore expected exception
650         }
651 
652         try
653         {
654             p1.closestPointOnLine(6, 7, 8, 9, Double.NaN, 11);
655             fail("NaN value should have thrown an ArithmeticException");
656         }
657         catch (ArithmeticException e)
658         {
659             // Ignore expected exception
660         }
661 
662         try
663         {
664             p1.closestPointOnLine(6, 7, 8, 9, 10, Double.NaN);
665             fail("NaN value should have thrown an ArithmeticException");
666         }
667         catch (ArithmeticException e)
668         {
669             // Ignore expected exception
670         }
671 
672         try
673         {
674             p1.closestPointOnLine(6, 7, 8, 6, 7, 8);
675             fail("identical points should have thrown a DrawRuntimeException");
676         }
677         catch (DrawRuntimeException dre)
678         {
679             // Ignore expected exception
680         }
681 
682     }
683 
684 }