geohash-poly
Advanced tools
Comparing version
102
index.js
var Readable = require('stream').Readable, | ||
geohash = require('ngeohash'), | ||
pip = require('point-in-polygon'), | ||
turf = require('turf'), | ||
turfExtent = require('turf-extent'), | ||
turfFeaturecollection = require('turf-featurecollection'), | ||
turfPolygon = require('turf-polygon'), | ||
turfIntersect = require('turf-intersect'), | ||
turf = { | ||
extent: turfExtent, | ||
featurecollection: turfFeaturecollection, | ||
polygon: turfPolygon, | ||
intersect: turfIntersect | ||
}, | ||
through2 = require('through2'), | ||
@@ -35,5 +44,7 @@ async = require('async'), | ||
var Hasher = function (options) { | ||
options = options || {}; | ||
var defaults = { | ||
precision: 6, | ||
precision: options.integerMode === true ? 32 : 6, | ||
rowMode: false, | ||
integerMode: false, | ||
geojson: [], | ||
@@ -44,3 +55,2 @@ splitAt: 2000, | ||
}; | ||
options = options || {}; | ||
for (var attrname in defaults) { | ||
@@ -55,2 +65,13 @@ this[attrname] = options.hasOwnProperty(attrname) && (options[attrname] !== null && typeof options[attrname] !== 'undefined') ? options[attrname] : defaults[attrname]; | ||
}); | ||
if (this.integerMode) { | ||
this.geohashEncode = geohash.encode_int; | ||
this.geohashDecode = geohash.decode_int; | ||
this.geohashDecodeBbox = geohash.decode_bbox_int; | ||
this.geohashNeighbor = geohash.neighbor_int; | ||
} else { | ||
this.geohashEncode = geohash.encode; | ||
this.geohashDecode = geohash.decode; | ||
this.geohashDecodeBbox = geohash.decode_bbox; | ||
this.geohashNeighbor = geohash.neighbor; | ||
} | ||
@@ -103,6 +124,6 @@ Readable.call(this, { | ||
if(!self.rowHash) { | ||
self.rowHash = geohash.encode(self.bounding[2], self.bounding[1], self.precision); | ||
self.rowHash = self.geohashEncode(self.bounding[2], self.bounding[1], self.precision); | ||
} | ||
var rowBox = geohash.decode_bbox(self.rowHash), | ||
var rowBox = self.geohashDecodeBbox(self.rowHash, self.precision), | ||
columnHash = self.rowHash, | ||
@@ -124,20 +145,16 @@ rowBuffer = 0.0002, | ||
turf.intersect(turf.featurecollection([clipper]), turf.featurecollection([currentGeojson]), function (err, intersection) { | ||
var prepare = null; | ||
if(intersection && intersection.features.length) { | ||
// 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); | ||
} | ||
}); | ||
var intersection = turf.intersect(turf.featurecollection([clipper]), turf.featurecollection([currentGeojson])); | ||
if(intersection && intersection.features.length) { | ||
// Calculate the row bounding and column hash based on the intersection | ||
var intersectionFeature = { type: 'Feature', geometry: intersection.features[0], properties: {} }; | ||
var extent = turf.extent(turf.featurecollection([intersectionFeature])); | ||
// 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 = self.geohashEncode(midY, self.rowBounding[1], self.precision); | ||
next(null, intersection.features[0]); | ||
} else { | ||
next(null, currentGeojson.geometry); | ||
} | ||
} else { | ||
@@ -150,4 +167,4 @@ next(null, currentGeojson.geometry); | ||
preparePoly(function (err, prepared) { | ||
var columnCenter = geohash.decode(columnHash), | ||
westerly = geohash.neighbor(geohash.encode(columnCenter.latitude, self.rowBounding[3], self.precision), [0, 1]); | ||
var columnCenter = self.geohashDecode(columnHash, self.precision), | ||
westerly = self.geohashNeighbor(self.geohashEncode(columnCenter.latitude, self.rowBounding[3], self.precision), [0, 1], self.precision); | ||
while (columnHash != westerly) { | ||
@@ -159,7 +176,7 @@ if(self.hashMode === 'inside' && inside(columnCenter, prepared)) { | ||
} | ||
columnHash = geohash.neighbor(columnHash, [0, 1]); | ||
columnCenter = geohash.decode(columnHash); | ||
columnHash = self.geohashNeighbor(columnHash, [0, 1], self.precision); | ||
columnCenter = self.geohashDecode(columnHash, self.precision); | ||
} | ||
var southNeighbour = geohash.neighbor(self.rowHash, [-1, 0]); | ||
var southNeighbour = self.geohashNeighbor(self.rowHash, [-1, 0], self.precision); | ||
@@ -183,3 +200,3 @@ // Check if the current rowHash was already the most southerly hash on the map. | ||
async.filter(rowHashes, function (h, cb) { | ||
var bb = geohash.decode_bbox(h); | ||
var bb = self.geohashDecodeBbox(h, self.precision); | ||
bb = turf.polygon([[ | ||
@@ -195,10 +212,9 @@ [bb[1], bb[2]], | ||
turf.intersect(turf.featurecollection([turf.polygon(prepared.coordinates)]), turf.featurecollection([bb]), function (err, intersected) { | ||
var keepIntersection = !self.threshold ? true : false; | ||
if(self.threshold && intersected.features.length && (intersected.features[0].type === 'Polygon' || intersected.features[0].type === 'MultiPolygon')) { | ||
var intersectedArea = geojsonArea.geometry(intersected.features[0]); | ||
keepIntersection = baseArea && intersectedArea / baseArea >= self.threshold; | ||
} | ||
cb(keepIntersection); | ||
}); | ||
var intersected = turf.intersect(turf.featurecollection([turf.polygon(prepared.coordinates)]), turf.featurecollection([bb])); | ||
var keepIntersection = !self.threshold ? true : false; | ||
if(self.threshold && intersected.features.length && (intersected.features[0].type === 'Polygon' || intersected.features[0].type === 'MultiPolygon')) { | ||
var intersectedArea = geojsonArea.geometry(intersected.features[0]); | ||
keepIntersection = baseArea && intersectedArea / baseArea >= self.threshold; | ||
} | ||
cb(keepIntersection); | ||
}, function (results) { | ||
@@ -213,8 +229,7 @@ done(null, results); | ||
if(!this.bounding) { | ||
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(); | ||
}); | ||
var extent = turf.extent(turf.featurecollection([currentGeojson])); | ||
// 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 { | ||
@@ -254,2 +269,3 @@ makeRow(); | ||
rowMode: options.rowMode ? true : false, | ||
integerMode: options.integerMode ? true : false, | ||
hashMode: options.hashMode, | ||
@@ -256,0 +272,0 @@ threshold: options.threshold |
{ | ||
"name": "geohash-poly", | ||
"version": "0.4.1", | ||
"version": "0.5.2", | ||
"description": "Transform a GeoJSON Polygon or MultiPolygon to a list of geohashes that form it.", | ||
@@ -21,7 +21,10 @@ "main": "index.js", | ||
"geojson-area": "^0.1.0", | ||
"ngeohash": "~0.2.0", | ||
"ngeohash": "0.6.0", | ||
"point-in-polygon": "0.0.0", | ||
"rc": "^0.6.0", | ||
"through2": "~0.4.0", | ||
"turf": "0.0.119" | ||
"turf-extent": "1.0.4", | ||
"turf-featurecollection": "1.0.1", | ||
"turf-intersect": "1.0.2", | ||
"turf-polygon": "1.0.3" | ||
}, | ||
@@ -28,0 +31,0 @@ "devDependencies": { |
@@ -57,2 +57,26 @@ # Geohash-poly | ||
Also, integer geohashes are available. | ||
```javascript | ||
geohashpoly({coords: polygon, precision: 34, integerMode: true}, function (err, hashes) { | ||
console.log(hashes); | ||
}); | ||
``` | ||
Results in: | ||
``` | ||
[ 5940702973, | ||
5940702975, | ||
5941052501, | ||
5940702972, | ||
5940702974, | ||
5941052500, | ||
5940702969, | ||
5940702971, | ||
5941052497, | ||
5940702968, | ||
5940702970, | ||
5941052496 ] | ||
``` | ||
## Options | ||
@@ -64,5 +88,5 @@ | ||
- `hashMode`: defines filtering of returned geohashes. See below. | ||
- `integerMode`: (true/false) Outputs integer versions of geohashes. Default precision for integer mode is 32 bits. | ||
## hashMode | ||
@@ -69,0 +93,0 @@ |
@@ -20,3 +20,4 @@ var hasher = require('../index'), | ||
async.timesSeries(geojson.properties.maxPrecision, function (n, next) { | ||
var precision = n + 1; | ||
var precision = n + 1, | ||
integerPrecision = precision * 5; | ||
var options = { | ||
@@ -42,2 +43,21 @@ coords: geojson.geometry.coordinates, | ||
}); | ||
if (integerPrecision % 2 == 0) { // https://github.com/sunng87/node-geohash says: "Bit depth must be even." | ||
it('should geohash ' + geojson.properties.comment + ' shape. Precision ' + integerPrecision + '. hashMode "extent" and integerMode true.', function (done) { | ||
options.integerMode = true; | ||
options.precision = integerPrecision; | ||
hasher(options, function (err, hashes) { | ||
should.not.exist(err); | ||
hashes.length.should.equal(geojson.properties.expectedExtent[n]); | ||
done(); | ||
}); | ||
}); | ||
it('should geohash ' + geojson.properties.comment + ' shape. Precision ' + integerPrecision + '. hashMode "inside" and integerMode true.', function (done) { | ||
options.hashMode = 'inside'; | ||
hasher(options, function (err, hashes) { | ||
should.not.exist(err); | ||
hashes.length.should.equal(geojson.properties.expectedInside[n]); | ||
done(); | ||
}); | ||
}); | ||
} | ||
next(); | ||
@@ -44,0 +64,0 @@ }, function (err) { |
245287
1.02%910
4.24%121
24.74%10
42.86%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated