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 units other than degrees #283

Closed
SirenHound opened this issue Sep 29, 2015 · 6 comments
Closed

buffer units other than degrees #283

SirenHound opened this issue Sep 29, 2015 · 6 comments
Labels

Comments

@SirenHound
Copy link

Am I missing something or does the buffer function just change all units to degrees at the equator and then buffer the geoJSON by degrees regardless of its latitude?

@stevevance
Copy link

The same happens to me.
It looks like this in Chicago (which is 41 degrees north):
screenshot 2015-09-30 19 39 58

@SirenHound
Copy link
Author

I'm glad it's not just me.
I wrote a patch, if people are happy with it I can try a pull request, using the GeoJSON as a proxy does seem a little kludgy to me, but it saves rewriting functions down the rabbit hole.
This should solve the latitude issue for locally sized shapes (buffers for points far from the offset longitude become skewed).
Uses a sphere, better use would be an oblate spheroid but that's a little more complicated, this at least moves in the right direction.

Constructive criticism appreciated.
Starting from line 2528 in turf.js:

module.exports = function(feature, radius, units){
  var buffered;
  var unitsPerDegree;

  switch(units){
    case 'miles':
      //radius = radius / 69.047;
      unitsPerDegree = 7917.5 * Math.PI / 180;
      break
    case 'feet':
      //radius = radius / 364568.0;
      unitsPerDegree = 41804000 * Math.PI / 180;
      break
    case 'kilometers':
    case 'kilometres':
      //radius = radius / 111.12;
      unitsPerDegree = 6371 * Math.PI / 180;
      break
    case 'meters':
    case 'metres':
      //radius = radius / 111120.0;
      unitsPerDegree = 6371000 * Math.PI / 180;
      break
    case 'degrees':
      unitsPerDegree = 1;
      break
  }


  if(feature.type === 'FeatureCollection'){
    var feature = combine(feature);
    feature.properties = {};
  }

  //create fake GeoJSON object with projected 'lnglats' to use with bufferOp
  var newLnglats = [];
  var lnglats = feature.geometry.coordinates[0];
  var lngOffset = lnglats[0][0]; //offset projection to minimize skewed buffers (will not work for global scale polygons)
  console.log(lngOffset, "offset");
  for (var i = 0; i < lnglats.length; i++){
    var x = (lnglats[i][0] - lngOffset) * Math.cos(lnglats[i][1]*Math.PI/180) * unitsPerDegree;
    var y = lnglats[i][1] * unitsPerDegree;
    newLnglats.push([x,y]);
  }
  var fakeGeoJSON = {type:"Feature", geometry: {type: "Polygon", coordinates:[newLnglats]}};

  buffered = bufferOp(fakeGeoJSON, radius);

  //put object back on sphere
  newBufferLnglats = [];
  bufferLnglats = buffered.features[0].geometry.coordinates[0];

  for (i = 0; i < bufferLnglats.length; i++){
    var lat = bufferLnglats[i][1] / unitsPerDegree;
    var lng = lngOffset + bufferLnglats[i][0] / Math.cos(lat*Math.PI/180) / unitsPerDegree;
    console.log("lng",lng);
    newBufferLnglats.push([lng, lat]);
  }
  buffered.features[0].geometry.coordinates[0] = newBufferLnglats;
    console.log(buffered.features[0].geometry.coordinates[0]);

  return buffered;

};

@SirenHound SirenHound reopened this Oct 1, 2015
@SirenHound
Copy link
Author

Actually, it just occurred to me that the above will only work for polygons (my use case), it may need additional checks for points etc

@SirenHound
Copy link
Author

For a single point you'd change this:

  //create fake GeoJSON object with projected 'lnglats' to use with bufferOp
  var newLnglats = [];
  var lnglats = feature.geometry.coordinates[0];

to this:

  //create fake GeoJSON object with projected 'lnglats' to use with bufferOp
  var newLnglats = [];
  var lnglats = [feature.geometry.coordinates];

You could set up a switch from feature.geometry.type if you like.

@DenisCarriere DenisCarriere added this to the 5.0.0 milestone Apr 10, 2017
@DenisCarriere
Copy link
Member

DenisCarriere commented Apr 10, 2017

This is still occurring in the current @turf/buffer module.

This could be fixed by using @turf/circle + @turf/dissolve (not implemented yet).

test/out/north-latitude-points.geojson
image

@DenisCarriere DenisCarriere modified the milestones: 4.2.0, 5.0.0 Apr 15, 2017
DenisCarriere added a commit that referenced this issue Apr 16, 2017
* buffer units other than degrees #283

* Translate properties

* Update typescript definition
@DenisCarriere DenisCarriere removed this from the 4.2.0 milestone Apr 17, 2017
@DenisCarriere
Copy link
Member

Duplicate issue, tracking issue here: #660

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

No branches or pull requests

3 participants