l1-path-finder
Version:
Fast shortest path finder for grids
97 lines (80 loc) • 2.34 kB
JavaScript
var ndarray = require('ndarray')
var uniq = require('uniq')
var ops = require('ndarray-ops')
var prefixSum = require('ndarray-prefix-sum')
var getContour = require('contour-2d')
var orient = require('robust-orientation')[3]
module.exports = createGeometry
function Geometry(corners, grid) {
this.corners = corners
this.grid = grid
}
var proto = Geometry.prototype
proto.stabRay = function(vx, vy, x) {
return this.stabBox(vx, vy, x, vy)
}
proto.stabTile = function(x, y) {
return this.stabBox(x, y, x, y)
}
proto.integrate = function(x, y) {
if(x < 0 || y < 0) {
return 0
}
return this.grid.get(
Math.min(x, this.grid.shape[0]-1)|0,
Math.min(y, this.grid.shape[1]-1)|0)
}
proto.stabBox = function(ax, ay, bx, by) {
var lox = Math.min(ax, bx)
var loy = Math.min(ay, by)
var hix = Math.max(ax, bx)
var hiy = Math.max(ay, by)
var s = this.integrate(lox-1,loy-1)
- this.integrate(lox-1,hiy)
- this.integrate(hix,loy-1)
+ this.integrate(hix,hiy)
return s > 0
}
function comparePair(a, b) {
var d = a[0] - b[0]
if(d) { return d }
return a[1] - b[1]
}
function createGeometry(grid) {
var loops = getContour(grid.transpose(1,0))
//Extract corners
var corners = []
for(var k=0; k<loops.length; ++k) {
var polygon = loops[k]
for(var i=0; i<polygon.length; ++i) {
var a = polygon[(i+polygon.length-1)%polygon.length]
var b = polygon[i]
var c = polygon[(i+1)%polygon.length]
if(orient(a, b, c) > 0) {
var offset = [0,0]
for(var j=0; j<2; ++j) {
if(b[j] - a[j]) {
offset[j] = b[j] - a[j]
} else {
offset[j] = b[j] - c[j]
}
offset[j] = b[j]+Math.min(Math.round(offset[j]/Math.abs(offset[j]))|0, 0)
}
if(offset[0] >= 0 && offset[0] < grid.shape[0] &&
offset[1] >= 0 && offset[1] < grid.shape[1] &&
grid.get(offset[0], offset[1]) === 0) {
corners.push(offset)
}
}
}
}
//Remove duplicate corners
uniq(corners, comparePair)
//Create integral image
var img = ndarray(new Int32Array(grid.shape[0]*grid.shape[1]), grid.shape)
ops.gts(img, grid, 0)
prefixSum(img)
//Return resulting geometry
return new Geometry(corners, img)
}