ops.split behaviour on closed rings
See original GitHub issueHi,
This is a bit of a fringe use case, but I’m extracting parts of a polygon boundary by splitting at vertices. The boundary is a LineString, but obviously also closed and a ring (which differs from closed in that it is is both closed and not self-intersecting?). When fed a ring LineString shapely.ops.split()
works given a MultiPoint or Point as a splitter, but the resulting number of parts is inconsistent, depending on the whether the splitting points happen to include the joining vertex for the closed boundary:
from shapely import geometry, ops
# examples where splitter doesn't contain joining vertex
poly = geometry.Polygon([(0,1),(1,0),(2,1),(1,2),(0,1)])
parts = ops.split(poly.boundary, geometry.MultiPoint([(1,0),(1,2)]))
len(parts) # 3
parts = ops.split(poly.boundary, geometry.Point((1,0)))
len(parts) # 2
# examples where splitter does contain joining vertex
poly = geometry.Polygon([(1,0),(2,1),(1,2),(0,1),(1,0)])
parts = ops.split(poly.boundary, geometry.MultiPoint([(1,0),(1,2)]))
len(parts) # 2
parts = ops.split(poly.boundary, geometry.Point((1,0)))
len(parts) # 1
I can see this isn’t simple - if you split a closed ring at a single point, then I guess the result depends on your definition of closed. If ‘closed’ means that the first and last vertex are coincident, then you shouldn’t be able to split a ring with a single point; if ‘closed’ is a separate attribute of the linestring, then it might make sense. With a multipoint, though, it would be more consistent to get back the same number of parts as points (assuming all the points fall on the boundary).
Operating system
Mac OS X 10.10.5
Shapely version and provenance
Python 3.6.4 installed using brew Shapely 1.6.4.post1 installed using pip
Issue Analytics
- State:
- Created 5 years ago
- Comments:5 (3 by maintainers)
Top GitHub Comments
The
shapely.ops.split
function currently treatsLineString
andLinearRing
geometries in the same way:The coordinate sequence of a geometry is iterated over, testing each segment of the string for intersection with the splitting point(s). If an intersection is found a new object is appended to the result and the iteration continues. No special consideration is given to closed geometries. If a splitting point occurs on the first or last vertex (which may be the same location) it is considered not to have been split.
This works for a common use case: consider a LineString representing the GPS trace for a circular walk. Although the geometry is “closed” (i.e. it has the same start and end position) it does have a defined beginning and end. Splitting this geometry at a point somewhere along the walk should return two lines: before and after.
A LinearRing used to denote the boundary of a polygon is also closed. However the actual start and end points of the line are less meaningful. You have to start drawing the line somewhere, but the exact position isn’t really important. If you consider the ring to be continuous then splitting it with a single point isn’t meaningful either.
I think it sounds reasonable that
split
should treat LineStrings and LinearRings differently. The change should be quite small: for LinearRings the first and last geometry returned should be concatenated. If a ring is split with a single point a single geometry will be returned, but with a new start/end location. If users needed the old behaviour it’s easy to convert to a LineString first, e.g.split(LineString(ring), point)
.Perhaps we should removed the
bug
tag? This feels more like a feature to me.That makes sense:
break
is something you do to a LinearRing and the number of LineString features you get back does not include features either side of the arbitrary startpoint (unless the breaking feature intersects that point). Does that mean you can’tsplit
a LinearRing?I’ve got no strong opinions, but I think it makes sense to clarify the distinction.