diff --git a/Source/Core/Intersections2D.js b/Source/Core/Intersections2D.js index 36f88b1eb673..660bca1fe0c8 100644 --- a/Source/Core/Intersections2D.js +++ b/Source/Core/Intersections2D.js @@ -1,8 +1,10 @@ define([ + './Cartesian2', './Cartesian3', './defined', './DeveloperError' ], function( + Cartesian2, Cartesian3, defined, DeveloperError) { @@ -278,5 +280,76 @@ define([ return new Cartesian3(l1, l2, l3); }; + /** + * Compute the intersection between 2 line segments + * + * @param {Number} x00 The x coordinate of the first line's first vertex. + * @param {Number} y00 The y coordinate of the first line's first vertex. + * @param {Number} x01 The x coordinate of the first line's second vertex. + * @param {Number} y01 The y coordinate of the first line's second vertex. + * @param {Number} x10 The x coordinate of the second line's first vertex. + * @param {Number} y10 The y coordinate of the second line's first vertex. + * @param {Number} x11 The x coordinate of the second line's second vertex. + * @param {Number} y11 The y coordinate of the second line's second vertex. + * @param {Cartesian2} [result] The instance into to which to copy the result. If this parameter + * is undefined, a new instance is created and returned. + * @returns {Cartesian2} The intersection point, undefined if there is no intersection point or lines are coincident. + * + * @example + * var result = Cesium.Intersections2D.computeLineSegmentLineSegmentIntersection(0.0, 0.0, 0.0, 2.0, -1, 1, 1, 1); + * // result === new Cesium.Cartesian2(0.0, 1.0); + */ + Intersections2D.computeLineSegmentLineSegmentIntersection = function(x00, y00, x01, y01, x10, y10, x11, y11, result) { + //>>includeStart('debug', pragmas.debug); + if (!defined(x00)) { + throw new DeveloperError('x00 is required.'); + } + if (!defined(y00)) { + throw new DeveloperError('y00 is required.'); + } + if (!defined(x01)) { + throw new DeveloperError('x01 is required.'); + } + if (!defined(y01)) { + throw new DeveloperError('y01 is required.'); + } + if (!defined(x10)) { + throw new DeveloperError('x10 is required.'); + } + if (!defined(y10)) { + throw new DeveloperError('y10 is required.'); + } + if (!defined(x11)) { + throw new DeveloperError('x11 is required.'); + } + if (!defined(y11)) { + throw new DeveloperError('y11 is required.'); + } + //>>includeEnd('debug'); + + var numerator1A = (x11 - x10) * (y00 - y10) - (y11 - y10) * (x00 - x10); + var numerator1B = (x01 - x00) * (y00 - y10) - (y01 - y00) * (x00 - x10); + var denominator1 = (y11 - y10) * (x01 - x00) - (x11 - x10) * (y01 - y00); + + // If denominator = 0, then lines are parallel. If denominator = 0 and both numerators are 0, then coincident + if (denominator1 === 0) { + return; + } + + var ua1 = numerator1A / denominator1; + var ub1 = numerator1B / denominator1; + + if (ua1 >= 0 && ua1 <= 1 && ub1 >= 0 && ub1 <= 1) { + if (!defined(result)) { + result = new Cartesian2(); + } + + result.x = x00 + ua1 * (x01 - x00); + result.y = y00 + ua1 * (y01 - y00); + + return result; + } + }; + return Intersections2D; }); diff --git a/Specs/Core/Intersections2DSpec.js b/Specs/Core/Intersections2DSpec.js index 5b4b34dc452c..f1b68d1c9eea 100644 --- a/Specs/Core/Intersections2DSpec.js +++ b/Specs/Core/Intersections2DSpec.js @@ -288,4 +288,58 @@ defineSuite([ expect(result3.z).toBeGreaterThan(0.0); }); }); + + describe('computeLineSegmentLineSegmentIntersection', function() { + it('returns the correct result for intersection point', function() { + var intersection = Intersections2D.computeLineSegmentLineSegmentIntersection(0.0, 0.0, 0.0, 2.0, -1.0, 1.0, 1.0, 1.0); + expect(intersection.x).toEqualEpsilon(0.0, 1e-15); + expect(intersection.y).toEqualEpsilon(1.0, 1e-15); + + var intersection = Intersections2D.computeLineSegmentLineSegmentIntersection(0.0, 0.0, 10.0, 5.0, 0.0, 5.0, 10.0, 0.0); + expect(intersection.x).toEqualEpsilon(5.0, 1e-15); + expect(intersection.y).toEqualEpsilon(2.5, 1e-15); + + var intersection = Intersections2D.computeLineSegmentLineSegmentIntersection(0.0, -5.0, 4.0, 3.0, -2.0, 1.0, 4.0, -2.0); + expect(intersection.x).toEqualEpsilon(2.0, 1e-15); + expect(intersection.y).toEqualEpsilon(-1.0, 1e-15); + }); + + it('returns the correct result for intersection point on a vertex', function() { + var intersection = Intersections2D.computeLineSegmentLineSegmentIntersection(0.0, 0.0, 0.0, 2.0, -1.0, 0.0, 1.0, 0.0); + expect(intersection.x).toEqualEpsilon(0.0, 1e-15); + expect(intersection.y).toEqualEpsilon(0.0, 1e-15); + + intersection = Intersections2D.computeLineSegmentLineSegmentIntersection(0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 2.0, 0.0); + expect(intersection.x).toEqualEpsilon(1.0, 1e-15); + expect(intersection.y).toEqualEpsilon(1.0, 1e-15); + + intersection = Intersections2D.computeLineSegmentLineSegmentIntersection(0.0, 0.0, 4.0, 3.0, 5.0, 0.0, 4.0, 3.0); + expect(intersection.x).toEqualEpsilon(4.0, 1e-15); + expect(intersection.y).toEqualEpsilon(3.0, 1e-15); + }); + + it('returns undefined for non-intersecting lines', function() { + var intersection = Intersections2D.computeLineSegmentLineSegmentIntersection(0.0, 0.0, 0.0, 5.0, 0.1, 4.8, 5.0, 0.0); + expect(intersection).toBeUndefined(); + + var intersection = Intersections2D.computeLineSegmentLineSegmentIntersection(10.0, 0.0, 0.0, -10.0, 0.0, 0.0, -8.0, -8.0); + expect(intersection).toBeUndefined(); + }); + + it('returns undefined for parallel lines', function() { + var intersection = Intersections2D.computeLineSegmentLineSegmentIntersection(0.0, 0.0, 0.0, 2.0, 1.0, 1.0, 1.0, 4.0); + expect(intersection).toBeUndefined(); + + var intersection = Intersections2D.computeLineSegmentLineSegmentIntersection(1.0, 1.0, 4.0, 4.0, 0.0, 0.0, 3.0, 3.0); + expect(intersection).toBeUndefined(); + }); + + it('returns undefined for coincident lines', function() { + var intersection = Intersections2D.computeLineSegmentLineSegmentIntersection(0.0, 0.0, 0.0, 2.0, 0.0, 1.0, 0.0, 4.0); + expect(intersection).toBeUndefined(); + + var intersection = Intersections2D.computeLineSegmentLineSegmentIntersection(0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 2.0); + expect(intersection).toBeUndefined(); + }); + }); });