geohash-poly
Advanced tools
Comparing version 0.2.0 to 0.2.4
115
index.js
@@ -11,5 +11,4 @@ var Readable = require('stream').Readable, | ||
*/ | ||
var inside = function (point, features) { | ||
var geopoly = features.features[0], | ||
inside = 0; | ||
var inside = function (point, geopoly) { | ||
var inside = 0; | ||
@@ -39,4 +38,5 @@ if(geopoly.type !== "Polygon" && geopoly.type !== "MultiPolygon") return false; | ||
rowMode: false, | ||
geojson: [] | ||
} | ||
geojson: [], | ||
splitAt: 2000 | ||
}; | ||
options = options || {}; | ||
@@ -56,3 +56,3 @@ for (var attrname in defaults) { | ||
}); | ||
} | ||
}; | ||
require('util').inherits(Hasher, Readable); | ||
@@ -68,12 +68,12 @@ | ||
Hasher.prototype._read = function (size) { | ||
var self = this | ||
var self = this; | ||
var hashes = []; | ||
async.doUntil(function (callback) { | ||
async.whilst(function () { | ||
return !hashes.length && self.geojson.length; | ||
}, function (callback) { | ||
self.getNextRow(function (err, results) { | ||
hashes = results; | ||
hashes = results || []; | ||
callback(err); | ||
}); | ||
}, function () { | ||
return hashes.length || !self.geojson.length; | ||
}, function () { | ||
if(!self.geojson.length && !hashes.length) return self.push(null); | ||
@@ -90,8 +90,9 @@ if(self.rowMode) return self.push(hashes); | ||
* getNextRow() | ||
* will get the next row of geohashes for the current index-0 polygon in the list. | ||
* will get the next row of geohashes for the current length-1 polygon in the list. | ||
* only uses the current row bounds for checking pointinpoly | ||
* rowHash persists so that it is available on the next iteration while the poly is still the same | ||
*/ | ||
Hasher.prototype.getNextRow = function (next) { | ||
var self = this; | ||
Hasher.prototype.getNextRow = function (done) { | ||
var self = this, | ||
currentGeojson = self.geojson[self.geojson.length-1]; | ||
@@ -106,32 +107,65 @@ var makeRow = function () { | ||
columnHash = self.rowHash, | ||
columnCenter = geohash.decode(columnHash), | ||
rowBuffer = 0.0002, | ||
rowHashes = []; | ||
clipper = turf.polygon([[ | ||
[ self.bounding[1] - rowBuffer, rowBox[2] + rowBuffer], // nw | ||
[ self.bounding[3] + rowBuffer, rowBox[2] + rowBuffer], // ne | ||
[ self.bounding[3] + rowBuffer, rowBox[0] - rowBuffer], // se | ||
[ self.bounding[1] - rowBuffer, rowBox[0] - rowBuffer], //sw | ||
[ self.bounding[1] - rowBuffer, rowBox[2] + rowBuffer] //nw | ||
]]); | ||
var preparePoly = function (next) { | ||
// Detect poly length | ||
if(currentGeojson.geometry.coordinates[0].length >= self.splitAt) { | ||
turf.intersect(turf.featurecollection([clipper]), turf.featurecollection([self.geojson[0]]), function (err, intersection) { | ||
if(intersection && intersection.features.length) { | ||
var westerly = geohash.neighbor(geohash.encode(columnCenter.latitude, self.bounding[3], self.precision), [0, 1]); | ||
while (columnHash != westerly) { | ||
if(inside(columnCenter, intersection)) rowHashes.push(columnHash); | ||
columnHash = geohash.neighbor(columnHash, [0, 1]); | ||
columnCenter = geohash.decode(columnHash); | ||
} | ||
clipper = turf.polygon([[ | ||
[ self.bounding[1] - rowBuffer, rowBox[2] + rowBuffer], // nw | ||
[ self.bounding[3] + rowBuffer, rowBox[2] + rowBuffer], // ne | ||
[ self.bounding[3] + rowBuffer, rowBox[0] - rowBuffer], // se | ||
[ self.bounding[1] - rowBuffer, rowBox[0] - rowBuffer], //sw | ||
[ self.bounding[1] - rowBuffer, rowBox[2] + rowBuffer] //nw | ||
]]); | ||
turf.intersect(turf.featurecollection([clipper]), turf.featurecollection([currentGeojson]), function (err, intersection) { | ||
var prepare = null; | ||
if(intersection && intersection.features.length) { | ||
self.rowHash = geohash.neighbor(self.rowHash, [-1, 0]); | ||
// Calculate the row bounding and column hash based on the intersection | ||
var intersectionFeature = { type: 'Feature', geometry: intersection.features[0], properties: {} }; | ||
turf.extent(turf.featurecollection([intersectionFeature]), function (err, extent) { | ||
// extent = [minX, minY, maxX, maxY], remap to match geohash lib | ||
self.rowBounding = [extent[1], extent[0], extent[3], extent[2]]; | ||
var midY = self.rowBounding[0]+(self.rowBounding[2]-self.rowBounding[0])/2; | ||
columnHash = geohash.encode(midY, self.rowBounding[1], self.precision); | ||
next(err, intersection.features[0]); | ||
}); | ||
} else { | ||
next(null, currentGeojson.geometry); | ||
} | ||
}); | ||
if(rowBox[2] <= self.bounding[0]) { | ||
self.geojson.shift(); | ||
self.rowHash = null; | ||
self.bounding = null; | ||
} | ||
} else { | ||
next(null, currentGeojson.geometry); | ||
} | ||
next(null, rowHashes); | ||
}; | ||
preparePoly(function (err, prepared) { | ||
var columnCenter = geohash.decode(columnHash), | ||
westerly = geohash.neighbor(geohash.encode(columnCenter.latitude, self.rowBounding[3], self.precision), [0, 1]); | ||
while (columnHash != westerly) { | ||
if(inside(columnCenter, prepared)) rowHashes.push(columnHash); | ||
columnHash = geohash.neighbor(columnHash, [0, 1]); | ||
columnCenter = geohash.decode(columnHash); | ||
} | ||
var southNeighbour = geohash.neighbor(self.rowHash, [-1, 0]); | ||
// Check if the current rowHash was already the most southerly hash on the map. | ||
// Also check if we are at or past the bottom of the bounding box. | ||
if(southNeighbour === self.rowHash || rowBox[0] <= self.bounding[0]) { | ||
self.geojson.pop(); | ||
self.rowHash = null; | ||
self.bounding = null; | ||
self.rowBounding = null; | ||
} else { | ||
self.rowHash = southNeighbour; | ||
} | ||
done(null, rowHashes); | ||
}); | ||
@@ -141,7 +175,8 @@ }; | ||
if(!this.bounding) { | ||
turf.extent(turf.featurecollection([this.geojson[0]]), function (err, extent) { | ||
turf.extent(turf.featurecollection([currentGeojson]), function (err, extent) { | ||
// extent = [minX, minY, maxX, maxY], remap to match geohash lib | ||
self.bounding = [extent[1], extent[0], extent[3], extent[2]]; | ||
self.rowBounding = self.bounding.slice(0); | ||
makeRow(); | ||
}) | ||
}); | ||
} else { | ||
@@ -162,3 +197,3 @@ makeRow(); | ||
.on('end', function () { | ||
next(null, results) | ||
next(null, results); | ||
}) | ||
@@ -165,0 +200,0 @@ .pipe(through2.obj(function (arr, enc, callback) { |
{ | ||
"name": "geohash-poly", | ||
"version": "0.2.0", | ||
"version": "0.2.4", | ||
"description": "Transform a GeoJSON Polygon or MultiPolygon to a list of geohashes that form it.", | ||
@@ -23,3 +23,10 @@ "main": "index.js", | ||
"through2": "~0.4.0" | ||
}, | ||
"devDependencies": { | ||
"should": "~3.1.3", | ||
"mocha": "~1.17.1", | ||
"ldjson-stream": "0.0.1", | ||
"joe": "~1.4.0", | ||
"joe-reporter-console": "~1.2.1" | ||
} | ||
} |
@@ -54,1 +54,15 @@ # Geohash-poly | ||
``` | ||
---------- | ||
## Completely unscientific benchmarks | ||
These are just from running my machine, running the streaming example in rowMode. | ||
### v0.2.1 | ||
+ Modifications: only performs an intersection on the poly if there are > n points in the polygon. | ||
+ Runtime: 84.20s | ||
### v0.2.0 | ||
+ Split the operating polygon to only utilize its current row, defined by bounding box E/W and geohash N/S. | ||
+ Runtime: 83.01s |
Sorry, the diff of this file is too big to display
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
236180
10
735
67
5
1