All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.djutils.draw.line.Polygon3d Maven / Gradle / Ivy

The newest version!
package org.djutils.draw.line;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

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. The constructors automatically remove the last point if it is a at the same location as the first point.
 * 

* Copyright (c) 2020-2024 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 = 20209999L; /** * Construct a new Polygon3d. * @param x double[]; the x coordinates of the points * @param y double[]; the y coordinates of the points * @param z double[]; the z coordinates of the points * @throws DrawRuntimeException when any two successive points are equal, or when there are too few points */ public Polygon3d(final double[] x, final double[] y, final double[] z) throws DrawRuntimeException { super(fixClosingPointX(Throw.whenNull(x, "x"), Throw.whenNull(y, "y"), Throw.whenNull(z, "z")), fixClosingPointY(x, y, z), fixClosingPointZ(x, y, z)); } /** * Ensure that the last point is not equal to the first. Remove the last point if necessary. * @param x double[]; the x coordinates of the points * @param y double[]; the y coordinates of the points * @param z double[]; the z coordinates of the points * @return double[]; the y coordinates of the points (possibly a copy with the last element removed) */ static double[] fixClosingPointX(final double[] x, final double[] y, final double[] z) { if (x.length > 1 && y.length == x.length && z.length == x.length && x[0] == x[x.length - 1] && y[0] == y[x.length - 1] && z[0] == z[z.length - 1]) { return Arrays.copyOf(x, x.length - 1); } return x; } /** * Ensure that the last point is not equal to the first. Remove the last point if necessary. * @param x double[]; the x coordinates of the points * @param y double[]; the y coordinates of the points * @param z double[]; the z coordinates of the points * @return double[]; the y coordinates of the points (possibly a copy with the last element removed) */ static double[] fixClosingPointY(final double[] x, final double[] y, final double[] z) { if (x.length > 1 && y.length == x.length && z.length == x.length && x[0] == x[x.length - 1] && y[0] == y[x.length - 1] && z[0] == z[z.length - 1]) { return Arrays.copyOf(y, x.length - 1); } return y; } /** * Ensure that the last point is not equal to the first. Remove the last point if necessary. * @param x double[]; the x coordinates of the points * @param y double[]; the y coordinates of the points * @param z double[]; the z coordinates of the points * @return double[]; the y coordinates of the points (possibly a copy with the last element removed) */ static double[] fixClosingPointZ(final double[] x, final double[] y, final double[] z) { if (x.length > 1 && y.length == x.length && z.length == x.length && x[0] == x[x.length - 1] && y[0] == y[x.length - 1] && z[0] == z[z.length - 1]) { return Arrays.copyOf(z, x.length - 1); } return z; } /** * Construct a new Polygon3d. * @param points Point3d[]; array of Point3d objects. * @throws NullPointerException when points is null * @throws DrawRuntimeException when points is too short, or contains successive duplicate points */ public Polygon3d(final Point3d[] points) throws NullPointerException, DrawRuntimeException { this(PolyLine3d.makeArray(Throw.whenNull(points, "points"), p -> p.x), PolyLine3d.makeArray(points, p -> p.y), PolyLine3d.makeArray(points, p -> p.z)); } /** * 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 NullPointerException when point1 or point2 is 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 NullPointerException, DrawRuntimeException { super(Throw.whenNull(point1, "point1"), Throw.whenNull(point2, "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[] result = otherPoints; Point3d lastPoint = result[result.length - 1]; if (point1.x == lastPoint.x && point1.y == lastPoint.y) { result = Arrays.copyOf(otherPoints, result.length - 1); lastPoint = result[result.length - 1]; } Throw.when(point1.x == lastPoint.x && point1.y == lastPoint.y, DrawRuntimeException.class, "Before last point and last point are at same location"); return result; } /** * Construct a new Polygon3d from a list of Point3d objects. * @param points List<Point3d>; the list of points * @throws NullPointerException when points is null * @throws DrawRuntimeException when points is too short, or the last two points are at the same location */ public Polygon3d(final List points) throws NullPointerException, DrawRuntimeException { super(fixClosingPoint(true, Throw.whenNull(points, "points"))); } /** * Ensure that the last point in the list is different from the first point by possibly removing the last point. * @param doNotModifyList boolean; if true; the list of points will not be modified (if the last point is to be removed; the * entire list up to the last point is duplicated) * @param points List<Point3d>; the list of points * @return List<Point3d>; the fixed list * @throws DrawRuntimeException when the (resulting) list is too short, or the before last and last point of points have the * same coordinates */ private static List fixClosingPoint(final boolean doNotModifyList, final List points) throws DrawRuntimeException { Throw.when(points.size() < 2, DrawRuntimeException.class, "Need at least two points"); Point3d firstPoint = points.get(0); Point3d lastPoint = points.get(points.size() - 1); List result = points; if (firstPoint.x == lastPoint.x && firstPoint.y == lastPoint.y && firstPoint.z == lastPoint.z) { if (doNotModifyList) { result = new ArrayList<>(points.size() - 1); for (int i = 0; i < points.size() - 1; i++) { result.add(points.get(i)); } } else { result.remove(points.size() - 1); } lastPoint = result.get(result.size() - 1); } Throw.when(firstPoint.x == lastPoint.x && firstPoint.y == lastPoint.y && firstPoint.z == lastPoint.z, DrawRuntimeException.class, "Before last point and last point are at same location"); return result; } /** * Construct a new Polygon3d from an iterator that yields Point3d. * @param iterator Iterator<Point3d>; the iterator */ public Polygon3d(final Iterator iterator) { this(fixClosingPoint(false, iteratorToList(Throw.whenNull(iterator, "iterator")))); } /** * Create a new Polygon3d, optionally filtering out repeating successive points. * @param filterDuplicates boolean; if true; filter out successive repeated points; otherwise do not filter * @param points Point3d...; the coordinates of the polygon as Point3d * @throws DrawRuntimeException when number of points < 2 */ public Polygon3d(final boolean filterDuplicates, final Point3d... points) throws DrawRuntimeException { this(PolyLine3d.cleanPoints(filterDuplicates, Arrays.stream(points).iterator())); } /** * Create a new Polygon3d, optionally filtering out repeating successive points. * @param filterDuplicates boolean; if true; filter out successive repeated points; otherwise do not filter * @param pointList List<Point3d>; list of the coordinates of the line as Point3d; any duplicate points in this list * are removed (this method may modify the provided list) * @throws DrawRuntimeException when number of non-equal points < 2 */ public Polygon3d(final boolean filterDuplicates, final List pointList) throws DrawRuntimeException { this(PolyLine3d.cleanPoints(filterDuplicates, pointList.iterator())); } /** * Construct a new Polygon3d from an existing one. This constructor is primarily intended for use in extending classes. * @param polygon Polygon3d; the existing Polygon3d */ public Polygon3d(final Polygon3d polygon) { super(polygon); } @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(Math.hypot(getX(size() - 1) - getX(0), getY(size() - 1) - getY(0)), getZ(size() - 1) - getZ(0)); } @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)); } @Override public Polygon2d project() throws DrawRuntimeException { double[] projectedX = new double[this.size()]; double[] projectedY = new double[this.size()]; int nextIndex = 0; for (int i = 0; i < this.size(); i++) { if (i > 0 && getX(i) == getX(i - 1) && getY(i) == getY(i - 1)) { continue; } projectedX[nextIndex] = getX(i); projectedY[nextIndex] = getY(i); nextIndex++; } if (nextIndex < projectedX.length) { return new Polygon2d(Arrays.copyOf(projectedX, nextIndex), Arrays.copyOf(projectedY, nextIndex)); } return new Polygon2d(projectedX, projectedY); } @Override public Polygon3d reverse() { return new Polygon3d(super.reverse().getPoints()); } @Override public final String toString() { return toString("%f", false); } @Override public String toString(final String doubleFormat, final boolean doNotIncludeClassName) { StringBuilder result = new StringBuilder(); if (!doNotIncludeClassName) { result.append("Polygon3d "); } result.append("[super="); result.append(super.toString(doubleFormat, false)); result.append("]"); return result.toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy