Path: blob/main/website/GAUSS/js/pathfinding.js
2941 views
var SearchGraphNode = function()1{2this.g = Number.MAX_VALUE;3this.h = null;4this.f = function() { return this.g + this.h; };5this.walkbox = null;6this.parentIdx = null;7};89var PathFinder = function()10{11this.open = [];12this.closed = [];13this.getHighestPriorityNodeIndex = function()14{15var minF = Number.MAX_VALUE;16var idx;1718for(var i = 0; i < this.open.length; i++)19{20var curr = this.open[i];21if(curr.f() < minF)22{23minF = curr.f();24idx = i;25}26}27return idx;28};29this.getClosedNodeNearestToGoal = function()30{31var minH = Number.MAX_VALUE;32var idx;3334for(var i = 0; i < this.closed.length; i++)35{36var curr = this.closed[i];37if(curr.h < minH)38{39minH = curr.f();40idx = i;41}42}43return this.closed[idx];44};4546this.walkboxIdxInsideList = function(wb, which)47{48var list = which == 'open' ? this.open : this.closed;49for(var i = 0; i < list.length; i++)50if(wb.id === list[i].walkbox.id)51return i;52return -1;53};54this.aStar = function(nodes, startPoint, destPoint)55{56var getNearestEndpoint = function(edge, p)57{58var dist1 = getDistanceFromPoints(edge[0], p);59var dist2 = getDistanceFromPoints(edge[1], p);6061if(dist1 < dist2)62return edge[0];63return edge[1];64};65var getNearestPointInWalkBox = function(point, skipInvisible)66{67var tmp = new Point(point.x, point.y);68var minDist = Infinity;69var p;70for(var i in nodes)71{72if(skipInvisible === true && nodes[i].visible === false)73continue;74p = nodes[i].polygon.getNearestPoint(point);75var dist = getDistanceBetweenPoints(p, point);76if (dist < minDist)77{78minDist = dist;79tmp = new Point(p.x, p.y);80}81}82return tmp;83};84var start;85var tmp = new Point(startPoint.x, startPoint.y);86start = getWalkboxFromPoint(nodes, tmp);87if(!start)88{89start = getNearestWalkBox(nodes, tmp);90if (!start)91{92alert("SEVERE PATHFINDING ERROR");93return [];94}95}9697tmp = new Point(destPoint.x, destPoint.y);98var goal = getWalkboxFromPoint(nodes, tmp);99if(!goal)100{101tmp = getNearestPointInWalkBox(tmp, true);102goal = getNearestWalkBox(nodes, tmp, true);103if(!goal)104{105alert("SEVERE PATHFINDING ERROR");106return [];107}108109}110destPoint = new Point(tmp.x, tmp.y);111112if(startPoint.x === destPoint.x && startPoint.y === destPoint.y)113return [];114115tmp = start.polygon.centroid;116var startPos = new paper.Point(tmp.x, tmp.y);117tmp = goal.polygon.centroid;118var goalPos = new paper.Point(tmp.x, tmp.y);119120var s = new SearchGraphNode();121s.walkbox = start;122s.g = 0;123s.h = startPos.getDistance(goalPos);124s.parentIdx = -1;125126this.open.push(s);127var goalFound = false;128while(!goalFound)129{130var highestPriorityIndex = this.getHighestPriorityNodeIndex();131var currNode = this.open[highestPriorityIndex];132if(!currNode) // disconnected node133break;134135if(currNode.walkbox.id === goal.id)136{137goalFound = true;138break;139}140this.open.splice(highestPriorityIndex, 1);141this.closed.push(currNode);142143var currNeighborsIds = currNode.walkbox.neighbors;144var currNeighbors = [];145for(var i = 0; i < currNeighborsIds.length; i++)146currNeighbors.push(nodes[currNeighborsIds[i].wbId]);147148for(var i = 0; i < currNeighbors.length; i++)149{150var neighbor = new SearchGraphNode();151neighbor.walkbox = currNeighbors[i];152var currNodeCenter = currNode.walkbox.polygon.centroid;153var neighborCenter = neighbor.walkbox.polygon.centroid;154var distance = currNodeCenter.getDistance(neighborCenter);155var cost = currNode.g + distance;156var neighborIdxInOpenList = this.walkboxIdxInsideList(neighbor.walkbox, 'open');157var neighborIdxInClosedList = this.walkboxIdxInsideList(neighbor.walkbox, 'closed');158159if(neighborIdxInOpenList != -1 && cost < this.open[neighborIdxInOpenList].g)160{161this.open.splice(neighborIdxInOpenList, 1);162neighborIdxInOpenList = -1;163}164if(neighborIdxInOpenList == -1 && neighborIdxInClosedList == -1)165{166neighbor.g = cost;167neighbor.h = neighborCenter.getDistance(goalPos);168neighbor.parentIdx = this.closed.indexOf(currNode);169this.open.push(neighbor);170}171}172}173var walkBoxesToTraverse = [];174var node = this.open[this.getHighestPriorityNodeIndex()];175if(!node) // disconnected node, start from the nearest visited node176walkBoxesToTraverse.push(this.getClosedNodeNearestToGoal().walkbox.id);177while(node && node.parentIdx != -1 && this.closed[node.parentIdx].walkbox != start)178{179node = this.closed[node.parentIdx];180walkBoxesToTraverse.unshift(node.walkbox.id);181}182183walkBoxesToTraverse.push(goal.id);184185this.open = [];186this.closed = [];187188var shortestPath = [];189var currWB = start.id;190191var startGoalEdge = [startPoint, destPoint];192for(var i = 0; i < walkBoxesToTraverse.length; i++)193{194var nextWb = walkBoxesToTraverse[i];195var commonEdge = getCommonEdge(nodes[currWB], nodes[nextWb]);196if(!commonEdge)197{198if(currWB !== nextWb)199destPoint = nodes[currWB].polygon.getNearestPoint(destPoint);200break;201}202var nextWayPoint = checkLineIntersection(startGoalEdge, commonEdge);203if(!nextWayPoint.inLines)204nextWayPoint = getNearestEndpoint(getCommonEdge(nodes[currWB], nodes[nextWb]), nextWayPoint);205nextWayPoint = new Point(nextWayPoint.x, nextWayPoint.y);206if(nodes[nextWb].visible === false)207{208destPoint = nextWayPoint;209break;210}211shortestPath.push(nextWayPoint);212currWB = nextWb;213}214215shortestPath.push(destPoint);216return shortestPath;217};218};219//TODO: modify the Open and Closed list with a hashmap in order to access an element in O(1)220221