/* * 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.Arrays; import com.revolsys.geometry.model.Dimension; import com.revolsys.geometry.model.Geometry; import com.revolsys.geometry.model.GeometryFactory; import com.revolsys.geometry.model.LineString; import com.revolsys.geometry.model.LinearRing; import com.revolsys.geometry.model.Point; import com.revolsys.geometry.model.coordinates.list.CoordinatesListUtil; import com.revolsys.geometry.model.vertex.Vertex; /** * Models an OGC SFS <code>LinearRing</code>. * A <code>LinearRing</code> is a {@link LineString} which is both closed and simple. * In other words, * the first and last coordinate in the ring must be equal, * and the interior of the ring must not self-intersect. * Either orientation of the ring is allowed. * <p> * A ring must have either 0 or 4 or more points. * The first and last points must be equal (in 2D). * If these conditions are not met, the constructors throw * an {@link IllegalArgumentException} * * @version 1.7 */ public class LinearRingDoubleGf extends LineStringDoubleGf implements LinearRing { private static final long serialVersionUID = -4261142084085851829L; public LinearRingDoubleGf(final GeometryFactory factory) { super(factory); } /** * Constructs a <code>LinearRing</code> with the vertices * specifed by the given {@link LineString}. * *@param coordinates a sequence points forming a closed and simple linestring, or * <code>null</code> to create the empty geometry. * * @throws IllegalArgumentException if the ring is not closed, or has too few points * */ public LinearRingDoubleGf(final GeometryFactory factory, final int axisCount, final int vertexCount, final double... coordinates) { super(factory, axisCount, vertexCount, coordinates); validate(); } @SuppressWarnings("unchecked") @Override public <V extends Geometry> V appendVertex(Point newPoint, final int... geometryId) { if (newPoint == null || newPoint.isEmpty()) { return (V)this; } else if (geometryId.length == 0) { final GeometryFactory geometryFactory = getGeometryFactory(); if (isEmpty()) { return newPoint.convertGeometry(geometryFactory); } else { newPoint = newPoint.convertGeometry(geometryFactory); final int vertexCount = getVertexCount(); final double[] coordinates = getCoordinates(); final int axisCount = getAxisCount(); final double[] newCoordinates = new double[axisCount * (vertexCount + 1)]; final Vertex fromPoint = getVertex(0); final int length = (vertexCount - 1) * axisCount; System.arraycopy(coordinates, 0, newCoordinates, 0, length); CoordinatesListUtil.setCoordinates(newCoordinates, axisCount, vertexCount - 1, newPoint); CoordinatesListUtil.setCoordinates(newCoordinates, axisCount, vertexCount, fromPoint); return (V)geometryFactory.linearRing(axisCount, newCoordinates); } } else { throw new IllegalArgumentException( "Geometry id's for LinearRings must have length 0. " + Arrays.toString(geometryId)); } } @Override public LinearRingDoubleGf clone() { return (LinearRingDoubleGf)super.clone(); } @Override public LinearRing deleteVertex(final int vertexIndex) { if (isEmpty()) { throw new IllegalArgumentException("Cannot delete vertex for empty LinearRing"); } else { final int vertexCount = getVertexCount(); if (vertexCount <= 4) { throw new IllegalArgumentException("LineString must have a minimum of 4 vertices"); } else if (vertexIndex >= 0 && vertexIndex < vertexCount) { final GeometryFactory geometryFactory = getGeometryFactory(); final double[] coordinates = getCoordinates(); final int axisCount = getAxisCount(); final double[] newCoordinates = new double[axisCount * (vertexCount - 1)]; if (vertexIndex == 0 || vertexIndex == vertexCount - 1) { System.arraycopy(coordinates, axisCount, newCoordinates, 0, (vertexCount - 2) * axisCount); System.arraycopy(coordinates, axisCount, newCoordinates, (vertexCount - 2) * axisCount, axisCount); } else { final int beforeLength = vertexIndex * axisCount; System.arraycopy(coordinates, 0, newCoordinates, 0, beforeLength); final int sourceIndex = (vertexIndex + 1) * axisCount; final int afterLength = (vertexCount - vertexIndex - 1) * axisCount; System.arraycopy(coordinates, sourceIndex, newCoordinates, vertexIndex * axisCount, afterLength); } return geometryFactory.linearRing(axisCount, newCoordinates); } else { throw new IllegalArgumentException("Vertex index must be between 0 and " + vertexCount); } } } /** * Returns <code>Dimension.FALSE</code>, since by definition LinearRings do * not have a boundary. * * @return Dimension.FALSE */ @Override public int getBoundaryDimension() { return Dimension.FALSE; } @SuppressWarnings("unchecked") @Override public <V extends Geometry> V insertVertex(Point newPoint, final int... vertexId) { if (vertexId.length == 1) { final GeometryFactory geometryFactory = getGeometryFactory(); if (newPoint == null || newPoint.isEmpty()) { return (V)this; } else if (isEmpty()) { return newPoint.convertGeometry(geometryFactory); } else { final int vertexIndex = vertexId[0]; final int vertexCount = getVertexCount(); if (vertexIndex == 0 || vertexIndex == vertexCount - 1) { return appendVertex(newPoint); } else { newPoint = newPoint.convertGeometry(geometryFactory); final double[] coordinates = getCoordinates(); final int axisCount = getAxisCount(); final double[] newCoordinates = new double[axisCount * (vertexCount + 1)]; final int beforeLength = vertexIndex * axisCount; System.arraycopy(coordinates, 0, newCoordinates, 0, beforeLength); CoordinatesListUtil.setCoordinates(newCoordinates, axisCount, vertexIndex, newPoint); final int afterSourceIndex = vertexIndex * axisCount; final int afterNewIndex = (vertexIndex + 1) * axisCount; final int afterLength = (vertexCount - vertexIndex) * axisCount; System.arraycopy(coordinates, afterSourceIndex, newCoordinates, afterNewIndex, afterLength); return (V)geometryFactory.linearRing(axisCount, newCoordinates); } } } else { throw new IllegalArgumentException("Geometry id's for " + getGeometryType() + " must have length 1. " + Arrays.toString(vertexId)); } } /** * Tests whether this ring is closed. * Empty rings are closed by definition. * * @return true if this ring is closed */ @Override public boolean isClosed() { if (isEmpty()) { // empty LinearRings are closed by definition return true; } else { return super.isClosed(); } } @Override public LinearRing move(final double... deltas) { final GeometryFactory geometryFactory = getGeometryFactory(); if (deltas == null || isEmpty()) { return this; } else { final double[] coordinates = moveCoordinates(deltas); final int axisCount = getAxisCount(); return geometryFactory.linearRing(axisCount, coordinates); } } @Override public LinearRing moveVertex(Point newPoint, final int vertexIndex) { if (newPoint == null || newPoint.isEmpty()) { return this; } else if (isEmpty()) { throw new IllegalArgumentException("Cannot move vertex for empty LinearRing"); } else { final int vertexCount = getVertexCount(); if (vertexIndex >= 0 && vertexIndex < vertexCount) { final GeometryFactory geometryFactory = getGeometryFactory(); newPoint = newPoint.convertGeometry(geometryFactory); final double[] coordinates = getCoordinates(); final int axisCount = getAxisCount(); if (vertexIndex == 0 || vertexIndex == vertexCount - 1) { CoordinatesListUtil.setCoordinates(coordinates, axisCount, 0, newPoint); CoordinatesListUtil.setCoordinates(coordinates, axisCount, vertexCount - 1, newPoint); } else { CoordinatesListUtil.setCoordinates(coordinates, axisCount, vertexIndex, newPoint); } return geometryFactory.linearRing(axisCount, coordinates); } else { throw new IllegalArgumentException("Vertex index must be between 0 and " + vertexCount); } } } @Override public LinearRing newGeometry(final GeometryFactory geometryFactory) { return (LinearRing)super.newGeometry(geometryFactory); } @Override public LinearRing reverse() { final int vertexCount = getVertexCount(); final int axisCount = getAxisCount(); final double[] coordinates = new double[vertexCount * axisCount]; for (int vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++) { for (int axisIndex = 0; axisIndex < axisCount; axisIndex++) { final int coordinateIndex = (vertexCount - 1 - vertexIndex) * axisCount + axisIndex; coordinates[coordinateIndex] = getCoordinate(vertexIndex, axisIndex); } } final GeometryFactory geometryFactory = getGeometryFactory(); final LinearRing reverseLine = geometryFactory.linearRing(axisCount, coordinates); return reverseLine; } private void validate() { if (isClosed()) { final int vertexCount = getVertexCount(); if (vertexCount >= 1 && vertexCount <= 2) { throw new IllegalArgumentException( "Invalid number of points in LinearRing (found " + vertexCount + " - must be 0 or >= 3)"); } } else { throw new IllegalArgumentException("Points of LinearRing do not form a closed linestring"); } } }