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

SingleSided buffer shows artifacts #665

Closed
hmundle opened this issue Aug 22, 2022 · 8 comments
Closed

SingleSided buffer shows artifacts #665

hmundle opened this issue Aug 22, 2022 · 8 comments
Assignees

Comments

@hmundle
Copy link

hmundle commented Aug 22, 2022

When I want to create a single sided buffer, GEOS shows strange result even for easy line inputs.

This is my input (geom): LINESTRING (50 50, 150 150, 150 100, 150 0)
image

This is my implementation:

geos::operation::buffer::BufferParameters bp;
bp.setSingleSided(true);
geos::operation::buffer::BufferOp ob(geom.get(), bp);
std::unique_ptr<Geometry> g3 = ob.getResultGeometry(d);

with d = -21.0

The resulting output shows artifacts from the seconds line segment:
POLYGON ((50 50, 129 129, 129 150, 129.25925925925927 150, 143.92517768386912 143.92517768386912, 150 150, 150 141.408903891521, 164.66591842460988 135.33408157539012, 164.8492424049175 135.1507575950825, 150 120.30151519016499, 150 100, 150 0, 129 0, 129 99.30151519016499, 64.8492424049175 35.1507575950825, 50 50))
image

If I am removing the vertex in the vertical line (geom = LINESTRING (50 50,150 150, 150 0)) the output is valid:
POLYGON ((50 50, 150 150, 150 0, 129 0, 129 99.30151519016499, 64.8492424049175 35.1507575950825, 50 50))
image

If I am changing to d = -20.0, the output is valid as well:
POLYGON ((50 50, 150 150, 150 100, 150 0, 130 0, 130 101.7157287525381, 64.14213562373095 35.85786437626905, 50 50))
image

I am using GEOS 3.11.0.

Why do tiny changes result in a big change in the output?
I can imagine, that it is difficult to implement a single sided buffer algorithm for any strange input line. But this one is not strange, is it?

Some reference I found on the Internet:
https://trac.osgeo.org/geos/ticket/712 (closed with wontfix)
https://trac.osgeo.org/geos/ticket/810 (still open)
http://lin-ear-th-inking.blogspot.com/2010/11/single-sided-buffers-in-jts.html (from Dr JTS)

I was thinking of fixing this issue, with the following approach:

  • Splitting the resulting polygon at the input line.
  • From that result only keeping the biggest polygon

Unfortunately I do not know, how to implement the polygon split in GEOS.
But doing this QGIS or OpenJump result in much better single-sided buffer (even if still not perfect). I tested this with a 50.000 buffer on the coastline from
https://trac.osgeo.org/geos/ticket/810
With cleanup approach:
image
vs. raw single-sided buffer output
image

@pramsey
Copy link
Member

pramsey commented Mar 10, 2023

Please check out the OffsetCurve functionality in the current main, the SingleSidedBuffer is deprecated and will disappear at some point in the future.

@strk
Copy link
Member

strk commented Apr 24, 2023

For the record: deprecation of SingleSidedBuffer happened in 2011: d48b19a

@strk
Copy link
Member

strk commented Apr 24, 2023

As the deprecating commit was mine, and it mentioned "use OffsetCurve instead", I guess the idea was to be able to re-implement SingleSided buffer in terms of OffsetCurve, so that part would still be good to do in GEOS itself, re-implementing SingleSidedBuffer that way, or the deprecation message would be false advertising.

I'm re-opeining this ticket to give that re-implementation a try.

@strk strk reopened this Apr 24, 2023
@strk strk self-assigned this Apr 24, 2023
@strk
Copy link
Member

strk commented Apr 24, 2023

This is a picture of how OffsetCurve (in green) compares with SingleSidedBuffer (in pink) for a distance of 21 on the original input (arrowed line):

image

In this case connecting the endpoints of offset curve to the endpoints of the input line would give what we're after, but I'm afraid an offset curve is not always a single line then the input line is complex, so the goal of a "single sided buffer" is probably still one that would be good to aim at with a specific API.

@strk
Copy link
Member

strk commented May 3, 2023

It looks like the BufferBuilder::bufferLineSingleSided contained an heuristic code that would fix this case, namely it would drop from the edge list those edges that would not intersect with the edges of a full buffer, effectively removing those forming the artifacts. The current code is NOT using that method, which first appeared in GEOS, but is instead using code being a port of code subsequently added in JTS.

@strk
Copy link
Member

strk commented May 4, 2023

I've just realized that the deprecated GEOSSingleSidedBuffer C-API function never returned an area, but was really just always returning effectively an offset curve, which explains the deprecation hint (and the confusion). What is referred to by "Single-Sided buffer" was never implemented natively in GEOS.

strk added a commit to strk/libgeos that referenced this issue May 4, 2023
strk added a commit to strk/libgeos that referenced this issue May 4, 2023
strk added a commit to strk/libgeos that referenced this issue May 4, 2023
strk added a commit to strk/libgeos that referenced this issue May 4, 2023
@strk
Copy link
Member

strk commented May 4, 2023

Port of the heuristic in BufferBuilder::bufferSingleSidedBuffer was ported to the current code with #891 -- fixing the small case in the original description of this code. It should be tested against a wider set of cases.

strk added a commit to strk/libgeos that referenced this issue May 4, 2023
@strk
Copy link
Member

strk commented May 6, 2023

@dr-jts here's a view of a PostGIS topology built from the input line and its right buffer:

image

Here's a detail:

image

In the detail you can see that by removing faces that are on the left side instead of the right side of the edges forming the input line we should be able (in this case) to obtain what the user wants.

strk added a commit to strk/libgeos that referenced this issue May 8, 2023
strk added a commit to strk/libgeos that referenced this issue May 8, 2023
@strk strk closed this as completed in 091f6d9 May 9, 2023
strk added a commit to strk/libgeos that referenced this issue May 17, 2023
strk added a commit to strk/libgeos that referenced this issue May 17, 2023
strk added a commit to strk/libgeos that referenced this issue May 17, 2023
strk added a commit to strk/libgeos that referenced this issue May 17, 2023
strk added a commit that referenced this issue May 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants