Repository: shapely/shapely
Pull request #2255 (2025-03-08 09:02:30)

TST: support sliced offsets in from_ragged_array
Closes https://github.com/shapely/shapely/issues/1745

It appears that we now already support this (because of the new cython implementation, https://github.com/shapely/shapely/pull/2142 and https://github.com/shapely/shapely/pull/2225), so just adding tests.

coveralls: ## Pull Request Test Coverage Report for [Build 13736027840](https://coveralls.io/builds/72608527)


### Details

* **0** of **0**   changed or added relevant lines in **0** files are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage increased (+**0.3%**) to **88.118%**

---



|  Totals | [![Coverage Status](https://coveralls.io/builds/72608527/badge)](https://coveralls.io/builds/72608527) |
| :-- | --: |
| Change from base [Build 13735192816](https://coveralls.io/builds/72607922): |  0.3% |
| Covered Lines: | 2707 |
| Relevant Lines: | 3072 |

---
##### 💛  - [Coveralls](https://coveralls.io)


Patch:
diff --git a/shapely/_ragged_array.py b/shapely/_ragged_array.py
index 73ff162..df157c0 100644
--- a/shapely/_ragged_array.py
+++ b/shapely/_ragged_array.py
@@ -347,6 +347,8 @@ def _point_from_flatcoords(coords):
 
 def _multipoint_from_flatcoords(coords, offsets):
     # recreate points
+    if len(offsets):
+        coords = coords[offsets[0] :]
     points = creation.points(coords)
 
     # recreate multipoints
@@ -364,6 +366,8 @@ def _multipoint_from_flatcoords(coords, offsets):
 
 def _linestring_from_flatcoords(coords, offsets):
     # recreate linestrings
+    if len(offsets):
+        coords = coords[offsets[0] :]
     linestring_n = np.diff(offsets)
     linestring_indices = np.repeat(np.arange(len(linestring_n)), linestring_n)
 
diff --git a/shapely/constructive.py b/shapely/constructive.py
index abce8fd..46462d6 100644
--- a/shapely/constructive.py
+++ b/shapely/constructive.py
@@ -1124,13 +1124,13 @@ def simplify(geometry, tolerance, preserve_topology=True, **kwargs):
 
 @multithreading_enabled
 def snap(geometry, reference, tolerance, **kwargs):
-    """Snap an input geometry to reference geometry's vertices.
+    """Snap the vertices and segments of the geometry to vertices of the reference.
 
-    Vertices of the first geometry are snapped to vertices of the second.
-    geometry, returning a new geometry; the input geometries are not modified.
-    The result geometry is the input geometry with the vertices snapped.
-    If no snapping occurs then the input geometry is returned unchanged.
-    The tolerance is used to control where snapping is performed.
+    Vertices and segments of the input geometry are snapped to vertices of the
+    reference geometry, returning a new geometry; the input geometries are not
+    modified. The result geometry is the input geometry with the vertices and
+    segments snapped. If no snapping occurs then the input geometry is returned
+    unchanged. The tolerance is used to control where snapping is performed.
 
     Where possible, this operation tries to avoid creating invalid geometries;
     however, it does not guarantee that output geometries will be valid. It is


Test patch:
diff --git a/shapely/tests/test_ragged_array.py b/shapely/tests/test_ragged_array.py
index 0e4d5df..32bc9e8 100644
--- a/shapely/tests/test_ragged_array.py
+++ b/shapely/tests/test_ragged_array.py
@@ -246,6 +246,15 @@ def test_linestrings():
     arr[-2] = shapely.from_wkt("LINESTRING EMPTY")
     assert_geometries_equal(result, arr)
 
+    # sliced
+    offsets_sliced = (offsets[0][1:],)
+    result = shapely.from_ragged_array(typ, coords, offsets_sliced)
+    assert_geometries_equal(result, arr[1:])
+
+    offsets_sliced = (offsets[0][:-1],)
+    result = shapely.from_ragged_array(typ, coords, offsets_sliced)
+    assert_geometries_equal(result, arr[:-1])
+
 
 def test_polygons():
     arr = shapely.from_wkt(
@@ -299,6 +308,17 @@ def test_polygons():
     arr[-2] = shapely.from_wkt("POLYGON EMPTY")
     assert_geometries_equal(result, arr)
 
+    # sliced:
+    # - indices into the coordinate array for the whole buffer
+    # - indices into the ring array for *just* the sliced part
+    offsets_sliced = (offsets[0], offsets[1][1:])
+    result = shapely.from_ragged_array(typ, coords, offsets_sliced)
+    assert_geometries_equal(result, arr[1:])
+
+    offsets_sliced = (offsets[0], offsets[1][:-1])
+    result = shapely.from_ragged_array(typ, coords, offsets_sliced)
+    assert_geometries_equal(result, arr[:-1])
+
 
 def test_multipoints():
     arr = shapely.from_wkt(
@@ -338,6 +358,15 @@ def test_multipoints():
     arr[-2] = shapely.from_wkt("MULTIPOINT EMPTY")
     assert_geometries_equal(result, arr)
 
+    # sliced:
+    offsets_sliced = (offsets[0][1:],)
+    result = shapely.from_ragged_array(typ, coords, offsets_sliced)
+    assert_geometries_equal(result, arr[1:])
+
+    offsets_sliced = (offsets[0][:-1],)
+    result = shapely.from_ragged_array(typ, coords, offsets_sliced)
+    assert_geometries_equal(result, arr[:-1])
+
 
 def test_multilinestrings():
     arr = shapely.from_wkt(
@@ -389,6 +418,17 @@ def test_multilinestrings():
     arr[-2] = shapely.from_wkt("MULTILINESTRING EMPTY")
     assert_geometries_equal(result, arr)
 
+    # sliced:
+    # - indices into the coordinate array for the whole buffer
+    # - indices into the line parts for *just* the sliced part
+    offsets_sliced = (offsets[0], offsets[1][1:])
+    result = shapely.from_ragged_array(typ, coords, offsets_sliced)
+    assert_geometries_equal(result, arr[1:])
+
+    offsets_sliced = (offsets[0], offsets[1][:-1])
+    result = shapely.from_ragged_array(typ, coords, offsets_sliced)
+    assert_geometries_equal(result, arr[:-1])
+
 
 def test_multipolygons():
     arr = shapely.from_wkt(
@@ -453,6 +493,16 @@ def test_multipolygons():
     arr[-2] = shapely.from_wkt("MULTIPOLYGON EMPTY")
     assert_geometries_equal(result, arr)
 
+    # sliced:
+    offsets_sliced = (offsets[0], offsets[1], offsets[2][1:])
+    result = shapely.from_ragged_array(typ, coords, offsets_sliced)
+    assert_geometries_equal(result, arr[1:])
+
+    offsets_sliced = (offsets[0], offsets[1], offsets[2][:-3])
+    result = shapely.from_ragged_array(typ, coords, offsets_sliced)
+    assert_geometries_equal(result, arr[:-3])
+    print(result)
+
 
 def test_mixture_point_multipoint():
     typ, coords, offsets = shapely.to_ragged_array([point, multi_point])