/* * GeoTools java GIS tookit (c) The Centre for Computational Geography 2002 * * 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 */ package uk.ac.leeds.ccg.geotools; import java.lang.*; import java.awt.*; /** * This class is intended for storing geographical line data such as * roads, rivers etc.

* * $Log: GeoLine.java,v $ * Revision 1.7 2002/01/19 18:00:34 loxnard * Fixed JavaDoc comments. * * * @author James Macgill * @author norbertf@users.sourceforge.net - fast point near line test * @author Ian Turton - accurate point near line test * @author Mathieu van Loon - line intersection algorithm * @version $Revision: 1.7 $ $Date: 2002/01/19 18:00:34 $ * @since 0.5.0 */ public class GeoLine extends GeoPolygon { /** * Sets which algorithm to use for point near line test. */ public boolean acurate = false; // this means it will be faster /** * Number of points in line. */ /** * Array of points. */ /** * Minimum bounding box for line. */ /** * Create a line. */ public GeoLine(){} //Empty /** * Construct a line. * * @param id Line ID. * @param xpoints Array of x values (npoints in size). * @param ypoints Array of y values (npoints in size). * @param npoints Number of points. */ public GeoLine(int id,double[] xpoints,double[] ypoints,int npoints) { super(id,xpoints,ypoints,npoints); } /** * Construct a line with no defined centroid or ID. * * @param xpoints Array of x values (npoints in size). * @param ypoints Array of y values (npoints in size). * @param npoints Number of points. */ public GeoLine(double[] xpoints,double[] ypoints,int npoints) { this(-1,xpoints,ypoints,npoints);} /** * Construct a GeoLine based on an existing GeoLine. * * @param line GeoLine to clone. */ public GeoLine(GeoLine line) { this(line.id,line.xpoints,line.ypoints,line.npoints);} /** * Constructs a GeoLine from an ID and an array of points. * * @param id Line ID. * @param points Array of points. */ public GeoLine(int id, GeoPoint[] points){ super(id,points); } /** * Sets which mode to use in point near line test. * @param f True for accurate but slower test. */ public void setAcurate(boolean f){ acurate = f; } /** * Tests whether a point is within a given distance of the line. * * @param p The point to test. * @param w The distance that is considered near. * @return boolean True if the specified point is near the line. */ public boolean isNear(GeoPoint p,double w){ GeoRectangle r = getBounds(); GeoRectangle biggerRect = new GeoRectangle( r.getX() - w, r.getY() - w, r.getWidth() + w*2, r.getHeight() +w*2 ); if(biggerRect.contains(p)){ if(!acurate){ for(int i=0;ip2.getY()){ GeoPoint tmp = p1; p1=p2; p2=tmp; } double dx=p2.getX()-p1.getX(); double dy=p2.getY()-p1.getY(); double alpha = Math.atan2(dy,dx); dy = (w)*Math.sin(Math.PI/2.0-alpha); dx = (w)*Math.cos(Math.PI/2.0-alpha); double [] x= new double[4]; double [] y= new double[4]; x[0]=p1.getX()-dx; y[0]=p1.getY()+dy; x[1]=p2.getX()-dx; y[1]=p2.getY()+dy; x[2]=p2.getX()+dx; y[2]=p2.getY()-dy; x[3]=p1.getX()+dx; y[3]=p1.getY()-dy; GeoPolygon gp = new GeoPolygon(0,0.0,0.0,x,y,4); GeoCircle gc = new GeoCircle(0,p1,(double)w); if(gc.contains(p)) return true; gc = new GeoCircle(0,p2,(double)w); if(gc.contains(p)) return true; if(gp.contains(p)) return true; } }// accurate } return false; } /** * Tests whether a point is within a given distance of the line. * @param x X coordinate of point to test. * @param y Y coordinate of point to test. * @param w Distance that is considered near. * @return True if the specified point is near the line. */ public boolean isNear(double x,double y,double w){ GeoPoint p = new GeoPoint(x,y); return isNear(p,w); } /** * This method is EXPERIMENTAL & BUGGY. Don't rely on this to work at this point. * The method checks for an intersection between this object's line and a given line. * Please note that, at this time, a line can only have two points! A geoline object * in general can have more than two points. * The algorithm used is taken from the comp.graphics.algorithms FAQ, * available at http://www.cs.ruu.nl/wais/html/na-dir/graphics/algorithms-faq.html * and posted regularly at that newsgroup. Subject 1.03 at this time of writing. * The algorithm basically solves the two line equations. I've adjusted the algorithm slightly. * In the FAQ r is calculated as r = numerator/denumerator, and s = numerator/denumerator. * As the denumerators are identical, and an intersection exists if both 0<=r<=1 and 0<=s<=1 * I calculate r = numerator, s = numerator. Then I check for 0<=r<=denumerator and 0<=s<=denumerator * This prevents any potential divide by zero as well. * * We don't calculate the intersection point, * though that should be done easily by solving : * Intersection point P.x = Line1.pointA.x + r * (Line1.pointB.x-Line1.pointA.x) * Intersection point P.y = Line1.pointA.y + r * (Line1.pointB.y-Line1.pointA.y) * (also taken from that faq). * One last thing : I'm definitely no expert at this, so don't trust me for * implementing this correctly. (though I checked the code before releasing :) ) * @param l The line to test against for intersection. * @param debug If true, debug output is given. * @return boolean True if lines intersect. * @throws IllegalArgumentException Thrown if either line has more or less than two points. */ public boolean intersects(GeoLine l, boolean debug) throws IllegalArgumentException { System.err.println("Geoline.intersects is called. this code is buggy. Don't use it."); // Check to make sure each line has only two points if(this.npoints > 2) throw new IllegalArgumentException("This geoline object has more than 2 points. I can't handle that. sorry"); if(l.npoints > 2) throw new IllegalArgumentException("The given geoline object has more than 2 points. I can't handle that. sorry"); // calculate stuff double r = ((this.ypoints[0] - l.ypoints[0]) * (l.xpoints[1] - l.xpoints[0])) - ((this.xpoints[0] - l.xpoints[0]) * (l.ypoints[1] - l.ypoints[0])); double s = ((this.ypoints[0] - l.ypoints[0]) * (this.xpoints[1] - this.xpoints[0])) - ((this.xpoints[0] - l.xpoints[0]) * (this.ypoints[1] - this.ypoints[0])); double denumerator = ((this.xpoints[1] - this.xpoints[0]) * (l.ypoints[1] - l.ypoints[0])) - ((this.ypoints[1] - this.ypoints[0]) * (l.xpoints[1] - l.xpoints[0])); // determine whether an intersection exists if(denumerator==0) { if(r==0) { // The lines are collinear. if(debug)System.out.println("Collinear lines found"); if(debug)System.out.println("r:"+r+"--s:"+s+"--d:"+denumerator); return true; } else { // The lines are parallel if(debug)System.out.println("parallel lines found"); if(debug)System.out.println("r:"+r+"--s:"+s+"--d:"+denumerator); return false; } } if(denumerator>0) { if(0<=r && r<=denumerator && 0<=s && s<=denumerator) { // an intersection exists if(debug)System.out.println("Intersection found"); if(debug)System.out.println("r:"+r+"--s:"+s+"--d:"+denumerator); return true; } else { // no intersection exists if(debug)System.out.println("No Intersection found"+s+"---"+r); // if(debug)System.out.println("r:"+r+"--s:"+s+"--d:"+denumerator); return false; } } else { if(denumerator<=r && r<=0 && denumerator<=s && s<=0) { // an intersection exists if(debug)System.out.println("R->Intersection found"); if(debug)System.out.println("R->r:"+r+"--s:"+s+"--d:"+denumerator); return true; } else { // no intersection exists r= r / denumerator; s= s /denumerator; if(debug)System.out.println("R->No Intersection found"+s+"---"+r); //if(debug)System.out.println("R->r:"+r+"--s:"+s+"--d:"+denumerator); return false; } } } /** * Returns a String representation of this line. * @return String in the form "GeoLine : [id id] {x1,y1,...,xn,yn}". */ public String toString(){ StringBuffer sb = new StringBuffer(); sb.append("GeoLine : [id "); sb.append(id); sb.append("] "); for(int i=0;i