Skip to content

Commit

Permalink
buffer units other than degrees #283
Browse files Browse the repository at this point in the history
  • Loading branch information
DenisCarriere committed Apr 15, 2017
1 parent fdceb1e commit 78d2014
Show file tree
Hide file tree
Showing 17 changed files with 5,391 additions and 3,463 deletions.
17 changes: 9 additions & 8 deletions packages/turf-buffer/bench.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ const fixtures = fs.readdirSync(directory).map(filename => {
/**
* Benchmark Results
*
* feature-collection-points x 3,792 ops/sec ±10.41% (82 runs sampled)
* geometry-collection-points x 4,346 ops/sec ±2.05% (90 runs sampled)
* linestring x 9,087 ops/sec ±2.14% (89 runs sampled)
* multi-linestring x 1,145 ops/sec ±9.46% (80 runs sampled)
* multi-point x 4,898 ops/sec ±4.73% (78 runs sampled)
* multi-polygon x 1,737 ops/sec ±9.31% (66 runs sampled)
* point x 11,907 ops/sec ±8.10% (72 runs sampled)
* polygon-with-holes x 6,417 ops/sec ±6.16% (79 runs sampled)
* feature-collection-points x 9,335 ops/sec ±1.37% (88 runs sampled)
* geometry-collection-points x 9,505 ops/sec ±1.57% (86 runs sampled)
* linestring x 7,977 ops/sec ±17.93% (75 runs sampled)
* multi-linestring x 1,371 ops/sec ±2.00% (88 runs sampled)
* multi-point x 515 ops/sec ±3.35% (85 runs sampled)
* multi-polygon x 2,549 ops/sec ±3.03% (88 runs sampled)
* north-latitude-points x 812 ops/sec ±2.31% (88 runs sampled)
* point x 42,867 ops/sec ±1.38% (89 runs sampled)
* polygon-with-holes x 7,397 ops/sec ±1.93% (88 runs sampled)
*/
const suite = new Benchmark.Suite('turf-buffer');
for (const {name, geojson} of fixtures) {
Expand Down
99 changes: 68 additions & 31 deletions packages/turf-buffer/index.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
// http://stackoverflow.com/questions/839899/how-do-i-calculate-a-point-on-a-circles-circumference
// radians = degrees * (pi/180)
// https://github.com/bjornharrtell/jsts/blob/master/examples/buffer.html

var jsts = require('jsts');
var helpers = require('@turf/helpers');
var circle = require('@turf/circle');
var dissolve = require('@turf/dissolve');
var meta = require('@turf/meta');
var coordEach = meta.coordEach;
var featureEach = meta.featureEach;
var featureCollection = helpers.featureCollection;
var jsts = require('jsts');
var normalize = require('@mapbox/geojson-normalize');
var distanceToDegrees = helpers.distanceToDegrees;
var point = helpers.point;

/**
* Calculates a buffer for input features for a given radius. Units supported are miles, kilometers, and degrees.
*
* @name buffer
* @param {(Feature|FeatureCollection)} feature input to be buffered
* @param {FeatureCollection|Feature<any>} feature input to be buffered
* @param {number} radius distance to draw the buffer
* @param {string} units any of the options supported by turf units
* @return {FeatureCollection<Polygon>|FeatureCollection<MultiPolygon>|Polygon|MultiPolygon} buffered features
* @param {string} [units=kilometers] any of the options supported by turf units
* @param {number} [steps=64] number of steps
* @return {FeatureCollection|Feature<Polygon|MultiPolygon>} buffered features
* @example
* var pt = {
* var point = {
* "type": "Feature",
* "properties": {},
* "geometry": {
Expand All @@ -26,33 +29,67 @@ var normalize = require('@mapbox/geojson-normalize');
* };
* var unit = 'miles';
*
* var buffered = turf.buffer(pt, 500, unit);
* var buffered = turf.buffer(point, 500, unit);
*
* //addToMap
* var addToMap = [pt, buffered]
* var addToMap = [point, buffered]
*/

module.exports = function (feature, radius, units) {
module.exports = function (geojson, radius, units, steps) {
if (radius === undefined || radius === null) throw new Error('radius is required');
steps = steps || 64;

var degrees = helpers.distanceToDegrees(radius, units);
var fc = normalize(feature);
var buffered = normalize(featureCollection(fc.features.map(function (f) {
return bufferOp(f, degrees);
})));
switch (geojson.type) {
case 'GeometryCollection':
case 'FeatureCollection':
var results = [];
var features = (geojson.features) ? geojson.features : geojson.geometries || [];

if (buffered.features.length > 1) return buffered;
else if (buffered.features.length === 1) return buffered.features[0];
features.forEach(function (feature) {
featureEach(buffer(feature, radius, units, steps), function (buffered) {
results.push(buffered);
});
});
return featureCollection(results);
}
return buffer(geojson, radius, units, steps);
};

function bufferOp(feature, radius) {
var reader = new jsts.io.GeoJSONReader();
var geom = reader.read(feature.geometry);
var buffered = geom.buffer(radius);
var writer = new jsts.io.GeoJSONWriter();
buffered = writer.write(buffered);
/**
* Buffer single Feature
*
* @private
* @param {Feature<any>} feature input to be buffered
* @param {number} radius distance to draw the buffer
* @param {string} [units='kilometers'] any of the options supported by turf units
* @param {number} [steps=64] number of steps
* @returns {Feature<Polygon|MultiPolygon>} buffered feature
*/
function buffer(feature, radius, units, steps) {
var properties = feature.properties || {};
var distance = distanceToDegrees(radius, units);
var geometry = (feature.type === 'Feature') ? feature.geometry : feature;

return {
type: 'Feature',
geometry: buffered,
properties: {}
};
switch (geometry.type) {
case 'Point':
return circle(feature, radius, steps, units);
case 'MultiPoint':
var polys = [];
coordEach(feature, function (coord) {
polys.push(circle(point(coord, properties), radius, steps, units));
});
return dissolve(featureCollection(polys));
case 'LineString':
case 'MultiLineString':
case 'Polygon':
case 'MultiPolygon':
var reader = new jsts.io.GeoJSONReader();
var geom = reader.read(geometry);
var buffered = geom.buffer(distance);
var writer = new jsts.io.GeoJSONWriter();
buffered = writer.write(buffered);
return helpers.feature(buffered, properties);
default:
throw new Error('geometry type ' + geometry.type + ' not supported');
}
}
9 changes: 7 additions & 2 deletions packages/turf-buffer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
"turf"
],
"author": "Turf Authors",
"contributors": [
"Tom MacWright <@tmcw>",
"Denis Carriere <@DenisCarriere>"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/Turfjs/turf/issues"
Expand All @@ -39,9 +43,10 @@
"write-json-file": "^2.0.0"
},
"dependencies": {
"@mapbox/geojson-normalize": "0.0.1",
"@turf/combine": "^4.1.0",
"@turf/circle": "^4.1.0",
"@turf/dissolve": "^4.1.0",
"@turf/helpers": "^4.1.0",
"@turf/meta": "^4.1.0",
"jsts": "1.3.0"
}
}
9 changes: 8 additions & 1 deletion packages/turf-buffer/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const path = require('path');
const load = require('load-json-file');
const write = require('write-json-file');
const truncate = require('@turf/truncate');
const featureEach = require('@turf/meta').featureEach;
const featureCollection = require('@turf/helpers').featureCollection;
const buffer = require('./');

const directories = {
Expand All @@ -25,7 +27,12 @@ test('turf-buffer', function (t) {
radius = radius || 50;
units = units || 'miles';

const results = truncate(buffer(geojson, radius, units, padding));
const buffered = truncate(buffer(geojson, radius, units, padding));

// Add Results to FeatureCollection
const results = featureCollection([]);
featureEach(buffered, feature => results.features.push(feature));
featureEach(geojson, feature => results.features.push(feature));

if (process.env.REGEN) write.sync(directories.out + filename, results);
t.deepEqual(results, load.sync(directories.out + filename), name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
"features": [
{
"type": "Feature",
"properties": {
"foo": "bar"
},
"properties": {},
"geometry": {
"type": "MultiPoint",
"coordinates": [
Expand Down
4 changes: 3 additions & 1 deletion packages/turf-buffer/test/in/linestring.geojson
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"type": "Feature",
"properties": {},
"properties": {
"foo": "bar"
},
"geometry": {
"type": "LineString",
"coordinates": [
Expand Down
4 changes: 3 additions & 1 deletion packages/turf-buffer/test/in/multi-point.geojson
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"type": "Feature",
"properties": {},
"properties": {
"radius": 300
},
"geometry": {
"type": "MultiPoint",
"coordinates": [
Expand Down
4 changes: 3 additions & 1 deletion packages/turf-buffer/test/in/point.geojson
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"type": "Feature",
"properties": {},
"properties": {
"foo": "bar"
},
"geometry": {
"type": "Point",
"coordinates": [
Expand Down
Loading

0 comments on commit 78d2014

Please sign in to comment.