{"version":3,"file":"Intersection.min.mjs","sources":["../../src/Intersection.ts"],"sourcesContent":["import { Point } from './Point';\nimport { createVector } from './util/misc/vectors';\n\n/* Adaptation of work of Kevin Lindsey (kevin@kevlindev.com) */\n\nexport type IntersectionType = 'Intersection' | 'Coincident' | 'Parallel';\n\nexport class Intersection {\n  declare points: Point[];\n\n  declare status?: IntersectionType;\n\n  constructor(status?: IntersectionType) {\n    this.status = status;\n    this.points = [];\n  }\n\n  /**\n   * Used to verify if a point is alredy in the collection\n   * @param {Point} point\n   * @returns {boolean}\n   */\n  private includes(point: Point): boolean {\n    return this.points.some((p) => p.eq(point));\n  }\n\n  /**\n   * Appends points of intersection\n   * @param {...Point[]} points\n   * @return {Intersection} thisArg\n   * @chainable\n   */\n  private append(...points: Point[]): Intersection {\n    this.points = this.points.concat(\n      points.filter((point) => {\n        return !this.includes(point);\n      })\n    );\n    return this;\n  }\n\n  /**\n   * check if point T is on the segment or line defined between A and B\n   *\n   * @param {Point} T the point we are checking for\n   * @param {Point} A one extremity of the segment\n   * @param {Point} B the other extremity of the segment\n   * @param [infinite] if true checks if `T` is on the line defined by `A` and `B`\n   * @returns true if `T` is contained\n   */\n  static isPointContained(T: Point, A: Point, B: Point, infinite = false) {\n    if (A.eq(B)) {\n      // Edge case: the segment is a point, we check for coincidence,\n      // infinite param has no meaning because there are infinite lines to consider\n      return T.eq(A);\n    } else if (A.x === B.x) {\n      // Edge case: horizontal line.\n      // we first check if T.x has the same value, and then if T.y is contained between A.y and B.y\n      return (\n        T.x === A.x &&\n        (infinite || (T.y >= Math.min(A.y, B.y) && T.y <= Math.max(A.y, B.y)))\n      );\n    } else if (A.y === B.y) {\n      // Edge case: vertical line.\n      // we first check if T.y has the same value, and then if T.x is contained between A.x and B.x\n      return (\n        T.y === A.y &&\n        (infinite || (T.x >= Math.min(A.x, B.x) && T.x <= Math.max(A.x, B.x)))\n      );\n    } else {\n      // Generic case: sloped line.\n      // we check that AT has the same slope as AB\n      // for the segment case we need both the vectors to have the same direction and for AT to be lte AB in size\n      // for the infinite case we check the absolute value of the slope, since direction is meaningless\n      const AB = createVector(A, B);\n      const AT = createVector(A, T);\n      const s = AT.divide(AB);\n      return infinite\n        ? Math.abs(s.x) === Math.abs(s.y)\n        : s.x === s.y && s.x >= 0 && s.x <= 1;\n    }\n  }\n\n  /**\n   * Use the ray casting algorithm to determine if {@link point} is in the polygon defined by {@link points}\n   * @see https://en.wikipedia.org/wiki/Point_in_polygon\n   * @param point\n   * @param points polygon points\n   * @returns\n   */\n  static isPointInPolygon(point: Point, points: Point[]) {\n    const other = new Point(point).setX(\n      Math.min(point.x - 1, ...points.map((p) => p.x))\n    );\n    let hits = 0;\n    for (let index = 0; index < points.length; index++) {\n      const inter = this.intersectSegmentSegment(\n        // polygon side\n        points[index],\n        points[(index + 1) % points.length],\n        // ray\n        point,\n        other\n      );\n      if (inter.includes(point)) {\n        // point is on the polygon side\n        return true;\n      }\n      hits += Number(inter.status === 'Intersection');\n    }\n    return hits % 2 === 1;\n  }\n\n  /**\n   * Checks if a line intersects another\n   * @see {@link https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection line intersection}\n   * @see {@link https://en.wikipedia.org/wiki/Cramer%27s_rule Cramer's rule}\n   * @static\n   * @param {Point} a1\n   * @param {Point} a2\n   * @param {Point} b1\n   * @param {Point} b2\n   * @param {boolean} [aInfinite=true] check segment intersection by passing `false`\n   * @param {boolean} [bInfinite=true] check segment intersection by passing `false`\n   * @return {Intersection}\n   */\n  static intersectLineLine(\n    a1: Point,\n    a2: Point,\n    b1: Point,\n    b2: Point,\n    aInfinite = true,\n    bInfinite = true\n  ): Intersection {\n    const a2xa1x = a2.x - a1.x,\n      a2ya1y = a2.y - a1.y,\n      b2xb1x = b2.x - b1.x,\n      b2yb1y = b2.y - b1.y,\n      a1xb1x = a1.x - b1.x,\n      a1yb1y = a1.y - b1.y,\n      uaT = b2xb1x * a1yb1y - b2yb1y * a1xb1x,\n      ubT = a2xa1x * a1yb1y - a2ya1y * a1xb1x,\n      uB = b2yb1y * a2xa1x - b2xb1x * a2ya1y;\n    if (uB !== 0) {\n      const ua = uaT / uB,\n        ub = ubT / uB;\n      if (\n        (aInfinite || (0 <= ua && ua <= 1)) &&\n        (bInfinite || (0 <= ub && ub <= 1))\n      ) {\n        return new Intersection('Intersection').append(\n          new Point(a1.x + ua * a2xa1x, a1.y + ua * a2ya1y)\n        );\n      } else {\n        return new Intersection();\n      }\n    } else {\n      if (uaT === 0 || ubT === 0) {\n        const segmentsCoincide =\n          aInfinite ||\n          bInfinite ||\n          Intersection.isPointContained(a1, b1, b2) ||\n          Intersection.isPointContained(a2, b1, b2) ||\n          Intersection.isPointContained(b1, a1, a2) ||\n          Intersection.isPointContained(b2, a1, a2);\n        return new Intersection(segmentsCoincide ? 'Coincident' : undefined);\n      } else {\n        return new Intersection('Parallel');\n      }\n    }\n  }\n\n  /**\n   * Checks if a segment intersects a line\n   * @see {@link intersectLineLine} for line intersection\n   * @static\n   * @param {Point} s1 boundary point of segment\n   * @param {Point} s2 other boundary point of segment\n   * @param {Point} l1 point on line\n   * @param {Point} l2 other point on line\n   * @return {Intersection}\n   */\n  static intersectSegmentLine(\n    s1: Point,\n    s2: Point,\n    l1: Point,\n    l2: Point\n  ): Intersection {\n    return Intersection.intersectLineLine(s1, s2, l1, l2, false, true);\n  }\n\n  /**\n   * Checks if a segment intersects another\n   * @see {@link intersectLineLine} for line intersection\n   * @static\n   * @param {Point} a1 boundary point of segment\n   * @param {Point} a2 other boundary point of segment\n   * @param {Point} b1 boundary point of segment\n   * @param {Point} b2 other boundary point of segment\n   * @return {Intersection}\n   */\n  static intersectSegmentSegment(\n    a1: Point,\n    a2: Point,\n    b1: Point,\n    b2: Point\n  ): Intersection {\n    return Intersection.intersectLineLine(a1, a2, b1, b2, false, false);\n  }\n\n  /**\n   * Checks if line intersects polygon\n   *\n   * @todo account for stroke\n   *\n   * @static\n   * @see {@link intersectSegmentPolygon} for segment intersection\n   * @param {Point} a1 point on line\n   * @param {Point} a2 other point on line\n   * @param {Point[]} points polygon points\n   * @param {boolean} [infinite=true] check segment intersection by passing `false`\n   * @return {Intersection}\n   */\n  static intersectLinePolygon(\n    a1: Point,\n    a2: Point,\n    points: Point[],\n    infinite = true\n  ): Intersection {\n    const result = new Intersection();\n    const length = points.length;\n\n    for (let i = 0, b1, b2, inter; i < length; i++) {\n      b1 = points[i];\n      b2 = points[(i + 1) % length];\n      inter = Intersection.intersectLineLine(a1, a2, b1, b2, infinite, false);\n      if (inter.status === 'Coincident') {\n        return inter;\n      }\n      result.append(...inter.points);\n    }\n\n    if (result.points.length > 0) {\n      result.status = 'Intersection';\n    }\n\n    return result;\n  }\n\n  /**\n   * Checks if segment intersects polygon\n   * @static\n   * @see {@link intersectLinePolygon} for line intersection\n   * @param {Point} a1 boundary point of segment\n   * @param {Point} a2 other boundary point of segment\n   * @param {Point[]} points polygon points\n   * @return {Intersection}\n   */\n  static intersectSegmentPolygon(\n    a1: Point,\n    a2: Point,\n    points: Point[]\n  ): Intersection {\n    return Intersection.intersectLinePolygon(a1, a2, points, false);\n  }\n\n  /**\n   * Checks if polygon intersects another polygon\n   *\n   * @todo account for stroke\n   *\n   * @static\n   * @param {Point[]} points1\n   * @param {Point[]} points2\n   * @return {Intersection}\n   */\n  static intersectPolygonPolygon(\n    points1: Point[],\n    points2: Point[]\n  ): Intersection {\n    const result = new Intersection(),\n      length = points1.length;\n    const coincidences: Intersection[] = [];\n\n    for (let i = 0; i < length; i++) {\n      const a1 = points1[i],\n        a2 = points1[(i + 1) % length],\n        inter = Intersection.intersectSegmentPolygon(a1, a2, points2);\n      if (inter.status === 'Coincident') {\n        coincidences.push(inter);\n        result.append(a1, a2);\n      } else {\n        result.append(...inter.points);\n      }\n    }\n\n    if (coincidences.length > 0 && coincidences.length === points1.length) {\n      return new Intersection('Coincident');\n    } else if (result.points.length > 0) {\n      result.status = 'Intersection';\n    }\n\n    return result;\n  }\n\n  /**\n   * Checks if polygon intersects rectangle\n   * @static\n   * @see {@link intersectPolygonPolygon} for polygon intersection\n   * @param {Point[]} points polygon points\n   * @param {Point} r1 top left point of rect\n   * @param {Point} r2 bottom right point of rect\n   * @return {Intersection}\n   */\n  static intersectPolygonRectangle(\n    points: Point[],\n    r1: Point,\n    r2: Point\n  ): Intersection {\n    const min = r1.min(r2),\n      max = r1.max(r2),\n      topRight = new Point(max.x, min.y),\n      bottomLeft = new Point(min.x, max.y);\n\n    return Intersection.intersectPolygonPolygon(points, [\n      min,\n      topRight,\n      max,\n      bottomLeft,\n    ]);\n  }\n}\n"],"names":["Intersection","constructor","status","this","points","includes","point","some","p","eq","append","_len","arguments","length","Array","_key","concat","filter","isPointContained","T","A","B","infinite","undefined","x","y","Math","min","max","AB","createVector","s","divide","abs","isPointInPolygon","other","Point","setX","map","hits","index","inter","intersectSegmentSegment","Number","intersectLineLine","a1","a2","b1","b2","aInfinite","bInfinite","a2xa1x","a2ya1y","b2xb1x","b2yb1y","a1xb1x","a1yb1y","uaT","ubT","uB","ua","ub","segmentsCoincide","intersectSegmentLine","s1","s2","l1","l2","intersectLinePolygon","result","i","intersectSegmentPolygon","intersectPolygonPolygon","points1","points2","coincidences","push","intersectPolygonRectangle","r1","r2","topRight","bottomLeft"],"mappings":"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"}