|
|
- (function() {
- 'use strict';
-
- if (typeof sigma === 'undefined') {
- throw 'sigma is not declared';
- }
-
- // Default function to compute path length between two nodes:
- // the euclidian
- var defaultPathLengthFunction = function(node1, node2, previousPathLength) {
- var isEverythingDefined =
- node1 != undefined &&
- node2 != undefined &&
- node1.x != undefined &&
- node1.y != undefined &&
- node2.x != undefined &&
- node2.y != undefined;
- if(!isEverythingDefined) {
- return undefined;
- }
-
- return (previousPathLength || 0) + Math.sqrt(
- Math.pow((node2.y - node1.y), 2) + Math.pow((node2.x - node1.x), 2)
- );
- };
-
- sigma.classes.graph.addMethod(
- 'astar',
- function(srcId, destId, settings) {
- var currentSettings = new sigma.classes.configurable(
- // Default settings
- {
- // Graph is directed, affects which edges are taken into account
- undirected: false,
- // Function to compute the distance between two connected node
- pathLengthFunction: defaultPathLengthFunction,
- // Function to compute an distance between two nodes
- // if undefined, uses pathLengthFunction
- heuristicLengthFunction: undefined
- },
- settings || {});
-
- var pathLengthFunction = currentSettings("pathLengthFunction"),
- heuristicLengthFunction = currentSettings("heuristicLengthFunction") || pathLengthFunction;
-
- var srcNode = this.nodes(srcId),
- destNode = this.nodes(destId);
-
- var closedList = {},
- openList = [];
-
- var addToLists = function(node, previousNode, pathLength, heuristicLength) {
- var nodeId = node.id;
- var newItem = {
- pathLength: pathLength,
- heuristicLength: heuristicLength,
- node: node,
- nodeId: nodeId,
- previousNode: previousNode
- };
-
- if(closedList[nodeId] == undefined || closedList[nodeId].pathLength > pathLength) {
- closedList[nodeId] = newItem;
-
- var item;
- var i;
- for(i = 0; i < openList.length; i++) {
- item = openList[i];
- if(item.heuristicLength > heuristicLength) {
- break;
- }
- }
-
- openList.splice(i, 0, newItem);
- }
- };
-
- addToLists(srcNode, null, 0, 0);
-
- var pathFound = false;
-
- // Depending of the type of graph (directed or not),
- // the neighbors are either the out neighbors or all.
- var allNeighbors;
- if(currentSettings("undirected")) {
- allNeighbors = this.allNeighborsIndex;
- }
- else {
- allNeighbors = this.outNeighborsIndex;
- }
-
-
- var inspectedItem,
- neighbors,
- neighbor,
- pathLength,
- heuristicLength,
- i;
- while(openList.length > 0) {
- inspectedItem = openList.shift();
-
- // We reached the destination node
- if(inspectedItem.nodeId == destId) {
- pathFound = true;
- break;
- }
-
- neighbors = Object.keys(allNeighbors[inspectedItem.nodeId]);
- for(i = 0; i < neighbors.length; i++) {
- neighbor = this.nodes(neighbors[i]);
- pathLength = pathLengthFunction(inspectedItem.node, neighbor, inspectedItem.pathLength);
- heuristicLength = heuristicLengthFunction(neighbor, destNode);
- addToLists(neighbor, inspectedItem.node, pathLength, heuristicLength);
- }
- }
-
- if(pathFound) {
- // Rebuilding path
- var path = [],
- currentNode = destNode;
-
- while(currentNode) {
- path.unshift(currentNode);
- currentNode = closedList[currentNode.id].previousNode;
- }
-
- return path;
- }
- else {
- return undefined;
- }
- }
- );
- }).call(window);
|