All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vividsolutions.jts.algorithm.LineIntersector Maven / Gradle / Ivy

There is a newer version: 0.1.4
Show newest version
/*
 * 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.vividsolutions.jts.algorithm;

/**
 * @version 1.7
 */
import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jts.util.*;
import com.vividsolutions.jts.io.WKTWriter;

/**
 * A LineIntersector is an algorithm that can both test whether
 * two line segments intersect and compute the intersection point(s)
 * if they do.
 * 

* There are three possible outcomes when determining whether two line segments intersect: *

    *
  • {@link #NO_INTERSECTION} - the segments do not intersect *
  • {@link #POINT_INTERSECTION - the segments intersect in a single point *
  • {@link #COLLINEAR_INTERSECTION - the segments are collinear and they intersect in a line segment *
* For segments which intersect in a single point, the point may be either an endpoint * or in the interior of each segment. * If the point lies in the interior of both segments, * this is termed a proper intersection. * The method {@link #isProper()} test for this situation. *

* The intersection point(s) may be computed in a precise or non-precise manner. * Computing an intersection point precisely involves rounding it * via a supplied {@link PrecisionModel}. *

* LineIntersectors do not perform an initial envelope intersection test * to determine if the segments are disjoint. * This is because this class is likely to be used in a context where * envelope overlap is already known to occur (or be likely). * * @version 1.7 */ public abstract class LineIntersector { /** * These are deprecated, due to ambiguous naming */ public final static int DONT_INTERSECT = 0; public final static int DO_INTERSECT = 1; public final static int COLLINEAR = 2; /** * Indicates that line segments do not intersect */ public final static int NO_INTERSECTION = 0; /** * Indicates that line segments intersect in a single point */ public final static int POINT_INTERSECTION = 1; /** * Indicates that line segments intersect in a line segment */ public final static int COLLINEAR_INTERSECTION = 2; /** * Computes the "edge distance" of an intersection point p along a segment. * The edge distance is a metric of the point along the edge. * The metric used is a robust and easy to compute metric function. * It is not equivalent to the usual Euclidean metric. * It relies on the fact that either the x or the y ordinates of the * points in the edge are unique, depending on whether the edge is longer in * the horizontal or vertical direction. *

* NOTE: This function may produce incorrect distances * for inputs where p is not precisely on p1-p2 * (E.g. p = (139,9) p1 = (139,10), p2 = (280,1) produces distanct 0.0, which is incorrect. *

* My hypothesis is that the function is safe to use for points which are the * result of rounding points which lie on the line, * but not safe to use for truncated points. */ public static double computeEdgeDistance( Coordinate p, Coordinate p0, Coordinate p1) { double dx = Math.abs(p1.x - p0.x); double dy = Math.abs(p1.y - p0.y); double dist = -1.0; // sentinel value if (p.equals(p0)) { dist = 0.0; } else if (p.equals(p1)) { if (dx > dy) dist = dx; else dist = dy; } else { double pdx = Math.abs(p.x - p0.x); double pdy = Math.abs(p.y - p0.y); if (dx > dy) dist = pdx; else dist = pdy; // // hack to ensure that non-endpoints always have a non-zero distance if (dist == 0.0 && ! p.equals(p0)) { dist = Math.max(pdx, pdy); } } Assert.isTrue(! (dist == 0.0 && ! p.equals(p0)), "Bad distance calculation"); return dist; } /** * This function is non-robust, since it may compute the square of large numbers. * Currently not sure how to improve this. */ public static double nonRobustComputeEdgeDistance( Coordinate p, Coordinate p1, Coordinate p2) { double dx = p.x - p1.x; double dy = p.y - p1.y; double dist = Math.sqrt(dx * dx + dy * dy); // dummy value Assert.isTrue(! (dist == 0.0 && ! p.equals(p1)), "Invalid distance calculation"); return dist; } protected int result; protected Coordinate[][] inputLines = new Coordinate[2][2]; protected Coordinate[] intPt = new Coordinate[2]; /** * The indexes of the endpoints of the intersection lines, in order along * the corresponding line */ protected int[][] intLineIndex; protected boolean isProper; protected Coordinate pa; protected Coordinate pb; /** * If makePrecise is true, computed intersection coordinates will be made precise * using Coordinate#makePrecise */ protected PrecisionModel precisionModel = null; //public int numIntersects = 0; public LineIntersector() { intPt[0] = new Coordinate(); intPt[1] = new Coordinate(); // alias the intersection points for ease of reference pa = intPt[0]; pb = intPt[1]; result = 0; } /** * Force computed intersection to be rounded to a given precision model * @param precisionModel * @deprecated use setPrecisionModel instead */ public void setMakePrecise(PrecisionModel precisionModel) { this.precisionModel = precisionModel; } /** * Force computed intersection to be rounded to a given precision model. * No getter is provided, because the precision model is not required to be specified. * @param precisionModel */ public void setPrecisionModel(PrecisionModel precisionModel) { this.precisionModel = precisionModel; } /** * Gets an endpoint of an input segment. * * @param segmentIndex the index of the input segment (0 or 1) * @param ptIndex the index of the endpoint (0 or 1) * @return the specified endpoint */ public Coordinate getEndpoint(int segmentIndex, int ptIndex) { return inputLines[segmentIndex][ptIndex]; } /** * Compute the intersection of a point p and the line p1-p2. * This function computes the boolean value of the hasIntersection test. * The actual value of the intersection (if there is one) * is equal to the value of p. */ public abstract void computeIntersection( Coordinate p, Coordinate p1, Coordinate p2); protected boolean isCollinear() { return result == COLLINEAR_INTERSECTION; } /** * Computes the intersection of the lines p1-p2 and p3-p4. * This function computes both the boolean value of the hasIntersection test * and the (approximate) value of the intersection point itself (if there is one). */ public void computeIntersection( Coordinate p1, Coordinate p2, Coordinate p3, Coordinate p4) { inputLines[0][0] = p1; inputLines[0][1] = p2; inputLines[1][0] = p3; inputLines[1][1] = p4; result = computeIntersect(p1, p2, p3, p4); //numIntersects++; } protected abstract int computeIntersect( Coordinate p1, Coordinate p2, Coordinate q1, Coordinate q2); /* public String toString() { String str = inputLines[0][0] + "-" + inputLines[0][1] + " " + inputLines[1][0] + "-" + inputLines[1][1] + " : " + getTopologySummary(); return str; } */ public String toString() { return WKTWriter.toLineString(inputLines[0][0], inputLines[0][1]) + " - " + WKTWriter.toLineString(inputLines[1][0], inputLines[1][1]) + getTopologySummary(); } private String getTopologySummary() { StringBuffer catBuf = new StringBuffer(); if (isEndPoint()) catBuf.append(" endpoint"); if (isProper) catBuf.append(" proper"); if (isCollinear()) catBuf.append(" collinear"); return catBuf.toString(); } protected boolean isEndPoint() { return hasIntersection() && !isProper; } /** * Tests whether the input geometries intersect. * * @return true if the input geometries intersect */ public boolean hasIntersection() { return result != NO_INTERSECTION; } /** * Returns the number of intersection points found. This will be either 0, 1 or 2. * * @return the number of intersection points found (0, 1, or 2) */ public int getIntersectionNum() { return result; } /** * Returns the intIndex'th intersection point * * @param intIndex is 0 or 1 * * @return the intIndex'th intersection point */ public Coordinate getIntersection(int intIndex) { return intPt[intIndex]; } protected void computeIntLineIndex() { if (intLineIndex == null) { intLineIndex = new int[2][2]; computeIntLineIndex(0); computeIntLineIndex(1); } } /** * Test whether a point is a intersection point of two line segments. * Note that if the intersection is a line segment, this method only tests for * equality with the endpoints of the intersection segment. * It does not return true if * the input point is internal to the intersection segment. * * @return true if the input point is one of the intersection points. */ public boolean isIntersection(Coordinate pt) { for (int i = 0; i < result; i++) { if (intPt[i].equals2D(pt)) { return true; } } return false; } /** * Tests whether either intersection point is an interior point of one of the input segments. * * @return true if either intersection point is in the interior of one of the input segments */ public boolean isInteriorIntersection() { if (isInteriorIntersection(0)) return true; if (isInteriorIntersection(1)) return true; return false; } /** * Tests whether either intersection point is an interior point of the specified input segment. * * @return true if either intersection point is in the interior of the input segment */ public boolean isInteriorIntersection(int inputLineIndex) { for (int i = 0; i < result; i++) { if (! ( intPt[i].equals2D(inputLines[inputLineIndex][0]) || intPt[i].equals2D(inputLines[inputLineIndex][1]) )) { return true; } } return false; } /** * Tests whether an intersection is proper. *
* The intersection between two line segments is considered proper if * they intersect in a single point in the interior of both segments * (e.g. the intersection is a single point and is not equal to any of the * endpoints). *

* The intersection between a point and a line segment is considered proper * if the point lies in the interior of the segment (e.g. is not equal to * either of the endpoints). * * @return true if the intersection is proper */ public boolean isProper() { return hasIntersection() && isProper; } /** * Computes the intIndex'th intersection point in the direction of * a specified input line segment * * @param segmentIndex is 0 or 1 * @param intIndex is 0 or 1 * * @return the intIndex'th intersection point in the direction of the specified input line segment */ public Coordinate getIntersectionAlongSegment(int segmentIndex, int intIndex) { // lazily compute int line array computeIntLineIndex(); return intPt[intLineIndex[segmentIndex][intIndex]]; } /** * Computes the index (order) of the intIndex'th intersection point in the direction of * a specified input line segment * * @param segmentIndex is 0 or 1 * @param intIndex is 0 or 1 * * @return the index of the intersection point along the input segment (0 or 1) */ public int getIndexAlongSegment(int segmentIndex, int intIndex) { computeIntLineIndex(); return intLineIndex[segmentIndex][intIndex]; } protected void computeIntLineIndex(int segmentIndex) { double dist0 = getEdgeDistance(segmentIndex, 0); double dist1 = getEdgeDistance(segmentIndex, 1); if (dist0 > dist1) { intLineIndex[segmentIndex][0] = 0; intLineIndex[segmentIndex][1] = 1; } else { intLineIndex[segmentIndex][0] = 1; intLineIndex[segmentIndex][1] = 0; } } /** * Computes the "edge distance" of an intersection point along the specified input line segment. * * @param segmentIndex is 0 or 1 * @param intIndex is 0 or 1 * * @return the edge distance of the intersection point */ public double getEdgeDistance(int segmentIndex, int intIndex) { double dist = computeEdgeDistance(intPt[intIndex], inputLines[segmentIndex][0], inputLines[segmentIndex][1]); return dist; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy