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.assertTrue;
7   import static org.junit.jupiter.api.Assertions.fail;
8   
9   import java.awt.geom.Point2D;
10  import java.util.Iterator;
11  import java.util.NoSuchElementException;
12  
13  import org.djutils.base.AngleUtil;
14  import org.djutils.draw.DrawRuntimeException;
15  import org.djutils.exceptions.Try;
16  import org.junit.jupiter.api.Test;
17  
18  /**
19   * DirectedPoint2dTest.java.
20   * <p>
21   * Copyright (c) 2023-2024 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
22   * for project information <a href="https://djutils.org" target="_blank"> https://djutils.org</a>. The DJUTILS project is
23   * distributed under a three-clause BSD-style license, which can be found at
24   * <a href="https://djutils.org/docs/license.html" target="_blank"> https://djutils.org/docs/license.html</a>.
25   * </p>
26   * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
27   * @author <a href="https://www.tudelft.nl/pknoppers">Peter Knoppers</a>
28   */
29  public class DirectedPoint2dTest
30  {
31      /**
32       * Test the methods that are not covered by the Ray2dTest.
33       */
34      @SuppressWarnings({"unlikely-arg-type"})
35      @Test
36      public void testMethods()
37      {
38          DirectedPoint2d dp = new DirectedPoint2d(1, 2, 3);
39          assertEquals(1, dp.getX(), 0.0, "x can be retrieved");
40          assertEquals(2, dp.getY(), 0.0, "y can be retrieved");
41          assertEquals(3, dp.getDirZ(), 0.0, "DirZ can be retrieved");
42          assertEquals(1, dp.size(), "size is 1");
43          Iterator<? extends DirectedPoint2d> it = dp.getPoints();
44          assertTrue(it.hasNext(), "iterator has at least one point to provide");
45          DirectedPoint2d p = it.next();
46          assertEquals(p.x, dp.x, 0, "x matches");
47          assertEquals(p.y, dp.y, 0, "y matches");
48          assertEquals(p.dirZ, dp.dirZ, 0, "dirZ matches");
49          assertFalse(it.hasNext(), "iterator is now exhausted");
50          DirectedPoint2d neg = dp.neg();
51          assertEquals(-1, neg.x, 0, "x is negated");
52          assertEquals(-2, neg.y, 0, "y is negated");
53          assertEquals(AngleUtil.normalizeAroundZero(3 + Math.PI), neg.dirZ, 0.0001, "dirZ is altered by pi");
54          try
55          {
56              it.next();
57              fail("exhausted iterator should have thrown an exception");
58          }
59          catch (NoSuchElementException nse)
60          {
61              // Ignore expected exception
62          }
63          assertTrue(dp.toString().startsWith("DirectedPoint2d"));
64          assertTrue(dp.toString(false).startsWith("DirectedPoint2d"));
65          assertTrue(dp.toString(true).startsWith("["));
66          assertEquals(dp, dp, "Equals to itself");
67          assertFalse(dp.equals("bla"), "Not equal to some random string");
68      }
69  
70      /**
71       * Test the DirectedPoint2d construction methods.
72       */
73      @SuppressWarnings("unlikely-arg-type")
74      @Test
75      public void testDirectedPoint2dConstruction()
76      {
77          DirectedPoint2d p = new DirectedPoint2d(10.0, -20.0, Math.PI);
78          assertEquals(10.0, p.x, 0, "x");
79          assertEquals(-20.0, p.y, 0, "y");
80          assertEquals(3.1415926, p.getDirZ(), 1E-6, "dirZ");
81  
82          Point2d p2d = new Point2d(10, -20);
83          p = new DirectedPoint2d(p2d, Math.PI);
84          assertEquals(10.0, p.x, 0, "x");
85          assertEquals(-20.0, p.y, 0, "y");
86          assertEquals(3.1415926, p.getDirZ(), 1E-6, "dirZ");
87          assertEquals(3.1415926, p.dirZ, 1E-6, "dirZ");
88  
89          try
90          {
91              new DirectedPoint2d(Double.NaN, 0, 0);
92              fail("NaN coordinate should have thrown an IllegalArgumentException");
93          }
94          catch (IllegalArgumentException iae)
95          {
96              // Ignore expected exception
97          }
98  
99          try
100         {
101             new DirectedPoint2d(0, Double.NaN, 0);
102             fail("NaN coordinate should have thrown an IllegalArgumentException");
103         }
104         catch (IllegalArgumentException iae)
105         {
106             // Ignore expected exception
107         }
108 
109         try
110         {
111             new DirectedPoint2d(0, 0, Double.NaN);
112             fail("NaN coordinate should have thrown an IllegalArgumentException");
113         }
114         catch (IllegalArgumentException iae)
115         {
116             // Ignore expected exception
117         }
118 
119         double[] p2Arr = new double[] {5.0, 6.0};
120         p = new DirectedPoint2d(p2Arr, Math.PI / 2.0);
121         assertEquals(5.0, p.x, 1E-6);
122         assertEquals(6.0, p.y, 1E-6);
123         assertEquals(3.1415926 / 2.0, p.getDirZ(), 1E-6);
124         Point2D.Double p2DD = new Point2D.Double(-0.1, -0.2);
125         p = new DirectedPoint2d(p2DD, Math.PI / 4.0);
126         assertEquals(-0.1, p.x, 1E-6);
127         assertEquals(-0.2, p.y, 1E-6);
128         assertEquals(p2DD, p.toPoint2D());
129         assertEquals(3.1415926 / 4.0, p.getDirZ(), 1E-6);
130 
131         Try.testFail(new Try.Execution()
132         {
133             @Override
134             public void execute() throws Throwable
135             {
136                 new DirectedPoint2d((Point2D.Double) null, 0.0);
137             }
138         }, "Should throw NPE", NullPointerException.class);
139 
140         Try.testFail(new Try.Execution()
141         {
142             @Override
143             public void execute() throws Throwable
144             {
145                 new DirectedPoint2d((Point2D.Double) null, Math.PI);
146             }
147         }, "Should throw NPE", NullPointerException.class);
148 
149         Try.testFail(new Try.Execution()
150         {
151             @Override
152             public void execute() throws Throwable
153             {
154                 new DirectedPoint2d(new double[] {}, Math.PI / 2.0);
155             }
156         }, "Should throw IAE", IllegalArgumentException.class);
157 
158         Try.testFail(new Try.Execution()
159         {
160             @Override
161             public void execute() throws Throwable
162             {
163                 new DirectedPoint2d(new double[] {1.0}, Math.PI / 4.0);
164             }
165         }, "Should throw IAE", IllegalArgumentException.class);
166 
167         Try.testFail(new Try.Execution()
168         {
169             @Override
170             public void execute() throws Throwable
171             {
172                 new DirectedPoint2d(new double[] {1.0, 2.0, 3.0}, Math.PI);
173             }
174         }, "Should throw IAE", IllegalArgumentException.class);
175 
176         // equals and hashCode
177         assertTrue(p.equals(p));
178         assertEquals(p.hashCode(), p.hashCode());
179         DirectedPoint3d p3d = p.translate(1, 2, 3);
180         assertFalse(p.equals(p3d));
181         assertFalse(p.equals(null));
182         assertNotEquals(p3d.hashCode(), p.hashCode());
183         assertEquals(p.x + 1.0, p3d.x, 0.00001, "translated x");
184         assertEquals(p.y + 2.0, p3d.y, 0.00001, "translated y");
185         assertEquals(0 + 3.0, p3d.z, 0.00001, "translated z");
186         assertEquals(Math.PI / 4.0, p.getDirZ(), 1E-6);
187         assertTrue(p.equals(p.translate(0.0, 0.0)));
188         assertFalse(p.equals(p.translate(1.0, 0.0)));
189         assertFalse(p.equals(p.translate(0.0, 1.0)));
190         assertFalse(p.equals(p.rotate(0.1)));
191 
192         // toString
193         p = new DirectedPoint2d(10.0, 20.0, Math.PI);
194         assertEquals("DirectedPoint2d [x=10.000000, y=20.000000, dirZ=3.141593]", p.toString());
195         assertEquals("DirectedPoint2d [x=10.0, y=20.0, dirZ=3.1]", p.toString("%.1f"));
196         assertEquals("[x=10, y=20, dirZ=3]", p.toString("%.0f", true));
197 
198         // epsilonEquals
199         DirectedPoint3d p3 = new DirectedPoint3d(p.translate(0.001, 0.0, 0.0), 0, p.dirZ);
200         DirectedPoint3d ref = new DirectedPoint3d(p.translate(0, 0, 0), 0, p.dirZ);
201         assertTrue(ref.epsilonEquals(p3, 0.09, 0.001));
202         assertTrue(p3.epsilonEquals(ref, 0.09, 0.001));
203         assertFalse(ref.epsilonEquals(p3, 0.0009, 0.001));
204         assertFalse(p3.epsilonEquals(ref, 0.0009, 0.001));
205         p3 = p.translate(0.0, 0.001, 0.0);
206         assertTrue(ref.epsilonEquals(p3, 0.09, 0.001));
207         assertTrue(p3.epsilonEquals(ref, 0.09, 0.001));
208         assertFalse(ref.epsilonEquals(p3, 0.0009, 0.001));
209         assertFalse(p3.epsilonEquals(ref, 0.0009, 0.001));
210         DirectedPoint2d p2 = p.translate(0.001, 0.0);
211         assertTrue(p.epsilonEquals(p2, 0.09, 0.001), "all");
212         assertFalse(p.epsilonEquals(p2, 0.0009, 0.001), "dx");
213         p2 = p.translate(0.0, 0.001);
214         assertTrue(p.epsilonEquals(p2, 0.09, 0.001), "all");
215         assertFalse(p.epsilonEquals(p2, 0.0009, 0.001), "dy");
216         p3 = p.translate(0.0, 0.0, 0.001);
217         assertTrue(ref.epsilonEquals(p3, 0.09, 0.001));
218         assertTrue(p3.epsilonEquals(ref, 0.09, 0.001));
219         assertFalse(ref.epsilonEquals(p3, 0.0009, 0.001));
220         assertFalse(p3.epsilonEquals(ref, 0.0009, 0.001));
221         DirectedPoint2d dp2 = p.rotate(0.001);
222         assertTrue(p.epsilonEquals(dp2, 0.09, 0.009));
223         assertTrue(dp2.epsilonEquals(p, 0.09, 0.009));
224         assertFalse(p.epsilonEquals(dp2, 0.0009, 0.0009));
225         assertFalse(dp2.epsilonEquals(p, 0.0009, 0.0009));
226     }
227 
228     /**
229      * Test the DirectedPoint2d operators.
230      */
231     @Test
232     public void testDirectedPoint2dOperators()
233     {
234         DirectedPoint2d p = new DirectedPoint2d(-0.1, -0.2, -Math.PI / 7);
235         DirectedPoint2d out = new DirectedPoint2d(p.abs(), p.dirZ);
236         assertEquals(0.1, out.x, 1E-6, "x");
237         assertEquals(0.2, out.y, 1E-6, "y");
238         assertEquals(-Math.PI / 7, out.getDirZ(), 1E-6, "dirZ");
239 
240         Iterator<? extends Point2d> i = p.getPoints();
241         assertTrue(i.hasNext(), "iterator has one point");
242         assertEquals(p, i.next(), "iterator returns p");
243         assertFalse(i.hasNext(), "iterator does not have another point");
244 
245         out = p.neg();
246         assertEquals(0.1, out.x, 1E-6, "neg x");
247         assertEquals(0.2, out.y, 1E-6, "neg y");
248         assertEquals(Math.PI - Math.PI / 7, out.getDirZ(), 1E-6, "neg dirZ");
249 
250         out = p.scale(1.0);
251         assertEquals(-0.1, out.x, 1E-6, "x");
252         assertEquals(-0.2, out.y, 1E-6, "y");
253         assertEquals(-Math.PI / 7, out.getDirZ(), 1E-6, "dirZ");
254 
255         out = p.scale(10.0);
256         assertEquals(-1.0, out.x, 1E-6, "10 x");
257         assertEquals(-2.0, out.y, 1E-6, "10 y");
258         assertEquals(-Math.PI / 7, out.getDirZ(), 1E-6, "dirZ");
259 
260         out = p.translate(5.0, -1.0);
261         assertEquals(4.9, out.x, 1E-6, "x");
262         assertEquals(-1.2, out.y, 1E-6, "y");
263         assertEquals(-Math.PI / 7, out.getDirZ(), 1E-6, "dirZ");
264 
265         out = p.translate(1.0, 3.0);
266         assertEquals(0.9, out.x, 1E-6, "x");
267         assertEquals(2.8, out.y, 1E-6, "y");
268         assertEquals(-Math.PI / 7, out.getDirZ(), 1E-6, "dirZ");
269 
270         out = p.rotate(- Math.PI / 4);
271         assertEquals(-0.1, out.x, 1E-6, "x");
272         assertEquals(-0.2, out.y, 1E-6, "y");
273         assertEquals(-Math.PI / 7 - Math.PI / 4, out.getDirZ(), 1E-6, "dirZ");
274 
275         // interpolate
276         DirectedPoint2d p1 = new DirectedPoint2d(1.0, 1.0, 0.0);
277         DirectedPoint2d p2 = new DirectedPoint2d(5.0, 5.0, Math.PI / 2.0);
278         assertEquals(p1, p1.interpolate(p2, 0.0), "p1 interpolated to p2 at 0");
279         assertEquals(p2, p1.interpolate(p2, 1.0), "p1 interpolated to p2 at 1");
280         assertEquals(p2, p2.interpolate(p1, 0.0), "p2 interpolated to p1 at 0");
281         assertEquals(p1, p2.interpolate(p1, 1.0), "p2 interpolated to p1 at 1");
282         assertEquals(p1, p1.interpolate(p1, 0.0), "p1 interpolated to itself at 0");
283         assertEquals(new DirectedPoint2d(3.0, 3.0, Math.PI / 4.0), p1.interpolate(p2, 0.5), "interpolated at halfway");
284 
285         // distance
286         assertEquals(Math.sqrt(32.0), p1.distance(p2), 0.001);
287         assertEquals(32.0, p1.distanceSquared(p2), 0.001);
288         // FIXME
289         // assertEquals(Math.sqrt(32.0), p1.horizontalDistance(p2), 0.001);
290         // assertEquals(32.0, p1.horizontalDistanceSquared(p2), 0.001);
291 
292         // direction
293         // assertEquals(Math.toRadians(45.0), p2.horizontalDirection(), 0.001);
294         // assertEquals(Math.toRadians(45.0), p1.horizontalDirection(p2), 0.001);
295         // assertEquals(0.0, new DirectedPoint2d(0.0, 0.0, Math.PI / 4.0).horizontalDirection(), 0.001);
296 
297         // normalize
298         DirectedPoint2d pn = new DirectedPoint2d(p2.normalize(), p.dirZ);
299         assertEquals(1.0 / Math.sqrt(2.0), pn.x, 0.001);
300         assertEquals(1.0 / Math.sqrt(2.0), pn.y, 0.001);
301 
302         Try.testFail(new Try.Execution()
303         {
304             @Override
305             public void execute() throws Throwable
306             {
307                 new DirectedPoint2d(0.0, 0.0, Math.PI / 4.0).normalize();
308             }
309         }, "Should throw DRtE", DrawRuntimeException.class);
310 
311         Try.testFail(new Try.Execution()
312         {
313             @Override
314             public void execute() throws Throwable
315             {
316                 p1.translate(Double.NaN, 2);
317             }
318         }, "Should throw IAE", IllegalArgumentException.class);
319 
320         Try.testFail(new Try.Execution()
321         {
322             @Override
323             public void execute() throws Throwable
324             {
325                 p1.translate(1, Double.NaN);
326             }
327         }, "Should throw IAE", IllegalArgumentException.class);
328 
329         Try.testFail(new Try.Execution()
330         {
331             @Override
332             public void execute() throws Throwable
333             {
334                 p1.translate(Double.NaN, 2, 3);
335             }
336         }, "Should throw IAE", IllegalArgumentException.class);
337 
338         Try.testFail(new Try.Execution()
339         {
340             @Override
341             public void execute() throws Throwable
342             {
343                 p1.translate(1, Double.NaN, 3);
344             }
345         }, "Should throw IAE", IllegalArgumentException.class);
346 
347         Try.testFail(new Try.Execution()
348         {
349             @Override
350             public void execute() throws Throwable
351             {
352                 p1.translate(1, 2, Double.NaN);
353             }
354         }, "Should throw IAE", IllegalArgumentException.class);
355 
356     }
357 
358     /**
359      * Test the DirectedPoint2d operators for NPE.
360      */
361     @Test
362     public void testDirectedPoint2dOperatorsNPE()
363     {
364         final DirectedPoint2d p1 = new DirectedPoint2d(1.0, 1.0, Math.PI / 4.0);
365 
366         Try.testFail(new Try.Execution()
367         {
368             @Override
369             public void execute() throws Throwable
370             {
371                 p1.interpolate(null, 0.5);
372             }
373         }, "Should throw NPE", NullPointerException.class);
374 
375         Try.testFail(new Try.Execution()
376         {
377             @Override
378             public void execute() throws Throwable
379             {
380                 p1.distance(null);
381             }
382         }, "Should throw NPE", NullPointerException.class);
383 
384         Try.testFail(new Try.Execution()
385         {
386             @Override
387             public void execute() throws Throwable
388             {
389                 p1.distanceSquared(null);
390             }
391         }, "Should throw NPE", NullPointerException.class);
392 
393     }
394 
395 }