/* * Copyright (c) 2016 Vivid Solutions. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Eclipse Distribution License v. 1.0 which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * * http://www.eclipse.org/org/documents/edl-v10.php. */ package org.locationtech.jts.algorithm; import org.locationtech.jts.geom.Coordinate; /** *@version 1.7 */ /** * A non-robust version of {@link LineIntersector}. * * @version 1.7 */ public class NonRobustLineIntersector extends LineIntersector { /** * @return true if both numbers are positive or if both numbers are negative. * Returns false if both numbers are zero. */ public static boolean isSameSignAndNonZero(double a, double b) { if (a == 0 || b == 0) { return false; } return (a < 0 && b < 0) || (a > 0 && b > 0); } public NonRobustLineIntersector() { } public void computeIntersection( Coordinate p, Coordinate p1, Coordinate p2) { double a1; double b1; double c1; /* * Coefficients of line eqns. */ double r; /* * 'Sign' values */ isProper = false; /* * Compute a1, b1, c1, where line joining points 1 and 2 * is "a1 x + b1 y + c1 = 0". */ a1 = p2.y - p1.y; b1 = p1.x - p2.x; c1 = p2.x * p1.y - p1.x * p2.y; /* * Compute r3 and r4. */ r = a1 * p.x + b1 * p.y + c1; // if r != 0 the point does not lie on the line if (r != 0) { result = NO_INTERSECTION; return; } // Point lies on line - check to see whether it lies in line segment. double dist = rParameter(p1, p2, p); if (dist < 0.0 || dist > 1.0) { result = NO_INTERSECTION; return; } isProper = true; if (p.equals(p1) || p.equals(p2)) { isProper = false; } result = POINT_INTERSECTION; } protected int computeIntersect( Coordinate p1, Coordinate p2, Coordinate p3, Coordinate p4) { double a1; double b1; double c1; /* * Coefficients of line eqns. */ double a2; /* * Coefficients of line eqns. */ double b2; /* * Coefficients of line eqns. */ double c2; double r1; double r2; double r3; double r4; /* * 'Sign' values */ //double denom, offset, num; /* Intermediate values */ isProper = false; /* * Compute a1, b1, c1, where line joining points 1 and 2 * is "a1 x + b1 y + c1 = 0". */ a1 = p2.y - p1.y; b1 = p1.x - p2.x; c1 = p2.x * p1.y - p1.x * p2.y; /* * Compute r3 and r4. */ r3 = a1 * p3.x + b1 * p3.y + c1; r4 = a1 * p4.x + b1 * p4.y + c1; /* * Check signs of r3 and r4. If both point 3 and point 4 lie on * same side of line 1, the line segments do not intersect. */ if (r3 != 0 && r4 != 0 && isSameSignAndNonZero(r3, r4)) { return NO_INTERSECTION; } /* * Compute a2, b2, c2 */ a2 = p4.y - p3.y; b2 = p3.x - p4.x; c2 = p4.x * p3.y - p3.x * p4.y; /* * Compute r1 and r2 */ r1 = a2 * p1.x + b2 * p1.y + c2; r2 = a2 * p2.x + b2 * p2.y + c2; /* * Check signs of r1 and r2. If both point 1 and point 2 lie * on same side of second line segment, the line segments do * not intersect. */ if (r1 != 0 && r2 != 0 && isSameSignAndNonZero(r1, r2)) { return NO_INTERSECTION; } /** * Line segments intersect: compute intersection point. */ double denom = a1 * b2 - a2 * b1; if (denom == 0) { return computeCollinearIntersection(p1, p2, p3, p4); } double numX = b1 * c2 - b2 * c1; pa.x = numX / denom; /* * TESTING ONLY * double valX = (( num < 0 ? num - offset : num + offset ) / denom); * double valXInt = (int) (( num < 0 ? num - offset : num + offset ) / denom); * if (valXInt != pa.x) // TESTING ONLY * System.out.println(val + " - int: " + valInt + ", floor: " + pa.x); */ double numY = a2 * c1 - a1 * c2; pa.y = numY / denom; // check if this is a proper intersection BEFORE truncating values, // to avoid spurious equality comparisons with endpoints isProper = true; if (pa.equals(p1) || pa.equals(p2) || pa.equals(p3) || pa.equals(p4)) { isProper = false; } // truncate computed point to precision grid // TESTING - don't force coord to be precise if (precisionModel != null) { precisionModel.makePrecise(pa); } return POINT_INTERSECTION; } /* * p1-p2 and p3-p4 are assumed to be collinear (although * not necessarily intersecting). Returns: * DONT_INTERSECT : the two segments do not intersect * COLLINEAR : the segments intersect, in the * line segment pa-pb. pa-pb is in * the same direction as p1-p2 * DO_INTERSECT : the inputLines intersect in a single point * only, pa */ private int computeCollinearIntersection( Coordinate p1, Coordinate p2, Coordinate p3, Coordinate p4) { double r1; double r2; double r3; double r4; Coordinate q3; Coordinate q4; double t3; double t4; r1 = 0; r2 = 1; r3 = rParameter(p1, p2, p3); r4 = rParameter(p1, p2, p4); // make sure p3-p4 is in same direction as p1-p2 if (r3 < r4) { q3 = p3; t3 = r3; q4 = p4; t4 = r4; } else { q3 = p4; t3 = r4; q4 = p3; t4 = r3; } // check for no intersection if (t3 > r2 || t4 < r1) { return NO_INTERSECTION; } // check for single point intersection if (q4 == p1) { pa.setCoordinate(p1); return POINT_INTERSECTION; } if (q3 == p2) { pa.setCoordinate(p2); return POINT_INTERSECTION; } // intersection MUST be a segment - compute endpoints pa.setCoordinate(p1); if (t3 > r1) { pa.setCoordinate(q3); } pb.setCoordinate(p2); if (t4 < r2) { pb.setCoordinate(q4); } return COLLINEAR_INTERSECTION; } /** * RParameter computes the parameter for the point p * in the parameterized equation * of the line from p1 to p2. * This is equal to the 'distance' of p along p1-p2 */ private double rParameter(Coordinate p1, Coordinate p2, Coordinate p) { double r; // compute maximum delta, for numerical stability // also handle case of p1-p2 being vertical or horizontal double dx = Math.abs(p2.x - p1.x); double dy = Math.abs(p2.y - p1.y); if (dx > dy) { r = (p.x - p1.x) / (p2.x - p1.x); } else { r = (p.y - p1.y) / (p2.y - p1.y); } return r; } }