Polygon3d.java
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.
* <p>
* Copyright (c) 2020-2021 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
* BSD-style license. See <a href="https://djutils.org/docs/current/djutils/licenses.html">DJUTILS License</a>.
* </p>
* @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
* @author <a href="https://www.tudelft.nl/pknoppers">Peter Knoppers</a>
*/
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));
}
}