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