/* * The JTS Topology Suite is a collection of Java classes that * implement the fundamental operations required to validate a given * geo-spatial data set to a known topological specification. * * Copyright (C) 2001 Vivid Solutions * * 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 * * For more information, contact: * * Vivid Solutions * Suite #1A * 2328 Government Street * Victoria BC V8T 5G5 * Canada * * (250)385-6040 * www.vividsolutions.com */ package com.revolsys.geometry.model.impl; import java.util.List; import com.revolsys.collection.list.Lists; import com.revolsys.geometry.model.BoundingBox; import com.revolsys.geometry.model.Geometry; import com.revolsys.geometry.model.GeometryFactory; import com.revolsys.geometry.model.LinearRing; import com.revolsys.geometry.model.Polygon; /** * 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. * <p> * The polygon model conforms to the assertions specified in the * <A HREF="http://www.opengis.org/techno/specs.htm">OpenGIS Simple Features * Specification for SQL</A>. * <p> * A <code>Polygon</code> is topologically valid if and only if: * <ul> * <li>the coordinates which define it are valid coordinates * <li>the linear rings for the shell and holes are valid * (i.e. are closed and do not self-intersect) * <li>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) * <li>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). * </ul> * *@version 1.7 */ public class PolygonImpl extends AbstractPolygon { private static final long serialVersionUID = 1L; private BoundingBox boundingBox; /** * The {@link GeometryFactory} used to create this Geometry */ private final GeometryFactory geometryFactory; private LinearRing[] rings; public PolygonImpl(final GeometryFactory geometryFactory) { this.geometryFactory = geometryFactory; } /** * Constructs a <code>Polygon</code> with the given exterior boundary and * interior boundaries. * *@param shell the outer boundary of the new <code>Polygon</code>, * or <code>null</code> or an empty <code>LinearRing</code> if the empty * geometry is to be created. *@param holes the inner boundaries of the new <code>Polygon</code> * , or <code>null</code> or empty <code>LinearRing</code>s if the empty * geometry is to be created. */ public PolygonImpl(final GeometryFactory factory, final LinearRing... rings) { this.geometryFactory = factory; if (rings == null || rings.length == 0) { } else if (Geometry.hasNullElements(rings)) { throw new IllegalArgumentException("rings must not contain null elements"); } else { if (rings[0].isEmpty()) { for (int i = 1; i < rings.length; i++) { final LinearRing ring = rings[i]; if (!ring.isEmpty()) { throw new IllegalArgumentException("shell is empty but hole " + (i - 1) + " is not"); } } } else { this.rings = rings; } } } /** * Creates and returns a full copy of this {@link Polygon} object. * (including all coordinates contained by it). * * @return a clone of this instance */ @Override public PolygonImpl clone() { final PolygonImpl poly = (PolygonImpl)super.clone(); if (this.rings != null) { poly.rings = this.rings.clone(); for (int i = 0; i < this.rings.length; i++) { poly.rings[i] = this.rings[i].clone(); } } return poly; } @Override public int getAxisCount() { return this.geometryFactory.getAxisCount(); } @Override public BoundingBox getBoundingBox() { if (this.boundingBox == null) { this.boundingBox = newBoundingBox(); } return this.boundingBox; } @Override public double getCoordinate(final int partIndex, final int ringIndex, final int vertexIndex, final int axisIndex) { if (partIndex == 0) { return getCoordinate(ringIndex, vertexIndex, axisIndex); } else { return Double.NaN; } } @Override public GeometryFactory getGeometryFactory() { return this.geometryFactory; } @Override public LinearRing getRing(final int ringIndex) { if (this.rings == null || ringIndex < 0 || ringIndex >= this.rings.length) { return null; } else { return this.rings[ringIndex]; } } @Override public int getRingCount() { if (this.rings == null) { return 0; } else { return this.rings.length; } } @Override public List<LinearRing> getRings() { return Lists.newArray(this.rings); } @Override public boolean isEmpty() { return this.rings == null; } }