Skip to content

Commit a9ba72d

Browse files
committed
Revert back to not enforcing geojson ring orientation
This is only required in the RFC7946 GeoJSON specification, which it won't be possible to fully support in pyshp. Instead sticking to the original 2008 GeoJSON, keeping all rings in the same orientation as stored in the shapefile. More details at SciTools/cartopy#2012.
1 parent 186933b commit a9ba72d

File tree

2 files changed

+34
-43
lines changed

2 files changed

+34
-43
lines changed

shapefile.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -349,11 +349,9 @@ def organize_polygon_rings(rings, return_errors=None):
349349
# where exterior rings are clockwise, and holes counterclockwise
350350
if is_cw(ring):
351351
# ring is exterior
352-
ring = rewind(ring) # GeoJSON and Shapefile exteriors have opposite orientation
353352
exteriors.append(ring)
354353
else:
355354
# ring is a hole
356-
ring = rewind(ring) # GeoJSON and Shapefile holes have opposite orientation
357355
holes.append(ring)
358356

359357
# if only one exterior, then all holes belong to that exterior
@@ -389,8 +387,8 @@ def organize_polygon_rings(rings, return_errors=None):
389387

390388
if len(exterior_candidates) > 1:
391389
# get hole sample point
392-
# Note: all rings now follow GeoJSON orientation, i.e. holes are clockwise
393-
hole_sample = ring_sample(holes[hole_i], ccw=False)
390+
ccw = not is_cw(holes[hole_i])
391+
hole_sample = ring_sample(holes[hole_i], ccw=ccw)
394392
# collect new exterior candidates
395393
new_exterior_candidates = []
396394
for ext_i in exterior_candidates:
@@ -434,8 +432,6 @@ def organize_polygon_rings(rings, return_errors=None):
434432
# add orphan holes as exteriors
435433
for hole_i in orphan_holes:
436434
ext = holes[hole_i]
437-
# since this was previously a clockwise ordered hole, inverse the winding order
438-
ext = rewind(ext)
439435
# add as single exterior without any holes
440436
poly = [ext]
441437
polys.append(poly)
@@ -450,8 +446,6 @@ def organize_polygon_rings(rings, return_errors=None):
450446
if return_errors is not None:
451447
return_errors['polygon_only_holes'] = len(holes)
452448
exteriors = holes
453-
# since these were previously clockwise ordered holes, inverse the winding order
454-
exteriors = [rewind(ext) for ext in exteriors]
455449
# add as single exterior without any holes
456450
polys = [[ext] for ext in exteriors]
457451
return polys

test_shapefile.py

Lines changed: 32 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
],
5050
[0],
5151
{'type':'Polygon','coordinates':[
52-
shapefile.rewind([(1,1),(1,9),(9,9),(9,1),(1,1)]),
52+
[(1,1),(1,9),(9,9),(9,1),(1,1)],
5353
]}
5454
),
5555
(shapefile.POLYGON, # single polygon, holes (ordered)
@@ -59,9 +59,9 @@
5959
],
6060
[0,5,5+5],
6161
{'type':'Polygon','coordinates':[
62-
shapefile.rewind([(1,1),(1,9),(9,9),(9,1),(1,1)]), # exterior
63-
shapefile.rewind([(2,2),(4,2),(4,4),(2,4),(2,2)]), # hole 1
64-
shapefile.rewind([(5,5),(7,5),(7,7),(5,7),(5,5)]), # hole 2
62+
[(1,1),(1,9),(9,9),(9,1),(1,1)], # exterior
63+
[(2,2),(4,2),(4,4),(2,4),(2,2)], # hole 1
64+
[(5,5),(7,5),(7,7),(5,7),(5,5)], # hole 2
6565
]}
6666
),
6767
(shapefile.POLYGON, # single polygon, holes (unordered)
@@ -72,9 +72,9 @@
7272
],
7373
[0,5,5+5],
7474
{'type':'Polygon','coordinates':[
75-
shapefile.rewind([(1,1),(1,9),(9,9),(9,1),(1,1)]), # exterior
76-
shapefile.rewind([(2,2),(4,2),(4,4),(2,4),(2,2)]), # hole 1
77-
shapefile.rewind([(5,5),(7,5),(7,7),(5,7),(5,5)]), # hole 2
75+
[(1,1),(1,9),(9,9),(9,1),(1,1)], # exterior
76+
[(2,2),(4,2),(4,4),(2,4),(2,2)], # hole 1
77+
[(5,5),(7,5),(7,7),(5,7),(5,5)], # hole 2
7878
]}
7979
),
8080
(shapefile.POLYGON, # multi polygon, no holes
@@ -84,10 +84,10 @@
8484
[0,5],
8585
{'type':'MultiPolygon','coordinates':[
8686
[ # poly 1
87-
shapefile.rewind([(1,1),(1,9),(9,9),(9,1),(1,1)]),
87+
[(1,1),(1,9),(9,9),(9,1),(1,1)],
8888
],
8989
[ # poly 2
90-
shapefile.rewind([(11,11),(11,19),(19,19),(19,11),(11,11)]),
90+
[(11,11),(11,19),(19,19),(19,11),(11,11)],
9191
],
9292
]}
9393
),
@@ -102,14 +102,14 @@
102102
[0,5,10,15,20,25],
103103
{'type':'MultiPolygon','coordinates':[
104104
[ # poly 1
105-
shapefile.rewind([(1,1),(1,9),(9,9),(9,1),(1,1)]), # exterior
106-
shapefile.rewind([(2,2),(4,2),(4,4),(2,4),(2,2)]), # hole 1
107-
shapefile.rewind([(5,5),(7,5),(7,7),(5,7),(5,5)]), # hole 2
105+
[(1,1),(1,9),(9,9),(9,1),(1,1)], # exterior
106+
[(2,2),(4,2),(4,4),(2,4),(2,2)], # hole 1
107+
[(5,5),(7,5),(7,7),(5,7),(5,5)], # hole 2
108108
],
109109
[ # poly 2
110-
shapefile.rewind([(11,11),(11,19),(19,19),(19,11),(11,11)]), # exterior
111-
shapefile.rewind([(12,12),(14,12),(14,14),(12,14),(12,12)]), # hole 1
112-
shapefile.rewind([(15,15),(17,15),(17,17),(15,17),(15,15)]), # hole 2
110+
[(11,11),(11,19),(19,19),(19,11),(11,11)], # exterior
111+
[(12,12),(14,12),(14,14),(12,14),(12,12)], # hole 1
112+
[(15,15),(17,15),(17,17),(15,17),(15,15)], # hole 2
113113
],
114114
]}
115115
),
@@ -123,15 +123,15 @@
123123
[0,5,10,15,20],
124124
{'type':'MultiPolygon','coordinates':[
125125
[ # poly 1
126-
shapefile.rewind([(1,1),(1,9),(9,9),(9,1),(1,1)]), # exterior 1
127-
shapefile.rewind([(2,2),(8,2),(8,8),(2,8),(2,2)]), # hole 1.1
126+
[(1,1),(1,9),(9,9),(9,1),(1,1)], # exterior 1
127+
[(2,2),(8,2),(8,8),(2,8),(2,2)], # hole 1.1
128128
],
129129
[ # poly 2
130-
shapefile.rewind([(3,3),(3,7),(7,7),(7,3),(3,3)]), # exterior 2
131-
shapefile.rewind([(4,4),(6,4),(6,6),(4,6),(4,4)]), # hole 2.1
130+
[(3,3),(3,7),(7,7),(7,3),(3,3)], # exterior 2
131+
[(4,4),(6,4),(6,6),(4,6),(4,4)], # hole 2.1
132132
],
133133
[ # poly 3
134-
shapefile.rewind([(4.5,4.5),(4.5,5.5),(5.5,5.5),(5.5,4.5),(4.5,4.5)]), # exterior 3
134+
[(4.5,4.5),(4.5,5.5),(5.5,5.5),(5.5,4.5),(4.5,4.5)], # exterior 3
135135
],
136136
]}
137137
),
@@ -145,15 +145,15 @@
145145
[0,5,10,15,20+3],
146146
{'type':'MultiPolygon','coordinates':[
147147
[ # poly 1
148-
shapefile.rewind([(1,1),(1,9),(9,9),(9,1),(1,1)]), # exterior 1
149-
shapefile.rewind([(2,2),(3,3),(4,2),(8,2),(8,8),(4,8),(2,8),(2,4),(2,2)]), # hole 1.1
148+
[(1,1),(1,9),(9,9),(9,1),(1,1)], # exterior 1
149+
[(2,2),(3,3),(4,2),(8,2),(8,8),(4,8),(2,8),(2,4),(2,2)], # hole 1.1
150150
],
151151
[ # poly 2
152-
shapefile.rewind([(3,3),(3,7),(7,7),(7,3),(3,3)]), # exterior 2
153-
shapefile.rewind([(4,4),(4,4),(6,4),(6,4),(6,4),(6,6),(4,6),(4,4)]), # hole 2.1
152+
[(3,3),(3,7),(7,7),(7,3),(3,3)], # exterior 2
153+
[(4,4),(4,4),(6,4),(6,4),(6,4),(6,6),(4,6),(4,4)], # hole 2.1
154154
],
155155
[ # poly 3
156-
shapefile.rewind([(4.5,4.5),(4.5,5.5),(5.5,5.5),(5.5,4.5),(4.5,4.5)]), # exterior 3
156+
[(4.5,4.5),(4.5,5.5),(5.5,5.5),(5.5,4.5),(4.5,4.5)], # exterior 3
157157
],
158158
]}
159159
),
@@ -169,17 +169,16 @@
169169
[0,5,10,15,20,25,30],
170170
{'type':'MultiPolygon','coordinates':[
171171
[ # poly 1
172-
shapefile.rewind([(1,1),(1,9),(9,9),(9,1),(1,1)]), # exterior
173-
shapefile.rewind([(2,2),(4,2),(4,4),(2,4),(2,2)]), # hole 1
174-
shapefile.rewind([(5,5),(7,5),(7,7),(5,7),(5,5)]), # hole 2
172+
[(1,1),(1,9),(9,9),(9,1),(1,1)], # exterior
173+
[(2,2),(4,2),(4,4),(2,4),(2,2)], # hole 1
174+
[(5,5),(7,5),(7,7),(5,7),(5,5)], # hole 2
175175
],
176176
[ # poly 2
177-
shapefile.rewind([(11,11),(11,19),(19,19),(19,11),(11,11)]), # exterior
178-
shapefile.rewind([(12,12),(14,12),(14,14),(12,14),(12,12)]), # hole 1
179-
shapefile.rewind([(15,15),(17,15),(17,17),(15,17),(15,15)]), # hole 2
177+
[(11,11),(11,19),(19,19),(19,11),(11,11)], # exterior
178+
[(12,12),(14,12),(14,14),(12,14),(12,12)], # hole 1
179+
[(15,15),(17,15),(17,17),(15,17),(15,15)], # hole 2
180180
],
181-
[ # poly 3 (orphaned hole)
182-
# Note: due to the hole-to-exterior conversion, should return the same ring orientation
181+
[ # poly 3 (orphaned hole)
183182
[(95,95),(97,95),(97,97),(95,97),(95,95)], # exterior
184183
],
185184
]}
@@ -191,11 +190,9 @@
191190
[0,5],
192191
{'type':'MultiPolygon','coordinates':[
193192
[ # poly 1
194-
# Note: due to the hole-to-exterior conversion, should return the same ring orientation
195193
[(1,1),(9,1),(9,9),(1,9),(1,1)],
196194
],
197195
[ # poly 2
198-
# Note: due to the hole-to-exterior conversion, should return the same ring orientation
199196
[(11,11),(19,11),(19,19),(11,19),(11,11)],
200197
],
201198
]}

0 commit comments

Comments
 (0)