package org.djutils.draw.line; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.List; import org.djutils.draw.DrawRuntimeException; import org.djutils.draw.point.Point3d; import org.junit.Test; /** * Polygon3dTest.java. *

* Copyright (c) 2020-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* BSD-style license. See DJUTILS License. *

* @author Alexander Verbraeck * @author Peter Knoppers */ public class Polygon3dTest { /** * Test the constructors. */ @Test public void testConstructors() { double[] x = new double[] { 1, 3, 5 }; double[] y = new double[] { 2, 1, 10 }; double[] z = new double[] { 2, 3, 4 }; Polygon3d polygon = new Polygon3d(x, y, z); checkPolygon("constructed from arrays", x, y, z, polygon); Polygon3d reversed = polygon.reverse(); for (int index = 0; index < 3; index++) { Point3d p = reversed.get(x.length - 1 - index); assertEquals("reversed x", x[index], p.x, 0.0001); assertEquals("reversed y", y[index], p.y, 0.0001); assertEquals("reversed z", z[index], p.z, 0.0001); } x = new double[] { 1, 3, 5, 1 }; y = new double[] { 2, 1, 10, 2 }; z = new double[] { 2, 3, 4, 2 }; polygon = new Polygon3d(x, y, z); // Last point is duplicate of first point; should be handled gracefully assertTrue("toString returns something descriptive", polygon.toString().startsWith("Polygon3d")); assertTrue("toString can suppress the class name", polygon.toString().indexOf(polygon.toString(true)) > 0); checkPolygon("constructed from arrays", x, y, z, polygon); Polygon3d otherPolygon = new Polygon3d(polygon.get(0), polygon.get(1), polygon.get(2), polygon.get(0)); assertEquals("polygon constructed from all points of existing polygon with first point duplicated at end is equal " + "to original", polygon, otherPolygon); // Make a Polygon3d from Point3d where last point differs from first only in y new Polygon3d(polygon.get(0), polygon.get(1), polygon.get(2), new Point3d(polygon.get(0).x, 123, polygon.get(0).z)); // Make a Polygon3d from Point3d where last point differs from first only in z new Polygon3d(polygon.get(0), polygon.get(1), polygon.get(2), new Point3d(polygon.get(0).x, polygon.get(0).y, 123)); x = new double[] { 1, 3, 1 }; // x coordinate of last point matches that of first y = new double[] { 2, 1, 10 }; // not true for y coordinates z = new double[] { 2, 3, 2 }; // true for z polygon = new Polygon3d(x, y, z); // System.out.println(polygon); checkPolygon("constructed from arrays with first and last x equal", x, y, z, polygon); x = new double[] { 1, 3, 1 }; // x coordinate of last point matches that of first y = new double[] { 2, 1, 2 }; // same for y z = new double[] { 2, 3, 4 }; // not true for z polygon = new Polygon3d(x, y, z); // System.out.println(polygon); checkPolygon("constructed from arrays with first and last x equal", x, y, z, polygon); x = new double[] { 1, 3, 5, 3 }; y = new double[] { 2, 2, 10, 10 }; z = new double[] { 4, 4, 4, 4 }; polygon = new Polygon3d(x, y, z); checkPolygon("constructed from arrays", x, y, z, polygon); // convert the points of polygon to an array of Point3d List list = new ArrayList<>(); polygon.getPoints().forEachRemaining(list::add); otherPolygon = new Polygon3d(list); assertEquals("Polygon created from polygon points is equal to original polygon", polygon, otherPolygon); otherPolygon = new Polygon3d(list.get(0), list.get(1), list.get(2), list.get(3)); assertEquals("Polygon created from all four points of existing polygon is equal to original", polygon, otherPolygon); Point3d[] pointArray = list.toArray(new Point3d[0]); otherPolygon = new Polygon3d(pointArray); assertEquals("Polygon created from array of points of existing polygon is equal to original", polygon, otherPolygon); list.add(list.get(0)); otherPolygon = new Polygon3d(list.iterator()); assertEquals("Polygon created from polygon points and duplicate of first point at end is equal to original polygon", polygon, otherPolygon); otherPolygon = new Polygon3d(list); assertEquals("Polygon created from polygon points and duplicate of first point at end is equal to original polygon", polygon, otherPolygon); // Add a point that only differs in y list.add(new Point3d(list.get(0).x, 123, list.get(0).z)); new Polygon3d(list.iterator()); list.add(list.get(0)); new Polygon3d(list.iterator()); // Add a point that only differs in z list.add(new Point3d(list.get(0).x, list.get(0).y, 123)); new Polygon3d(list.iterator()); list.add(list.get(0)); new Polygon3d(list.iterator()); // Make last TWO points duplicate of first point list.add(list.get(0)); try { new Polygon3d(list); fail("last two points equal to first point should have thrown a DrawRuntimeException"); } catch (DrawRuntimeException dre) { // Ignore expected exception } try { polygon.getSegment(-1); fail("Negative index should have thrown a DrawRuntimeException"); } catch (DrawRuntimeException dre) { // Ignore expected exception } try { polygon.getSegment(polygon.size()); fail("index equal to size (or more) should have thrown a DrawRuntimeException"); } catch (DrawRuntimeException dre) { // Ignore expected exception } try { new Polygon3d(new double[] { 1, 2, 3 }, new double[] { 1, 2, 3 }, new double[] { 1, 2, 3, 4 }); fail("unequal length of coordinate array should have thrown a DrawRuntimeException"); } catch (DrawRuntimeException dre) { // Ignore expected exception } try { new Polygon3d(new double[] { 1, 2, 3 }, new double[] { 1, 2, 3, 4 }, new double[] { 1, 2, 3 }); fail("unequal length of coordinate array should have thrown a DrawRuntimeException"); } catch (DrawRuntimeException dre) { // Ignore expected exception } try { new Polygon3d(new double[] { 1, 2, 3, 4 }, new double[] { 1, 2, 3 }, new double[] { 1, 2, 3 }); fail("unequal length of coordinate array should have thrown a DrawRuntimeException"); } catch (DrawRuntimeException dre) { // Ignore expected exception } try { new Polygon3d(null, new double[] { 1, 2, 3 }, new double[] { 1, 2, 3 }); fail("null for x array hould have thrown a NullPointerException"); } catch (NullPointerException npe) { // Ignore expected exception } try { new Polygon3d(new double[] { 1, 2, 3 }, null, new double[] { 1, 2, 3 }); fail("null for x array hould have thrown a NullPointerException"); } catch (NullPointerException npe) { // Ignore expected exception } try { new Polygon3d(new double[] { 1, 2, 3 }, new double[] { 1, 2, 3 }, null); fail("null for x array hould have thrown a NullPointerException"); } catch (NullPointerException npe) { // Ignore expected exception } try { new Polygon3d(new double[] { 1 }, new double[] { 1 }, new double[] { 1 }); fail("too short coordinate array should have thrown a DrawRuntimeException"); } catch (DrawRuntimeException dre) { // Ignore expected exception } try { new Polygon3d(new Point3d(1, 2, 3), new Point3d(1, 2, 3), new Point3d[] {}); fail("too short coordinate array should have thrown a DrawRuntimeException"); } catch (DrawRuntimeException dre) { // Ignore expected exception } try { new Polygon3d(new Point3d(1, 2, 3), new Point3d(1, 2, 3), (Point3d[]) null); fail("too short coordinate array should have thrown a DrawRuntimeException"); } catch (DrawRuntimeException dre) { // Ignore expected exception } try { new Polygon3d(new Point3d(1, 2, 3), new Point3d(3, 2, 5), new Point3d[] { new Point3d(1, 2, 3), new Point3d(1, 2, 3) }); fail("two identical points at end, matching first point should have thrown a DrawRuntimeException"); } catch (DrawRuntimeException dre) { // Ignore expected exception } list.clear(); list.add(new Point3d(1, 2, 3)); try { new Polygon3d(list); fail("too short list should have thrown a DrawRuntimeException"); } catch (DrawRuntimeException dre) { // Ignore expected exception } } /** * Verify the various properties of a Polygon3d. * @param where String; description of the test * @param x double[]; the expected x coordinates * @param y double[]; the expected y coordinates * @param z double[]; the expected z coordinates * @param polygon Polygon3d; the Polygon3d */ private void checkPolygon(final String where, final double[] x, final double[] y, final double[] z, final Polygon3d polygon) { double cumulativeLength = 0; for (int index = 0; index < polygon.size(); index++) { assertEquals(where + " x[index]", x[index], polygon.getX(index), Math.ulp(x[index])); assertEquals(where + " y[index]", y[index], polygon.getY(index), Math.ulp(y[index])); assertEquals(where + " z[index]", z[index], polygon.getZ(index), Math.ulp(z[index])); LineSegment3d segment = polygon.getSegment(index); assertEquals(where + " segment start x", x[index], segment.startX, Math.ulp(x[index])); assertEquals(where + " segment start y", y[index], segment.startY, Math.ulp(y[index])); assertEquals(where + " segment start z", z[index], segment.startZ, Math.ulp(z[index])); int wrappedIndex = (index + 1) % polygon.size(); assertEquals(where + " segment end x", x[wrappedIndex], segment.endX, Math.ulp(x[wrappedIndex])); assertEquals(where + " segment end y", y[wrappedIndex], segment.endY, Math.ulp(y[wrappedIndex])); assertEquals(where + " segment end z", z[wrappedIndex], segment.endZ, Math.ulp(z[wrappedIndex])); cumulativeLength += segment.getLength(); } assertEquals(where + " circumference", cumulativeLength, polygon.getLength(), polygon.size() * Math.ulp(cumulativeLength)); } /** * Test the debugging output methods. */ @Test public void testExports() { Point3d[] points = new Point3d[] { new Point3d(123.456, 345.678, 901.234), new Point3d(234.567, 456.789, 12.345), new Point3d(-12.345, -34.567, 45.678) }; Polygon3d pl = new Polygon3d(points); String[] out = pl.toExcel().split("\\n"); assertEquals("Excel output consists of one line per point plus one", points.length + 1, out.length); for (int index = 0; index <= points.length; index++) { String[] fields = out[index].split("\\t"); assertEquals("each line consists of three fields", 3, fields.length); try { double x = Double.parseDouble(fields[0].trim()); assertEquals("x matches", points[index % pl.size()].x, x, 0.001); } catch (NumberFormatException nfe) { fail("First field " + fields[0] + " does not parse as a double"); } try { double y = Double.parseDouble(fields[1].trim()); assertEquals("y matches", points[index % pl.size()].y, y, 0.001); } catch (NumberFormatException nfe) { fail("Second field " + fields[1] + " does not parse as a double"); } try { double z = Double.parseDouble(fields[2].trim()); assertEquals("z matches", points[index % pl.size()].z, z, 0.001); } catch (NumberFormatException nfe) { fail("Second field " + fields[2] + " does not parse as a double"); } } } }