/** * Determines the orientation of a LineSegment relative to this segment. The concept of * orientation is specified as follows: Given two line segments A and L, * * <ul * <li> * A is to the left of a segment L if A lies wholly in the closed half-plane lying to the left * of L * <li>A is to the right of a segment L if A lies wholly in the closed half-plane lying to the * right of L * <li>otherwise, A has indeterminate orientation relative to L. This happens if A is collinear * with L or if A crosses the line determined by L. * </ul> * * @param seg the LineSegment to compare * @return 1 if <code>seg</code> is to the left of this segment * @return -1 if <code>seg</code> is to the right of this segment * @return 0 if <code>seg</code> is collinear to or crosses this segment */ public int orientationIndex(LineSegment seg) { int orient0 = CGAlgorithms.orientationIndex(p0, p1, seg.p0); int orient1 = CGAlgorithms.orientationIndex(p0, p1, seg.p1); // this handles the case where the points are L or collinear if (orient0 >= 0 && orient1 >= 0) return Math.max(orient0, orient1); // this handles the case where the points are R or collinear if (orient0 <= 0 && orient1 <= 0) return Math.max(orient0, orient1); // points lie on opposite sides ==> indeterminate orientation return 0; }
private void findRightmostEdgeAtVertex() { /** * The rightmost point is an interior vertex, so it has a segment on either side of it. If these * segments are both above or below the rightmost point, we need to determine their relative * orientation to decide which is rightmost. */ Coordinate[] pts = minDe.getEdge().getCoordinates(); Assert.isTrue( minIndex > 0 && minIndex < pts.length, "rightmost point expected to be interior vertex of edge"); Coordinate pPrev = pts[minIndex - 1]; Coordinate pNext = pts[minIndex + 1]; int orientation = CGAlgorithms.computeOrientation(minCoord, pNext, pPrev); boolean usePrev = false; // both segments are below min point if (pPrev.y < minCoord.y && pNext.y < minCoord.y && orientation == CGAlgorithms.COUNTERCLOCKWISE) { usePrev = true; } else if (pPrev.y > minCoord.y && pNext.y > minCoord.y && orientation == CGAlgorithms.CLOCKWISE) { usePrev = true; } // if both segments are on the same side, do nothing - either is safe // to select as a rightmost segment if (usePrev) { minIndex = minIndex - 1; } }
private void tryDist(Coordinate p, Coordinate p0, Coordinate p1) { double dist = CGAlgorithms.distancePointLine(p, p0, p1); if (dist < minDist) { minDist = dist; intPt = p; } }
public void computeIntersection(Coordinate p, Coordinate p1, Coordinate p2) { isProper = false; // do between check first, since it is faster than the orientation test if (Envelope.intersects(p1, p2, p)) { if ((CGAlgorithms.orientationIndex(p1, p2, p) == 0) && (CGAlgorithms.orientationIndex(p2, p1, p) == 0)) { isProper = true; if (p.equals(p1) || p.equals(p2)) { isProper = false; } result = POINT_INTERSECTION; return; } } result = NO_INTERSECTION; }
/** * Find the innermost enclosing shell EdgeRing containing the argument EdgeRing, if any. The * innermost enclosing ring is the <i>smallest</i> enclosing ring. The algorithm used depends on * the fact that: <br> * ring A contains ring B iff envelope(ring A) contains envelope(ring B) <br> * This routine is only safe to use if the chosen point of the hole is known to be properly * contained in a shell (which is guaranteed to be the case if the hole does not touch its shell) * * @return containing EdgeRing, if there is one or null if no containing EdgeRing is found */ public static EdgeRing findEdgeRingContaining(EdgeRing testEr, List shellList) { LinearRing testRing = testEr.getRing(); Envelope testEnv = testRing.getEnvelopeInternal(); Coordinate testPt = testRing.getCoordinateN(0); EdgeRing minShell = null; Envelope minShellEnv = null; for (Iterator it = shellList.iterator(); it.hasNext(); ) { EdgeRing tryShell = (EdgeRing) it.next(); LinearRing tryShellRing = tryShell.getRing(); Envelope tryShellEnv = tryShellRing.getEnvelopeInternal(); // the hole envelope cannot equal the shell envelope // (also guards against testing rings against themselves) if (tryShellEnv.equals(testEnv)) continue; // hole must be contained in shell if (!tryShellEnv.contains(testEnv)) continue; testPt = CoordinateArrays.ptNotInList(testRing.getCoordinates(), tryShellRing.getCoordinates()); boolean isContained = false; if (CGAlgorithms.isPointInRing(testPt, tryShellRing.getCoordinates())) isContained = true; // check if this new containing ring is smaller than the current minimum ring if (isContained) { if (minShell == null || minShellEnv.contains(tryShellEnv)) { minShell = tryShell; minShellEnv = minShell.getRing().getEnvelopeInternal(); } } } return minShell; }
/** * Finds the endpoint of the segments P and Q which is closest to the other segment. This is a * reasonable surrogate for the true intersection points in ill-conditioned cases (e.g. where two * segments are nearly coincident, or where the endpoint of one segment lies almost on the other * segment). * * <p>This replaces the older CentralEndpoint heuristic, which chose the wrong endpoint in some * cases where the segments had very distinct slopes and one endpoint lay almost on the other * segment. * * @param p1 an endpoint of segment P * @param p2 an endpoint of segment P * @param q1 an endpoint of segment Q * @param q2 an endpoint of segment Q * @return the nearest endpoint to the other segment */ private static Coordinate nearestEndpoint( Coordinate p1, Coordinate p2, Coordinate q1, Coordinate q2) { Coordinate nearestPt = p1; double minDist = CGAlgorithms.distancePointLine(p1, q1, q2); double dist = CGAlgorithms.distancePointLine(p2, q1, q2); if (dist < minDist) { minDist = dist; nearestPt = p2; } dist = CGAlgorithms.distancePointLine(q1, p1, p2); if (dist < minDist) { minDist = dist; nearestPt = q1; } dist = CGAlgorithms.distancePointLine(q2, p1, p2); if (dist < minDist) { minDist = dist; nearestPt = q2; } return nearestPt; }
/** * Computes the perpendicular distance between the (infinite) line defined by this line segment * and a point. * * @return the perpendicular distance between the defined line and the given point */ public double distancePerpendicular(Coordinate p) { return CGAlgorithms.distancePointLinePerpendicular(p, p0, p1); }
/** * Computes the distance between this line segment and a given point. * * @return the distance from this segment to the given point */ public double distance(Coordinate p) { return CGAlgorithms.distancePointLine(p, p0, p1); }
/** * Computes the distance between this line segment and another segment. * * @return the distance to the other segment */ public double distance(LineSegment ls) { return CGAlgorithms.distanceLineLine(p0, p1, ls.p0, ls.p1); }
/** * Determines the orientation index of a {@link Coordinate} relative to this segment. The * orientation index is as defined in {@link CGAlgorithms#computeOrientation}. * * @param p the coordinate to compare * @return 1 (LEFT) if <code>p</code> is to the left of this segment * @return -1 (RIGHT) if <code>p</code> is to the right of this segment * @return 0 (COLLINEAR) if <code>p</code> is collinear with this segment * @see CGAlgorithms#computeOrientation(Coordinate, Coordinate, Coordinate) */ public int orientationIndex(Coordinate p) { return CGAlgorithms.orientationIndex(p0, p1, p); }
protected int computeIntersect(Coordinate p1, Coordinate p2, Coordinate q1, Coordinate q2) { isProper = false; // first try a fast test to see if the envelopes of the lines intersect if (!Envelope.intersects(p1, p2, q1, q2)) return NO_INTERSECTION; // for each endpoint, compute which side of the other segment it lies // if both endpoints lie on the same side of the other segment, // the segments do not intersect int Pq1 = CGAlgorithms.orientationIndex(p1, p2, q1); int Pq2 = CGAlgorithms.orientationIndex(p1, p2, q2); if ((Pq1 > 0 && Pq2 > 0) || (Pq1 < 0 && Pq2 < 0)) { return NO_INTERSECTION; } int Qp1 = CGAlgorithms.orientationIndex(q1, q2, p1); int Qp2 = CGAlgorithms.orientationIndex(q1, q2, p2); if ((Qp1 > 0 && Qp2 > 0) || (Qp1 < 0 && Qp2 < 0)) { return NO_INTERSECTION; } boolean collinear = Pq1 == 0 && Pq2 == 0 && Qp1 == 0 && Qp2 == 0; if (collinear) { return computeCollinearIntersection(p1, p2, q1, q2); } /** * At this point we know that there is a single intersection point (since the lines are not * collinear). */ /** * Check if the intersection is an endpoint. If it is, copy the endpoint as the intersection * point. Copying the point rather than computing it ensures the point has the exact value, * which is important for robustness. It is sufficient to simply check for an endpoint which is * on the other line, since at this point we know that the inputLines must intersect. */ if (Pq1 == 0 || Pq2 == 0 || Qp1 == 0 || Qp2 == 0) { isProper = false; /** * Check for two equal endpoints. This is done explicitly rather than by the orientation tests * below in order to improve robustness. * * <p>[An example where the orientation tests fail to be consistent is the following (where * the true intersection is at the shared endpoint POINT (19.850257749638203 * 46.29709338043669) * * <p>LINESTRING ( 19.850257749638203 46.29709338043669, 20.31970698357233 46.76654261437082 ) * and LINESTRING ( -48.51001596420236 -22.063180333403878, 19.850257749638203 * 46.29709338043669 ) * * <p>which used to produce the INCORRECT result: (20.31970698357233, 46.76654261437082, NaN) */ if (p1.equals2D(q1) || p1.equals2D(q2)) { intPt[0] = p1; } else if (p2.equals2D(q1) || p2.equals2D(q2)) { intPt[0] = p2; } /** Now check to see if any endpoint lies on the interior of the other segment. */ else if (Pq1 == 0) { intPt[0] = new Coordinate(q1); } else if (Pq2 == 0) { intPt[0] = new Coordinate(q2); } else if (Qp1 == 0) { intPt[0] = new Coordinate(p1); } else if (Qp2 == 0) { intPt[0] = new Coordinate(p2); } } else { isProper = true; intPt[0] = intersection(p1, p2, q1, q2); } return POINT_INTERSECTION; }
/** * Tests whether this ring is a hole. Due to the way the edges in the polyongization graph are * linked, a ring is a hole if it is oriented counter-clockwise. * * @return <code>true</code> if this ring is a hole */ public boolean isHole() { LinearRing ring = getRing(); return CGAlgorithms.isCCW(ring.getCoordinates()); }