shapely / shapely/shapely

LineString.buffer surprising results

Open
#2,270 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

geos needs test upstream bug
Dominant language
Python
Stars
4.5k
Forks
631
Avg merge
1d 11h
Merged PRs (30d)
10

Description

Thanks for all the great work on Shapely! I ran into something that I found a little surprising: LineString.buffer of geometry representing a circle of radius r has interiors, even when the buffer distance is larger than r? Is this the correct behavior? I could see the arguments either way.

If you brute force a solution by inflating every point on the path by the larger pad, r = cascaded_union([Point(c).buffer(pad) for c in L.segmentize(0.001).coords]) it produces a clean circle of the expected radius with no interiors.

Image

import matplotlib.pyplot as plt
import numpy as np
from shapely.geometry import LineString, Point


def plot(polygon, ax):
    ax.plot(*polygon.exterior.xy, color="b")
    for i in polygon.interiors:
        ax.plot(*i.xy, color="r")


if __name__ == "__main__":
    # show on a unit circle                                                                    
    r = 1.0

    # create a linestring that from a closed circle of radius `r`                          
    L = LineString(Point([0, 0]).buffer(r).exterior)

    fig, axs = plt.subplots(3, 3)

    # try padding by different amounts                                                     
    for i, pad in enumerate(np.linspace(0.001, r * 2, 9)):
        # apply the buffer                                                                 
        padded = L.buffer(pad)

        # plot it                                                                          
        ax = axs[i // 3, i % 3]
        plot(padded, ax)
        ax.set_xlabel(f"pad={pad}")

        # if we have buffered the closed curve by more than the original radius            
        # there should be no interiors?                                                    
        if pad > r:
            print("should be no interiors?")
            # assert len(padded.interiors) == 0                                            

    fig.show()

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the provided Python script and examining LineString.buffer as the pad exceeds the circle radius. Trace the buffer behavior responsible for the polygon interiors; done means determining whether those interiors are correct and, if not, identifying the expected result and a regression test.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
computer-graphics
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.