package org.djutils.draw.line; import java.util.Arrays; import org.djutils.draw.DrawRuntimeException; import org.djutils.draw.point.Point3d; import org.djutils.exceptions.Throw; /** * Polygon3d.java. Closed PolyLine3d. The actual closing point (which is the same as the starting point) is NOT included in the * super PolyLine3d. *

* Copyright (c) 2020-2021 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 Polygon3d extends PolyLine3d { /** */ private static final long serialVersionUID = 20210126L; /** * Construct a new Polygon3d. * @param point1 Point3d; the first point of the new Polygon3d * @param point2 Point3d; the second point of the new Polygon3d * @param otherPoints Point3d[]; all remaining points of the new Polygon3d (may be null) * @throws DrawRuntimeException when point1 is equal to the last point of otherPoints, or any two successive points are * equal */ public Polygon3d(final Point3d point1, final Point3d point2, final Point3d[] otherPoints) throws DrawRuntimeException { super(point1, point2, fixClosingPoint(point1, otherPoints)); } /** * Ensure that the last point of otherPoints is not equal to point1. Remove the last point if necessary. * @param point1 Point3d; the first point of a new Polygon3d * @param otherPoints Point3d[]; the remaining points of a new Polygon3d (may be null) * @return Point3d[]; otherPoints (possibly a copy thereof with the last entry removed) */ private static Point3d[] fixClosingPoint(final Point3d point1, final Point3d[] otherPoints) { if (otherPoints == null || otherPoints.length == 0) { return otherPoints; } Point3d lastPoint = otherPoints[otherPoints.length - 1]; if (point1.x == lastPoint.x && point1.y == lastPoint.y) { return Arrays.copyOf(otherPoints, otherPoints.length - 1); } return otherPoints; } /** * Compute the surface of this Polygon3d. Sign of the result reflects the winding-ness of this this Polygon3d. If this * Polygon3d self-intersects, the result is bogus. * @return double; the surface of this Polygon3d */ public double surface() { double result = 0; // We initialize previous point to the last point of this Polygon3d to avoid wrapping problems double prevX = getX(size() - 1); double prevY = getY(size() - 1); for (int i = 0; i < size(); i++) { double thisX = getX(i); double thisY = getY(i); result += prevX * thisY - thisX * prevY; prevX = thisX; prevY = thisY; } return result / 2; } /** {@inheritDoc} */ @Override public double getLength() { // Length a polygon is computed by taking the length of the PolyLine and adding the length of the closing segment return super.getLength() + Math.hypot(getX(size() - 1) - getX(0), getY(size() - 1) - getY(0)); } /** {@inheritDoc} */ @Override public LineSegment3d getSegment(final int index) { if (index < size() - 1) { return super.getSegment(index); } Throw.when(index != size() - 1, DrawRuntimeException.class, "index must be in range 0..size() - 1"); return new LineSegment3d(getX(index), getY(index), getZ(index), getX(0), getY(0), getZ(0)); } }