sharedstreets
Version:
SharedStreets, a 'digital commons' for the street
113 lines (89 loc) • 3.32 kB
text/typescript
import distance from '@turf/distance';
import * as turfHelpers from '@turf/helpers';
const jkstra = require('jkstra');
class PathStackFrame {
static defaultOptions = {
direction: jkstra.OUT,
edgeCost: (e, costDone) => 1,
edgeFilter: null // take all edges
}
graph;
edges;
options;
edge;
startEdgeCost;
currentEdgeCost;
visitedNodes = [];
constructor(graph, start, startCost, visitedNodes, options) {
this.graph = graph;
this.options = options;
this.startEdgeCost = startCost;
this.visitedNodes = JSON.parse(JSON.stringify(visitedNodes));
this.edges = this.graph.incidentEdges(start, jkstra.OUT, this.options.edgeFilter);
}
nextEdge() {
if(this.edges.length > 0) {
this.edge = this.edges.pop();
this.currentEdgeCost = this.options.edgeCost(this.edge);
this.visitedNodes[this.edge.from.data] = true;
return this.edge;
}
else
return null;
}
isVisited(node) {
return this.visitedNodes[node.data] == true ? true : false;
}
getCurrentEdge() {
return this.edge;
}
getTotalEdgeCost() {
return this.startEdgeCost + this.currentEdgeCost;
}
}
export class PathSearch {
graph;
start;
end;
min;
max;
options;
minCost = []
constructor(graph) {
this.graph = graph;
}
findPath(start, end, endCoord:turfHelpers.Coord, min, max, options) {
var results = [];
var stack = [];
var visitedNodes = {};
stack.push(new PathStackFrame(this.graph, start, 0, visitedNodes, options));
var currentStackFrame = stack[0];
while(stack.length > 0) {
var nextEdge;
while(nextEdge = currentStackFrame.nextEdge()) {
var remainingDistance = distance(nextEdge.data.start, endCoord, {'units':'meters'})
if((currentStackFrame.getTotalEdgeCost() - currentStackFrame.currentEdgeCost > 0 ) && currentStackFrame.getTotalEdgeCost() - currentStackFrame.currentEdgeCost + remainingDistance > max) {
continue;
}
else if(nextEdge.to.data == end.data) {
if(currentStackFrame.getTotalEdgeCost() < max && currentStackFrame.getTotalEdgeCost() > min) {
var path = stack.map((e) => {return e.edge.data.id});
results.push({path:path, length:currentStackFrame.getTotalEdgeCost()});
}
else
continue; // path found but too short...
}
else {
if(!currentStackFrame.isVisited(nextEdge.to)) {
currentStackFrame = new PathStackFrame(this.graph, nextEdge.to, currentStackFrame.getTotalEdgeCost(), currentStackFrame.visitedNodes, options);
stack.push(currentStackFrame);
}
}
}
var lastFrame = stack.pop();
//minCost[lastFrame.edge.from] = lastFrame.minCost;
currentStackFrame = stack[stack.length-1];
}
return results;
}
}