/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2003-2008, Open Source Geospatial Foundation (OSGeo) * * 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; * version 2.1 of the License. * * 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. */ package org.geotools.graph.util.geom; import java.util.Collection; import java.util.Iterator; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineSegment; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.PrecisionModel; public class GeometryUtil { private static GeometryFactory geomFactory; private static PrecisionModel precModel; public static boolean isEqual(Coordinate[] c1, Coordinate c2[]) { return(isEqual(c1,c2,false)); } public static boolean isEqual( Coordinate[] c1, Coordinate c2[], boolean reverse ) { if (c1.length != c2.length) return(false); if (!reverse) { for (int i = 0; i < c1.length; i++) { if (!c1[i].equals(c2[i])) return(false); } return(true); } for (int i = 0; i < c1.length; i++) { if (!c1[i].equals(c2[c1.length-i-1])) return(false); } return(true); } public static LineString joinLinestrings(LineString l1, LineString l2) { Coordinate[] merged = new Coordinate[ l1.getNumPoints()+l2.getNumPoints()-1 ]; //linestrings could join in one of 4 ways: // tip to tail // tail to tip // tip to tip // tail to tail if ( l1.getCoordinateN(l1.getNumPoints()-1).equals(l2.getCoordinateN(0)) ) { //tip to tail for (int i = 0; i < l1.getNumPoints(); i++) { merged[i] = l1.getCoordinateN(i); } for (int i = 0; i < l2.getNumPoints()-1; i++) { merged[i+l1.getNumPoints()] = l2.getCoordinateN(i+1); } } else if ( l2.getCoordinateN(l2.getNumPoints()-1).equals(l1.getCoordinateN(0)) ) { //tail to tip for (int i = 0; i < l2.getNumPoints(); i++) { merged[i] = l2.getCoordinateN(i); } for (int i = 0; i < l1.getNumPoints()-1; i++) { merged[i+l2.getNumPoints()] = l1.getCoordinateN(i+1); } } else if ( l1.getCoordinateN(l1.getNumPoints()-1).equals( l2.getCoordinateN(l2.getNumPoints()-1) ) ) { //tip to tip for (int i = 0; i < l1.getNumPoints(); i++) { merged[i] = l1.getCoordinateN(i); } for (int i = 0; i < l2.getNumPoints()-1; i++) { merged[i+l1.getNumPoints()] = l2.getCoordinateN(l2.getNumPoints()-2-i); } } else if ( l1.getCoordinateN(0).equals(l2.getCoordinateN(0)) ) { //tail to tail for (int i = 0; i < l2.getNumPoints(); i++) { merged[i] = l2.getCoordinateN(l2.getNumPoints()-1-i); } for (int i = 0; i < l1.getNumPoints()-1; i++) { merged[i+l2.getNumPoints()] = l1.getCoordinateN(i+1); } } else return(null); return(gf().createLineString(merged)); } public static double angleBetween(LineSegment l1, LineSegment l2, double tol){ //analyze slopes //TODO straight vertical lines double s1 = (l1.p1.y - l1.p0.y) / (l1.p1.x - l1.p0.x); double s2 = (l2.p1.y - l2.p0.y) / (l2.p1.x - l2.p0.x); if (Math.abs(s1 - s2) < tol) return(0); if (Math.abs(s1 + s2) < tol) return(Math.PI); //not of equal slope, transform lines so that they are tail to tip and // use the cosine law to calculate angle between //transform line segments tail to tail, originating at (0,0) LineSegment tls1 = new LineSegment( new Coordinate(0,0), new Coordinate(l1.p1.x-l1.p0.x,l1.p1.y-l1.p0.y) ); LineSegment tls2 = new LineSegment( new Coordinate(0,0), new Coordinate(l2.p1.x-l2.p0.x,l2.p1.y-l2.p0.y) ); //line segment for third side of triangle LineSegment ls3 = new LineSegment(tls1.p1, tls2.p1); double c = ls3.getLength(); double a = tls1.getLength(); double b = tls2.getLength(); return( Math.acos((a*a + b*b - c*c) / (2*a*b)) ); } public static double angleBetween(LineString l1, LineString l2, double tol) { LineSegment ls1 = new LineSegment( l1.getCoordinateN(l1.getNumPoints()-2), l1.getCoordinateN(l1.getNumPoints()-1) ); LineSegment ls2 = new LineSegment( l2.getCoordinateN(0), l2.getCoordinateN(1) ); return(angleBetween(ls1,ls2, tol)); } public static double dx(LineString ls) { return( ls.getPointN(ls.getNumPoints()-1).getX() - ls.getPointN(0).getX() ); } public static double dy(LineString ls) { return( ls.getPointN(ls.getNumPoints()-1).getY() - ls.getPointN(0).getY() ); } // public static Geometry reverseGeometry(Geometry geometry) { // if (geometry instanceof Point) return(geometry); // if (geometry instanceof LineString) { // return( // gf().createLineString(reverseCoordinates(geometry.getCoordinates())) // ); // } // //TODO: implement polygon and multi geometries // return(null); // } // public static Coordinate[] reverseCoordinates(Coordinate[] c) { // int n = c.length; // Coordinate[] reversed = new Coordinate[n]; // for (int i = 0; i < n; i++) reversed[i] = c[n-i-1]; // return(reversed); // } public static Geometry reverseGeometry(Geometry geom, boolean modify) { if (geom instanceof Point) return(geom); if (geom instanceof LineString) { Coordinate[] reversed = reverseCoordinates(geom.getCoordinates(), modify); if (modify) return(geom); else return(gf().createLineString(reversed)); } return(null); } public static Coordinate[] reverseCoordinates(Coordinate[] c, boolean modify) { if (modify) { int n = c.length/2; //truncate if odd number for (int i = 0; i < n; i++) { Coordinate tmp = c[i]; c[i] = c[c.length-1-i]; c[c.length-1-i] = tmp; } return(c); } else { Coordinate[] cnew = new Coordinate[c.length]; for (int i = 0; i < c.length; i++) { cnew[i] = c[c.length-1-i]; } return(cnew); } } public static double averageDistance(LineString to, Collection from) { double avg = 0; int n = 0; for (Iterator itr = from.iterator(); itr.hasNext();) { LineString ls = (LineString)itr.next(); n += ls.getNumPoints(); for (int i = 0; i < ls.getNumPoints(); i++) { avg += ls.getPointN(i).distance(to); } } return(avg/((double)n)); } public static LineString simplifyLineString(LineString line) { double x = 0d; double y = 0d; int n = line.getNumPoints(); for (int i = 0; i < n; i++) { Coordinate c = line.getCoordinateN(i); x += c.x; y += c.y; } x /= (double)n; y /= (double)n; LineString simple = gf().createLineString( new Coordinate[] { line.getCoordinateN(0), new Coordinate(x,y), line.getCoordinateN(n-1) } ); return(simple); } public static PrecisionModel basicPrecisionModel() { return(pm()); } public static GeometryFactory gf() { if (geomFactory == null) { geomFactory = new GeometryFactory(); } return(geomFactory); } public static PrecisionModel pm() { if (precModel == null) { precModel = new PrecisionModel(); } return(precModel); } // public static LineString normalize(LineString line, double sample) { // Coordinate[] orig = line.getCoordinates(); // ArrayList normal = new ArrayList(); // // // return(null); // } public static LineString normalizeLinestring(LineString line, double sample) { Coordinate[] c = line.getCoordinates(); boolean[] remove = new boolean[c.length]; int nremove = 0; double[] add = new double[c.length]; int nadd = 0; //special case if linestirng 2 coordinates if (c.length == 2) { if (distance(c,0,1) > sample) { //do the point interepolation int n = (int) (distance(c,0,1) / sample); if (n > 1) { nadd += n-1; add[0] = distance(c,0,1) / ((double)n); } } else return(line); } else { int i = 0; while(i < c.length-2) { //Coordinate c1 = c[i]; int j = i+1; while(j < c.length-1) { //Coordinate c2 = c[j]; if (distance(c,i,j) < sample) { remove[j] = true; nremove++; j++; } else break; } int n = (int) (distance(c,i,j) / (sample)); if (n > 1) { add[i] = distance(c,i,j) / ((double)n); nadd += n-1; } i = j; } //the last two points that will not be removed may need to be adjusted for (int k = c.length-2; k >= 1; k--) { if (!remove[k]) { //if distance between this point and last point is less then sample // remove this point, and find the point before it, and asjust the // interval in which to add points if (distance(c, c.length-1, k) < sample) { remove[k] = true; nremove++; //move backward to find the last coordinate that wasn't removed // and readjust any points that were added int l = k-1; for (; l >= 0; l--) { if (!remove[l]) break; } if (l > -1) { int n = (int) (distance(c,l,k) / sample); if (n > 1) { add[l] = 0d; nadd -= (n-1); } //recalculate n = (int)(distance(c,l,c.length-1) / sample); if (n > 1) { add[l] = distance(c,l,c.length-1) / ((double)n); nadd += n-1; } } } else { //if the last point is the second to last in the coordinate // array, we may have to add points inbetween if (k == c.length-2) { //determine if we need to add any points between last two points int n = (int) (distance(c,k,c.length-1) / sample); if (n > 1) { nadd += n-1; add[k] = distance(c,k,c.length-1) / ((double)n); } } } break; } } // if (!remove[c.length-2]) { // if (c[c.length-1].distance(c[c.length-2]) < sample) { // remove[c.length-2] = true; // nremove++; // // //move backward to find the last coordinate that wasn't removed // // and readjust any points that were added // int k = c.length-3; // for (; k >= 0; k--) { // if (!remove[k]) break; // } // // if (k > -1) { // int n = (int) (c[k].distance(c[c.length-2]) / sample); // if (n > 1) { // add[k] = 0d; // nadd -= (n-1); // } // // //recalculate // n = (int)(c[k].distance(c[c.length-1]) / sample); // if (n > 1) { // add[k] = c[k].distance(c[c.length-1]) / ((double)n); // nadd += n-1; // } // // } // } // else { // //determine if we need to add any points between last two points // int n = (int) (c[c.length-2].distance(c[c.length-1]) / sample); // if (n > 1) { // nadd += n-1; // add[c.length-2] = c[c.length-2].distance(c[c.length-1]) / ((double)n); // } // // } // } } Coordinate[] newc = new Coordinate[c.length-nremove+nadd]; //Coordinate[] newc = new Coordinate[c.length-nremove]; int j = 0; for (int i = 0; i < c.length; i++) { if (!remove[i]) { newc[j++] = c[i]; if (add[i] > 0d) { int next = -1; for (int k = i+1; k < c.length && next == -1;k++) { if (!remove[k]) next = k; } if (next == -1) continue; double dx = (c[next].x-c[i].x)*(add[i])/distance(c,i,next); double dy = (c[next].y-c[i].y)*(add[i])/distance(c,i,next); int n = (int) (distance(c,i,next) / add[i] + + 0.000001); for (int k = 1; k < n; k++) { newc[j++] = new Coordinate(c[i].x + k*dx, c[i].y + k*dy); } } } } // for (int i = 0; i < newc.length; i++) { // Coordinate coord = newc[i]; // if (coord != null) // System.out.println("POINT(" + coord.x + " " + coord.y + ")"); // else System.out.println("null"); // } return(gf().createLineString(newc)); } public static double distance(Coordinate[] c, int i, int j) { if (i > j) { int tmp = i; i = j; j = tmp; } double dist = 0d; for (int k = i; k < j; k++) { dist += c[k].distance(c[k+1]); } return(dist); } }