From 768a0a0f43c267a101c3e1b890eba46569d85005 Mon Sep 17 00:00:00 2001 From: rafaelcastrocouto Date: Wed, 4 Jun 2014 15:10:42 -0300 Subject: [PATCH] Proper commit for trace finder --- lib/pathfinding-browser.js | 116 ++++++++++++++++++++++++++++++++- lib/pathfinding-browser.min.js | 2 +- src/PathFinding.js | 3 +- src/finders/TraceFinder.js | 109 +++++++++++++++++++++++++++++++ visual/index.html | 25 +++++++ visual/js/panel.js | 19 ++++++ 6 files changed, 270 insertions(+), 4 deletions(-) create mode 100644 src/finders/TraceFinder.js diff --git a/lib/pathfinding-browser.js b/lib/pathfinding-browser.js index 41e0b13c..08e926f2 100644 --- a/lib/pathfinding-browser.js +++ b/lib/pathfinding-browser.js @@ -398,10 +398,11 @@ module.exports = { 'BiBreadthFirstFinder' : require('./finders/BiBreadthFirstFinder'), 'BiDijkstraFinder' : require('./finders/BiDijkstraFinder'), 'JumpPointFinder' : require('./finders/JumpPointFinder'), - 'IDAStarFinder' : require('./finders/IDAStarFinder') + 'IDAStarFinder' : require('./finders/IDAStarFinder'), + 'TraceFinder' : require('./finders/TraceFinder') }; -},{"./core/Grid":4,"./core/Heuristic":5,"./core/Node":6,"./core/Util":7,"./finders/AStarFinder":8,"./finders/BestFirstFinder":9,"./finders/BiAStarFinder":10,"./finders/BiBestFirstFinder":11,"./finders/BiBreadthFirstFinder":12,"./finders/BiDijkstraFinder":13,"./finders/BreadthFirstFinder":14,"./finders/DijkstraFinder":15,"./finders/IDAStarFinder":16,"./finders/JumpPointFinder":17,"heap":1}],4:[function(require,module,exports){ +},{"./core/Grid":4,"./core/Heuristic":5,"./core/Node":6,"./core/Util":7,"./finders/AStarFinder":8,"./finders/BestFirstFinder":9,"./finders/BiAStarFinder":10,"./finders/BiBestFirstFinder":11,"./finders/BiBreadthFirstFinder":12,"./finders/BiDijkstraFinder":13,"./finders/BreadthFirstFinder":14,"./finders/DijkstraFinder":15,"./finders/IDAStarFinder":16,"./finders/JumpPointFinder":17,"./finders/TraceFinder":18,"heap":1}],4:[function(require,module,exports){ var Node = require('./Node'); /** @@ -1859,6 +1860,117 @@ JumpPointFinder.prototype._findNeighbors = function(node) { module.exports = JumpPointFinder; +},{"../core/Heuristic":5,"../core/Util":7,"heap":1}],18:[function(require,module,exports){ +var Heap = require('heap'); +var Util = require('../core/Util'); +var Heuristic = require('../core/Heuristic'); + +/** + * A* path-finder. + * based upon https://github.com/bgrins/javascript-astar + * @constructor + * @param {object} opt + * @param {boolean} opt.allowDiagonal Whether diagonal movement is allowed. + * @param {boolean} opt.dontCrossCorners Disallow diagonal movement touching block corners. + * @param {function} opt.heuristic Heuristic function to estimate the distance + * (defaults to manhattan). + * @param {integer} opt.weight Weight to apply to the heuristic to allow for suboptimal paths, + * in order to speed up the search. + */ +function TraceFinder(opt) { + opt = opt || {}; + this.allowDiagonal = opt.allowDiagonal; + this.dontCrossCorners = opt.dontCrossCorners; + this.heuristic = opt.heuristic || Heuristic.manhattan; +} + +/** + * Find and return the the path. + * @return {Array.<[number, number]>} The path, including both start and + * end positions. + */ +TraceFinder.prototype.findPath = function(startX, startY, endX, endY, grid) { + + var openList = new Heap(function(nodeA, nodeB) { + return nodeA.f - nodeB.f; + }), + startNode = grid.getNodeAt(startX, startY), + endNode = grid.getNodeAt(endX, endY), + heuristic = this.heuristic, + allowDiagonal = this.allowDiagonal, + dontCrossCorners = this.dontCrossCorners, + abs = Math.abs, SQRT2 = Math.SQRT2, + node, neighbors, neighbor, i, l, x, y, ng; + + // set the `g` and `f` value of the start node to be 0 + startNode.g = 0; + startNode.f = 0; + + // push the start node into the open list + openList.push(startNode); + startNode.opened = true; + + // while the open list is not empty + while (!openList.empty()) { + // pop the position of node which has the minimum `f` value. + node = openList.pop(); + node.closed = true; + + // if reached the end position, construct the path and return it + if (node === endNode) { + return Util.backtrace(endNode); + } + + // get neigbours of the current node + neighbors = grid.getNeighbors(node, allowDiagonal, dontCrossCorners); + + var ar = neighbors.length; + + for (i = 0, l = neighbors.length; i < l; ++i) { + neighbor = neighbors[i]; + + if (neighbor.closed) { + continue; + } + + x = neighbor.x; + y = neighbor.y; + + // get the distance between current node and the neighbor + // and calculate the next g score + ng = node.g + ((x - node.x === 0 || y - node.y === 0) ? 1 : SQRT2); + + // check if the neighbor has not been inspected yet, or + // can be reached with smaller cost from the current node + if (!neighbor.opened || ng < neighbor.g) { + neighbor.g = ng * ar/9; //the trace magic + neighbor.h = neighbor.h || heuristic(abs(x - endX), abs(y - endY)); + neighbor.f = neighbor.g + neighbor.h; + neighbor.parent = node; + + if (!neighbor.opened) { + //openList.push(neighbor); + openList.push(neighbor); + neighbor.opened = true; + } else { + // the neighbor can be reached with smaller cost. + // Since its f value has been updated, we have to + // update its position in the open list + + //openList.updateItem(neighbor); + openList.updateItem(neighbor); + } + } + } // end for each neighbor + + } // end while not open list empty + + // fail to find the path + return []; +}; + +module.exports = TraceFinder; + },{"../core/Heuristic":5,"../core/Util":7,"heap":1}]},{},[3])(3) }); ; \ No newline at end of file diff --git a/lib/pathfinding-browser.min.js b/lib/pathfinding-browser.min.js index bb713983..a9c7fbb9 100644 --- a/lib/pathfinding-browser.min.js +++ b/lib/pathfinding-browser.min.js @@ -1 +1 @@ -!function(t){if("function"==typeof bootstrap)bootstrap("pf",t);else if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makePF=t}else"undefined"!=typeof window?window.PF=t():global.PF=t()}(function(){return function(t,e,r){function n(r,o){if(!e[r]){if(!t[r]){var s="function"==typeof require&&require;if(!o&&s)return s(r,!0);if(i)return i(r,!0);throw new Error("Cannot find module '"+r+"'")}var a=e[r]={exports:{}};t[r][0].call(a.exports,function(e){var i=t[r][1][e];return n(i?i:e)},a,a.exports)}return e[r].exports}for(var i="function"==typeof require&&require,o=0;ot?-1:t>e?1:0},h=function(t,e,i,o,s){var a;if(null==i&&(i=0),null==s&&(s=r),0>i)throw new Error("lo must be non-negative");for(null==o&&(o=t.length);o>i;)a=n((i+o)/2),s(e,t[a])<0?o=a:i=a+1;return[].splice.apply(t,[i,i-i].concat(e)),e},s=function(t,e,n){return null==n&&(n=r),t.push(e),d(t,0,t.length-1,n)},o=function(t,e){var n,i;return null==e&&(e=r),n=t.pop(),t.length?(i=t[0],t[0]=n,g(t,0,e)):i=n,i},u=function(t,e,n){var i;return null==n&&(n=r),i=t[0],t[0]=e,g(t,0,n),i},a=function(t,e,n){var i;return null==n&&(n=r),t.length&&n(t[0],e)<0&&(i=[t[0],e],e=i[0],t[0]=i[1],g(t,0,n)),e},i=function(t,e){var i,o,s,a,u,h;for(null==e&&(e=r),a=function(){h=[];for(var e=0,r=n(t.length/2);r>=0?r>e:e>r;r>=0?e++:e--)h.push(e);return h}.apply(this).reverse(),u=[],o=0,s=a.length;s>o;o++)i=a[o],u.push(g(t,i,e));return u},f=function(t,e,n){var i;return null==n&&(n=r),i=t.indexOf(e),-1!==i?(d(t,0,i,n),g(t,i,n)):void 0},l=function(t,e,n){var o,s,u,h,p;if(null==n&&(n=r),s=t.slice(0,e),!s.length)return s;for(i(s,n),p=t.slice(e),u=0,h=p.length;h>u;u++)o=p[u],a(s,o,n);return s.sort(n).reverse()},c=function(t,e,n){var s,a,u,l,c,f,d,g,y,b;if(null==n&&(n=r),10*e<=t.length){if(l=t.slice(0,e).sort(n),!l.length)return l;for(u=l[l.length-1],g=t.slice(e),c=0,d=g.length;d>c;c++)s=g[c],n(s,u)<0&&(h(l,s,0,null,n),l.pop(),u=l[l.length-1]);return l}for(i(t,n),b=[],a=f=0,y=p(e,t.length);y>=0?y>f:f>y;a=y>=0?++f:--f)b.push(o(t,n));return b},d=function(t,e,n,i){var o,s,a;for(null==i&&(i=r),o=t[n];n>e&&(a=n-1>>1,s=t[a],i(o,s)<0);)t[n]=s,n=a;return t[n]=o},g=function(t,e,n){var i,o,s,a,u;for(null==n&&(n=r),o=t.length,u=e,s=t[e],i=2*e+1;o>i;)a=i+1,o>a&&!(n(t[i],t[a])<0)&&(i=a),t[e]=t[i],e=i,i=2*e+1;return t[e]=s,d(t,u,e,n)},t=function(){function t(t){this.cmp=null!=t?t:r,this.nodes=[]}return t.push=s,t.pop=o,t.replace=u,t.pushpop=a,t.heapify=i,t.nlargest=l,t.nsmallest=c,t.prototype.push=function(t){return s(this.nodes,t,this.cmp)},t.prototype.pop=function(){return o(this.nodes,this.cmp)},t.prototype.peek=function(){return this.nodes[0]},t.prototype.contains=function(t){return-1!==this.nodes.indexOf(t)},t.prototype.replace=function(t){return u(this.nodes,t,this.cmp)},t.prototype.pushpop=function(t){return a(this.nodes,t,this.cmp)},t.prototype.heapify=function(){return i(this.nodes,this.cmp)},t.prototype.updateItem=function(t){return f(this.nodes,t,this.cmp)},t.prototype.clear=function(){return this.nodes=[]},t.prototype.empty=function(){return 0===this.nodes.length},t.prototype.size=function(){return this.nodes.length},t.prototype.clone=function(){var e;return e=new t,e.nodes=this.nodes.slice(0),e},t.prototype.toArray=function(){return this.nodes.slice(0)},t.prototype.insert=t.prototype.push,t.prototype.remove=t.prototype.pop,t.prototype.top=t.prototype.peek,t.prototype.front=t.prototype.peek,t.prototype.has=t.prototype.contains,t.prototype.copy=t.prototype.clone,t}(),("undefined"!=typeof e&&null!==e?e.exports:void 0)?e.exports=t:window.Heap=t}.call(this)},{}],3:[function(t,e){e.exports={Heap:t("heap"),Node:t("./core/Node"),Grid:t("./core/Grid"),Util:t("./core/Util"),Heuristic:t("./core/Heuristic"),AStarFinder:t("./finders/AStarFinder"),BestFirstFinder:t("./finders/BestFirstFinder"),BreadthFirstFinder:t("./finders/BreadthFirstFinder"),DijkstraFinder:t("./finders/DijkstraFinder"),BiAStarFinder:t("./finders/BiAStarFinder"),BiBestFirstFinder:t("./finders/BiBestFirstFinder"),BiBreadthFirstFinder:t("./finders/BiBreadthFirstFinder"),BiDijkstraFinder:t("./finders/BiDijkstraFinder"),JumpPointFinder:t("./finders/JumpPointFinder"),IDAStarFinder:t("./finders/IDAStarFinder")}},{"./core/Grid":4,"./core/Heuristic":5,"./core/Node":6,"./core/Util":7,"./finders/AStarFinder":8,"./finders/BestFirstFinder":9,"./finders/BiAStarFinder":10,"./finders/BiBestFirstFinder":11,"./finders/BiBreadthFirstFinder":12,"./finders/BiDijkstraFinder":13,"./finders/BreadthFirstFinder":14,"./finders/DijkstraFinder":15,"./finders/IDAStarFinder":16,"./finders/JumpPointFinder":17,heap:1}],4:[function(t,e){function r(t,e,r){this.width=t,this.height=e,this.nodes=this._buildNodes(t,e,r)}var n=t("./Node");r.prototype._buildNodes=function(t,e,r){var i,o,s=new Array(e);for(i=0;e>i;++i)for(s[i]=new Array(t),o=0;t>o;++o)s[i][o]=new n(o,i);if(void 0===r)return s;if(r.length!==e||r[0].length!==t)throw new Error("Matrix size does not fit");for(i=0;e>i;++i)for(o=0;t>o;++o)r[i][o]&&(s[i][o].walkable=!1);return s},r.prototype.getNodeAt=function(t,e){return this.nodes[e][t]},r.prototype.isWalkableAt=function(t,e){return this.isInside(t,e)&&this.nodes[e][t].walkable},r.prototype.isInside=function(t,e){return t>=0&&t=0&&et;++t)for(u[t]=new Array(i),e=0;i>e;++e)u[t][e]=new n(e,t,s[t][e].walkable);return a.nodes=u,a},e.exports=r},{"./Node":6}],5:[function(t,e){e.exports={manhattan:function(t,e){return t+e},euclidean:function(t,e){return Math.sqrt(t*t+e*e)},chebyshev:function(t,e){return Math.max(t,e)}}},{}],6:[function(t,e){function r(t,e,r){this.x=t,this.y=e,this.walkable=void 0===r?!0:r}e.exports=r},{}],7:[function(t,e,r){function n(t){for(var e=[[t.x,t.y]];t.parent;)t=t.parent,e.push([t.x,t.y]);return e.reverse()}function i(t,e){var r=n(t),i=n(e);return r.concat(i.reverse())}function o(t){var e,r,n,i,o,s=0;for(e=1;et?1:-1,o=n>e?1:-1,u=s-a;;){if(l.push([t,e]),t===r&&e===n)break;h=2*u,h>-a&&(u-=a,t+=i),s>h&&(u+=s,e+=o)}return l}function a(t){var e,r,n,i,o,a,u=[],h=t.length;if(2>h)return u;for(o=0;h-1>o;++o)for(e=t[o],r=t[o+1],n=s(e[0],e[1],r[0],r[1]),i=n.length,a=0;i-1>a;++a)u.push(n[a]);return u.push(t[h-1]),u}function u(t,e){var r,n,i,o,a,u,h,p,l,c,f,d,g,y=e.length,b=e[0][0],A=e[0][1],k=e[y-1][0],w=e[y-1][1];for(r=b,n=A,a=e[1][0],u=e[1][1],h=[[r,n]],p=2;y>p;++p){for(c=e[p],i=c[0],o=c[1],f=s(r,n,i,o),g=!1,l=1;lp;++p)h=u[p],h.closed||(c=h.x,f=h.y,d=a.g+(0===c-a.x||0===f-a.y?1:x),(!h.opened||dp;++p)if(h=u[p],!h.closed){if(h.opened===C)return i.biBacktrace(a,h);c=h.x,f=h.y,d=a.g+(0===c-a.x||0===f-a.y?1:W),(!h.opened||dp;++p)if(h=u[p],!h.closed){if(h.opened===N)return i.biBacktrace(h,a);c=h.x,f=h.y,d=a.g+(0===c-a.x||0===f-a.y?1:W),(!h.opened||dh;++h)if(a=s[h],!a.closed)if(a.opened){if(a.by===A)return n.biBacktrace(u,a)}else f.push(a),a.parent=u,a.opened=!0,a.by=b;for(u=d.shift(),u.closed=!0,s=o.getNeighbors(u,g,y),h=0,p=s.length;p>h;++h)if(a=s[h],!a.closed)if(a.opened){if(a.by===b)return n.biBacktrace(a,u)}else d.push(a),a.parent=u,a.opened=!0,a.by=A}return[]},e.exports=r},{"../core/Util":7}],13:[function(t,e){function r(t){n.call(this,t),this.heuristic=function(){return 0}}var n=t("./BiAStarFinder");r.prototype=new n,r.prototype.constructor=r,e.exports=r},{"./BiAStarFinder":10}],14:[function(t,e){function r(t){t=t||{},this.allowDiagonal=t.allowDiagonal,this.dontCrossCorners=t.dontCrossCorners}var n=t("../core/Util");r.prototype.findPath=function(t,e,r,i,o){var s,a,u,h,p,l=[],c=this.allowDiagonal,f=this.dontCrossCorners,d=o.getNodeAt(t,e),g=o.getNodeAt(r,i);for(l.push(d),d.opened=!0;l.length;){if(u=l.shift(),u.closed=!0,u===g)return n.backtrace(g);for(s=o.getNeighbors(u,c,f),h=0,p=s.length;p>h;++h)a=s[h],a.closed||a.opened||(l.push(a),a.opened=!0,a.parent=u)}return[]},e.exports=r},{"../core/Util":7}],15:[function(t,e){function r(t){n.call(this,t),this.heuristic=function(){return 0}}var n=t("./AStarFinder");r.prototype=new n,r.prototype.constructor=r,e.exports=r},{"./AStarFinder":8}],16:[function(t,e){function r(t){t=t||{},this.allowDiagonal=t.allowDiagonal,this.dontCrossCorners=t.dontCrossCorners,this.heuristic=t.heuristic||n.manhattan,this.weight=t.weight||1,this.trackRecursion=t.trackRecursion||!1,this.timeLimit=t.timeLimit||1/0}t("../core/Util");var n=t("../core/Heuristic"),i=t("../core/Node");r.prototype.findPath=function(t,e,r,n,o){var s,a,u,h=0,p=(new Date).getTime(),l=function(t,e){return this.heuristic(Math.abs(e.x-t.x),Math.abs(e.y-t.y))}.bind(this),c=function(t,e){return t.x===e.x||t.y===e.y?1:Math.SQRT2},f=function(t,e,r,n,s){if(h++,this.timeLimit>0&&(new Date).getTime()-p>1e3*this.timeLimit)return 1/0;var a=e+l(t,g)*this.weight;if(a>r)return a;if(t==g)return n[s]=[t.x,t.y],t;var u,d,y,b,A=o.getNeighbors(t,this.allowDiagonal,this.dontCrossCorners);for(y=0,u=1/0;b=A[y];++y){if(this.trackRecursion&&(b.retainCount=b.retainCount+1||1,b.tested!==!0&&(b.tested=!0)),d=f(b,e+c(t,b),r,n,s+1),d instanceof i)return n[s]=[t.x,t.y],d;this.trackRecursion&&0===--b.retainCount&&(b.tested=!1),u>d&&(u=d)}return u}.bind(this),d=o.getNodeAt(t,e),g=o.getNodeAt(r,n),y=l(d,g);for(s=0;!0;++s){if(a=[],u=f(d,0,y,a,0),1/0===u)return[];if(u instanceof i)return a;y=u}return[]},e.exports=r},{"../core/Heuristic":5,"../core/Node":6,"../core/Util":7}],17:[function(t,e){function r(t){t=t||{},this.heuristic=t.heuristic||o.manhattan,this.trackJumpRecursion=t.trackJumpRecursion||!1}var n=t("heap"),i=t("../core/Util"),o=t("../core/Heuristic");r.prototype.findPath=function(t,e,r,o,s){var a,u=this.openList=new n(function(t,e){return t.f-e.f}),h=this.startNode=s.getNodeAt(t,e),p=this.endNode=s.getNodeAt(r,o);for(this.grid=s,h.g=0,h.f=0,u.push(h),h.opened=!0;!u.empty();){if(a=u.pop(),a.closed=!0,a===p)return i.expandPath(i.backtrace(p));this._identifySuccessors(a)}return[]},r.prototype._identifySuccessors=function(t){var e,r,n,i,s,a,u,h,p,l,c=this.grid,f=this.heuristic,d=this.openList,g=this.endNode.x,y=this.endNode.y,b=t.x,A=t.y,k=Math.abs;for(Math.max,e=this._findNeighbors(t),i=0,s=e.length;s>i;++i)if(r=e[i],n=this._jump(r[0],r[1],b,A)){if(a=n[0],u=n[1],l=c.getNodeAt(a,u),l.closed)continue;h=o.euclidean(k(a-b),k(u-A)),p=t.g+h,(!l.opened||pa;++a)s=o[a],f.push([s.x,s.y]);return f},e.exports=r},{"../core/Heuristic":5,"../core/Util":7,heap:1}]},{},[3])(3)}); \ No newline at end of file +!function(t){if("function"==typeof bootstrap)bootstrap("pf",t);else if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makePF=t}else"undefined"!=typeof window?window.PF=t():global.PF=t()}(function(){return function(t,e,r){function n(r,o){if(!e[r]){if(!t[r]){var s="function"==typeof require&&require;if(!o&&s)return s(r,!0);if(i)return i(r,!0);throw new Error("Cannot find module '"+r+"'")}var a=e[r]={exports:{}};t[r][0].call(a.exports,function(e){var i=t[r][1][e];return n(i?i:e)},a,a.exports)}return e[r].exports}for(var i="function"==typeof require&&require,o=0;ot?-1:t>e?1:0},h=function(t,e,i,o,s){var a;if(null==i&&(i=0),null==s&&(s=r),0>i)throw new Error("lo must be non-negative");for(null==o&&(o=t.length);o>i;)a=n((i+o)/2),s(e,t[a])<0?o=a:i=a+1;return[].splice.apply(t,[i,i-i].concat(e)),e},s=function(t,e,n){return null==n&&(n=r),t.push(e),d(t,0,t.length-1,n)},o=function(t,e){var n,i;return null==e&&(e=r),n=t.pop(),t.length?(i=t[0],t[0]=n,g(t,0,e)):i=n,i},u=function(t,e,n){var i;return null==n&&(n=r),i=t[0],t[0]=e,g(t,0,n),i},a=function(t,e,n){var i;return null==n&&(n=r),t.length&&n(t[0],e)<0&&(i=[t[0],e],e=i[0],t[0]=i[1],g(t,0,n)),e},i=function(t,e){var i,o,s,a,u,h;for(null==e&&(e=r),a=function(){h=[];for(var e=0,r=n(t.length/2);r>=0?r>e:e>r;r>=0?e++:e--)h.push(e);return h}.apply(this).reverse(),u=[],o=0,s=a.length;s>o;o++)i=a[o],u.push(g(t,i,e));return u},f=function(t,e,n){var i;return null==n&&(n=r),i=t.indexOf(e),-1!==i?(d(t,0,i,n),g(t,i,n)):void 0},l=function(t,e,n){var o,s,u,h,p;if(null==n&&(n=r),s=t.slice(0,e),!s.length)return s;for(i(s,n),p=t.slice(e),u=0,h=p.length;h>u;u++)o=p[u],a(s,o,n);return s.sort(n).reverse()},c=function(t,e,n){var s,a,u,l,c,f,d,g,y,b;if(null==n&&(n=r),10*e<=t.length){if(l=t.slice(0,e).sort(n),!l.length)return l;for(u=l[l.length-1],g=t.slice(e),c=0,d=g.length;d>c;c++)s=g[c],n(s,u)<0&&(h(l,s,0,null,n),l.pop(),u=l[l.length-1]);return l}for(i(t,n),b=[],a=f=0,y=p(e,t.length);y>=0?y>f:f>y;a=y>=0?++f:--f)b.push(o(t,n));return b},d=function(t,e,n,i){var o,s,a;for(null==i&&(i=r),o=t[n];n>e&&(a=n-1>>1,s=t[a],i(o,s)<0);)t[n]=s,n=a;return t[n]=o},g=function(t,e,n){var i,o,s,a,u;for(null==n&&(n=r),o=t.length,u=e,s=t[e],i=2*e+1;o>i;)a=i+1,o>a&&!(n(t[i],t[a])<0)&&(i=a),t[e]=t[i],e=i,i=2*e+1;return t[e]=s,d(t,u,e,n)},t=function(){function t(t){this.cmp=null!=t?t:r,this.nodes=[]}return t.push=s,t.pop=o,t.replace=u,t.pushpop=a,t.heapify=i,t.nlargest=l,t.nsmallest=c,t.prototype.push=function(t){return s(this.nodes,t,this.cmp)},t.prototype.pop=function(){return o(this.nodes,this.cmp)},t.prototype.peek=function(){return this.nodes[0]},t.prototype.contains=function(t){return-1!==this.nodes.indexOf(t)},t.prototype.replace=function(t){return u(this.nodes,t,this.cmp)},t.prototype.pushpop=function(t){return a(this.nodes,t,this.cmp)},t.prototype.heapify=function(){return i(this.nodes,this.cmp)},t.prototype.updateItem=function(t){return f(this.nodes,t,this.cmp)},t.prototype.clear=function(){return this.nodes=[]},t.prototype.empty=function(){return 0===this.nodes.length},t.prototype.size=function(){return this.nodes.length},t.prototype.clone=function(){var e;return e=new t,e.nodes=this.nodes.slice(0),e},t.prototype.toArray=function(){return this.nodes.slice(0)},t.prototype.insert=t.prototype.push,t.prototype.remove=t.prototype.pop,t.prototype.top=t.prototype.peek,t.prototype.front=t.prototype.peek,t.prototype.has=t.prototype.contains,t.prototype.copy=t.prototype.clone,t}(),("undefined"!=typeof e&&null!==e?e.exports:void 0)?e.exports=t:window.Heap=t}.call(this)},{}],3:[function(t,e){e.exports={Heap:t("heap"),Node:t("./core/Node"),Grid:t("./core/Grid"),Util:t("./core/Util"),Heuristic:t("./core/Heuristic"),AStarFinder:t("./finders/AStarFinder"),BestFirstFinder:t("./finders/BestFirstFinder"),BreadthFirstFinder:t("./finders/BreadthFirstFinder"),DijkstraFinder:t("./finders/DijkstraFinder"),BiAStarFinder:t("./finders/BiAStarFinder"),BiBestFirstFinder:t("./finders/BiBestFirstFinder"),BiBreadthFirstFinder:t("./finders/BiBreadthFirstFinder"),BiDijkstraFinder:t("./finders/BiDijkstraFinder"),JumpPointFinder:t("./finders/JumpPointFinder"),IDAStarFinder:t("./finders/IDAStarFinder"),TraceFinder:t("./finders/TraceFinder")}},{"./core/Grid":4,"./core/Heuristic":5,"./core/Node":6,"./core/Util":7,"./finders/AStarFinder":8,"./finders/BestFirstFinder":9,"./finders/BiAStarFinder":10,"./finders/BiBestFirstFinder":11,"./finders/BiBreadthFirstFinder":12,"./finders/BiDijkstraFinder":13,"./finders/BreadthFirstFinder":14,"./finders/DijkstraFinder":15,"./finders/IDAStarFinder":16,"./finders/JumpPointFinder":17,"./finders/TraceFinder":18,heap:1}],4:[function(t,e){function r(t,e,r){this.width=t,this.height=e,this.nodes=this._buildNodes(t,e,r)}var n=t("./Node");r.prototype._buildNodes=function(t,e,r){var i,o,s=new Array(e);for(i=0;e>i;++i)for(s[i]=new Array(t),o=0;t>o;++o)s[i][o]=new n(o,i);if(void 0===r)return s;if(r.length!==e||r[0].length!==t)throw new Error("Matrix size does not fit");for(i=0;e>i;++i)for(o=0;t>o;++o)r[i][o]&&(s[i][o].walkable=!1);return s},r.prototype.getNodeAt=function(t,e){return this.nodes[e][t]},r.prototype.isWalkableAt=function(t,e){return this.isInside(t,e)&&this.nodes[e][t].walkable},r.prototype.isInside=function(t,e){return t>=0&&t=0&&et;++t)for(u[t]=new Array(i),e=0;i>e;++e)u[t][e]=new n(e,t,s[t][e].walkable);return a.nodes=u,a},e.exports=r},{"./Node":6}],5:[function(t,e){e.exports={manhattan:function(t,e){return t+e},euclidean:function(t,e){return Math.sqrt(t*t+e*e)},chebyshev:function(t,e){return Math.max(t,e)}}},{}],6:[function(t,e){function r(t,e,r){this.x=t,this.y=e,this.walkable=void 0===r?!0:r}e.exports=r},{}],7:[function(t,e,r){function n(t){for(var e=[[t.x,t.y]];t.parent;)t=t.parent,e.push([t.x,t.y]);return e.reverse()}function i(t,e){var r=n(t),i=n(e);return r.concat(i.reverse())}function o(t){var e,r,n,i,o,s=0;for(e=1;et?1:-1,o=n>e?1:-1,u=s-a;;){if(l.push([t,e]),t===r&&e===n)break;h=2*u,h>-a&&(u-=a,t+=i),s>h&&(u+=s,e+=o)}return l}function a(t){var e,r,n,i,o,a,u=[],h=t.length;if(2>h)return u;for(o=0;h-1>o;++o)for(e=t[o],r=t[o+1],n=s(e[0],e[1],r[0],r[1]),i=n.length,a=0;i-1>a;++a)u.push(n[a]);return u.push(t[h-1]),u}function u(t,e){var r,n,i,o,a,u,h,p,l,c,f,d,g,y=e.length,b=e[0][0],A=e[0][1],k=e[y-1][0],w=e[y-1][1];for(r=b,n=A,a=e[1][0],u=e[1][1],h=[[r,n]],p=2;y>p;++p){for(c=e[p],i=c[0],o=c[1],f=s(r,n,i,o),g=!1,l=1;lp;++p)h=u[p],h.closed||(c=h.x,f=h.y,d=a.g+(0===c-a.x||0===f-a.y?1:x),(!h.opened||dp;++p)if(h=u[p],!h.closed){if(h.opened===C)return i.biBacktrace(a,h);c=h.x,f=h.y,d=a.g+(0===c-a.x||0===f-a.y?1:N),(!h.opened||dp;++p)if(h=u[p],!h.closed){if(h.opened===W)return i.biBacktrace(h,a);c=h.x,f=h.y,d=a.g+(0===c-a.x||0===f-a.y?1:N),(!h.opened||dh;++h)if(a=s[h],!a.closed)if(a.opened){if(a.by===A)return n.biBacktrace(u,a)}else f.push(a),a.parent=u,a.opened=!0,a.by=b;for(u=d.shift(),u.closed=!0,s=o.getNeighbors(u,g,y),h=0,p=s.length;p>h;++h)if(a=s[h],!a.closed)if(a.opened){if(a.by===b)return n.biBacktrace(a,u)}else d.push(a),a.parent=u,a.opened=!0,a.by=A}return[]},e.exports=r},{"../core/Util":7}],13:[function(t,e){function r(t){n.call(this,t),this.heuristic=function(){return 0}}var n=t("./BiAStarFinder");r.prototype=new n,r.prototype.constructor=r,e.exports=r},{"./BiAStarFinder":10}],14:[function(t,e){function r(t){t=t||{},this.allowDiagonal=t.allowDiagonal,this.dontCrossCorners=t.dontCrossCorners}var n=t("../core/Util");r.prototype.findPath=function(t,e,r,i,o){var s,a,u,h,p,l=[],c=this.allowDiagonal,f=this.dontCrossCorners,d=o.getNodeAt(t,e),g=o.getNodeAt(r,i);for(l.push(d),d.opened=!0;l.length;){if(u=l.shift(),u.closed=!0,u===g)return n.backtrace(g);for(s=o.getNeighbors(u,c,f),h=0,p=s.length;p>h;++h)a=s[h],a.closed||a.opened||(l.push(a),a.opened=!0,a.parent=u)}return[]},e.exports=r},{"../core/Util":7}],15:[function(t,e){function r(t){n.call(this,t),this.heuristic=function(){return 0}}var n=t("./AStarFinder");r.prototype=new n,r.prototype.constructor=r,e.exports=r},{"./AStarFinder":8}],16:[function(t,e){function r(t){t=t||{},this.allowDiagonal=t.allowDiagonal,this.dontCrossCorners=t.dontCrossCorners,this.heuristic=t.heuristic||n.manhattan,this.weight=t.weight||1,this.trackRecursion=t.trackRecursion||!1,this.timeLimit=t.timeLimit||1/0}t("../core/Util");var n=t("../core/Heuristic"),i=t("../core/Node");r.prototype.findPath=function(t,e,r,n,o){var s,a,u,h=0,p=(new Date).getTime(),l=function(t,e){return this.heuristic(Math.abs(e.x-t.x),Math.abs(e.y-t.y))}.bind(this),c=function(t,e){return t.x===e.x||t.y===e.y?1:Math.SQRT2},f=function(t,e,r,n,s){if(h++,this.timeLimit>0&&(new Date).getTime()-p>1e3*this.timeLimit)return 1/0;var a=e+l(t,g)*this.weight;if(a>r)return a;if(t==g)return n[s]=[t.x,t.y],t;var u,d,y,b,A=o.getNeighbors(t,this.allowDiagonal,this.dontCrossCorners);for(y=0,u=1/0;b=A[y];++y){if(this.trackRecursion&&(b.retainCount=b.retainCount+1||1,b.tested!==!0&&(b.tested=!0)),d=f(b,e+c(t,b),r,n,s+1),d instanceof i)return n[s]=[t.x,t.y],d;this.trackRecursion&&0===--b.retainCount&&(b.tested=!1),u>d&&(u=d)}return u}.bind(this),d=o.getNodeAt(t,e),g=o.getNodeAt(r,n),y=l(d,g);for(s=0;!0;++s){if(a=[],u=f(d,0,y,a,0),1/0===u)return[];if(u instanceof i)return a;y=u}return[]},e.exports=r},{"../core/Heuristic":5,"../core/Node":6,"../core/Util":7}],17:[function(t,e){function r(t){t=t||{},this.heuristic=t.heuristic||o.manhattan,this.trackJumpRecursion=t.trackJumpRecursion||!1}var n=t("heap"),i=t("../core/Util"),o=t("../core/Heuristic");r.prototype.findPath=function(t,e,r,o,s){var a,u=this.openList=new n(function(t,e){return t.f-e.f}),h=this.startNode=s.getNodeAt(t,e),p=this.endNode=s.getNodeAt(r,o);for(this.grid=s,h.g=0,h.f=0,u.push(h),h.opened=!0;!u.empty();){if(a=u.pop(),a.closed=!0,a===p)return i.expandPath(i.backtrace(p));this._identifySuccessors(a)}return[]},r.prototype._identifySuccessors=function(t){var e,r,n,i,s,a,u,h,p,l,c=this.grid,f=this.heuristic,d=this.openList,g=this.endNode.x,y=this.endNode.y,b=t.x,A=t.y,k=Math.abs;for(Math.max,e=this._findNeighbors(t),i=0,s=e.length;s>i;++i)if(r=e[i],n=this._jump(r[0],r[1],b,A)){if(a=n[0],u=n[1],l=c.getNodeAt(a,u),l.closed)continue;h=o.euclidean(k(a-b),k(u-A)),p=t.g+h,(!l.opened||pa;++a)s=o[a],f.push([s.x,s.y]);return f},e.exports=r},{"../core/Heuristic":5,"../core/Util":7,heap:1}],18:[function(t,e){function r(t){t=t||{},this.allowDiagonal=t.allowDiagonal,this.dontCrossCorners=t.dontCrossCorners,this.heuristic=t.heuristic||o.manhattan}var n=t("heap"),i=t("../core/Util"),o=t("../core/Heuristic");r.prototype.findPath=function(t,e,r,o,s){var a,u,h,p,l,c,f,d,g=new n(function(t,e){return t.f-e.f}),y=s.getNodeAt(t,e),b=s.getNodeAt(r,o),A=this.heuristic,k=this.allowDiagonal,w=this.dontCrossCorners,v=Math.abs,m=Math.SQRT2;for(y.g=0,y.f=0,g.push(y),y.opened=!0;!g.empty();){if(a=g.pop(),a.closed=!0,a===b)return i.backtrace(b);u=s.getNeighbors(a,k,w);var x=u.length;for(p=0,l=u.length;l>p;++p)h=u[p],h.closed||(c=h.x,f=h.y,d=a.g+(0===c-a.x||0===f-a.y?1:m),(!h.opened||d} The path, including both start and + * end positions. + */ +TraceFinder.prototype.findPath = function(startX, startY, endX, endY, grid) { + + var openList = new Heap(function(nodeA, nodeB) { + return nodeA.f - nodeB.f; + }), + startNode = grid.getNodeAt(startX, startY), + endNode = grid.getNodeAt(endX, endY), + heuristic = this.heuristic, + allowDiagonal = this.allowDiagonal, + dontCrossCorners = this.dontCrossCorners, + abs = Math.abs, SQRT2 = Math.SQRT2, + node, neighbors, neighbor, i, l, x, y, ng; + + // set the `g` and `f` value of the start node to be 0 + startNode.g = 0; + startNode.f = 0; + + // push the start node into the open list + openList.push(startNode); + startNode.opened = true; + + // while the open list is not empty + while (!openList.empty()) { + // pop the position of node which has the minimum `f` value. + node = openList.pop(); + node.closed = true; + + // if reached the end position, construct the path and return it + if (node === endNode) { + return Util.backtrace(endNode); + } + + // get neigbours of the current node + neighbors = grid.getNeighbors(node, allowDiagonal, dontCrossCorners); + + var ar = neighbors.length; + + for (i = 0, l = neighbors.length; i < l; ++i) { + neighbor = neighbors[i]; + + if (neighbor.closed) { + continue; + } + + x = neighbor.x; + y = neighbor.y; + + // get the distance between current node and the neighbor + // and calculate the next g score + ng = node.g + ((x - node.x === 0 || y - node.y === 0) ? 1 : SQRT2); + + // check if the neighbor has not been inspected yet, or + // can be reached with smaller cost from the current node + if (!neighbor.opened || ng < neighbor.g) { + neighbor.g = ng * ar/9; //the trace magic + neighbor.h = neighbor.h || heuristic(abs(x - endX), abs(y - endY)); + neighbor.f = neighbor.g + neighbor.h; + neighbor.parent = node; + + if (!neighbor.opened) { + //openList.push(neighbor); + openList.push(neighbor); + neighbor.opened = true; + } else { + // the neighbor can be reached with smaller cost. + // Since its f value has been updated, we have to + // update its position in the open list + + //openList.updateItem(neighbor); + openList.updateItem(neighbor); + } + } + } // end for each neighbor + + } // end while not open list empty + + // fail to find the path + return []; +}; + +module.exports = TraceFinder; diff --git a/visual/index.html b/visual/index.html index b9b71c0c..408ba0cb 100644 --- a/visual/index.html +++ b/visual/index.html @@ -183,6 +183,31 @@

Options


+ +

Trace

+
+
+

Heuristic

+
+
+ +
+ +
+ +
+
+ +
+

Options

+
+
+ +
+ +
+
+
diff --git a/visual/js/panel.js b/visual/js/panel.js index f6ed6a56..b1633fbd 100644 --- a/visual/js/panel.js +++ b/visual/js/panel.js @@ -165,6 +165,25 @@ var Panel = { }); break; + + case 'trace_header': + allowDiagonal = typeof $('#trace_section ' + + '.allow_diagonal:checked').val() !== 'undefined'; + biDirectional = typeof $('#trace_section ' + + '.bi-directional:checked').val() !=='undefined'; + dontCrossCorners = typeof $('#trace_section ' + + '.dont_cross_corners:checked').val() !=='undefined'; + + heuristic = $('input[name=trace_heuristic]:checked').val(); + + finder = new PF.TraceFinder({ + allowDiagonal: allowDiagonal, + dontCrossCorners: dontCrossCorners, + heuristic: PF.Heuristic[heuristic] + }); + + break; + } return finder;