geo-adjacency 1.1.2__py3-none-any.whl → 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- geo_adjacency/adjacency.py +73 -19
- {geo_adjacency-1.1.2.dist-info → geo_adjacency-1.2.0.dist-info}/METADATA +1 -1
- geo_adjacency-1.2.0.dist-info/RECORD +8 -0
- geo_adjacency-1.1.2.dist-info/RECORD +0 -8
- {geo_adjacency-1.1.2.dist-info → geo_adjacency-1.2.0.dist-info}/LICENSE +0 -0
- {geo_adjacency-1.1.2.dist-info → geo_adjacency-1.2.0.dist-info}/WHEEL +0 -0
geo_adjacency/adjacency.py
CHANGED
|
@@ -27,7 +27,7 @@ import numpy as np
|
|
|
27
27
|
import shapely.ops
|
|
28
28
|
from scipy.spatial import distance
|
|
29
29
|
from scipy.spatial import Voronoi
|
|
30
|
-
from shapely import LineString, Point, Polygon, MultiPolygon
|
|
30
|
+
from shapely import LineString, Point, Polygon, MultiPolygon, box
|
|
31
31
|
from shapely.geometry.base import BaseGeometry
|
|
32
32
|
|
|
33
33
|
from geo_adjacency.exception import ImmutablePropertyError
|
|
@@ -48,8 +48,12 @@ c_handler: logging.StreamHandler = logging.StreamHandler()
|
|
|
48
48
|
c_handler.setLevel(logging.WARNING)
|
|
49
49
|
|
|
50
50
|
# Create formatters and add it to handlers
|
|
51
|
-
c_format: logging.Formatter = logging.Formatter(
|
|
52
|
-
|
|
51
|
+
c_format: logging.Formatter = logging.Formatter(
|
|
52
|
+
"%(name)s - %(levelname)s - %(message)s"
|
|
53
|
+
)
|
|
54
|
+
f_format: logging.Formatter = logging.Formatter(
|
|
55
|
+
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
56
|
+
)
|
|
53
57
|
c_handler.setFormatter(c_format)
|
|
54
58
|
|
|
55
59
|
# Add handlers to the logger
|
|
@@ -61,6 +65,7 @@ class _Feature:
|
|
|
61
65
|
A _Feature is a wrapper around a Shapely geometry that allows us to easily determine if two
|
|
62
66
|
geometries are adjacent.
|
|
63
67
|
"""
|
|
68
|
+
|
|
64
69
|
__slots__ = ("_geometry", "_coords", "voronoi_points")
|
|
65
70
|
|
|
66
71
|
def __init__(self, geometry: BaseGeometry):
|
|
@@ -77,7 +82,9 @@ class _Feature:
|
|
|
77
82
|
"Cannot create _Feature for geometry type '%s'." % type(geometry)
|
|
78
83
|
)
|
|
79
84
|
|
|
80
|
-
assert geometry.is_valid,
|
|
85
|
+
assert geometry.is_valid, (
|
|
86
|
+
"Could not process invalid geometry: %s" % geometry.wkt
|
|
87
|
+
)
|
|
81
88
|
|
|
82
89
|
self._geometry: BaseGeometry = geometry
|
|
83
90
|
self._coords: Union[List[Tuple[float, float]], None] = None
|
|
@@ -181,6 +188,8 @@ class AdjacencyEngine:
|
|
|
181
188
|
"_vor",
|
|
182
189
|
"_all_features",
|
|
183
190
|
"_all_coordinates",
|
|
191
|
+
"_max_distance",
|
|
192
|
+
"_bounding_rectangle",
|
|
184
193
|
)
|
|
185
194
|
|
|
186
195
|
def __init__(
|
|
@@ -188,8 +197,7 @@ class AdjacencyEngine:
|
|
|
188
197
|
source_geoms: List[BaseGeometry],
|
|
189
198
|
target_geoms: Union[List[BaseGeometry], None] = None,
|
|
190
199
|
obstacle_geoms: Union[List[BaseGeometry], None] = None,
|
|
191
|
-
|
|
192
|
-
max_segment_length: Union[float, None] = None,
|
|
200
|
+
**kwargs,
|
|
193
201
|
):
|
|
194
202
|
"""
|
|
195
203
|
Note: only Multipolygons, Polygons, LineStrings and Points are supported. It is assumed all
|
|
@@ -203,13 +211,36 @@ class AdjacencyEngine:
|
|
|
203
211
|
obstacle_geoms (Union[List[BaseGeometry], None]), optional): List
|
|
204
212
|
of Shapely geometries. These features will not be tested for adjacency, but they can
|
|
205
213
|
prevent a source and target feature from being adjacent.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
214
|
+
|
|
215
|
+
Keyword Args:
|
|
216
|
+
densify_features (bool, optional): If True, we will add additional points to the
|
|
217
|
+
features to improve accuracy of the voronoi diagram. If densify_features is True and
|
|
218
|
+
max_segment_length is false, then the max_segment_length will be calculated based on
|
|
219
|
+
the average segment length of all features, divided by 5.
|
|
220
|
+
max_segment_length (Union[float, None], optional): The maximum distance between vertices
|
|
221
|
+
that we want iIn projection units. densify_features must be True, or an error will be thrown.
|
|
222
|
+
max_distance (Union[float, None], optional): The maximum distance between two features
|
|
223
|
+
for them to be candidates for adjacency. Units are same as geometry coordinate system.
|
|
224
|
+
bounding_box (Union[float, float, float, float, None], optional): Set a bounding box
|
|
225
|
+
for the analysis. Only include features that intersect the box in the output.
|
|
226
|
+
This is useful for removing data from the edges from the final analysis, as these
|
|
227
|
+
are often not accurate. This is particularly helpful when analyzing a large data set
|
|
228
|
+
in a windowed fashion. Expected format is (minx, miny, maxx, maxy).
|
|
229
|
+
|
|
230
|
+
"""
|
|
231
|
+
|
|
232
|
+
densify_features = kwargs.get("densify_features", False)
|
|
233
|
+
max_segment_length = kwargs.get("max_segment_length", None)
|
|
234
|
+
self._max_distance = kwargs.get("max_distance", None)
|
|
235
|
+
|
|
236
|
+
if kwargs.get("bounding_box", None):
|
|
237
|
+
minx, miny, maxx, maxy = kwargs.get("bounding_box")
|
|
238
|
+
assert (
|
|
239
|
+
minx < maxx and miny < maxy
|
|
240
|
+
), "Bounding box must have minx < maxx and miny < maxy"
|
|
241
|
+
self._bounding_rectangle: Polygon = box(minx, miny, maxx, maxy)
|
|
242
|
+
else:
|
|
243
|
+
self._bounding_rectangle = None
|
|
213
244
|
|
|
214
245
|
if max_segment_length and not densify_features:
|
|
215
246
|
raise ValueError(
|
|
@@ -398,7 +429,9 @@ class AdjacencyEngine:
|
|
|
398
429
|
def vor(self, _):
|
|
399
430
|
raise ImmutablePropertyError("Property vor is immutable.")
|
|
400
431
|
|
|
401
|
-
def _get_voronoi_vertex_idx_for_coord_idx(
|
|
432
|
+
def _get_voronoi_vertex_idx_for_coord_idx(
|
|
433
|
+
self, feature_coord_index: int
|
|
434
|
+
) -> Generator[int, None, None]:
|
|
402
435
|
"""
|
|
403
436
|
For a given feature coordinate index, return the indices of the voronoi vertices. Ignore
|
|
404
437
|
any "-1"s, which indicate vertices at infinity; these provide no adjacency information.
|
|
@@ -409,7 +442,11 @@ class AdjacencyEngine:
|
|
|
409
442
|
Returns:
|
|
410
443
|
Generator[int, None, None]: A generator of the indices of the voronoi vertices.
|
|
411
444
|
"""
|
|
412
|
-
return (
|
|
445
|
+
return (
|
|
446
|
+
i
|
|
447
|
+
for i in self.vor.regions[self.vor.point_region[feature_coord_index]]
|
|
448
|
+
if i != -1
|
|
449
|
+
)
|
|
413
450
|
|
|
414
451
|
def _tag_feature_with_voronoi_vertices(self):
|
|
415
452
|
"""
|
|
@@ -446,11 +483,28 @@ class AdjacencyEngine:
|
|
|
446
483
|
"""
|
|
447
484
|
min_overlapping_voronoi_vertices = 2
|
|
448
485
|
for source_index, source_feature in enumerate(source_set):
|
|
486
|
+
if (
|
|
487
|
+
self._bounding_rectangle is not None
|
|
488
|
+
and not self._bounding_rectangle.intersects(source_feature.geometry)
|
|
489
|
+
):
|
|
490
|
+
continue
|
|
449
491
|
for target_index, target_feature in enumerate(target_set):
|
|
450
|
-
if source_feature != target_feature
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
492
|
+
if source_feature != target_feature:
|
|
493
|
+
if (
|
|
494
|
+
self._max_distance is not None
|
|
495
|
+
and source_feature.geometry.distance(target_feature.geometry)
|
|
496
|
+
> self._max_distance
|
|
497
|
+
) or (
|
|
498
|
+
self._bounding_rectangle is not None
|
|
499
|
+
and not self._bounding_rectangle.intersects(
|
|
500
|
+
target_feature.geometry
|
|
501
|
+
)
|
|
502
|
+
):
|
|
503
|
+
continue
|
|
504
|
+
if source_feature._is_adjacent(
|
|
505
|
+
target_feature, min_overlapping_voronoi_vertices
|
|
506
|
+
):
|
|
507
|
+
self._adjacency_dict[source_index].append(target_index)
|
|
454
508
|
|
|
455
509
|
def get_adjacency_dict(self) -> Dict[int, List[int]]:
|
|
456
510
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: geo-adjacency
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: A package to determine which geometries are adjacent to each other, accounting for obstacles and gaps between features.
|
|
5
5
|
Home-page: https://asmyth01.github.io/geo-adjacency/
|
|
6
6
|
License: MIT
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
geo_adjacency/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
geo_adjacency/adjacency.py,sha256=pIxXEQjcjFKH95Xk27O8qYrD3ZY88JWOA7qOId82JW4,22941
|
|
3
|
+
geo_adjacency/exception.py,sha256=zZNdBOm5LpuiCpNuqH1FNLhiPnQqyCyuhOTMBDnLSTQ,230
|
|
4
|
+
geo_adjacency/utils.py,sha256=57Q-nRZQlW1QetlLoucbDr1jm3CRHYRCVzrarm7xxZw,4188
|
|
5
|
+
geo_adjacency-1.2.0.dist-info/LICENSE,sha256=p0PMGdB2iuOndKPbBCVhTNe9TMIxZRpJ64bQ_CoUIqY,1065
|
|
6
|
+
geo_adjacency-1.2.0.dist-info/METADATA,sha256=hbT90t7FAtGb2tzr4GgnZrfA_2KESFEW2upzVAxSaYk,3857
|
|
7
|
+
geo_adjacency-1.2.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
8
|
+
geo_adjacency-1.2.0.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
geo_adjacency/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
geo_adjacency/adjacency.py,sha256=bL6ErCwgtpvNu0XfgpQwCJ6RlK2M-vi-qx_veE1_0Rk,20844
|
|
3
|
-
geo_adjacency/exception.py,sha256=zZNdBOm5LpuiCpNuqH1FNLhiPnQqyCyuhOTMBDnLSTQ,230
|
|
4
|
-
geo_adjacency/utils.py,sha256=57Q-nRZQlW1QetlLoucbDr1jm3CRHYRCVzrarm7xxZw,4188
|
|
5
|
-
geo_adjacency-1.1.2.dist-info/LICENSE,sha256=p0PMGdB2iuOndKPbBCVhTNe9TMIxZRpJ64bQ_CoUIqY,1065
|
|
6
|
-
geo_adjacency-1.1.2.dist-info/METADATA,sha256=fpHyeHH726bndsYxfE_CWAtJLmBN9MlN3lFiraRX8PA,3857
|
|
7
|
-
geo_adjacency-1.1.2.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
8
|
-
geo_adjacency-1.1.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|