Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace jsts @turf/buffer #674

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions packages/turf-buffer/bench.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,19 @@ const fixtures = fs.readdirSync(directory).map(filename => {
/**
* Benchmark Results
*
* ==polygon-offset:after==
* feature-collection-points x 9,876 ops/sec ±0.88% (89 runs sampled)
* geometry-collection-points x 9,919 ops/sec ±0.90% (91 runs sampled)
* linestring x 219 ops/sec ±1.37% (83 runs sampled)
* multi-linestring x 61.91 ops/sec ±4.88% (64 runs sampled)
* multi-point x 995 ops/sec ±24.51% (82 runs sampled)
* multi-polygon x 42.77 ops/sec ±0.92% (56 runs sampled)
* north-latitude-points x 842 ops/sec ±1.23% (91 runs sampled)
* northern-polygon x 236 ops/sec ±1.83% (83 runs sampled)
* point x 43,814 ops/sec ±1.19% (94 runs sampled)
* polygon-with-holes x 79.33 ops/sec ±16.13% (65 runs sampled)
*
* ==jsts:before ==
* 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)
Expand Down
56 changes: 34 additions & 22 deletions packages/turf-buffer/index.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
var jsts = require('jsts');
var helpers = require('@turf/helpers');
var meta = require('@turf/meta');
var Offset = require('polygon-offset');
var circle = require('@turf/circle');
var helpers = require('@turf/helpers');
var dissolve = require('@turf/dissolve');
var meta = require('@turf/meta');
var getCoords = require('@turf/invariant').getCoords;
var point = helpers.point;
var polygon = helpers.polygon;
var coordEach = meta.coordEach;
var featureEach = meta.featureEach;
var featureCollection = helpers.featureCollection;
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 {FeatureCollection|Feature<any>} feature input to be buffered
* @param {FeatureCollection|Geometry|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
Expand All @@ -37,6 +39,7 @@ var point = helpers.point;

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

// default params
Expand All @@ -62,41 +65,50 @@ module.exports = function (geojson, radius, units, steps) {
* Buffer single Feature
*
* @private
* @param {Feature<any>} feature input to be buffered
* @param {Geometry|Feature<any>} geojson 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 || {};
function buffer(geojson, radius, units, steps) {
// validation
if (!geojson) throw new Error('geojson is required');
if (radius === undefined || radius === null) throw new Error('radius is required');
if (steps <= 0) throw new Error('steps must be greater than 0');

// prevent input mutation
geojson = JSON.parse(JSON.stringify(geojson));

// default params
var properties = geojson.properties || {};
var distance = distanceToDegrees(radius, units);
var geometry = (feature.type === 'Feature') ? feature.geometry : feature;
var coords = getCoords(geojson);
var type = (geojson.geometry) ? geojson.geometry.type : geojson.type;

switch (geometry.type) {
switch (type) {
case 'Point':
var poly = circle(feature, radius, steps, units);
poly.properties = properties;
return poly;
var pointBuffer = circle(coords, radius, steps, units);
pointBuffer.properties = properties;
return pointBuffer;
case 'MultiPoint':
var polys = [];
coordEach(feature, function (coord) {
coordEach(geojson, function (coord) {
var poly = circle(point(coord, properties), radius, steps, units);
poly.properties = properties;
polys.push(poly);
});
return dissolve(featureCollection(polys));
case 'LineString':
case 'MultiLineString':
var lineOffset = new Offset(coords, steps);
var lineBuffer = lineOffset.offsetLine(distance);
return polygon(lineBuffer, properties);
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');
// Polygon-offset has issues when arcSegments is greater than 32
var polyOffset = new Offset(coords, (steps > 32) ? 32 : steps);
var polyBuffer = polyOffset.margin(distance);
return polygon(polyBuffer, properties);
}
}
3 changes: 2 additions & 1 deletion packages/turf-buffer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
"@turf/circle": "^4.2.0",
"@turf/dissolve": "^4.2.0",
"@turf/helpers": "^4.2.0",
"@turf/invariant": "^4.2.0",
"@turf/meta": "^4.2.0",
"jsts": "1.3.0"
"polygon-offset": "^0.3.1"
}
}
39 changes: 34 additions & 5 deletions packages/turf-buffer/test.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
const test = require('tape');
const fs = require('fs');
const test = require('tape');
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 {featureEach} = require('@turf/meta');
const {featureCollection, point, polygon} = require('@turf/helpers');
const buffer = require('./');

const directories = {
in: path.join(__dirname, 'test', 'in') + path.sep,
out: path.join(__dirname, 'test', 'out') + path.sep
};

const fixtures = fs.readdirSync(directories.in).map(filename => {
let fixtures = fs.readdirSync(directories.in).map(filename => {
return {
filename,
name: path.parse(filename).name,
geojson: load.sync(directories.in + filename)
};
});
// fixtures = fixtures.filter(({name}) => name === 'northern-polygon');

test('turf-buffer', function (t) {
test('turf-buffer', t => {
for (const {filename, name, geojson} of fixtures) {
let {radius, units, padding} = geojson.properties || {};
radius = radius || 50;
Expand All @@ -39,3 +40,31 @@ test('turf-buffer', function (t) {
}
t.end();
});

test('turf-buffer - Support Geometry Objects', t => {
const pt = point([61, 5]);
const poly = polygon([[[11, 0], [22, 4], [31, 0], [31, 11], [21, 15], [11, 11], [11, 0]]]);

t.assert(buffer(pt.geometry, 10));
t.assert(buffer(poly.geometry, 10));
t.end();
});

test('turf-buffer - Prevent Input Mutation', t => {
const pt = point([61, 5]);
const poly = polygon([[[11, 0], [22, 4], [31, 0], [31, 11], [21, 15], [11, 11], [11, 0]]]);
const collection = featureCollection([pt, poly]);

const beforePt = JSON.parse(JSON.stringify(pt));
const beforePoly = JSON.parse(JSON.stringify(poly));
const beforeCollection = JSON.parse(JSON.stringify(collection));

buffer(pt, 10);
buffer(poly, 10);
buffer(collection, 10);

t.deepEqual(pt, beforePt, 'pt should not mutate');
t.deepEqual(poly, beforePoly, 'poly should not mutate');
t.deepEqual(collection, beforeCollection, 'collection should not mutate');
t.end();
});
Loading