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

com.hazelcast.shaded.org.locationtech.jts.geom.Polygon Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
/*
 * Copyright (c) 2016 Vivid Solutions.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * and Eclipse Distribution License v. 1.0 which accompanies this distribution.
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
 * and the Eclipse Distribution License is available at
 *
 * http://www.eclipse.org/org/documents/edl-v10.php.
 */
package com.hazelcast.shaded.org.locationtech.jts.geom;

import java.util.Arrays;

import com.hazelcast.shaded.org.locationtech.jts.algorithm.Area;
import com.hazelcast.shaded.org.locationtech.jts.algorithm.Orientation;


/**
 * Represents a polygon with linear edges, which may include holes.
 * The outer boundary (shell)
 * and inner boundaries (holes) of the polygon are represented by {@link LinearRing}s.
 * The boundary rings of the polygon may have any orientation.
 * Polygons are closed, simple geometries by definition.
 * 

* The polygon model conforms to the assertions specified in the * OpenGIS Simple Features * Specification for SQL. *

* A Polygon is topologically valid if and only if: *

    *
  • the coordinates which define it are valid coordinates *
  • the linear rings for the shell and holes are valid * (i.e. are closed and do not self-intersect) *
  • holes touch the shell or another hole at at most one point * (which implies that the rings of the shell and holes must not cross) *
  • the interior of the polygon is connected, * or equivalently no sequence of touching holes * makes the interior of the polygon disconnected * (i.e. effectively split the polygon into two pieces). *
* *@version 1.7 */ public class Polygon extends Geometry implements Polygonal { private static final long serialVersionUID = -3494792200821764533L; /** * The exterior boundary, * or null if this Polygon * is empty. */ protected LinearRing shell = null; /** * The interior boundaries, if any. * This instance var is never null. * If there are no holes, the array is of zero length. */ protected LinearRing[] holes; /** * Constructs a Polygon with the given exterior boundary. * *@param shell the outer boundary of the new Polygon, * or null or an empty LinearRing if the empty * geometry is to be created. *@param precisionModel the specification of the grid of allowable points * for this Polygon *@param SRID the ID of the Spatial Reference System used by this * Polygon * @deprecated Use GeometryFactory instead */ public Polygon(LinearRing shell, PrecisionModel precisionModel, int SRID) { this(shell, new LinearRing[]{}, new GeometryFactory(precisionModel, SRID)); } /** * Constructs a Polygon with the given exterior boundary and * interior boundaries. * *@param shell the outer boundary of the new Polygon, * or null or an empty LinearRing if the empty * geometry is to be created. *@param holes the inner boundaries of the new Polygon * , or null or empty LinearRings if the empty * geometry is to be created. *@param precisionModel the specification of the grid of allowable points * for this Polygon *@param SRID the ID of the Spatial Reference System used by this * Polygon * @deprecated Use GeometryFactory instead */ public Polygon(LinearRing shell, LinearRing[] holes, PrecisionModel precisionModel, int SRID) { this(shell, holes, new GeometryFactory(precisionModel, SRID)); } /** * Constructs a Polygon with the given exterior boundary and * interior boundaries. * *@param shell the outer boundary of the new Polygon, * or null or an empty LinearRing if the empty * geometry is to be created. *@param holes the inner boundaries of the new Polygon * , or null or empty LinearRings if the empty * geometry is to be created. */ public Polygon(LinearRing shell, LinearRing[] holes, GeometryFactory factory) { super(factory); if (shell == null) { shell = getFactory().createLinearRing(); } if (holes == null) { holes = new LinearRing[]{}; } if (hasNullElements(holes)) { throw new IllegalArgumentException("holes must not contain null elements"); } if (shell.isEmpty() && hasNonEmptyElements(holes)) { throw new IllegalArgumentException("shell is empty but holes are not"); } this.shell = shell; this.holes = holes; } public Coordinate getCoordinate() { return shell.getCoordinate(); } public Coordinate[] getCoordinates() { if (isEmpty()) { return new Coordinate[]{}; } Coordinate[] coordinates = new Coordinate[getNumPoints()]; int k = -1; Coordinate[] shellCoordinates = shell.getCoordinates(); for (int x = 0; x < shellCoordinates.length; x++) { k++; coordinates[k] = shellCoordinates[x]; } for (int i = 0; i < holes.length; i++) { Coordinate[] childCoordinates = holes[i].getCoordinates(); for (int j = 0; j < childCoordinates.length; j++) { k++; coordinates[k] = childCoordinates[j]; } } return coordinates; } public int getNumPoints() { int numPoints = shell.getNumPoints(); for (int i = 0; i < holes.length; i++) { numPoints += holes[i].getNumPoints(); } return numPoints; } public int getDimension() { return 2; } public int getBoundaryDimension() { return 1; } public boolean isEmpty() { return shell.isEmpty(); } public boolean isRectangle() { if (getNumInteriorRing() != 0) return false; if (shell == null) return false; if (shell.getNumPoints() != 5) return false; CoordinateSequence seq = shell.getCoordinateSequence(); // check vertices have correct values Envelope env = getEnvelopeInternal(); for (int i = 0; i < 5; i++) { double x = seq.getX(i); if (! (x == env.getMinX() || x == env.getMaxX())) return false; double y = seq.getY(i); if (! (y == env.getMinY() || y == env.getMaxY())) return false; } // check vertices are in right order double prevX = seq.getX(0); double prevY = seq.getY(0); for (int i = 1; i <= 4; i++) { double x = seq.getX(i); double y = seq.getY(i); boolean xChanged = x != prevX; boolean yChanged = y != prevY; if (xChanged == yChanged) return false; prevX = x; prevY = y; } return true; } public LinearRing getExteriorRing() { return shell; } public int getNumInteriorRing() { return holes.length; } public LinearRing getInteriorRingN(int n) { return holes[n]; } public String getGeometryType() { return Geometry.TYPENAME_POLYGON; } /** * Returns the area of this Polygon * *@return the area of the polygon */ public double getArea() { double area = 0.0; area += Area.ofRing(shell.getCoordinateSequence()); for (int i = 0; i < holes.length; i++) { area -= Area.ofRing(holes[i].getCoordinateSequence()); } return area; } /** * Returns the perimeter of this Polygon * *@return the perimeter of the polygon */ public double getLength() { double len = 0.0; len += shell.getLength(); for (int i = 0; i < holes.length; i++) { len += holes[i].getLength(); } return len; } /** * Computes the boundary of this geometry * * @return a lineal geometry (which may be empty) * @see Geometry#getBoundary */ public Geometry getBoundary() { if (isEmpty()) { return getFactory().createMultiLineString(); } LinearRing[] rings = new LinearRing[holes.length + 1]; rings[0] = shell; for (int i = 0; i < holes.length; i++) { rings[i + 1] = holes[i]; } // create LineString or MultiLineString as appropriate if (rings.length <= 1) return getFactory().createLinearRing(rings[0].getCoordinateSequence()); return getFactory().createMultiLineString(rings); } protected Envelope computeEnvelopeInternal() { return shell.getEnvelopeInternal(); } public boolean equalsExact(Geometry other, double tolerance) { if (!isEquivalentClass(other)) { return false; } Polygon otherPolygon = (Polygon) other; Geometry thisShell = shell; Geometry otherPolygonShell = otherPolygon.shell; if (!thisShell.equalsExact(otherPolygonShell, tolerance)) { return false; } if (holes.length != otherPolygon.holes.length) { return false; } for (int i = 0; i < holes.length; i++) { if (!((Geometry) holes[i]).equalsExact(otherPolygon.holes[i], tolerance)) { return false; } } return true; } public void apply(CoordinateFilter filter) { shell.apply(filter); for (int i = 0; i < holes.length; i++) { holes[i].apply(filter); } } public void apply(CoordinateSequenceFilter filter) { shell.apply(filter); if (! filter.isDone()) { for (int i = 0; i < holes.length; i++) { holes[i].apply(filter); if (filter.isDone()) break; } } if (filter.isGeometryChanged()) geometryChanged(); } public void apply(GeometryFilter filter) { filter.filter(this); } public void apply(GeometryComponentFilter filter) { filter.filter(this); shell.apply(filter); for (int i = 0; i < holes.length; i++) { holes[i].apply(filter); } } /** * Creates and returns a full copy of this {@link Polygon} object. * (including all coordinates contained by it). * * @return a clone of this instance * @deprecated */ public Object clone() { return copy(); } protected Polygon copyInternal() { LinearRing shellCopy = (LinearRing) shell.copy(); LinearRing[] holeCopies = new LinearRing[this.holes.length]; for (int i = 0; i < holes.length; i++) { holeCopies[i] = (LinearRing) holes[i].copy(); } return new Polygon(shellCopy, holeCopies, factory); } public Geometry convexHull() { return getExteriorRing().convexHull(); } public void normalize() { shell = normalized(shell, true); for (int i = 0; i < holes.length; i++) { holes[i] = normalized(holes[i], false); } Arrays.sort(holes); } protected int compareToSameClass(Object o) { Polygon poly = (Polygon) o; LinearRing thisShell = shell; LinearRing otherShell = poly.shell; int shellComp = thisShell.compareToSameClass(otherShell); if (shellComp != 0) return shellComp; int nHole1 = getNumInteriorRing(); int nHole2 = ((Polygon) o).getNumInteriorRing(); int i = 0; while (i < nHole1 && i < nHole2) { LinearRing thisHole = (LinearRing) getInteriorRingN(i); LinearRing otherHole = (LinearRing) poly.getInteriorRingN(i); int holeComp = thisHole.compareToSameClass(otherHole); if (holeComp != 0) return holeComp; i++; } if (i < nHole1) return 1; if (i < nHole2) return -1; return 0; } protected int compareToSameClass(Object o, CoordinateSequenceComparator comp) { Polygon poly = (Polygon) o; LinearRing thisShell = shell; LinearRing otherShell = poly.shell; int shellComp = thisShell.compareToSameClass(otherShell, comp); if (shellComp != 0) return shellComp; int nHole1 = getNumInteriorRing(); int nHole2 = poly.getNumInteriorRing(); int i = 0; while (i < nHole1 && i < nHole2) { LinearRing thisHole = (LinearRing) getInteriorRingN(i); LinearRing otherHole = (LinearRing) poly.getInteriorRingN(i); int holeComp = thisHole.compareToSameClass(otherHole, comp); if (holeComp != 0) return holeComp; i++; } if (i < nHole1) return 1; if (i < nHole2) return -1; return 0; } protected int getTypeCode() { return Geometry.TYPECODE_POLYGON; } private LinearRing normalized(LinearRing ring, boolean clockwise) { LinearRing res = (LinearRing) ring.copy(); normalize(res, clockwise); return res; } private void normalize(LinearRing ring, boolean clockwise) { if (ring.isEmpty()) { return; } CoordinateSequence seq = ring.getCoordinateSequence(); int minCoordinateIndex = CoordinateSequences.minCoordinateIndex(seq, 0, seq.size()-2); CoordinateSequences.scroll(seq, minCoordinateIndex, true); if (Orientation.isCCW(seq) == clockwise) CoordinateSequences.reverse(seq); } public Polygon reverse() { return (Polygon) super.reverse(); } protected Polygon reverseInternal() { LinearRing shell = (LinearRing) getExteriorRing().reverse(); LinearRing[] holes = new LinearRing[getNumInteriorRing()]; for (int i = 0; i < holes.length; i++) { holes[i] = (LinearRing) getInteriorRingN(i).reverse(); } return getFactory().createPolygon(shell, holes); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy