/* * Given two edges AB and CD such that robustCrossing() is true, return their * intersection point. Useful properties of getIntersection (GI): * * (1) GI(b,a,c,d) == GI(a,b,d,c) == GI(a,b,c,d) (2) GI(c,d,a,b) == * GI(a,b,c,d) * * The returned intersection point X is guaranteed to be close to the edges AB * and CD, but if the edges intersect at a very small angle then X may not be * close to the true mathematical intersection point P. See the description of * "DEFAULT_INTERSECTION_TOLERANCE" below for details. */ public static S2Point GetIntersection(S2Point a0, S2Point a1, S2Point b0, S2Point b1) { Preconditions.CheckArgument(RobustCrossing(a0, a1, b0, b1) > 0, "Input edges a0a1 and b0b1 muct have a true robustCrossing."); // We use robustCrossProd() to get accurate results even when two endpoints // are close together, or when the two line segments are nearly parallel. var aNorm = S2Point.Normalize(S2.RobustCrossProd(a0, a1)); var bNorm = S2Point.Normalize(S2.RobustCrossProd(b0, b1)); var x = S2Point.Normalize(S2.RobustCrossProd(aNorm, bNorm)); // Make sure the intersection point is on the correct side of the sphere. // Since all vertices are unit length, and edges are less than 180 degrees, // (a0 + a1) and (b0 + b1) both have positive dot product with the // intersection point. We use the sum of all vertices to make sure that the // result is unchanged when the edges are reversed or exchanged. if (x.DotProd(a0 + a1 + b0 + b1) < 0) { x = -x; } // The calculation above is sufficient to ensure that "x" is within // DEFAULT_INTERSECTION_TOLERANCE of the great circles through (a0,a1) and // (b0,b1). // However, if these two great circles are very close to parallel, it is // possible that "x" does not lie between the endpoints of the given line // segments. In other words, "x" might be on the great circle through // (a0,a1) but outside the range covered by (a0,a1). In this case we do // additional clipping to ensure that it does. if (S2.OrderedCcw(a0, x, a1, aNorm) && S2.OrderedCcw(b0, x, b1, bNorm)) { return(x); } // Find the acceptable endpoint closest to x and return it. An endpoint is // acceptable if it lies between the endpoints of the other line segment. var r = new CloserResult(10, x); if (S2.OrderedCcw(b0, a0, b1, bNorm)) { r.ReplaceIfCloser(x, a0); } if (S2.OrderedCcw(b0, a1, b1, bNorm)) { r.ReplaceIfCloser(x, a1); } if (S2.OrderedCcw(a0, b0, a1, aNorm)) { r.ReplaceIfCloser(x, b0); } if (S2.OrderedCcw(a0, b1, a1, aNorm)) { r.ReplaceIfCloser(x, b1); } return(r.Vmin); }
/* * Given two edges AB and CD such that robustCrossing() is true, return their * intersection point. Useful properties of getIntersection (GI): * * (1) GI(b,a,c,d) == GI(a,b,d,c) == GI(a,b,c,d) (2) GI(c,d,a,b) == * GI(a,b,c,d) * * The returned intersection point X is guaranteed to be close to the edges AB * and CD, but if the edges intersect at a very small angle then X may not be * close to the true mathematical intersection point P. See the description of * "DEFAULT_INTERSECTION_TOLERANCE" below for details. */ public static S2Point GetIntersection(S2Point a0, S2Point a1, S2Point b0, S2Point b1) { Preconditions.CheckArgument(RobustCrossing(a0, a1, b0, b1) > 0, "Input edges a0a1 and b0b1 muct have a true robustCrossing."); // We use robustCrossProd() to get accurate results even when two endpoints // are close together, or when the two line segments are nearly parallel. var aNorm = S2Point.Normalize(S2.RobustCrossProd(a0, a1)); var bNorm = S2Point.Normalize(S2.RobustCrossProd(b0, b1)); var x = S2Point.Normalize(S2.RobustCrossProd(aNorm, bNorm)); // Make sure the intersection point is on the correct side of the sphere. // Since all vertices are unit length, and edges are less than 180 degrees, // (a0 + a1) and (b0 + b1) both have positive dot product with the // intersection point. We use the sum of all vertices to make sure that the // result is unchanged when the edges are reversed or exchanged. if (x.DotProd(a0 + a1 + b0 + b1) < 0) { x = -x; } // The calculation above is sufficient to ensure that "x" is within // DEFAULT_INTERSECTION_TOLERANCE of the great circles through (a0,a1) and // (b0,b1). // However, if these two great circles are very close to parallel, it is // possible that "x" does not lie between the endpoints of the given line // segments. In other words, "x" might be on the great circle through // (a0,a1) but outside the range covered by (a0,a1). In this case we do // additional clipping to ensure that it does. if (S2.OrderedCcw(a0, x, a1, aNorm) && S2.OrderedCcw(b0, x, b1, bNorm)) { return x; } // Find the acceptable endpoint closest to x and return it. An endpoint is // acceptable if it lies between the endpoints of the other line segment. var r = new CloserResult(10, x); if (S2.OrderedCcw(b0, a0, b1, bNorm)) { r.ReplaceIfCloser(x, a0); } if (S2.OrderedCcw(b0, a1, b1, bNorm)) { r.ReplaceIfCloser(x, a1); } if (S2.OrderedCcw(a0, b0, a1, aNorm)) { r.ReplaceIfCloser(x, b0); } if (S2.OrderedCcw(a0, b1, a1, aNorm)) { r.ReplaceIfCloser(x, b1); } return r.Vmin; }