1 package org.djutils.draw.line;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertFalse;
5 import static org.junit.Assert.assertTrue;
6 import static org.junit.Assert.fail;
7
8 import java.util.ArrayList;
9 import java.util.Arrays;
10 import java.util.List;
11
12 import org.djutils.draw.DrawRuntimeException;
13 import org.djutils.draw.point.Point2d;
14 import org.junit.Test;
15
16
17
18
19
20
21
22
23
24
25 public class Polygon2dTest
26 {
27
28
29
30
31 @Test
32 public void testConstructors()
33 {
34 double[] x = new double[] { 1, 3, 5 };
35 double[] y = new double[] { 2, 1, 10 };
36 double actualSurface = ((x[0] - x[2]) * (y[1] - y[0]) - (x[0] - x[1]) * (y[2] - y[0])) / 2;
37
38 Polygon2d polygon = new Polygon2d(x, y);
39 checkPolygon("constructed from arrays", x, y, polygon, actualSurface, true);
40 Polygon2d reversed = polygon.reverse();
41 assertEquals("surface of reversed polygon", -actualSurface, reversed.surface(), Math.ulp(-actualSurface));
42 assertTrue("reversed polygon is also convex", reversed.isConvex());
43
44 x = new double[] { 1, 3, 5, 1 };
45 y = new double[] { 2, 1, 10, 2 };
46 polygon = new Polygon2d(x, y);
47 assertTrue("toString returns something descriptive", polygon.toString().startsWith("Polygon2d"));
48 assertTrue("toString can suppress the class name", polygon.toString().indexOf(polygon.toString(true)) > 0);
49 checkPolygon("constructed from arrays", x, y, polygon, actualSurface, true);
50 assertEquals("surface of reversed polygon", -actualSurface, polygon.reverse().surface(), Math.ulp(-actualSurface));
51 Polygon2d otherPolygon = new Polygon2d(polygon.get(0), polygon.get(1), polygon.get(2), polygon.get(0));
52 assertEquals("polygon constructed from all points of existing polygon with first point duplicated at end is equal "
53 + "to original", polygon, otherPolygon);
54
55 new Polygon2d(polygon.get(0), polygon.get(1), polygon.get(2), new Point2d(polygon.get(0).x, 123));
56
57 x = new double[] { 1, 3, 1 };
58 y = new double[] { 2, 1, 10 };
59 polygon = new Polygon2d(x, y);
60
61 actualSurface = ((x[0] - x[2]) * (y[1] - y[0]) - (x[0] - x[1]) * (y[2] - y[0])) / 2;
62 checkPolygon("constructed from arrays with first and last x equal", x, y, polygon, actualSurface, true);
63
64 x = new double[] { 1, 3, 5, 3 };
65 y = new double[] { 2, 2, 10, 10 };
66 actualSurface = 2 * 8;
67 polygon = new Polygon2d(x, y);
68 checkPolygon("constructed from arrays", x, y, polygon, actualSurface, true);
69 assertEquals("surface of reversed polygon", -actualSurface, polygon.reverse().surface(), Math.ulp(-actualSurface));
70
71 List<Point2d> list = new ArrayList<>();
72 polygon.getPoints().forEachRemaining(list::add);
73 otherPolygon = new Polygon2d(list);
74 assertEquals("Polygon created from polygon points is equal to original polygon", polygon, otherPolygon);
75 otherPolygon = new Polygon2d(list.get(0), list.get(1), list.get(2), list.get(3));
76 assertEquals("Polygon created from all four points of existing polygon is equal to original", polygon, otherPolygon);
77
78 Point2d[] pointArray = list.toArray(new Point2d[0]);
79 otherPolygon = new Polygon2d(pointArray);
80 assertEquals("Polygon created from array of points of existing polygon is equal to original", polygon, otherPolygon);
81
82 list.add(list.get(0));
83 otherPolygon = new Polygon2d(list.iterator());
84 assertEquals("Polygon created from polygon points and duplicate of first point at end is equal to original polygon",
85 polygon, otherPolygon);
86
87 otherPolygon = new Polygon2d(list);
88 assertEquals("Polygon created from polygon points and duplicate of first point at end is equal to original polygon",
89 polygon, otherPolygon);
90
91 list.add(new Point2d(list.get(0).x, 123));
92 new Polygon2d(list.iterator());
93 list.add(list.get(0));
94 new Polygon2d(list.iterator());
95
96
97 list.add(list.get(0));
98 try
99 {
100 new Polygon2d(list);
101 fail("last two points equal to first point should have thrown a DrawRuntimeException");
102 }
103 catch (DrawRuntimeException dre)
104 {
105
106 }
107
108
109 x = new double[] {0, 5, 10, 5, 10, 0, 0};
110 y = new double[] {0, 0, 0, 5, 10, 10, 5};
111 polygon = new Polygon2d(x, y);
112 checkPolygon("non convex polygon", x, y, polygon, 100 - 25, false);
113 assertFalse("reversed non-convex polygon is also non-convex", polygon.reverse().isConvex());
114
115 try
116 {
117 polygon.getSegment(-1);
118 fail("Negative index should have thrown a DrawRuntimeException");
119 }
120 catch (DrawRuntimeException dre)
121 {
122
123 }
124
125 try
126 {
127 polygon.getSegment(polygon.size());
128 fail("index equal to size (or more) should have thrown a DrawRuntimeException");
129 }
130 catch (DrawRuntimeException dre)
131 {
132
133 }
134
135 try
136 {
137 new Polygon2d(new double[] { 1, 2, 3 }, new double[] { 1, 2, 3, 4 });
138 fail("unequal length of coordinate array should have thrown a DrawRuntimeException");
139 }
140 catch (DrawRuntimeException dre)
141 {
142
143 }
144
145 try
146 {
147 new Polygon2d(new double[] { 1, 2, 3, 4 }, new double[] { 1, 2, 3 });
148 fail("unequal length of coordinate array should have thrown a DrawRuntimeException");
149 }
150 catch (DrawRuntimeException dre)
151 {
152
153 }
154
155 try
156 {
157 new Polygon2d(null, new double[] { 1, 2, 3 });
158 fail("null for x array hould have thrown a NullPointerException");
159 }
160 catch (NullPointerException npe)
161 {
162
163 }
164
165 try
166 {
167 new Polygon2d(new double[] { 1, 2, 3 }, null);
168 fail("null for x array hould have thrown a NullPointerException");
169 }
170 catch (NullPointerException npe)
171 {
172
173 }
174
175 try
176 {
177 new Polygon2d(new double[] { 1 }, new double[] { 1 });
178 fail("too short coordinate array should have thrown a DrawRuntimeException");
179 }
180 catch (DrawRuntimeException dre)
181 {
182
183 }
184
185 try
186 {
187 new Polygon2d(new Point2d(1, 2), new Point2d(1, 2), new Point2d[] {});
188 fail("too short coordinate array should have thrown a DrawRuntimeException");
189 }
190 catch (DrawRuntimeException dre)
191 {
192
193 }
194
195 try
196 {
197 new Polygon2d(new Point2d(1, 2), new Point2d(1, 2), (Point2d[]) null);
198 fail("too short coordinate array should have thrown a DrawRuntimeException");
199 }
200 catch (DrawRuntimeException dre)
201 {
202
203 }
204
205 try
206 {
207 new Polygon2d(new Point2d(1, 2), new Point2d(3, 2), new Point2d[] { new Point2d(1, 2), new Point2d(1, 2) });
208 fail("two identical points at end, matching first point should have thrown a DrawRuntimeException");
209 }
210 catch (DrawRuntimeException dre)
211 {
212
213 }
214
215 list.clear();
216 list.add(new Point2d(1, 2));
217 try
218 {
219 new Polygon2d(list);
220 fail("too short list should have thrown a DrawRuntimeException");
221 }
222 catch (DrawRuntimeException dre)
223 {
224
225 }
226
227 }
228
229
230
231
232 @Test
233 public void filterTest()
234 {
235 Point2d[] points = new Point2d[] {new Point2d(1, 2), new Point2d(1, 2), new Point2d(4, 5)};
236 try
237 {
238 new Polygon2d(false, points);
239 fail("duplicate point should have thrown a DrawRuntimeException");
240 }
241 catch (DrawRuntimeException dre)
242 {
243
244 }
245
246 assertEquals("After filtering; there are two points left", 2, new Polygon2d(true, points).size());
247
248 List<Point2d> list = Arrays.asList(points);
249 try
250 {
251 new Polygon2d(false, list);
252 fail("duplicate point should have thrown a DrawRuntimeException");
253 }
254 catch (DrawRuntimeException dre)
255 {
256
257 }
258
259 assertEquals("After filtering; there are two points left", 2, new Polygon2d(true, list).size());
260 }
261
262
263
264
265
266
267
268
269
270
271 private void checkPolygon(final String where, final double[] x, final double[] y, final Polygon2d polygon,
272 final double expectedSurface, final boolean isConvex)
273 {
274 double cumulativeLength = 0;
275 for (int index = 0; index < polygon.size(); index++)
276 {
277 assertEquals(where + " x[index]", x[index], polygon.getX(index), Math.ulp(x[index]));
278 assertEquals(where + " y[index]", y[index], polygon.getY(index), Math.ulp(y[index]));
279 LineSegment2d segment = polygon.getSegment(index);
280 assertEquals(where + " segment start x", x[index], segment.startX, Math.ulp(x[index]));
281 assertEquals(where + " segment start y", y[index], segment.startY, Math.ulp(y[index]));
282 int wrappedIndex = (index + 1) % polygon.size();
283 assertEquals(where + " segment end x", x[wrappedIndex], segment.endX, Math.ulp(x[wrappedIndex]));
284 assertEquals(where + " segment end y", y[wrappedIndex], segment.endY, Math.ulp(y[wrappedIndex]));
285 cumulativeLength += segment.getLength();
286 }
287 assertEquals(where + " surface", expectedSurface, polygon.surface(), Math.ulp(expectedSurface));
288 assertEquals(where + " circumference", cumulativeLength, polygon.getLength(),
289 polygon.size() * Math.ulp(cumulativeLength));
290 assertEquals(where + " is convex?", isConvex, polygon.isConvex());
291 }
292
293
294
295
296 @Test
297 public void containsTest()
298 {
299
300 Polygon2d polygon = new Polygon2d(new double[] { 4.8, 10.2, 15.2, 9.8 }, new double[] { -10.1, -10.1, 0.1, 0.1 });
301
302 for (int x = 0; x < 20; x += 1)
303 {
304 for (int y = -15; y < 5; y++)
305 {
306 boolean expected = y <= 0 && y >= -10 && x >= 10 + y * 0.5 && x <= 15 + y * 0.5;
307
308
309
310 assertEquals("contains", expected, polygon.contains(x, y));
311 assertEquals("contains", expected, polygon.contains(new Point2d(x, y)));
312 }
313 }
314 }
315
316
317
318
319 @Test
320 public void testExports()
321 {
322 Point2d[] points =
323 new Point2d[] { new Point2d(123.456, 345.678), new Point2d(234.567, 456.789), new Point2d(-12.345, -34.567) };
324 Polygon2d pl = new Polygon2d(points);
325 String[] out = pl.toExcel().split("\\n");
326 assertEquals("Excel output consists of one line per point plus one", points.length + 1, out.length);
327 for (int index = 0; index <= points.length; index++)
328 {
329 String[] fields = out[index].split("\\t");
330 assertEquals("each line consists of two fields", 2, fields.length);
331 try
332 {
333 double x = Double.parseDouble(fields[0].trim());
334 assertEquals("x matches", points[index % pl.size()].x, x, 0.001);
335 }
336 catch (NumberFormatException nfe)
337 {
338 fail("First field " + fields[0] + " does not parse as a double");
339 }
340 try
341 {
342 double y = Double.parseDouble(fields[1].trim());
343 assertEquals("y matches", points[index % pl.size()].y, y, 0.001);
344 }
345 catch (NumberFormatException nfe)
346 {
347 fail("Second field " + fields[1] + " does not parse as a double");
348 }
349 }
350
351 out = pl.toPlot().split(" L");
352 assertEquals("Plotter output consists of one coordinate pair per point plus one", points.length + 1, out.length);
353 for (int index = 0; index < points.length; index++)
354 {
355 String[] fields = out[index].split(",");
356 assertEquals("each line consists of two fields", 2, fields.length);
357 if (index == 0)
358 {
359 assertTrue(fields[0].startsWith("M"));
360 fields[0] = fields[0].substring(1);
361 }
362 try
363 {
364 double x = Double.parseDouble(fields[0].trim());
365 assertEquals("x matches", points[index % pl.size()].x, x, 0.001);
366 }
367 catch (NumberFormatException nfe)
368 {
369 fail("First field " + fields[0] + " does not parse as a double");
370 }
371 try
372 {
373 double y = Double.parseDouble(fields[1].trim());
374 assertEquals("y matches", points[index % pl.size()].y, y, 0.001);
375 }
376 catch (NumberFormatException nfe)
377 {
378 fail("Second field " + fields[1] + " does not parse as a double");
379 }
380 }
381
382 }
383
384 }