4

In the example below I have a linestring PostGIS table (in black and yellow) and a single sided ST_Buffer output polygon (in red). The buffer distance is based on an attribute value stored in the linestring table.

As you can see one of the buffers is incorrect, and cuts a section of itself out for a certain amount of it. Why has this happened? Can it be fixed? Seems to be an issue where the linestring section becomes concave.

enter image description here

Try this for yourself using a similar query:

SELECT ST_BUFFER('LineString (638327 331059, 638337 331048, 638337 331037, 638343 331023, 638358 331014, 638380 330991, 638382 330978, 638391 330966, 638410 330959, 638420 330953)',50,'side=right')

In another example I'm seeing this happen (the black line is 1 feature, as is the buffer polygon):

enter image description here

And try this one with this:

SELECT ST_BUFFER('LineString (600296 172961, 600304 172962, 600307 172965, 600307 172969, 600307 172971, 600309 172974, 600308 172976, 600307 172979, 600306 172981, 600307 172982, 600311 172980, 600313 172979, 600317 172979, 600321 172982, 600325 172982, 600327 172979, 600328 172976, 600331 172974, 600338 172974)',10,'side=right')

Increase the buffer distances for stranger results. EPSG: 27700 in both cases.

7

These are caused by deficiencies in the single-sided buffer algorithm (not bugs, they are known limitations of the algorithm design).

This is logged as a GEOS issue. No ETA for a fix yet though.

5
  • Thanks for the link and updating that ticket with my examples. Perhaps a solution is to 1. Do a normal buffer of the line, 2. Split that output buffer poly by the line, 3. Delete the unwanted half of the buffer.
    – Theo F
    Aug 19 '20 at 7:37
  • @TheoF I've also think at this solution but there is two problems: 1) If you want to cut the normal buffer with your line then the endcap of your buffer need to be flat (otherwise the line will be too short to cut the buffer polygon), but unfortunately, buffer(geom,integer,'endcap=flat') also produce some unwanted spiky polygon if the buffer width is too big. 2) You could also extend both side of your line and then use this extended line to cut a "normal" buffer, it will works but only if the line extension do not self intersects the original line.
    – obchardon
    Aug 19 '20 at 9:15
  • @obchardon in my projects, the lines form a big circular coastlines of an island (GB), so the whole coastline eventually meets itself. The biggest challenge would be automatically removing the unwanted (left) side of the buffer... I could maybe shift the linestring 'left' a bit and use that to select the split buffer it intersects...
    – Theo F
    Aug 19 '20 at 11:23
  • @dr_jts this is also a problem with normal buffering but when using 'endcap=flat' or 'endcap=butt'
    – Theo F
    Aug 19 '20 at 22:53
  • 1
    Yes, there are some problems with non-round end caps.
    – dr_jts
    Aug 19 '20 at 23:11
0

I've created a workaround pipeline which fixes this issue. It does involve creating a few temporary intermediate tables along the way, but you can delete them on the fly.

  1. Buffer your line using ST_BUFFER normally, you will not have a chaotic output. (ie. Don't use the 'side=left/right' parameter).
  2. Use ST_Split to split the buffer from step 1 in half along the center using the line. ST_UNION the line with adjacent connecting lines! this will ensure the cutting line extends through and beyond the buffer. It won't cut anything otherwise.
  3. Buffer your line again but this time only buffer one side. This must be the side you don't want.
  4. Create a point table using ST_PointOnSurface for each 'wrong' side buffer shape.
  5. Use this new point table to delete any polygons from the split polygon buffer (from step 2) found intersecting the points.
  6. Now you are left with the full buffer shape with the 'wrong' side removed from it. ie. you are left with the desired correct side.

I have summed this up massively and assumed for each line segment you have an adjacent connecting line to help with cutting. I also did this for a coastline with 1000s of segments. So I used a host table to insert each iteration of the steps above into. To loop through each line segment I made sure the line table had an auto-incrementing id column (so for each line segment I could merge it with the segment before and after it: ie. n-1, n, n+1). I'll update this answer soon to clarify more.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.