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