23
23
from urllib .parse import urlparse , urlunparse
24
24
from urllib .request import urlopen , Request
25
25
26
+ from typing import Any , Union , Iterable , ByteString
27
+ from collections .abc import Sequence
28
+
26
29
# Create named logger
27
30
logger = logging .getLogger (__name__ )
28
31
89
92
NODATA = - 10e38 # as per the ESRI shapefile spec, only used for m-values.
90
93
91
94
92
- def b (v , encoding = "utf-8" , encodingErrors = "strict" ):
95
+ def b (v : Any , encoding = "utf-8" , encodingErrors = "strict" ) -> bytes :
93
96
if isinstance (v , str ):
94
97
# For python 3 encode str to bytes.
95
98
return v .encode (encoding , encodingErrors )
@@ -104,7 +107,9 @@ def b(v, encoding="utf-8", encodingErrors="strict"):
104
107
return str (v ).encode (encoding , encodingErrors )
105
108
106
109
107
- def u (v , encoding = "utf-8" , encodingErrors = "strict" ):
110
+ def u (
111
+ v : Union [bytes , str , None , int , ByteString ], encoding = "utf-8" , encodingErrors = "strict"
112
+ ) -> str :
108
113
if isinstance (v , bytes ):
109
114
# For python 3 decode bytes to str.
110
115
return v .decode (encoding , encodingErrors )
@@ -119,11 +124,11 @@ def u(v, encoding="utf-8", encodingErrors="strict"):
119
124
return bytes (v ).decode (encoding , encodingErrors )
120
125
121
126
122
- def is_string (v ) :
127
+ def is_string (v : Any ) -> bool :
123
128
return isinstance (v , str )
124
129
125
130
126
- def pathlike_obj (path ) :
131
+ def pathlike_obj (path : Any ) -> Any :
127
132
if isinstance (path , os .PathLike ):
128
133
return os .fsdecode (path )
129
134
else :
@@ -140,8 +145,11 @@ class _Array(array.array):
140
145
def __repr__ (self ):
141
146
return str (self .tolist ())
142
147
148
+ Point_T = Sequence [float ]
149
+ Coords_T = Sequence [Point_T ]
150
+ BBox_T = tuple [float , float , float , float ]
143
151
144
- def signed_area (coords , fast = False ):
152
+ def signed_area (coords : Coords_T , fast : bool = False ) -> float :
145
153
"""Return the signed area enclosed by a ring using the linear time
146
154
algorithm. A value >= 0 indicates a counter-clockwise oriented ring.
147
155
A faster version is possible by setting 'fast' to True, which returns
@@ -157,43 +165,47 @@ def signed_area(coords, fast=False):
157
165
return area2 / 2.0
158
166
159
167
160
- def is_cw (coords ) :
168
+ def is_cw (coords : Coords_T ) -> bool :
161
169
"""Returns True if a polygon ring has clockwise orientation, determined
162
170
by a negatively signed area.
163
171
"""
164
172
area2 = signed_area (coords , fast = True )
165
173
return area2 < 0
166
174
167
175
168
- def rewind (coords ) :
176
+ def rewind (coords : Coords_T ) -> list [ Point_T ] :
169
177
"""Returns the input coords in reversed order."""
170
178
return list (reversed (coords ))
171
179
172
180
173
- def ring_bbox (coords ) :
181
+ def ring_bbox (coords : Coords_T ) -> BBox_T :
174
182
"""Calculates and returns the bounding box of a ring."""
175
183
xs , ys = zip (* coords )
176
184
bbox = min (xs ), min (ys ), max (xs ), max (ys )
177
185
return bbox
178
186
179
187
180
- def bbox_overlap (bbox1 , bbox2 ):
188
+ def bbox_overlap (
189
+ bbox1 : BBox_T , bbox2 : BBox_T
190
+ ) -> bool :
181
191
"""Tests whether two bounding boxes overlap, returning a boolean"""
182
192
xmin1 , ymin1 , xmax1 , ymax1 = bbox1
183
193
xmin2 , ymin2 , xmax2 , ymax2 = bbox2
184
194
overlap = xmin1 <= xmax2 and xmax1 >= xmin2 and ymin1 <= ymax2 and ymax1 >= ymin2
185
195
return overlap
186
196
187
197
188
- def bbox_contains (bbox1 , bbox2 ):
198
+ def bbox_contains (
199
+ bbox1 : BBox_T , bbox2 : BBox_T
200
+ ) -> bool :
189
201
"""Tests whether bbox1 fully contains bbox2, returning a boolean"""
190
202
xmin1 , ymin1 , xmax1 , ymax1 = bbox1
191
203
xmin2 , ymin2 , xmax2 , ymax2 = bbox2
192
204
contains = xmin1 < xmin2 and xmax1 > xmax2 and ymin1 < ymin2 and ymax1 > ymax2
193
205
return contains
194
206
195
207
196
- def ring_contains_point (coords , p ) :
208
+ def ring_contains_point (coords : Coords_T , p : Point_T ) -> bool :
197
209
"""Fast point-in-polygon crossings algorithm, MacMartin optimization.
198
210
199
211
Adapted from code by Eric Haynes
@@ -238,7 +250,9 @@ def ring_contains_point(coords, p):
238
250
return inside_flag
239
251
240
252
241
- def ring_sample (coords , ccw = False ):
253
+ def ring_sample (
254
+ coords : Coords_T , ccw : bool = False
255
+ ) -> Point_T :
242
256
"""Return a sample point guaranteed to be within a ring, by efficiently
243
257
finding the first centroid of a coordinate triplet whose orientation
244
258
matches the orientation of the ring and passes the point-in-ring test.
@@ -286,7 +300,7 @@ def itercoords():
286
300
raise Exception ("Unexpected error: Unable to find a ring sample point." )
287
301
288
302
289
- def ring_contains_ring (coords1 , coords2 ):
303
+ def ring_contains_ring (coords1 , coords2 ) -> bool :
290
304
"""Returns True if all vertexes in coords2 are fully inside coords1."""
291
305
return all ((ring_contains_point (coords1 , p2 ) for p2 in coords2 ))
292
306
0 commit comments