{"version":3,"file":"three-pathfinding.modern.mjs","sources":["../src/Utils.js","../src/BinaryHeap.js","../src/Channel.js","../src/Pathfinding.js","../src/Builder.js","../src/AStar.js","../src/PathfindingHelper.js"],"sourcesContent":["import { BufferAttribute, BufferGeometry } from 'three';\n\nclass Utils {\n\n  static roundNumber (value, decimals) {\n    const factor = Math.pow(10, decimals);\n    return Math.round(value * factor) / factor;\n  }\n\n  static sample (list) {\n    return list[Math.floor(Math.random() * list.length)];\n  }\n\n  static distanceToSquared (a, b) {\n\n    var dx = a.x - b.x;\n    var dy = a.y - b.y;\n    var dz = a.z - b.z;\n\n    return dx * dx + dy * dy + dz * dz;\n\n  }\n\n  //+ Jonas Raoni Soares Silva\n  //@ http://jsfromhell.com/math/is-point-in-poly [rev. #0]\n  static isPointInPoly (poly, pt) {\n    for (var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)\n      ((poly[i].z <= pt.z && pt.z < poly[j].z) || (poly[j].z <= pt.z && pt.z < poly[i].z)) && (pt.x < (poly[j].x - poly[i].x) * (pt.z - poly[i].z) / (poly[j].z - poly[i].z) + poly[i].x) && (c = !c);\n    return c;\n  }\n\n  static isVectorInPolygon (vector, polygon, vertices) {\n\n    // reference point will be the centroid of the polygon\n    // We need to rotate the vector as well as all the points which the polygon uses\n\n    var lowestPoint = 100000;\n    var highestPoint = -100000;\n\n    var polygonVertices = [];\n\n    polygon.vertexIds.forEach((vId) => {\n      lowestPoint = Math.min(vertices[vId].y, lowestPoint);\n      highestPoint = Math.max(vertices[vId].y, highestPoint);\n      polygonVertices.push(vertices[vId]);\n    });\n\n    if (vector.y < highestPoint + 0.5 && vector.y > lowestPoint - 0.5 &&\n      this.isPointInPoly(polygonVertices, vector)) {\n      return true;\n    }\n    return false;\n  }\n\n  static triarea2 (a, b, c) {\n    var ax = b.x - a.x;\n    var az = b.z - a.z;\n    var bx = c.x - a.x;\n    var bz = c.z - a.z;\n    return bx * az - ax * bz;\n  }\n\n  static vequal (a, b) {\n    return this.distanceToSquared(a, b) < 0.00001;\n  }\n\n  /**\n   * Modified version of BufferGeometryUtils.mergeVertices, ignoring vertex\n   * attributes other than position.\n   *\n   * @param {THREE.BufferGeometry} geometry\n   * @param {number} tolerance\n   * @return {THREE.BufferGeometry>}\n   */\n  static mergeVertices (geometry, tolerance = 1e-4) {\n\n    tolerance = Math.max( tolerance, Number.EPSILON );\n\n    // Generate an index buffer if the geometry doesn't have one, or optimize it\n    // if it's already available.\n    var hashToIndex = {};\n    var indices = geometry.getIndex();\n    var positions = geometry.getAttribute( 'position' );\n    var vertexCount = indices ? indices.count : positions.count;\n\n    // Next value for triangle indices.\n    var nextIndex = 0;\n\n    var newIndices = [];\n    var newPositions = [];\n\n    // Convert the error tolerance to an amount of decimal places to truncate to.\n    var decimalShift = Math.log10( 1 / tolerance );\n    var shiftMultiplier = Math.pow( 10, decimalShift );\n\n    for ( var i = 0; i < vertexCount; i ++ ) {\n\n      var index = indices ? indices.getX( i ) : i;\n\n      // Generate a hash for the vertex attributes at the current index 'i'.\n      var hash = '';\n\n      // Double tilde truncates the decimal value.\n      hash += `${ ~ ~ ( positions.getX( index ) * shiftMultiplier ) },`;\n      hash += `${ ~ ~ ( positions.getY( index ) * shiftMultiplier ) },`;\n      hash += `${ ~ ~ ( positions.getZ( index ) * shiftMultiplier ) },`;\n\n      // Add another reference to the vertex if it's already\n      // used by another index.\n      if ( hash in hashToIndex ) {\n\n        newIndices.push( hashToIndex[ hash ] );\n\n      } else {\n\n        newPositions.push( positions.getX( index ) );\n        newPositions.push( positions.getY( index ) );\n        newPositions.push( positions.getZ( index ) );\n\n        hashToIndex[ hash ] = nextIndex;\n        newIndices.push( nextIndex );\n        nextIndex ++;\n\n      }\n\n    }\n\n    // Construct merged BufferGeometry.\n\n    const positionAttribute = new BufferAttribute(\n      new Float32Array( newPositions ),\n      positions.itemSize,\n      positions.normalized\n    );\n\n    const result = new BufferGeometry();\n    result.setAttribute( 'position', positionAttribute );\n    result.setIndex( newIndices );\n\n    return result;\n\n  }\n}\n\nexport { Utils };\n","// javascript-astar\n// http://github.com/bgrins/javascript-astar\n// Freely distributable under the MIT License.\n// Implements the astar search algorithm in javascript using a binary heap.\n\nclass BinaryHeap {\n  constructor (scoreFunction) {\n    this.content = [];\n    this.scoreFunction = scoreFunction;\n  }\n\n  push (element) {\n    // Add the new element to the end of the array.\n    this.content.push(element);\n\n    // Allow it to sink down.\n    this.sinkDown(this.content.length - 1);\n  }\n\n  pop () {\n    // Store the first element so we can return it later.\n    const result = this.content[0];\n    // Get the element at the end of the array.\n    const end = this.content.pop();\n    // If there are any elements left, put the end element at the\n    // start, and let it bubble up.\n    if (this.content.length > 0) {\n      this.content[0] = end;\n      this.bubbleUp(0);\n    }\n    return result;\n  }\n\n  remove (node) {\n    const i = this.content.indexOf(node);\n\n    // When it is found, the process seen in 'pop' is repeated\n    // to fill up the hole.\n    const end = this.content.pop();\n\n    if (i !== this.content.length - 1) {\n      this.content[i] = end;\n\n      if (this.scoreFunction(end) < this.scoreFunction(node)) {\n        this.sinkDown(i);\n      } else {\n        this.bubbleUp(i);\n      }\n    }\n  }\n\n  size () {\n    return this.content.length;\n  }\n\n  rescoreElement (node) {\n    this.sinkDown(this.content.indexOf(node));\n  }\n\n  sinkDown (n) {\n    // Fetch the element that has to be sunk.\n    const element = this.content[n];\n\n    // When at 0, an element can not sink any further.\n    while (n > 0) {\n      // Compute the parent element's index, and fetch it.\n      const parentN = ((n + 1) >> 1) - 1;\n      const parent = this.content[parentN];\n\n      if (this.scoreFunction(element) < this.scoreFunction(parent)) {\n        // Swap the elements if the parent is greater.\n        this.content[parentN] = element;\n        this.content[n] = parent;\n        // Update 'n' to continue at the new position.\n        n = parentN;\n      } else {\n        // Found a parent that is less, no need to sink any further.\n        break;\n      }\n    }\n  }\n\n  bubbleUp (n) {\n    // Look up the target element and its score.\n    const length = this.content.length,\n      element = this.content[n],\n      elemScore = this.scoreFunction(element);\n\n    while (true) {\n      // Compute the indices of the child elements.\n      const child2N = (n + 1) << 1,\n        child1N = child2N - 1;\n      // This is used to store the new position of the element,\n      // if any.\n      let swap = null;\n      let child1Score;\n      // If the first child exists (is inside the array)...\n      if (child1N < length) {\n        // Look it up and compute its score.\n        const child1 = this.content[child1N];\n        child1Score = this.scoreFunction(child1);\n\n        // If the score is less than our element's, we need to swap.\n        if (child1Score < elemScore) {\n          swap = child1N;\n        }\n      }\n\n      // Do the same checks for the other child.\n      if (child2N < length) {\n        const child2 = this.content[child2N],\n          child2Score = this.scoreFunction(child2);\n        if (child2Score < (swap === null ? elemScore : child1Score)) {\n          swap = child2N;\n        }\n      }\n\n      // If the element needs to be moved, swap it, and continue.\n      if (swap !== null) {\n        this.content[n] = this.content[swap];\n        this.content[swap] = element;\n        n = swap;\n      }\n\n      // Otherwise, we are done.\n      else {\n        break;\n      }\n    }\n  }\n\n}\n\nexport { BinaryHeap };\n","import { Utils } from './Utils';\n\nclass Channel {\n  constructor () {\n    this.portals = [];\n  }\n\n  push (p1, p2) {\n    if (p2 === undefined) p2 = p1;\n    this.portals.push({\n      left: p1,\n      right: p2\n    });\n  }\n\n  stringPull () {\n    const portals = this.portals;\n    const pts = [];\n    // Init scan state\n    let portalApex, portalLeft, portalRight;\n    let apexIndex = 0,\n      leftIndex = 0,\n      rightIndex = 0;\n\n    portalApex = portals[0].left;\n    portalLeft = portals[0].left;\n    portalRight = portals[0].right;\n\n    // Add start point.\n    pts.push(portalApex);\n\n    for (let i = 1; i < portals.length; i++) {\n      const left = portals[i].left;\n      const right = portals[i].right;\n\n      // Update right vertex.\n      if (Utils.triarea2(portalApex, portalRight, right) <= 0.0) {\n        if (Utils.vequal(portalApex, portalRight) || Utils.triarea2(portalApex, portalLeft, right) > 0.0) {\n          // Tighten the funnel.\n          portalRight = right;\n          rightIndex = i;\n        } else {\n          // Right over left, insert left to path and restart scan from portal left point.\n          pts.push(portalLeft);\n          // Make current left the new apex.\n          portalApex = portalLeft;\n          apexIndex = leftIndex;\n          // Reset portal\n          portalLeft = portalApex;\n          portalRight = portalApex;\n          leftIndex = apexIndex;\n          rightIndex = apexIndex;\n          // Restart scan\n          i = apexIndex;\n          continue;\n        }\n      }\n\n      // Update left vertex.\n      if (Utils.triarea2(portalApex, portalLeft, left) >= 0.0) {\n        if (Utils.vequal(portalApex, portalLeft) || Utils.triarea2(portalApex, portalRight, left) < 0.0) {\n          // Tighten the funnel.\n          portalLeft = left;\n          leftIndex = i;\n        } else {\n          // Left over right, insert right to path and restart scan from portal right point.\n          pts.push(portalRight);\n          // Make current right the new apex.\n          portalApex = portalRight;\n          apexIndex = rightIndex;\n          // Reset portal\n          portalLeft = portalApex;\n          portalRight = portalApex;\n          leftIndex = apexIndex;\n          rightIndex = apexIndex;\n          // Restart scan\n          i = apexIndex;\n          continue;\n        }\n      }\n    }\n\n    if ((pts.length === 0) || (!Utils.vequal(pts[pts.length - 1], portals[portals.length - 1].left))) {\n      // Append last point to path.\n      pts.push(portals[portals.length - 1].left);\n    }\n\n    this.path = pts;\n    return pts;\n  }\n}\n\nexport { Channel };\n","import {\n\tVector3,\n\tPlane,\n\tTriangle,\n} from 'three';\n\nimport { Utils } from './Utils';\nimport { AStar } from './AStar';\nimport { Builder } from './Builder';\nimport { Channel } from './Channel';\n\n/**\n * Defines an instance of the pathfinding module, with one or more zones.\n */\nclass Pathfinding {\n\tconstructor () {\n\t\tthis.zones = {};\n\t}\n\n\t/**\n\t * (Static) Builds a zone/node set from navigation mesh geometry.\n\t * @param  {BufferGeometry} geometry\n\t * @param  {number} tolerance Vertex welding tolerance.\n\t * @return {Zone}\n\t */\n\tstatic createZone (geometry, tolerance = 1e-4) {\n\t\treturn Builder.buildZone(geometry, tolerance);\n\t}\n\n\t/**\n\t * Sets data for the given zone.\n\t * @param {string} zoneID\n\t * @param {Zone} zone\n\t */\n\tsetZoneData (zoneID, zone) {\n\t\tthis.zones[zoneID] = zone;\n\t}\n\n\t/**\n\t * Returns a random node within a given range of a given position.\n\t * @param  {string} zoneID\n\t * @param  {number} groupID\n\t * @param  {Vector3} nearPosition\n\t * @param  {number} nearRange\n\t * @return {Node}\n\t */\n\tgetRandomNode (zoneID, groupID, nearPosition, nearRange) {\n\n\t\tif (!this.zones[zoneID]) return new Vector3();\n\n\t\tnearPosition = nearPosition || null;\n\t\tnearRange = nearRange || 0;\n\n\t\tconst candidates = [];\n\t\tconst polygons = this.zones[zoneID].groups[groupID];\n\n\t\tpolygons.forEach((p) => {\n\t\t\tif (nearPosition && nearRange) {\n\t\t\t\tif (Utils.distanceToSquared(nearPosition, p.centroid) < nearRange * nearRange) {\n\t\t\t\t\tcandidates.push(p.centroid);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcandidates.push(p.centroid);\n\t\t\t}\n\t\t});\n\n\t\treturn Utils.sample(candidates) || new Vector3();\n\t}\n\n\t/**\n\t * Returns the closest node to the target position.\n\t * @param  {Vector3} position\n\t * @param  {string}  zoneID\n\t * @param  {number}  groupID\n\t * @param  {boolean} checkPolygon\n\t * @return {Node}\n\t */\n\tgetClosestNode (position, zoneID, groupID, checkPolygon = false) {\n\t\tconst nodes = this.zones[zoneID].groups[groupID];\n\t\tconst vertices = this.zones[zoneID].vertices;\n\t\tlet closestNode = null;\n\t\tlet closestDistance = Infinity;\n\n\t\tnodes.forEach((node) => {\n\t\t\tconst distance = Utils.distanceToSquared(node.centroid, position);\n\t\t\tif (distance < closestDistance\n\t\t\t\t\t&& (!checkPolygon || Utils.isVectorInPolygon(position, node, vertices))) {\n\t\t\t\tclosestNode = node;\n\t\t\t\tclosestDistance = distance;\n\t\t\t}\n\t\t});\n\n\t\treturn closestNode;\n\t}\n\n\t/**\n\t * Returns a path between given start and end points. If a complete path\n\t * cannot be found, will return the nearest endpoint available.\n\t *\n\t * @param  {Vector3} startPosition Start position.\n\t * @param  {Vector3} targetPosition Destination.\n\t * @param  {string} zoneID ID of current zone.\n\t * @param  {number} groupID Current group ID.\n\t * @return {Array<Vector3>} Array of points defining the path.\n\t */\n\tfindPath (startPosition, targetPosition, zoneID, groupID) {\n\t\tconst nodes = this.zones[zoneID].groups[groupID];\n\t\tconst vertices = this.zones[zoneID].vertices;\n\n\t\tconst closestNode = this.getClosestNode(startPosition, zoneID, groupID, true);\n\t\tconst farthestNode = this.getClosestNode(targetPosition, zoneID, groupID, true);\n\n\t\t// If we can't find any node, just go straight to the target\n\t\tif (!closestNode || !farthestNode) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst paths = AStar.search(nodes, closestNode, farthestNode);\n\n\t\tconst getPortalFromTo = function (a, b) {\n\t\t\tfor (var i = 0; i < a.neighbours.length; i++) {\n\t\t\t\tif (a.neighbours[i] === b.id) {\n\t\t\t\t\treturn a.portals[i];\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t// We have the corridor, now pull the rope.\n\t\tconst channel = new Channel();\n\t\tchannel.push(startPosition);\n\t\tfor (let i = 0; i < paths.length; i++) {\n\t\t\tconst polygon = paths[i];\n\t\t\tconst nextPolygon = paths[i + 1];\n\n\t\t\tif (nextPolygon) {\n\t\t\t\tconst portals = getPortalFromTo(polygon, nextPolygon);\n\t\t\t\tchannel.push(\n\t\t\t\t\tvertices[portals[0]],\n\t\t\t\t\tvertices[portals[1]]\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tchannel.push(targetPosition);\n\t\tchannel.stringPull();\n\n\t\t// Return the path, omitting first position (which is already known).\n\t\tconst path = channel.path.map((c) => new Vector3(c.x, c.y, c.z));\n\t\tpath.shift();\n\t\treturn path;\n\t}\n}\n\n/**\n * Returns closest node group ID for given position.\n * @param  {string} zoneID\n * @param  {Vector3} position\n * @return {number}\n */\nPathfinding.prototype.getGroup = (function() {\n\tconst plane = new Plane();\n\treturn function (zoneID, position, checkPolygon = false) {\n\t\tif (!this.zones[zoneID]) return null;\n\n\t\tlet closestNodeGroup = null;\n\t\tlet distance = Math.pow(50, 2);\n\t\tconst zone = this.zones[zoneID];\n\n\t\tfor (let i = 0; i < zone.groups.length; i++) {\n\t\t\tconst group = zone.groups[i];\n\t\t\tfor (const node of group) {\n\t\t\t\tif (checkPolygon) {\n\t\t\t\t\tplane.setFromCoplanarPoints(\n\t\t\t\t\t\tzone.vertices[node.vertexIds[0]],\n\t\t\t\t\t\tzone.vertices[node.vertexIds[1]],\n\t\t\t\t\t\tzone.vertices[node.vertexIds[2]]\n\t\t\t\t\t);\n\t\t\t\t\tif (Math.abs(plane.distanceToPoint(position)) < 0.01) {\n\t\t\t\t\t\tconst poly = [\n\t\t\t\t\t\t\tzone.vertices[node.vertexIds[0]],\n\t\t\t\t\t\t\tzone.vertices[node.vertexIds[1]],\n\t\t\t\t\t\t\tzone.vertices[node.vertexIds[2]]\n\t\t\t\t\t\t];\n\t\t\t\t\t\tif(Utils.isPointInPoly(poly, position)) {\n\t\t\t\t\t\t\treturn i;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst measuredDistance = Utils.distanceToSquared(node.centroid, position);\n\t\t\t\tif (measuredDistance < distance) {\n\t\t\t\t\tclosestNodeGroup = i;\n\t\t\t\t\tdistance = measuredDistance;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn closestNodeGroup;\n\t};\n}());\n\n/**\n * Clamps a step along the navmesh, given start and desired endpoint. May be\n * used to constrain first-person / WASD controls.\n *\n * @param  {Vector3} start\n * @param  {Vector3} end Desired endpoint.\n * @param  {Node} node\n * @param  {string} zoneID\n * @param  {number} groupID\n * @param  {Vector3} endTarget Updated endpoint.\n * @return {Node} Updated node.\n */\nPathfinding.prototype.clampStep = (function () {\n\tconst point = new Vector3();\n\tconst plane = new Plane();\n\tconst triangle = new Triangle();\n\n\tconst endPoint = new Vector3();\n\n\tlet closestNode;\n\tlet closestPoint = new Vector3();\n\tlet closestDistance;\n\n\treturn function (startRef, endRef, node, zoneID, groupID, endTarget) {\n\t\tconst vertices = this.zones[zoneID].vertices;\n\t\tconst nodes = this.zones[zoneID].groups[groupID];\n\n\t\tconst nodeQueue = [node];\n\t\tconst nodeDepth = {};\n\t\tnodeDepth[node.id] = 0;\n\n\t\tclosestNode = undefined;\n\t\tclosestPoint.set(0, 0, 0);\n\t\tclosestDistance = Infinity;\n\n\t\t// Project the step along the current node.\n\t\tplane.setFromCoplanarPoints(\n\t\t\tvertices[node.vertexIds[0]],\n\t\t\tvertices[node.vertexIds[1]],\n\t\t\tvertices[node.vertexIds[2]]\n\t\t);\n\t\tplane.projectPoint(endRef, point);\n\t\tendPoint.copy(point);\n\n\t\tfor (let currentNode = nodeQueue.pop(); currentNode; currentNode = nodeQueue.pop()) {\n\n\t\t\ttriangle.set(\n\t\t\t\tvertices[currentNode.vertexIds[0]],\n\t\t\t\tvertices[currentNode.vertexIds[1]],\n\t\t\t\tvertices[currentNode.vertexIds[2]]\n\t\t\t);\n\n\t\t\ttriangle.closestPointToPoint(endPoint, point);\n\n\t\t\tif (point.distanceToSquared(endPoint) < closestDistance) {\n\t\t\t\tclosestNode = currentNode;\n\t\t\t\tclosestPoint.copy(point);\n\t\t\t\tclosestDistance = point.distanceToSquared(endPoint);\n\t\t\t}\n\n\t\t\tconst depth = nodeDepth[currentNode.id];\n\t\t\tif (depth > 2) continue;\n\n\t\t\tfor (let i = 0; i < currentNode.neighbours.length; i++) {\n\t\t\t\tconst neighbour = nodes[currentNode.neighbours[i]];\n\t\t\t\tif (neighbour.id in nodeDepth) continue;\n\n\t\t\t\tnodeQueue.push(neighbour);\n\t\t\t\tnodeDepth[neighbour.id] = depth + 1;\n\t\t\t}\n\t\t}\n\n\t\tendTarget.copy(closestPoint);\n\t\treturn closestNode;\n\t};\n}());\n\n/**\n * Defines a zone of interconnected groups on a navigation mesh.\n *\n * @type {Object}\n * @property {Array<Group>} groups\n * @property {Array<Vector3>} vertices\n */\nconst Zone = {}; // jshint ignore:line\n\n/**\n * Defines a group within a navigation mesh.\n *\n * @type {Object}\n */\nconst Group = {}; // jshint ignore:line\n\n/**\n * Defines a node (or polygon) within a group.\n *\n * @type {Object}\n * @property {number} id\n * @property {Array<number>} neighbours IDs of neighboring nodes.\n * @property {Array<number>} vertexIds\n * @property {Vector3} centroid\n * @property {Array<Array<number>>} portals Array of portals, each defined by two vertex IDs.\n * @property {boolean} closed\n * @property {number} cost\n */\nconst Node = {}; // jshint ignore:line\n\nexport { Pathfinding };\n","import { Vector3 } from 'three';\n\nimport { Utils } from './Utils';\n\nclass Builder {\n  /**\n   * Constructs groups from the given navigation mesh.\n   * @param  {BufferGeometry} geometry\n   * @param  {number} tolerance\n   * @return {Zone}\n   */\n  static buildZone (geometry, tolerance) {\n\n    const navMesh = this._buildNavigationMesh(geometry, tolerance);\n\n    const zone = {};\n\n    navMesh.vertices.forEach((v) => {\n      v.x = Utils.roundNumber(v.x, 2);\n      v.y = Utils.roundNumber(v.y, 2);\n      v.z = Utils.roundNumber(v.z, 2);\n    });\n\n    zone.vertices = navMesh.vertices;\n\n    const groups = this._buildPolygonGroups(navMesh);\n\n    // TODO: This block represents a large portion of navigation mesh construction time\n    // and could probably be optimized. For example, construct portals while\n    // determining the neighbor graph.\n    zone.groups = new Array(groups.length);\n    groups.forEach((group, groupIndex) => {\n\n      const indexByPolygon = new Map(); // { polygon: index in group }\n      group.forEach((poly, polyIndex) => { indexByPolygon.set(poly, polyIndex); });\n\n      const newGroup = new Array(group.length);\n      group.forEach((poly, polyIndex) => {\n\n        const neighbourIndices = [];\n        poly.neighbours.forEach((n) => neighbourIndices.push(indexByPolygon.get(n)));\n\n        // Build a portal list to each neighbour\n        const portals = [];\n        poly.neighbours.forEach((n) => portals.push(this._getSharedVerticesInOrder(poly, n)));\n\n        const centroid = new Vector3( 0, 0, 0 );\n        centroid.add( zone.vertices[ poly.vertexIds[0] ] );\n        centroid.add( zone.vertices[ poly.vertexIds[1] ] );\n        centroid.add( zone.vertices[ poly.vertexIds[2] ] );\n        centroid.divideScalar( 3 );\n        centroid.x = Utils.roundNumber(centroid.x, 2);\n        centroid.y = Utils.roundNumber(centroid.y, 2);\n        centroid.z = Utils.roundNumber(centroid.z, 2);\n\n        newGroup[polyIndex] = {\n          id: polyIndex,\n          neighbours: neighbourIndices,\n          vertexIds: poly.vertexIds,\n          centroid: centroid,\n          portals: portals\n        };\n      });\n\n      zone.groups[groupIndex] = newGroup;\n    });\n\n    return zone;\n  }\n\n  /**\n   * Constructs a navigation mesh from the given geometry.\n   * @param {BufferGeometry} geometry\n   * @return {Object}\n   */\n  static _buildNavigationMesh (geometry, tolerance) {\n    geometry = Utils.mergeVertices(geometry, tolerance);\n    return this._buildPolygonsFromGeometry(geometry);\n  }\n\n  /**\n   * Spreads the group ID of the given polygon to all connected polygons\n   * @param {Object} seed\n   */\n  static _spreadGroupId (seed) {\n    let nextBatch = new Set([seed]);\n\n    while(nextBatch.size > 0) {\n      const batch = nextBatch;\n      nextBatch = new Set();\n\n      batch.forEach((polygon) => {\n        polygon.group = seed.group;\n        polygon.neighbours.forEach((neighbour) => {\n          if(neighbour.group === undefined) {\n            nextBatch.add(neighbour);\n          }\n        });\n      });\n    }\n  }\n\n  static _buildPolygonGroups (navigationMesh) {\n\n    const polygons = navigationMesh.polygons;\n\n    const polygonGroups = [];\n\n    polygons.forEach((polygon) => {\n      if (polygon.group !== undefined) {\n        // this polygon is already part of a group\n        polygonGroups[polygon.group].push(polygon);\n      } else {\n        // we need to make a new group and spread its ID to neighbors\n        polygon.group = polygonGroups.length;\n        this._spreadGroupId(polygon);\n        polygonGroups.push([polygon]);\n      }\n    });\n\n    return polygonGroups;\n  }\n\n  static _buildPolygonNeighbours (polygon, vertexPolygonMap) {\n    const neighbours = new Set();\n\n    const groupA = vertexPolygonMap[polygon.vertexIds[0]];\n    const groupB = vertexPolygonMap[polygon.vertexIds[1]];\n    const groupC = vertexPolygonMap[polygon.vertexIds[2]];\n\n    // It's only necessary to iterate groups A and B. Polygons contained only\n    // in group C cannot share a >1 vertex with this polygon.\n    // IMPORTANT: Bublé cannot compile for-of loops.\n    groupA.forEach((candidate) => {\n      if (candidate === polygon) return;\n      if (groupB.includes(candidate) || groupC.includes(candidate)) {\n        neighbours.add(candidate);\n      }\n    });\n    groupB.forEach((candidate) => {\n      if (candidate === polygon) return;\n      if (groupC.includes(candidate)) {\n        neighbours.add(candidate);\n      }\n    });\n\n    return neighbours;\n  }\n\n  static _buildPolygonsFromGeometry (geometry) {\n\n    const polygons = [];\n    const vertices = [];\n\n    const position = geometry.attributes.position;\n    const index = geometry.index;\n\n    // Constructing the neighbor graph brute force is O(n²). To avoid that,\n    // create a map from vertices to the polygons that contain them, and use it\n    // while connecting polygons. This reduces complexity to O(n*m), where 'm'\n    // is related to connectivity of the mesh.\n\n    /** Array of polygon objects by vertex index. */\n    const vertexPolygonMap = [];\n\n    for (let i = 0; i < position.count; i++) {\n      vertices.push(new Vector3().fromBufferAttribute(position, i));\n      vertexPolygonMap[i] = [];\n    }\n\n    // Convert the faces into a custom format that supports more than 3 vertices\n    for (let i = 0; i < geometry.index.count; i += 3) {\n      const a = index.getX(i);\n      const b = index.getX(i + 1);\n      const c = index.getX(i + 2);\n      const poly = {vertexIds: [a, b, c], neighbours: null};\n      polygons.push(poly);\n      vertexPolygonMap[a].push(poly);\n      vertexPolygonMap[b].push(poly);\n      vertexPolygonMap[c].push(poly);\n    }\n\n    // Build a list of adjacent polygons\n    polygons.forEach((polygon) => {\n      polygon.neighbours = this._buildPolygonNeighbours(polygon, vertexPolygonMap);\n    });\n\n    return {\n      polygons: polygons,\n      vertices: vertices\n    };\n  }\n\n  static _getSharedVerticesInOrder (a, b) {\n\n    const aList = a.vertexIds;\n    const a0 = aList[0], a1 = aList[1], a2 = aList[2];\n\n    const bList = b.vertexIds;\n    const shared0 = bList.includes(a0);\n    const shared1 = bList.includes(a1);\n    const shared2 = bList.includes(a2);\n\n    // it seems that we shouldn't have an a and b with <2 shared vertices here unless there's a bug\n    // in the neighbor identification code, or perhaps a malformed input geometry; 3 shared vertices\n    // is a kind of embarrassing but possible geometry we should handle\n    if (shared0 && shared1 && shared2) {\n      return Array.from(aList);\n    } else if (shared0 && shared1) {\n      return [a0, a1];\n    } else if (shared1 && shared2) {\n      return [a1, a2];\n    } else if (shared0 && shared2) {\n      return [a2, a0]; // this ordering will affect the string pull algorithm later, not clear if significant\n    } else {\n      console.warn(\"Error processing navigation mesh neighbors; neighbors with <2 shared vertices found.\");\n      return [];\n    }\n  }\n}\n\nexport { Builder };\n","import { BinaryHeap } from './BinaryHeap';\nimport { Utils } from './Utils.js';\n\nclass AStar {\n  static init (graph) {\n    for (let x = 0; x < graph.length; x++) {\n      //for(var x in graph) {\n      const node = graph[x];\n      node.f = 0;\n      node.g = 0;\n      node.h = 0;\n      node.cost = 1.0;\n      node.visited = false;\n      node.closed = false;\n      node.parent = null;\n    }\n  }\n\n  static cleanUp (graph) {\n    for (let x = 0; x < graph.length; x++) {\n      const node = graph[x];\n      delete node.f;\n      delete node.g;\n      delete node.h;\n      delete node.cost;\n      delete node.visited;\n      delete node.closed;\n      delete node.parent;\n    }\n  }\n\n  static heap () {\n    return new BinaryHeap(function (node) {\n      return node.f;\n    });\n  }\n\n  static search (graph, start, end) {\n    this.init(graph);\n    //heuristic = heuristic || astar.manhattan;\n\n\n    const openHeap = this.heap();\n\n    openHeap.push(start);\n\n    while (openHeap.size() > 0) {\n\n      // Grab the lowest f(x) to process next.  Heap keeps this sorted for us.\n      const currentNode = openHeap.pop();\n\n      // End case -- result has been found, return the traced path.\n      if (currentNode === end) {\n        let curr = currentNode;\n        const ret = [];\n        while (curr.parent) {\n          ret.push(curr);\n          curr = curr.parent;\n        }\n        this.cleanUp(ret);\n        return ret.reverse();\n      }\n\n      // Normal case -- move currentNode from open to closed, process each of its neighbours.\n      currentNode.closed = true;\n\n      // Find all neighbours for the current node. Optionally find diagonal neighbours as well (false by default).\n      const neighbours = this.neighbours(graph, currentNode);\n\n      for (let i = 0, il = neighbours.length; i < il; i++) {\n        const neighbour = neighbours[i];\n\n        if (neighbour.closed) {\n          // Not a valid node to process, skip to next neighbour.\n          continue;\n        }\n\n        // The g score is the shortest distance from start to current node.\n        // We need to check if the path we have arrived at this neighbour is the shortest one we have seen yet.\n        const gScore = currentNode.g + neighbour.cost;\n        const beenVisited = neighbour.visited;\n\n        if (!beenVisited || gScore < neighbour.g) {\n\n          // Found an optimal (so far) path to this node.  Take score for node to see how good it is.\n          neighbour.visited = true;\n          neighbour.parent = currentNode;\n          if (!neighbour.centroid || !end.centroid) throw new Error('Unexpected state');\n          neighbour.h = neighbour.h || this.heuristic(neighbour.centroid, end.centroid);\n          neighbour.g = gScore;\n          neighbour.f = neighbour.g + neighbour.h;\n\n          if (!beenVisited) {\n            // Pushing to heap will put it in proper place based on the 'f' value.\n            openHeap.push(neighbour);\n          } else {\n            // Already seen the node, but since it has been rescored we need to reorder it in the heap\n            openHeap.rescoreElement(neighbour);\n          }\n        }\n      }\n    }\n\n    // No result was found - empty array signifies failure to find path.\n    return [];\n  }\n\n  static heuristic (pos1, pos2) {\n    return Utils.distanceToSquared(pos1, pos2);\n  }\n\n  static neighbours (graph, node) {\n    const ret = [];\n\n    for (let e = 0; e < node.neighbours.length; e++) {\n      ret.push(graph[node.neighbours[e]]);\n    }\n\n    return ret;\n  }\n}\n\nexport { AStar };\n","import {\n  BoxGeometry,\n  SphereGeometry,\n  BufferAttribute,\n  BufferGeometry,\n  Line,\n  LineBasicMaterial,\n  Mesh,\n  MeshBasicMaterial,\n  Object3D,\n  Vector3,\n} from 'three';\n\nconst colors = {\n  PLAYER: 0xEE836F,\n  TARGET: 0xDCCB18,\n  PATH: 0x00A3AF,\n  WAYPOINT: 0x00A3AF,\n  CLAMPED_STEP: 0xDCD3B2,\n  CLOSEST_NODE: 0x43676B,\n};\n\nconst OFFSET = 0.2;\n\n/**\n * Helper for debugging pathfinding behavior.\n */\nclass PathfindingHelper extends Object3D {\n  constructor () {\n    super();\n\n    this._playerMarker = new Mesh(\n      new SphereGeometry( 0.25, 32, 32 ),\n      new MeshBasicMaterial( { color: colors.PLAYER } )\n    );\n\n    this._targetMarker = new Mesh(\n      new BoxGeometry( 0.3, 0.3, 0.3 ),\n      new MeshBasicMaterial( { color: colors.TARGET } )\n    );\n\n\n    this._nodeMarker = new Mesh(\n      new BoxGeometry( 0.1, 0.8, 0.1 ),\n      new MeshBasicMaterial( { color: colors.CLOSEST_NODE } )\n    );\n\n\n    this._stepMarker = new Mesh(\n      new BoxGeometry( 0.1, 1, 0.1 ),\n      new MeshBasicMaterial( { color: colors.CLAMPED_STEP } )\n    );\n\n    this._pathMarker = new Object3D();\n\n    this._pathLineMaterial = new LineBasicMaterial( { color: colors.PATH, linewidth: 2 } ) ;\n    this._pathPointMaterial = new MeshBasicMaterial( { color: colors.WAYPOINT } );\n    this._pathPointGeometry = new SphereGeometry( 0.08 );\n\n    this._markers = [\n      this._playerMarker,\n      this._targetMarker,\n      this._nodeMarker,\n      this._stepMarker,\n      this._pathMarker,\n    ];\n\n    this._markers.forEach( ( marker ) => {\n\n      marker.visible = false;\n\n      this.add( marker );\n\n    } );\n\n  }\n\n  /**\n   * @param {Array<Vector3>} path\n   * @return {this}\n   */\n  setPath ( path ) {\n\n    while ( this._pathMarker.children.length ) {\n\n      this._pathMarker.children[ 0 ].visible = false;\n      this._pathMarker.remove( this._pathMarker.children[ 0 ] );\n\n    }\n\n    path = [ this._playerMarker.position ].concat( path );\n\n    // Draw debug lines\n    const geometry = new BufferGeometry();\n    geometry.setAttribute('position', new BufferAttribute(new Float32Array(path.length * 3), 3));\n    for (let i = 0; i < path.length; i++) {\n      geometry.attributes.position.setXYZ(i, path[ i ].x, path[ i ].y + OFFSET, path[ i ].z);\n    }\n    this._pathMarker.add( new Line( geometry, this._pathLineMaterial ) );\n\n    for ( let i = 0; i < path.length - 1; i++ ) {\n\n      const node = new Mesh( this._pathPointGeometry, this._pathPointMaterial );\n      node.position.copy( path[ i ] );\n      node.position.y += OFFSET;\n      this._pathMarker.add( node );\n\n    }\n\n    this._pathMarker.visible = true;\n\n    return this;\n\n  }\n\n  /**\n   * @param {Vector3} position\n   * @return {this}\n   */\n  setPlayerPosition( position ) {\n\n    this._playerMarker.position.copy( position );\n    this._playerMarker.visible = true;\n    return this;\n\n  }\n\n  /**\n   * @param {Vector3} position\n   * @return {this}\n   */\n  setTargetPosition( position ) {\n\n    this._targetMarker.position.copy( position );\n    this._targetMarker.visible = true;\n    return this;\n\n  }\n\n  /**\n   * @param {Vector3} position\n   * @return {this}\n   */\n  setNodePosition( position ) {\n\n    this._nodeMarker.position.copy( position );\n    this._nodeMarker.visible = true;\n    return this;\n\n  }\n\n  /**\n   * @param {Vector3} position\n   * @return {this}\n   */\n  setStepPosition( position ) {\n\n    this._stepMarker.position.copy( position );\n    this._stepMarker.visible = true;\n    return this;\n\n  }\n\n  /**\n   * Hides all markers.\n   * @return {this}\n   */\n  reset () {\n\n    while ( this._pathMarker.children.length ) {\n\n      this._pathMarker.children[ 0 ].visible = false;\n      this._pathMarker.remove( this._pathMarker.children[ 0 ] );\n\n    }\n\n    this._markers.forEach( ( marker ) => {\n\n      marker.visible = false;\n\n    } );\n\n    return this;\n\n  }\n\n}\n\nexport { PathfindingHelper };\n"],"names":["Utils","static","value","decimals","factor","Math","pow","round","list","floor","random","length","a","b","dx","x","dy","y","dz","z","poly","pt","c","i","l","j","vector","polygon","vertices","lowestPoint","highestPoint","polygonVertices","vertexIds","forEach","vId","min","max","push","this","isPointInPoly","distanceToSquared","geometry","tolerance","Number","EPSILON","hashToIndex","indices","getIndex","positions","getAttribute","vertexCount","count","nextIndex","newIndices","newPositions","decimalShift","log10","shiftMultiplier","index","getX","hash","getY","getZ","positionAttribute","BufferAttribute","Float32Array","itemSize","normalized","result","BufferGeometry","setAttribute","setIndex","BinaryHeap","constructor","scoreFunction","content","element","sinkDown","pop","end","bubbleUp","remove","node","indexOf","size","rescoreElement","n","parentN","parent","elemScore","child2N","child1N","child1Score","swap","Channel","portals","p1","p2","undefined","left","right","stringPull","pts","portalApex","portalLeft","portalRight","apexIndex","leftIndex","rightIndex","triarea2","vequal","path","Pathfinding","zones","navMesh","_buildNavigationMesh","zone","v","roundNumber","groups","_buildPolygonGroups","Array","group","groupIndex","indexByPolygon","Map","polyIndex","set","newGroup","neighbourIndices","neighbours","get","_getSharedVerticesInOrder","centroid","Vector3","add","divideScalar","id","mergeVertices","_buildPolygonsFromGeometry","seed","nextBatch","Set","batch","neighbour","navigationMesh","polygonGroups","polygons","_spreadGroupId","vertexPolygonMap","groupB","groupC","candidate","includes","position","attributes","fromBufferAttribute","_buildPolygonNeighbours","aList","a0","a1","a2","bList","shared0","shared1","shared2","from","console","warn","buildZone","setZoneData","zoneID","getRandomNode","groupID","nearPosition","nearRange","candidates","p","sample","getClosestNode","checkPolygon","closestNode","closestDistance","Infinity","distance","isVectorInPolygon","findPath","startPosition","targetPosition","nodes","farthestNode","paths","graph","f","g","h","cost","visited","closed","start","init","openHeap","heap","currentNode","curr","ret","cleanUp","reverse","il","gScore","beenVisited","Error","heuristic","pos1","pos2","e","search","getPortalFromTo","channel","nextPolygon","map","shift","prototype","getGroup","plane","Plane","closestNodeGroup","setFromCoplanarPoints","abs","distanceToPoint","measuredDistance","clampStep","point","triangle","Triangle","endPoint","closestPoint","startRef","endRef","endTarget","nodeQueue","nodeDepth","projectPoint","copy","closestPointToPoint","depth","PathfindingHelper","Object3D","super","_playerMarker","Mesh","SphereGeometry","MeshBasicMaterial","color","_targetMarker","BoxGeometry","_nodeMarker","_stepMarker","_pathMarker","_pathLineMaterial","LineBasicMaterial","linewidth","_pathPointMaterial","_pathPointGeometry","_markers","marker","visible","setPath","children","concat","setXYZ","Line","setPlayerPosition","setTargetPosition","setNodePosition","setStepPosition","reset"],"mappings":"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"}