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

buffer endcap and join strategies #639

Open
dhivehi opened this issue Apr 2, 2017 · 5 comments
Open

buffer endcap and join strategies #639

dhivehi opened this issue Apr 2, 2017 · 5 comments

Comments

@dhivehi
Copy link
Collaborator

dhivehi commented Apr 2, 2017

Currently turf buffer seems to support "end_round" as end strategy and "join_round" as join strategy. It would be nice if your can provide the strategies as follows:

  • For join strategies, 'join_round' and 'join_miter'.
  • For end strategies, 'end_round' and 'end_flat'.

More ref: https://dev.mysql.com/doc/refman/5.7/en/spatial-operator-functions.html#function_st-buffer-strategy

@rowanwins
Copy link
Member

Thanks for the suggestions @dhivehi

Currently the buffer module is a wrapper around jsts and we're trying to remove this dependency. Once we've done that hopefully we'll be in a better position to implement those additional suggestions.

Cheers

@DenisCarriere DenisCarriere added this to the 5.0.0 milestone Apr 8, 2017
@morganherlocker morganherlocker changed the title Requesting for more strategies in turf buffer buffer endcap and join strategies Jun 5, 2017
@nboisteault
Copy link

👍

@stebogit stebogit modified the milestones: 5.0.0, 5.1.0 Nov 8, 2017
@DenisCarriere DenisCarriere modified the milestones: 5.1.0, 5.2.0 Nov 21, 2017
@bartvde
Copy link

bartvde commented Nov 1, 2019

Are there any plans for incorporating this into turf? I recently did this by using mainstream jsts instead of the turf ES6 fork of JSTS, and passing in the endCap here:

  // 2 is endCap flat
  let buffered = BufferOp.bufferOp(geom, distance, undefined, 2);

but it required copying some of the turf buffer code to achieve it.

Any guidance appreciated. Are you open for PRs to change to mainstream jsts and add this to the buffer operation? Or what would be a good strategy?

@oli-clive-griffin
Copy link

@bartvde long shot but are you able to remember how using jsts went? I'm really needing a mitre join buffer in js and this is looking like one of the best options

@axekan
Copy link

axekan commented Apr 24, 2024

For those wanting to use this right now using jsts, you can use patch-package to add the required changes to 6.5.0 until support for this gets added.

Below is the patch file I used. With these changes you can run :

buffer(feature, 100, { units: 'meters', joinStyle: 'mitre' })

The documentation for the parameters can be found in the docs for the java library https://locationtech.github.io/jts/javadoc/.
I'm unsure what the purpose of the steps parameter was in the original version, but I used it as the 'Quadrant segments' parameter in BufferParameters.

diff --git a/node_modules/@turf/buffer/dist/es/index.js b/node_modules/@turf/buffer/dist/es/index.js
index 0ba5731..efe8a35 100644
--- a/node_modules/@turf/buffer/dist/es/index.js
+++ b/node_modules/@turf/buffer/dist/es/index.js
@@ -1,9 +1,22 @@
 import center from '@turf/center';
 import { GeoJSONReader, BufferOp, GeoJSONWriter } from 'turf-jsts';
+import { BufferParameters } from 'turf-jsts/src/org/locationtech/jts/operation/buffer';
 import { featureEach, geomEach } from '@turf/meta';
 import { geoAzimuthalEquidistant } from 'd3-geo';
 import { featureCollection, earthRadius, radiansToLength, lengthToRadians, feature } from '@turf/helpers';
 
+const endCap = {
+  round: BufferParameters.CAP_ROUND,
+  flat: BufferParameters.CAP_FLAT,
+  square: BufferParameters.CAP_SQUARE,
+};
+
+const join = {
+  round: BufferParameters.JOIN_ROUND,
+  mitre: BufferParameters.JOIN_MITRE,
+  bevel: BufferParameters.JOIN_BEVEL,
+};
+
 /**
  * Calculates a buffer for input features for a given radius. Units supported are miles, kilometers, and degrees.
  *
@@ -19,6 +32,9 @@ import { featureCollection, earthRadius, radiansToLength, lengthToRadians, featu
  * @param {Object} [options={}] Optional parameters
  * @param {string} [options.units="kilometers"] any of the options supported by turf units
  * @param {number} [options.steps=8] number of steps
+ * @param {string} [options.endCapStyle="round"] the end cap style to use
+ * @param {string} [options.joinStyle="round"] the join style to use
+ * @param {number} [options.mitreLimit=10] the limit on the mitre ratio used for very sharp corners
  * @returns {FeatureCollection|Feature<Polygon|MultiPolygon>|undefined} buffered features
  * @example
  * var point = turf.point([-90.548630, 14.616599]);
@@ -34,6 +50,9 @@ function buffer(geojson, radius, options) {
   // use user supplied options or default values
   var units = options.units || "kilometers";
   var steps = options.steps || 8;
+  var endCapStyle = endCap[options.endCapStyle || "round"];
+  var joinStyle = join[options.joinStyle || "round"];
+  var mitreLimit = options.mitreLimit || 10;
 
   // validation
   if (!geojson) throw new Error("geojson is required");
@@ -48,13 +67,13 @@ function buffer(geojson, radius, options) {
   switch (geojson.type) {
     case "GeometryCollection":
       geomEach(geojson, function (geometry) {
-        var buffered = bufferFeature(geometry, radius, units, steps);
+        var buffered = bufferFeature(geometry, radius, units, steps, endCapStyle, joinStyle, mitreLimit);
         if (buffered) results.push(buffered);
       });
       return featureCollection(results);
     case "FeatureCollection":
       featureEach(geojson, function (feature) {
-        var multiBuffered = bufferFeature(feature, radius, units, steps);
+        var multiBuffered = bufferFeature(feature, radius, units, steps, endCapStyle, joinStyle, mitreLimit);
         if (multiBuffered) {
           featureEach(multiBuffered, function (buffered) {
             if (buffered) results.push(buffered);
@@ -63,7 +82,7 @@ function buffer(geojson, radius, options) {
       });
       return featureCollection(results);
   }
-  return bufferFeature(geojson, radius, units, steps);
+  return bufferFeature(geojson, radius, units, steps, endCapStyle, joinStyle, mitreLimit);
 }
 
 /**
@@ -76,7 +95,7 @@ function buffer(geojson, radius, options) {
  * @param {number} [steps=8] number of steps
  * @returns {Feature<Polygon|MultiPolygon>} buffered feature
  */
-function bufferFeature(geojson, radius, units, steps) {
+function bufferFeature(geojson, radius, units, steps, endCapStyle, joinStyle, mitreLimit) {
   var properties = geojson.properties || {};
   var geometry = geojson.type === "Feature" ? geojson.geometry : geojson;
 
@@ -84,7 +103,7 @@ function bufferFeature(geojson, radius, units, steps) {
   if (geometry.type === "GeometryCollection") {
     var results = [];
     geomEach(geojson, function (geometry) {
-      var buffered = bufferFeature(geometry, radius, units, steps);
+      var buffered = bufferFeature(geometry, radius, units, steps, endCapStyle, joinStyle, mitreLimit);
       if (buffered) results.push(buffered);
     });
     return featureCollection(results);
@@ -101,7 +120,9 @@ function bufferFeature(geojson, radius, units, steps) {
   var reader = new GeoJSONReader();
   var geom = reader.read(projected);
   var distance = radiansToLength(lengthToRadians(radius, units), "meters");
-  var buffered = BufferOp.bufferOp(geom, distance, steps);
+  var bufferParams = new BufferParameters(steps, endCapStyle, joinStyle, mitreLimit);
+  var bufferOp = new BufferOp(geom, bufferParams);
+  var buffered = bufferOp.getResultGeometry(distance);
   var writer = new GeoJSONWriter();
   buffered = writer.write(buffered);
 
diff --git a/node_modules/@turf/buffer/index.d.ts b/node_modules/@turf/buffer/index.d.ts
index 825769b..551ad90 100644
--- a/node_modules/@turf/buffer/index.d.ts
+++ b/node_modules/@turf/buffer/index.d.ts
@@ -15,6 +15,9 @@ import {
 interface Options {
   units?: Units;
   steps?: number;
+  endCapStyle?: "round" | "flat" | "square";
+  joinStyle?: "round" | "mitre" | "bevel";
+  mitreLimit?: number;
 }
 
 /**

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants