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.
@@ -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("%(name)s - %(levelname)s - %(message)s")
52
- f_format: logging.Formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
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, "Could not process invalid geometry: %s" % geometry.wkt
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
- densify_features: bool = False,
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
- densify_features (bool, optional): If
207
- True, we will add additional points to the features to improve accuracy of the voronoi
208
- diagram. If densify_features is True and max_segment_length is false, then the max_segment_length
209
- will be calculated based on the average segment length of all features, divided by 5.
210
- max_segment_length (Union[float, None], optional): The maximum distance between vertices that we want.
211
- In projection units. densify_features must be True, or an error will be thrown.
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(self, feature_coord_index: int) -> Generator[int, None, None]:
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 (i for i in self.vor.regions[self.vor.point_region[feature_coord_index]] if i != -1)
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 and source_feature._is_adjacent(
451
- target_feature, min_overlapping_voronoi_vertices
452
- ):
453
- self._adjacency_dict[source_index].append(target_index)
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.1.2
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,,