123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- import Cartesian2 from "./Cartesian2.js";
- import Cartesian3 from "./Cartesian3.js";
- import Check from "./Check.js";
- import defined from "./defined.js";
- import DeveloperError from "./DeveloperError.js";
- /**
- * Contains functions for operating on 2D triangles.
- *
- * @namespace Intersections2D
- */
- const Intersections2D = {};
- /**
- * Splits a 2D triangle at given axis-aligned threshold value and returns the resulting
- * polygon on a given side of the threshold. The resulting polygon may have 0, 1, 2,
- * 3, or 4 vertices.
- *
- * @param {number} threshold The threshold coordinate value at which to clip the triangle.
- * @param {boolean} keepAbove true to keep the portion of the triangle above the threshold, or false
- * to keep the portion below.
- * @param {number} u0 The coordinate of the first vertex in the triangle, in counter-clockwise order.
- * @param {number} u1 The coordinate of the second vertex in the triangle, in counter-clockwise order.
- * @param {number} u2 The coordinate of the third vertex in the triangle, in counter-clockwise order.
- * @param {number[]} [result] The array into which to copy the result. If this parameter is not supplied,
- * a new array is constructed and returned.
- * @returns {number[]} The polygon that results after the clip, specified as a list of
- * vertices. The vertices are specified in counter-clockwise order.
- * Each vertex is either an index from the existing list (identified as
- * a 0, 1, or 2) or -1 indicating a new vertex not in the original triangle.
- * For new vertices, the -1 is followed by three additional numbers: the
- * index of each of the two original vertices forming the line segment that
- * the new vertex lies on, and the fraction of the distance from the first
- * vertex to the second one.
- *
- * @example
- * const result = Cesium.Intersections2D.clipTriangleAtAxisAlignedThreshold(0.5, false, 0.2, 0.6, 0.4);
- * // result === [2, 0, -1, 1, 0, 0.25, -1, 1, 2, 0.5]
- */
- Intersections2D.clipTriangleAtAxisAlignedThreshold = function (
- threshold,
- keepAbove,
- u0,
- u1,
- u2,
- result
- ) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(threshold)) {
- throw new DeveloperError("threshold is required.");
- }
- if (!defined(keepAbove)) {
- throw new DeveloperError("keepAbove is required.");
- }
- if (!defined(u0)) {
- throw new DeveloperError("u0 is required.");
- }
- if (!defined(u1)) {
- throw new DeveloperError("u1 is required.");
- }
- if (!defined(u2)) {
- throw new DeveloperError("u2 is required.");
- }
- //>>includeEnd('debug');
- if (!defined(result)) {
- result = [];
- } else {
- result.length = 0;
- }
- let u0Behind;
- let u1Behind;
- let u2Behind;
- if (keepAbove) {
- u0Behind = u0 < threshold;
- u1Behind = u1 < threshold;
- u2Behind = u2 < threshold;
- } else {
- u0Behind = u0 > threshold;
- u1Behind = u1 > threshold;
- u2Behind = u2 > threshold;
- }
- const numBehind = u0Behind + u1Behind + u2Behind;
- let u01Ratio;
- let u02Ratio;
- let u12Ratio;
- let u10Ratio;
- let u20Ratio;
- let u21Ratio;
- if (numBehind === 1) {
- if (u0Behind) {
- u01Ratio = (threshold - u0) / (u1 - u0);
- u02Ratio = (threshold - u0) / (u2 - u0);
- result.push(1);
- result.push(2);
- if (u02Ratio !== 1.0) {
- result.push(-1);
- result.push(0);
- result.push(2);
- result.push(u02Ratio);
- }
- if (u01Ratio !== 1.0) {
- result.push(-1);
- result.push(0);
- result.push(1);
- result.push(u01Ratio);
- }
- } else if (u1Behind) {
- u12Ratio = (threshold - u1) / (u2 - u1);
- u10Ratio = (threshold - u1) / (u0 - u1);
- result.push(2);
- result.push(0);
- if (u10Ratio !== 1.0) {
- result.push(-1);
- result.push(1);
- result.push(0);
- result.push(u10Ratio);
- }
- if (u12Ratio !== 1.0) {
- result.push(-1);
- result.push(1);
- result.push(2);
- result.push(u12Ratio);
- }
- } else if (u2Behind) {
- u20Ratio = (threshold - u2) / (u0 - u2);
- u21Ratio = (threshold - u2) / (u1 - u2);
- result.push(0);
- result.push(1);
- if (u21Ratio !== 1.0) {
- result.push(-1);
- result.push(2);
- result.push(1);
- result.push(u21Ratio);
- }
- if (u20Ratio !== 1.0) {
- result.push(-1);
- result.push(2);
- result.push(0);
- result.push(u20Ratio);
- }
- }
- } else if (numBehind === 2) {
- if (!u0Behind && u0 !== threshold) {
- u10Ratio = (threshold - u1) / (u0 - u1);
- u20Ratio = (threshold - u2) / (u0 - u2);
- result.push(0);
- result.push(-1);
- result.push(1);
- result.push(0);
- result.push(u10Ratio);
- result.push(-1);
- result.push(2);
- result.push(0);
- result.push(u20Ratio);
- } else if (!u1Behind && u1 !== threshold) {
- u21Ratio = (threshold - u2) / (u1 - u2);
- u01Ratio = (threshold - u0) / (u1 - u0);
- result.push(1);
- result.push(-1);
- result.push(2);
- result.push(1);
- result.push(u21Ratio);
- result.push(-1);
- result.push(0);
- result.push(1);
- result.push(u01Ratio);
- } else if (!u2Behind && u2 !== threshold) {
- u02Ratio = (threshold - u0) / (u2 - u0);
- u12Ratio = (threshold - u1) / (u2 - u1);
- result.push(2);
- result.push(-1);
- result.push(0);
- result.push(2);
- result.push(u02Ratio);
- result.push(-1);
- result.push(1);
- result.push(2);
- result.push(u12Ratio);
- }
- } else if (numBehind !== 3) {
- // Completely in front of threshold
- result.push(0);
- result.push(1);
- result.push(2);
- }
- // else Completely behind threshold
- return result;
- };
- /**
- * Compute the barycentric coordinates of a 2D position within a 2D triangle.
- *
- * @param {number} x The x coordinate of the position for which to find the barycentric coordinates.
- * @param {number} y The y coordinate of the position for which to find the barycentric coordinates.
- * @param {number} x1 The x coordinate of the triangle's first vertex.
- * @param {number} y1 The y coordinate of the triangle's first vertex.
- * @param {number} x2 The x coordinate of the triangle's second vertex.
- * @param {number} y2 The y coordinate of the triangle's second vertex.
- * @param {number} x3 The x coordinate of the triangle's third vertex.
- * @param {number} y3 The y coordinate of the triangle's third vertex.
- * @param {Cartesian3} [result] The instance into to which to copy the result. If this parameter
- * is undefined, a new instance is created and returned.
- * @returns {Cartesian3} The barycentric coordinates of the position within the triangle.
- *
- * @example
- * const result = Cesium.Intersections2D.computeBarycentricCoordinates(0.0, 0.0, 0.0, 1.0, -1, -0.5, 1, -0.5);
- * // result === new Cesium.Cartesian3(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0);
- */
- Intersections2D.computeBarycentricCoordinates = function (
- x,
- y,
- x1,
- y1,
- x2,
- y2,
- x3,
- y3,
- result
- ) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(x)) {
- throw new DeveloperError("x is required.");
- }
- if (!defined(y)) {
- throw new DeveloperError("y is required.");
- }
- if (!defined(x1)) {
- throw new DeveloperError("x1 is required.");
- }
- if (!defined(y1)) {
- throw new DeveloperError("y1 is required.");
- }
- if (!defined(x2)) {
- throw new DeveloperError("x2 is required.");
- }
- if (!defined(y2)) {
- throw new DeveloperError("y2 is required.");
- }
- if (!defined(x3)) {
- throw new DeveloperError("x3 is required.");
- }
- if (!defined(y3)) {
- throw new DeveloperError("y3 is required.");
- }
- //>>includeEnd('debug');
- const x1mx3 = x1 - x3;
- const x3mx2 = x3 - x2;
- const y2my3 = y2 - y3;
- const y1my3 = y1 - y3;
- const inverseDeterminant = 1.0 / (y2my3 * x1mx3 + x3mx2 * y1my3);
- const ymy3 = y - y3;
- const xmx3 = x - x3;
- const l1 = (y2my3 * xmx3 + x3mx2 * ymy3) * inverseDeterminant;
- const l2 = (-y1my3 * xmx3 + x1mx3 * ymy3) * inverseDeterminant;
- const l3 = 1.0 - l1 - l2;
- if (defined(result)) {
- result.x = l1;
- result.y = l2;
- result.z = l3;
- return result;
- }
- 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
- * const 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);
- Check.typeOf.number("x00", x00);
- Check.typeOf.number("y00", y00);
- Check.typeOf.number("x01", x01);
- Check.typeOf.number("y01", y01);
- Check.typeOf.number("x10", x10);
- Check.typeOf.number("y10", y10);
- Check.typeOf.number("x11", x11);
- Check.typeOf.number("y11", y11);
- //>>includeEnd('debug');
- const numerator1A = (x11 - x10) * (y00 - y10) - (y11 - y10) * (x00 - x10);
- const numerator1B = (x01 - x00) * (y00 - y10) - (y01 - y00) * (x00 - x10);
- const 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;
- }
- const ua1 = numerator1A / denominator1;
- const 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;
- }
- };
- export default Intersections2D;
|