/*
* The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
* for visualizing and manipulating spatial features with geometry and attributes.
*
* Copyright (C) 2003 Vivid Solutions
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; 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.vividsolutions.jump.util;
import java.util.*;
import com.vividsolutions.jts.algorithm.CGAlgorithms;
import com.vividsolutions.jts.algorithm.RobustCGAlgorithms;
import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jts.util.Assert;
/**
* Some utility functions for handling Coordinate arrays.
*/
public class CoordinateArrays {
//<<TODO:REFACTORING>> JTS already has a class named CoordinateArrays.
//I wonder if we should collapse this class into that one. [Jon Aquino]
// MD - yep, at some point.
private static final CGAlgorithms cga = new RobustCGAlgorithms();
private final static Coordinate[] coordArrayType = new Coordinate[0];
public static Coordinate[] toCoordinateArray(List coordList) {
return (Coordinate[]) coordList.toArray(coordArrayType);
}
//<<TODO:REFACTORING>> This functionality is duplicated in
//the protected method Geometry#reversePointOrder. Perhaps we should
//make that method public and deprecate this method, or have this method
//delegate to the other. [Jon Aquino]
//MD: Geometry#reversePointOrder could delegate to this method. Can't do it other way around.
public static void reverse(Coordinate[] coord) {
int last = coord.length - 1;
int mid = last / 2;
for (int i = 0; i <= mid; i++) {
Coordinate tmp = coord[i];
coord[i] = coord[last - i];
coord[last - i] = tmp;
}
}
/**
* Converts an array of coordinates to a line or point, as appropriate.
* @param coords the coordinates of a line or point
* @param fact a factory used to create the Geometry
* @return a line if there is more than one coordinate; a point if there is
* just one coordinate; an empty point otherwise
*/
public static Geometry toLineOrPoint(Coordinate[] coords,
GeometryFactory fact) {
if (coords.length > 1) {
return fact.createLineString(coords);
}
if (coords.length == 1) {
return fact.createPoint(coords[0]);
}
return fact.createPoint((Coordinate)null);
}
public static boolean equals(Coordinate[] coord1, Coordinate[] coord2) {
if (coord1 == coord2) {
return true;
}
if ((coord1 == null) || (coord2 == null)) {
return false;
}
if (coord1.length != coord2.length) {
return false;
}
for (int i = 0; i < coord1.length; i++) {
if (!coord1[i].equals(coord2[i])) {
return false;
}
}
return true;
}
/**
* Converts a collection of coordinate arrays to a collection of geometries.
* @param coordArrays a collection of Coordinate[]
* @param fact a factory used to create the Geometries
* @return a collection of LineStrings and Points
*/
public static List fromCoordinateArrays(List coordArrays,
GeometryFactory fact) {
List geomList = new ArrayList();
for (Iterator i = coordArrays.iterator(); i.hasNext();) {
Coordinate[] coords = (Coordinate[]) i.next();
Geometry geom = toLineOrPoint(coords, fact);
geomList.add(geom);
}
return geomList;
}
/**
* Extract the coordinate arrays for a geometry into a List.
* @param g the Geometry to extract from
* @param coordArrayList the List to add the coordinate arrays to
* @param orientPolygons whether or not the arrays in the List should be
* oriented (clockwise for the shell, counterclockwise for the holes)
*/
public static void addCoordinateArrays(Geometry g, boolean orientPolygons,
List coordArrayList) {
if (g.getDimension() <= 0) {
return;
} else if (g instanceof LineString) {
LineString l = (LineString) g;
coordArrayList.add(l.getCoordinates());
} else if (g instanceof Polygon) {
Polygon poly = (Polygon) g;
Coordinate[] shell = poly.getExteriorRing().getCoordinates();
if (orientPolygons) {
shell = ensureOrientation(shell, CGAlgorithms.CLOCKWISE);
}
coordArrayList.add(shell);
for (int i = 0; i < poly.getNumInteriorRing(); i++) {
Coordinate[] hole = poly.getInteriorRingN(i).getCoordinates();
if (orientPolygons) {
hole = ensureOrientation(hole, CGAlgorithms.COUNTERCLOCKWISE);
}
coordArrayList.add(hole);
}
} else if (g instanceof GeometryCollection) {
GeometryCollection gc = (GeometryCollection) g;
for (int i = 0; i < gc.getNumGeometries(); i++) {
addCoordinateArrays(gc.getGeometryN(i), orientPolygons,
coordArrayList);
}
} else {
Assert.shouldNeverReachHere("Geometry of type " +
g.getClass().getName() + " not handled");
}
}
/**
* Sets the orientation of an array of coordinates.
* @param coord the coordinates to inspect
* @param desiredOrientation CGAlgorithms.CLOCKWISE or CGAlgorithms.COUNTERCLOCKWISE
* @return a new array with entries in reverse order, if the orientation is
* incorrect; otherwise, the original array
*/
public static Coordinate[] ensureOrientation(Coordinate[] coord,
int desiredOrientation) {
if (coord.length == 0) {
return coord;
}
int orientation = cga.isCCW(coord) ? CGAlgorithms.COUNTERCLOCKWISE
: CGAlgorithms.CLOCKWISE;
if (orientation != desiredOrientation) {
Coordinate[] reverse = (Coordinate[]) coord.clone();
CoordinateArrays.reverse(reverse);
return reverse;
}
return coord;
}
/**
* Extract the coordinate arrays for a geometry.
* Polygons will be checked to ensure their rings are oriented correctly.
* Note: coordinates from Points or MultiPoints will not be extracted.
* @param g the Geometry to extract from
* @param orientPolygons ensure that Polygons are correctly oriented
* @return a list of Coordinate[]
*/
public static List toCoordinateArrays(Geometry g, boolean orientPolygons) {
List coordArrayList = new ArrayList();
addCoordinateArrays(g, orientPolygons, coordArrayList);
return coordArrayList;
}
}