org.geolatte.geom.Polygon Maven / Gradle / Ivy
Show all versions of geolatte-geom Show documentation
/*
* This file is part of the GeoLatte project.
*
* GeoLatte 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 3 of the License, or
* (at your option) any later version.
*
* GeoLatte 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 GeoLatte. If not, see .
*
* Copyright (C) 2010 - 2011 and Ownership of code is shared by:
* Qmino bvba - Romeinsestraat 18 - 3001 Heverlee (http://www.qmino.com)
* Geovise bvba - Generaal Eisenhowerlei 9 - 2140 Antwerpen (http://www.geovise.com)
*/
package org.geolatte.geom;
import org.geolatte.geom.crs.CoordinateReferenceSystem;
import java.util.Arrays;
import java.util.Iterator;
/**
* A planar surface defined by 1 exterior boundary and 0 or more interior boundaries. Each interior boundary defines a
* hole in the Polygon
.
*
* The exterior boundary LinearRing
defines the "top" of the surface which is the side of the surface
* from which the exterior boundary appears to traverse the boundary in a counter clockwise direction. The interior
* LinearRing
s will have the opposite orientation and appear as clockwise when viewed from the "top".
*
* The rules that define valid Polygon
s are as follows
*
* Polygon
s are topologically closed;
* - The boundary of a
Polygon
consists of a set of LinearRing
s that make up its
* exterior and interior boundaries;
* - No two rings in the boundary cross and the rings in the boundary of a
Polygon
may
* intersect at a Point
but only as a tangent
* - A
Polygon
may not have cut lines, spikes or punctures;
* - The interior of every
Polygon
is a connected point set;
* - The exterior of a
Polygon
with 1 or more holes is not connected. Each hole defines a
* connected component of the exterior
*
*
* @author Karel Maesen, Geovise BVBA
* creation-date: 4/14/11
*/
public class Polygon extends Geometry
implements Polygonal
, Complex
> {
private final LinearRing
[] rings;
@SuppressWarnings("unchecked")
public Polygon(CoordinateReferenceSystem
crs) {
super(crs);
rings = (LinearRing
[])new LinearRing[0];
}
/**
* Creates a Polygon
with no holes, and having the specified PositionSequence
as exterior boundary
*
* @param positionSequence the PositionSequence
representing the exterior boundary
* @throws IllegalArgumentException when the specified PositionSequence
does not form a
* LinearRing
(i.e., is empty or not closed).
*/
@SuppressWarnings("unchecked")
public Polygon(PositionSequence
positionSequence, CoordinateReferenceSystem
crs) {
this(new LinearRing
(positionSequence, crs));
}
/**
* Creates a Polygon
with the specified array of exterior and interior boundaries.
*
* @param rings the array of the Polygon
's boundaries: the first element is the exterior boundary, all subsequent rings represent
* interior boundaries.
* @throws IllegalArgumentException when the specified PositionSequence
does not form a
* LinearRing
(i.e., is empty or not closed).
*/
public Polygon(LinearRing
... rings) {
super(nestPositionSequences(rings), getCrs(rings));
checkRings(rings);
this.rings = Arrays.copyOf(rings, rings.length);
}
private void checkRings(LinearRing
[] rings) {
CoordinateReferenceSystem
crs = getCrs(rings);
for (LinearRing
ring : rings) {
checkLinearRing(ring, crs);
}
}
private void checkLinearRing(LinearRing
ring, CoordinateReferenceSystem
crs) {
if (ring == null) throw new IllegalArgumentException("NULL linear ring is not valid.");
if (ring.isEmpty()) throw new IllegalArgumentException("Empty linear ring is not valid.");
if (!ring.getCoordinateReferenceSystem().equals(crs)) throw new IllegalArgumentException("Linear ring with different CRS than exterior boundary.");
}
/**
* Returns the exterior boundary of this Polygon
.
*
* @return a LinearRing
representing the exterior boundary of this Polygon
.
*/
public LinearRing
getExteriorRing() {
return this.isEmpty() ?
new LinearRing
(getPositions(), getCoordinateReferenceSystem()) :
this.rings[0];
}
/**
* returns the number of interior boundaries.
*
* @return the number of interior boundaries
*/
public int getNumInteriorRing() {
return this.isEmpty() ?
0 :
this.rings.length - 1;
}
/**
* Returns the specified interior ring.
*
* @param index the (zero-based) position of the interior boundary in the list of interior boundaries.
* @return the LinearRing
at the position specified by the parameter index.
*/
public LinearRing
getInteriorRingN(int index) {
return this.rings[index + 1];
}
@Override
public int getDimension() {
return 2;
}
@Override
public GeometryType getGeometryType() {
return GeometryType.POLYGON;
}
/**
* Returns an Iterator
over the boundaries of this Polygon
.
*
*
The boundaries are returned in order, with the first element being the exterior boundary.
*
* @return an Iterator
over the boundaries of this Polygon
.
*/
public Iterator> iterator() {
return new Iterator>() {
private int index = 0;
@Override
public boolean hasNext() {
return index < rings.length;
}
@Override
public LinearRing next() {
return rings[index++];
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
@Override
public void accept(GeometryVisitor
visitor) {
visitor.visit(this);
//TODO visit the individual rings
}
@Override
public int getNumGeometries() {
return rings.length;
}
@Override
public Class extends Geometry> getComponentType() {
return LinearRing.class;
}
/**
* Returns the components
*
* @return an array containing all component objects
*/
@Override
public LinearRing
[] components() {
return Arrays.copyOf(this.rings, this.rings.length);
}
@Override
@SuppressWarnings("unchecked")
public Polygon as(Class castToType){
checkCast(castToType);
return (Polygon)this;
}
}