/* File SimplePolygon2D.java
*
* Project : Java Geometry Library
*
* ===========================================
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. if not, write to :
* The Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
// package
package math.geom2d.polygon;
// Imports
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import math.geom2d.AffineTransform2D;
import math.geom2d.Box2D;
import math.geom2d.GeometricObject2D;
import math.geom2d.Point2D;
import math.geom2d.circulinear.*;
import math.geom2d.line.LineSegment2D;
import math.geom2d.point.PointSets2D;
import math.geom2d.transform.CircleInversion2D;
/**
* Represent a polygonal domain whose boundary is a single closed polyline.
*/
public class SimplePolygon2D implements Polygon2D {
// ===================================================================
// Static constructors
/**
* Static factory for creating a new SimplePolygon2D from a collection of
* points.
* @since 0.8.1
*/
public static SimplePolygon2D create(Collection extends Point2D> points) {
return new SimplePolygon2D(points);
}
/**
* Static factory for creating a new SimplePolygon2D from an array of
* points.
* @since 0.8.1
*/
public static SimplePolygon2D create(Point2D... points) {
return new SimplePolygon2D(points);
}
// ===================================================================
// class variables
/**
* The inner ordered list of vertices. The last point is connected to the
* first one.
*/
protected ArrayList vertices;
// ===================================================================
// constructors
/**
* Empty constructor: no vertex.
*/
public SimplePolygon2D() {
vertices = new ArrayList();
}
/**
* Constructor from an array of points
*
* @param vertices the vertices stored in an array of Point2D
*/
public SimplePolygon2D(Point2D... vertices) {
this.vertices = new ArrayList(vertices.length);
for (Point2D vertex : vertices)
this.vertices.add(vertex);
}
/**
* Constructor from two arrays, one for each coordinate.
*
* @param xcoords
* the x coordinate of each vertex
* @param ycoords
* the y coordinate of each vertex
*/
public SimplePolygon2D(double[] xcoords, double[] ycoords) {
vertices = new ArrayList(xcoords.length);
for (int i = 0; i < xcoords.length; i++)
vertices.add(new Point2D(xcoords[i], ycoords[i]));
}
public SimplePolygon2D(Collection extends Point2D> points) {
this.vertices = new ArrayList(points.size());
this.vertices.addAll(points);
}
/**
* Ensure the polygon has enough memory for storing the required number of
* vertices.
*/
public SimplePolygon2D(int nVertices) {
vertices = new ArrayList(nVertices);
}
/**
* Creates a simple polygon with the given linear ring representing its
* boundary.
* @param ring the boundary of the polygon
*/
public SimplePolygon2D(LinearRing2D ring) {
this.vertices = new ArrayList(ring.vertexNumber());
this.vertices.addAll(ring.vertices());
}
public SimplePolygon2D(SimplePolygon2D poly) {
this.vertices = new ArrayList(poly.vertexNumber());
this.vertices.addAll(poly.vertices);
}
// ===================================================================
// methods specific to SimplePolygon2D
/**
* Computes the winding number of the polygon. Algorithm adapted from
* http://www.geometryalgorithms.com/Archive/algorithm_0103/algorithm_0103.htm
*
* @param x the x-coordinate of the point
* @param y the y-coordinate of the point
* @return the number of windings of the curve around the point
*/
public int getWindingNumber(double x, double y) {
return Polygons2D.windingNumber(vertices, new Point2D(x, y));
}
/**
* Returns a simplified version of this polygon, by using Douglas-Peucker
* algorithm.
*/
public SimplePolygon2D simplify(double distMax) {
return new SimplePolygon2D(Polylines2D.simplifyClosedPolyline(this.vertices, distMax));
}
/**
* Returns the linear ring that composes the boundary of this polygon.
* @since 0.9.3
*/
public LinearRing2D getRing() {
return new LinearRing2D(this.vertices);
}
// ===================================================================
// management of vertex list
/**
* Adds a point as the last vertex.
*/
public void addVertex(Point2D point) {
this.vertices.add(point);
}
/**
* Adds a point as the last vertex.
* @since 0.9.3
*/
public void insertVertex(int index, Point2D point) {
this.vertices.add(index, point);
}
/**
* Changes the position of the i-th vertex.
*/
public void setVertex(int index, Point2D position) {
this.vertices.set(index, position);
}
/**
* Removes a vertex of the polygon.
*
* @param point the vertex to be removed.
*/
public boolean removeVertex(Point2D point) {
return this.vertices.remove(point);
}
/**
* Removes a vertex of the polygon specified by its index.
* @since 0.9.3
*/
public void removeVertex(int index) {
this.vertices.remove(index);
}
/**
* Removes all the vertices of the polygon.
*/
public void clearVertices() {
this.vertices.clear();
}
/**
* Computes the index of the closest vertex to the input point.
*/
public int closestVertexIndex(Point2D point) {
double minDist = Double.POSITIVE_INFINITY;
int index = -1;
for (int i = 0; i < vertices.size(); i++) {
double dist = vertices.get(i).distance(point);
if (dist < minDist) {
index = i;
minDist = dist;
}
}
return index;
}
/**
* Computes the signed area of the polygon. Algorithm is taken from page:
* http://local.wasp.uwa.edu.au/~pbourke/geometry/polyarea/. Signed are
* is positive if polygon is oriented counter-clockwise, and negative
* otherwise. Result is wrong if polygon is self-intersecting.
*
* @return the signed area of the polygon.
*/
public double area() {
return Polygons2D.computeArea(this);
}
/**
* Computes the centroid (center of mass) of the polygon. Algorithm is taken
* from page:
* http://local.wasp.uwa.edu.au/~pbourke/geometry/polyarea/.
*
* @return the centroid of the polygon
*/
public Point2D centroid() {
return Polygons2D.computeCentroid(this);
}
/**
* Returns the points of the polygon. The result is a pointer to the inner
* collection of vertices.
*/
public Collection vertices() {
return vertices;
}
/**
* Returns the i-th vertex of the polygon.
*
* @param i index of the vertex, between 0 and the number of vertices
*/
public Point2D vertex(int i) {
return vertices.get(i);
}
/**
* Returns the number of vertices of the polygon.
*
* @since 0.6.3
*/
public int vertexNumber() {
return vertices.size();
}
/**
* Returns the set of edges, as a collection of LineSegment2D.
*/
public Collection edges() {
int nPoints = this.vertices.size();
ArrayList edges = new ArrayList(nPoints);
if (nPoints==0)
return edges;
for (int i = 0; i pts2 =
PointSets2D.filterMultipleVertices(this.vertices, true);
SimplePolygon2D poly2 = new SimplePolygon2D(pts2);
return CirculinearDomains2D.computeBuffer(poly2, dist);
}
//
return CirculinearDomains2D.computeBuffer(this, dist);
}
// ===================================================================
// methods inherited from Domain2D interface
/* (non-Javadoc)
* @see math.geom2d.domain.Domain2D#asPolygon(int)
*/
public Polygon2D asPolygon(int n) {
return this;
}
/**
* Returns a set of one LinearRing2D, which encloses the polygon.
*/
public CirculinearContourArray2D boundary() {
Point2D[] array = new Point2D[this.vertices.size()];
for (int i = 0; i(
new LinearRing2D(array));
}
/* (non-Javadoc)
* @see math.geom2d.domain.Domain2D#contours()
*/
public Collection contours() {
ArrayList rings = new ArrayList(1);
rings.add(new LinearRing2D(vertices));
return rings;
}
/**
* Returns the polygon created by reversing the order of the vertices.
*/
public SimplePolygon2D complement() {
int nPoints = this.vertices.size();
Point2D[] res = new Point2D[nPoints];
if (nPoints>0)
res[0] = this.vertices.get(0);
for (int i = 1; i0;
}
public boolean isEmpty() {
return vertices.size() == 0;
}
/**
* Returns the new Polygon created by an affine transform of this polygon.
* If the transform is not direct, the order of vertices is reversed.
*/
public SimplePolygon2D transform(AffineTransform2D trans) {
int nPoints = this.vertices.size();
Point2D[] array = new Point2D[nPoints];
Point2D[] res = new Point2D[nPoints];
for (int i = 0; i < nPoints; i++) {
array[i] = this.vertices.get(i);
res[i] = new Point2D();
}
trans.transform(array, res);
SimplePolygon2D poly = new SimplePolygon2D(res);
if (!trans.isDirect())
poly = poly.complement();
return poly;
}
// ===================================================================
// methods inherited from Shape interface
/**
* Returns true if the point p lies inside the polygon, with precision
* given by Shape2D.ACCURACY.
*/
public boolean contains(Point2D p) {
return contains(p.x(), p.y());
}
/**
* Returns true if the point (x, y) lies inside the polygon, with precision
* given by Shape2D.ACCURACY.
*/
public boolean contains(double x, double y) {
if (this.boundary().contains(x, y))
return true;
double area = this.area();
int winding = this.getWindingNumber(x, y);
if (area > 0) {
return winding == 1;
} else {
return winding == 0;
}
}
/**
* Returns a general path iterator.
*/
public java.awt.geom.GeneralPath getGeneralPath() {
java.awt.geom.GeneralPath path = new java.awt.geom.GeneralPath();
if (vertices.size() < 2)
return path;
// move to first point
Point2D point = vertices.get(0);
path.moveTo((float) (point.x()), (float) (point.y()));
// line to each point
for (int i = 0; i array = new ArrayList(vertices.size());
for(Point2D point : vertices)
array.add(point);
return new SimplePolygon2D(array);
}
}
Ads help maintain this website.