vector2dggs 0.10.1__py3-none-any.whl → 0.11.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.
vector2dggs/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__: str = "0.10.1"
1
+ __version__: str = "0.11.0"
vector2dggs/common.py CHANGED
@@ -18,7 +18,7 @@ from pathlib import Path, PurePath
18
18
  from urllib.parse import urlparse
19
19
  from tqdm import tqdm
20
20
  from tqdm.dask import TqdmCallback
21
- from multiprocessing.dummy import Pool
21
+ from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor, as_completed
22
22
  from shapely.geometry import GeometryCollection
23
23
 
24
24
  import vector2dggs.constants as const
@@ -313,6 +313,47 @@ def polyfill(
313
313
  def polyfill_star(args) -> None:
314
314
  return polyfill(*args)
315
315
 
316
+ def bisection_preparation(df: pd.DataFrame, dggs: str, parent_res: int, cut_crs: pyproj.CRS = None, cut_threshold: Union[None, float] = None) -> tuple[pd.DataFrame, pyproj.CRS, Union[None, float]]:
317
+ cut_threshold = float(cut_threshold) if cut_threshold != None else None
318
+
319
+ if cut_threshold and cut_crs:
320
+ df = df.to_crs(cut_crs)
321
+ else:
322
+ cut_crs = df.crs
323
+
324
+ if cut_crs is None:
325
+ LOGGER.warning("Input has no defined CRS, and cut_crs is not specified")
326
+ elif cut_threshold != 0:
327
+ LOGGER.debug("Cutting with CRS: %s", df.crs)
328
+
329
+ if not cut_crs.is_projected and cut_threshold != 0:
330
+ LOGGER.warning(
331
+ f"CRS {cut_crs} is not a projected coordinate system. (units: {cut_crs.axis_info[0].unit_name}) Bisection will result in sections of varying area"
332
+ )
333
+ elif cut_threshold != 0:
334
+ LOGGER.debug(
335
+ f"Using CRS units for input polygon bisection: {cut_crs.axis_info[0].unit_name}"
336
+ )
337
+
338
+ if cut_threshold == None:
339
+ unit_name = cut_crs.axis_info[0].unit_name
340
+ cut_threshold_m2 = const.DEFAULT_AREA_THRESHOLD_M2(dggs, (int(parent_res)))
341
+ if unit_name == "metre":
342
+ cut_threshold = cut_threshold_m2
343
+ elif unit_name == "feet":
344
+ cut_threshold = cut_threshold_m2 * 3.28084
345
+ else:
346
+ cut_threshold = 100000000 if cut_crs.is_projected else 0.5
347
+ LOGGER.warning(
348
+ f'Unspecified cut_threshold for {"projected" if cut_crs.is_projected else "geographic"} CRS: {cut_crs}, with squared units: {unit_name}'
349
+ )
350
+ LOGGER.debug(f"Using default cut_threshold of {cut_threshold} ({unit_name}^2)")
351
+
352
+ return df, cut_crs, cut_threshold
353
+
354
+ def bisect_geometry(geometry, cut_threshold):
355
+ return GeometryCollection(katana.katana(geometry, cut_threshold))
356
+
316
357
 
317
358
  def index(
318
359
  dggs: str,
@@ -326,7 +367,7 @@ def index(
326
367
  keep_attributes: bool,
327
368
  chunksize: int,
328
369
  spatial_sorting: str,
329
- cut_threshold: int,
370
+ cut_threshold: Union[None, float],
330
371
  processes: int,
331
372
  compression: str = "snappy",
332
373
  id_field: str = None,
@@ -356,9 +397,7 @@ def index(
356
397
  # Read file
357
398
  df = gpd.read_file(input_file, layer=layer)
358
399
 
359
- if cut_crs:
360
- df = df.to_crs(cut_crs)
361
- LOGGER.debug("Cutting with CRS: %s", df.crs)
400
+ df, cut_crs, cut_threshold = bisection_preparation(df, dggs, parent_res, cut_crs, cut_threshold)
362
401
 
363
402
  if id_field:
364
403
  df = df.set_index(id_field)
@@ -370,13 +409,21 @@ def index(
370
409
  # Remove all attributes except the geometry
371
410
  df = df.loc[:, ["geometry"]]
372
411
 
373
- LOGGER.debug("Cutting large geometries")
374
- with tqdm(total=df.shape[0], desc="Splitting") as pbar:
375
- for index, row in df.iterrows():
376
- df.loc[index, "geometry"] = GeometryCollection(
377
- katana.katana(row.geometry, cut_threshold)
378
- )
379
- pbar.update(1)
412
+ LOGGER.debug("Bisecting large geometries")
413
+
414
+ if cut_threshold is not None and cut_threshold > 0:
415
+ with ThreadPoolExecutor(max_workers=max(1, processes)) as executor:
416
+ futures = []
417
+ for index, row in df.iterrows():
418
+ future = executor.submit(bisect_geometry, row.geometry, cut_threshold)
419
+ futures.append((index, future))
420
+
421
+ with tqdm(total=len(futures), desc="Bisection") as pbar:
422
+ for index, future in futures:
423
+ df.at[index, "geometry"] = future.result()
424
+ pbar.update(1)
425
+ else:
426
+ LOGGER.debug("No bisection applied to input.")
380
427
 
381
428
  LOGGER.debug("Exploding geometry collections and multipolygons")
382
429
  df = (
@@ -427,28 +474,33 @@ def index(
427
474
  resolution,
428
475
  )
429
476
  with tempfile.TemporaryDirectory(suffix=".parquet") as tmpdir2:
430
- with Pool(processes=processes) as pool:
431
- args = [
432
- (
433
- dggs,
434
- dggsfunc,
435
- secondary_index_func,
436
- filepath,
437
- spatial_sort_col,
438
- resolution,
439
- parent_res,
440
- tmpdir2,
441
- compression,
442
- )
443
- for filepath in filepaths
444
- ]
445
- list(
446
- tqdm(
447
- pool.imap(polyfill_star, args),
448
- total=len(args),
449
- desc="DGGS indexing",
450
- )
477
+
478
+ args = [
479
+ (
480
+ dggs,
481
+ dggsfunc,
482
+ secondary_index_func,
483
+ filepath,
484
+ spatial_sort_col,
485
+ resolution,
486
+ parent_res,
487
+ tmpdir2,
488
+ compression,
451
489
  )
490
+ for filepath in filepaths
491
+ ]
492
+
493
+ with ProcessPoolExecutor(max_workers=processes) as executor:
494
+ futures = {executor.submit(polyfill_star, arg): arg for arg in args}
495
+
496
+ for future in tqdm(
497
+ as_completed(futures), total=len(futures), desc="DGGS indexing"
498
+ ):
499
+ try:
500
+ future.result()
501
+ except Exception as e:
502
+ LOGGER.error(f"Task failed with {e}")
503
+ raise (e)
452
504
 
453
505
  parent_partitioning(
454
506
  dggs,
vector2dggs/constants.py CHANGED
@@ -8,20 +8,6 @@ MIN_RHP, MAX_RHP = 0, 15
8
8
  MIN_S2, MAX_S2 = 0, 30
9
9
  MIN_GEOHASH, MAX_GEOHASH = 1, 12
10
10
 
11
- DEFAULTS = {
12
- "id": None,
13
- "k": False,
14
- "ch": 50,
15
- "s": "none",
16
- "crs": None,
17
- "c": 5000,
18
- "t": (multiprocessing.cpu_count() - 1),
19
- "cp": "snappy",
20
- "lyr": None,
21
- "g": "geom",
22
- "tempdir": tempfile.tempdir,
23
- }
24
-
25
11
  SPATIAL_SORTING_METHODS = ["hilbert", "morton", "geohash", "none"]
26
12
 
27
13
  DEFAULT_DGGS_PARENT_RES = {
@@ -70,6 +56,86 @@ S2_CELLS_MAX_AREA_M2_BY_LEVEL = {
70
56
  30: 0.93 * 1e-4,
71
57
  }
72
58
 
59
+ # https://h3geo.org/docs/core-library/restable/
60
+ H3_CELLS_MAX_AREA_KM2_BY_LEVEL = {
61
+ 0: 4977807.027442012,
62
+ 1: 729486.875275344,
63
+ 2: 104599.807218925,
64
+ 3: 14950.773301379,
65
+ 4: 2135.986983965,
66
+ 5: 305.144308779,
67
+ 6: 43.592111685,
68
+ 7: 6.227445905,
69
+ 8: 0.889635157,
70
+ 9: 0.127090737,
71
+ 10: 0.018155820,
72
+ 11: 0.002593689,
73
+ 12: 0.000370527,
74
+ 13: 0.000052932,
75
+ 14: 0.000007562,
76
+ 15: 0.000001080,
77
+ }
78
+
79
+ RHP_CELLS_AREA_KM2_BY_LEVEL = {
80
+ 0: 100151150.62856922,
81
+ 1: 11127905.62539658,
82
+ 2: 1236433.9583773974,
83
+ 3: 137381.55093082195,
84
+ 4: 15264.616770091328,
85
+ 5: 1696.0685300101482,
86
+ 6: 188.4520588900164,
87
+ 7: 20.939117654446267,
88
+ 8: 2.326568628271808,
89
+ 9: 0.25850762536353417,
90
+ 10: 0.02872306948483713,
91
+ 11: 0.003191452164981904,
92
+ 12: 0.0003546057961091004,
93
+ 13: 3.940064401212227 * 1e-5,
94
+ 14: 4.377849334680252 * 1e-6,
95
+ 15: 4.864277038533613 * 1e-7,
96
+ }
97
+
98
+ # https://www.movable-type.co.uk/scripts/geohash.html
99
+ GEOHASH_MAX_CELL_AREA_KM2_BY_LEVEL = {
100
+ 1: 5000 * 5000,
101
+ 2: 1250 * 625,
102
+ 3: 156 * 156,
103
+ 4: 39.1 * 19.5,
104
+ 5: 4.89 * 4.89,
105
+ 6: 1.22 * 0.61,
106
+ 7: 153 * 153 / 1e6,
107
+ 8: 38.2 * 19.1 / 1e6,
108
+ 9: 4.77 * 4.77 / 1e6,
109
+ 10: 1.19 * 0.596 / 1e6,
110
+ 11: 149 * 149 / 1e9,
111
+ 12: 37.2 * 18.6 / 1e9,
112
+ }
113
+
114
+ DGGS_CELL_AREA_M2_BY_RES = {
115
+ "s2": lambda res: S2_CELLS_MAX_AREA_M2_BY_LEVEL[res],
116
+ "h3": lambda res: H3_CELLS_MAX_AREA_KM2_BY_LEVEL[res] * 1e6,
117
+ "rhp": lambda res: RHP_CELLS_AREA_KM2_BY_LEVEL[res] * 1e6,
118
+ "geohash": lambda res: GEOHASH_MAX_CELL_AREA_KM2_BY_LEVEL[res] * 1e6,
119
+ }
120
+
121
+ DEFAULT_AREA_THRESHOLD_M2 = lambda dggs, parent_res: DGGS_CELL_AREA_M2_BY_RES[dggs](
122
+ parent_res
123
+ )
124
+
125
+ DEFAULTS = {
126
+ "id": None,
127
+ "k": False,
128
+ "ch": 50,
129
+ "s": "none",
130
+ "crs": None,
131
+ "c": None,
132
+ "t": (multiprocessing.cpu_count() - 1),
133
+ "cp": "snappy",
134
+ "lyr": None,
135
+ "g": "geom",
136
+ "tempdir": tempfile.tempdir,
137
+ }
138
+
73
139
 
74
140
  warnings.filterwarnings(
75
141
  "ignore"
vector2dggs/geohash.py CHANGED
@@ -217,10 +217,10 @@ def gh_compaction(
217
217
  @click.option(
218
218
  "-c",
219
219
  "--cut_threshold",
220
- required=True,
220
+ required=False,
221
221
  default=const.DEFAULTS["c"],
222
- type=int,
223
- help="Cutting up large geometries into smaller geometries based on a target length. Units are assumed to match the input CRS units unless the `--cut_crs` is also given, in which case units match the units of the supplied CRS.",
222
+ type=float,
223
+ help="Cutting up large geometries into smaller geometries based on a target area. Units are assumed to match the input CRS units unless the `--cut_crs` is also given, in which case units match the units of the supplied CRS. If left unspecified, the threshold will be the maximum area of a cell at the parent resolution, in square metres or feet according to the CRS. A threshold of 0 will skip bissection entirely (effectively ignoring --cut_crs).",
224
224
  nargs=1,
225
225
  )
226
226
  @click.option(
@@ -333,5 +333,3 @@ def geohash(
333
333
  )
334
334
  except:
335
335
  raise
336
- else:
337
- sys.exit(0)
vector2dggs/h3.py CHANGED
@@ -136,10 +136,10 @@ def h3compaction(
136
136
  @click.option(
137
137
  "-c",
138
138
  "--cut_threshold",
139
- required=True,
139
+ required=False,
140
140
  default=const.DEFAULTS["c"],
141
- type=int,
142
- help="Cutting up large geometries into smaller geometries based on a target length. Units are assumed to match the input CRS units unless the `--cut_crs` is also given, in which case units match the units of the supplied CRS.",
141
+ type=float,
142
+ help="Cutting up large geometries into smaller geometries based on a target area. Units are assumed to match the input CRS units unless the `--cut_crs` is also given, in which case units match the units of the supplied CRS. If left unspecified, the threshold will be the maximum area of a cell at the parent resolution, in square metres or feet according to the CRS. A threshold of 0 will skip bissection entirely (effectively ignoring --cut_crs).",
143
143
  nargs=1,
144
144
  )
145
145
  @click.option(
@@ -253,5 +253,3 @@ def h3(
253
253
  )
254
254
  except:
255
255
  raise
256
- else:
257
- sys.exit(0)
vector2dggs/katana.py CHANGED
@@ -30,14 +30,17 @@ def katana(
30
30
  geometry: Union[BaseGeometry, None],
31
31
  threshold: float,
32
32
  count: int = 0,
33
+ max_recursion_depth: int = 250,
33
34
  check_2D: bool = True,
34
35
  ) -> List[BaseGeometry]:
35
36
  """
36
37
  Recursively split a geometry into two parts across its shortest dimension.
37
38
  Invalid input `geometry` will silently be made valid (if possible).
38
39
  Any LinearRings will be converted to Polygons.
40
+ `threshold`: maximum acceptable area of the bounding box for any output geometry.
41
+ `count`: used to track recursion depth
39
42
  """
40
- if geometry is None:
43
+ if (geometry is None) or (geometry.is_empty):
41
44
  return []
42
45
  if isinstance(geometry, LinearRing):
43
46
  geometry = Polygon(geometry)
@@ -52,9 +55,7 @@ def katana(
52
55
  bounds = geometry.bounds
53
56
  width = bounds[2] - bounds[0]
54
57
  height = bounds[3] - bounds[1]
55
- if max(width, height) <= threshold or count == 250:
56
- # either the polygon is smaller than the threshold, or the maximum
57
- # number of recursions has been reached
58
+ if ((width * height) <= threshold) or (count >= max_recursion_depth):
58
59
  return [geometry]
59
60
  if height >= width:
60
61
  # split left to right
@@ -64,6 +65,8 @@ def katana(
64
65
  # split top to bottom
65
66
  a = box(bounds[0], bounds[1], bounds[0] + width / 2, bounds[3])
66
67
  b = box(bounds[0] + width / 2, bounds[1], bounds[2], bounds[3])
68
+ # Add additional vertices to help prevent indexing errors from use of EPSG:4386 later under the presence of long edges
69
+ a, b = map(lambda g: g.segmentize(min(width, height) / 4), [a, b])
67
70
  result = []
68
71
  for d in (
69
72
  a,
vector2dggs/rHP.py CHANGED
@@ -153,17 +153,17 @@ def rhpcompaction(
153
153
  @click.option(
154
154
  "-c",
155
155
  "--cut_threshold",
156
- required=True,
156
+ required=False,
157
157
  default=const.DEFAULTS["c"],
158
- type=int,
159
- help="Cutting up large geometries into smaller geometries based on a target length. Units are assumed to match the input CRS units unless the `--cut_crs` is also given, in which case units match the units of the supplied CRS.",
158
+ type=float,
159
+ help="Cutting up large geometries into smaller geometries based on a target area. Units are assumed to match the input CRS units unless the `--cut_crs` is also given, in which case units match the units of the supplied CRS. If left unspecified, the threshold will be the maximum area of a cell at the parent resolution, in square metres or feet according to the CRS. A threshold of 0 will skip bissection entirely (effectively ignoring --cut_crs).",
160
160
  nargs=1,
161
161
  )
162
162
  @click.option(
163
163
  "-t",
164
164
  "--threads",
165
165
  required=False,
166
- default=const.DEFAULTS["t"],
166
+ default=1,
167
167
  type=int,
168
168
  help="Amount of threads used for operation",
169
169
  nargs=1,
@@ -270,5 +270,3 @@ def rhp(
270
270
  )
271
271
  except:
272
272
  raise
273
- else:
274
- sys.exit(0)
vector2dggs/s2.py CHANGED
@@ -9,6 +9,7 @@ from s2geometry import pywraps2 as S2
9
9
 
10
10
  import pandas as pd
11
11
  import geopandas as gpd
12
+ from shapely import force_2d
12
13
  from shapely.geometry import box, Polygon, LineString, Point
13
14
  from shapely.ops import transform
14
15
  from pyproj import CRS, Transformer
@@ -71,6 +72,7 @@ def s2_polyfill_polygons(df: gpd.GeoDataFrame, level: int) -> gpd.GeoDataFrame:
71
72
  def generate_s2_covering(
72
73
  geom: Polygon, level: int, centroid_inside: bool = True
73
74
  ) -> set[S2.S2CellId]:
75
+ geom = force_2d(geom)
74
76
  # Prepare loops: first the exterior loop, then the interior loops
75
77
  loops = []
76
78
  # Exterior ring
@@ -296,10 +298,10 @@ def s2_compaction(
296
298
  @click.option(
297
299
  "-c",
298
300
  "--cut_threshold",
299
- required=True,
301
+ required=False,
300
302
  default=const.DEFAULTS["c"],
301
- type=int,
302
- help="Cutting up large geometries into smaller geometries based on a target length. Units are assumed to match the input CRS units unless the `--cut_crs` is also given, in which case units match the units of the supplied CRS.",
303
+ type=float,
304
+ help="Cutting up large geometries into smaller geometries based on a target area. Units are assumed to match the input CRS units unless the `--cut_crs` is also given, in which case units match the units of the supplied CRS. If left unspecified, the threshold will be the maximum area of a cell at the parent resolution, in square metres or feet according to the CRS. A threshold of 0 will skip bissection entirely (effectively ignoring --cut_crs).",
303
305
  nargs=1,
304
306
  )
305
307
  @click.option(
@@ -412,5 +414,3 @@ def s2(
412
414
  )
413
415
  except:
414
416
  raise
415
- else:
416
- sys.exit(0)
@@ -1,7 +1,8 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.1
2
2
  Name: vector2dggs
3
- Version: 0.10.1
3
+ Version: 0.11.0
4
4
  Summary: CLI DGGS indexer for vector geospatial data
5
+ Home-page: https://github.com/manaakiwhenua/vector2dggs
5
6
  License: LGPL-3.0-or-later
6
7
  Keywords: dggs,vector,h3,rHEALPix,cli
7
8
  Author: James Ardo
@@ -12,8 +13,6 @@ Requires-Python: >=3.11,<4.0
12
13
  Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)
13
14
  Classifier: Programming Language :: Python :: 3
14
15
  Classifier: Programming Language :: Python :: 3.11
15
- Classifier: Programming Language :: Python :: 3.12
16
- Classifier: Programming Language :: Python :: 3.13
17
16
  Classifier: Topic :: Scientific/Engineering
18
17
  Classifier: Topic :: Scientific/Engineering :: GIS
19
18
  Classifier: Topic :: Scientific/Engineering :: Information Analysis
@@ -122,12 +121,17 @@ Options:
122
121
  used for cutting large geometries (see
123
122
  `--cut_threshold`). Defaults to the same CRS
124
123
  as the input. Should be a valid EPSG code.
125
- -c, --cut_threshold INTEGER Cutting up large geometries into smaller
126
- geometries based on a target length. Units
127
- are assumed to match the input CRS units
128
- unless the `--cut_crs` is also given, in
129
- which case units match the units of the
130
- supplied CRS. [default: 5000; required]
124
+ -c, --cut_threshold FLOAT Cutting up large geometries into smaller
125
+ geometries based on a target area. Units are
126
+ assumed to match the input CRS units unless
127
+ the `--cut_crs` is also given, in which case
128
+ units match the units of the supplied CRS.
129
+ If left unspecified, the threshold will be
130
+ the maximum area of a cell at the parent
131
+ resolution, in square metres or feet
132
+ according to the CRS. A threshold of 0 will
133
+ skip bissection entirely (effectively
134
+ ignoring --cut_crs).
131
135
  -t, --threads INTEGER Amount of threads used for operation
132
136
  [default: NUM_CPUS - 1]
133
137
  -cp, --compression TEXT Compression method to use for the output
@@ -240,6 +244,17 @@ Alternatively, it is also possible to install using pip with `pip install -e .`,
240
244
 
241
245
  Please run `black .` before committing.
242
246
 
247
+ #### Tests
248
+
249
+ Tests are included. To run them, set up a poetry environment, then follow these instructons:
250
+
251
+ ```bash
252
+ cd tests
253
+ python ./test_vector2dggs.py
254
+ ```
255
+
256
+ Test data are included at `tests/data/`.
257
+
243
258
  ## Example commands
244
259
 
245
260
  With a local GPKG:
@@ -262,14 +277,14 @@ vector2dggs h3 -v DEBUG -id ogc_fid -r 9 -p 5 -t 4 --overwrite -lyr topo50_lake
262
277
  title={{vector2dggs}},
263
278
  author={Ardo, James and Law, Richard},
264
279
  url={https://github.com/manaakiwhenua/vector2dggs},
265
- version={0.10.1},
280
+ version={0.11.0},
266
281
  date={2023-04-20}
267
282
  }
268
283
  ```
269
284
 
270
285
  APA/Harvard
271
286
 
272
- > Ardo, J., & Law, R. (2023). vector2dggs (0.10.1) [Computer software]. https://github.com/manaakiwhenua/vector2dggs
287
+ > Ardo, J., & Law, R. (2023). vector2dggs (0.11.0) [Computer software]. https://github.com/manaakiwhenua/vector2dggs
273
288
 
274
289
  [![manaakiwhenua-standards](https://github.com/manaakiwhenua/vector2dggs/workflows/manaakiwhenua-standards/badge.svg)](https://github.com/manaakiwhenua/manaakiwhenua-standards)
275
290
 
@@ -0,0 +1,15 @@
1
+ vector2dggs/__init__.py,sha256=NhOfSRUl_Py_CNCpR3FsS3g_Mf4pHgA87tFPBLl3BQM,28
2
+ vector2dggs/cli.py,sha256=d_4skD62k6pXUWgDdVHbDwpe4A4yo62ZFx8Cp_6GpBA,767
3
+ vector2dggs/common.py,sha256=hHhO_BZVL8GLFpzwm9Jw5cSaIy1bNk_hs0snEcNNVjQ,16893
4
+ vector2dggs/constants.py,sha256=UIQoS8IsfeFR1eoIkmByq9UgoJkkqI3pbUqSNCEfFmo,3476
5
+ vector2dggs/geohash.py,sha256=Px4EcRJ1cFFVMHJB7zgZLZXKYXhLQObxvE_QqMYLEKw,10593
6
+ vector2dggs/h3.py,sha256=UnCH0m0Z9zGc_kSg5igFEz565f7Nr3aVe5Vex01WKRw,7603
7
+ vector2dggs/katana.py,sha256=xD8BJ5hRQZyioStIMRJ_Gt1D9x9RotqP-YrB3TKHCSM,3850
8
+ vector2dggs/rHP.py,sha256=KILnXvAzSinied3mLw4IURLlcK78U7xcSnKQ5afPzn4,8286
9
+ vector2dggs/s2.py,sha256=6i6ecnPykgGRG-ZiyUP7JjgQzPUUklMZwd-JYs4X8K8,13063
10
+ vector2dggs-0.11.0.dist-info/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
11
+ vector2dggs-0.11.0.dist-info/COPYING.LESSER,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
12
+ vector2dggs-0.11.0.dist-info/METADATA,sha256=hZhgdrp7LiRGfIPbWyC3nl1ri1RtOLN9BE85CgqyCQg,13170
13
+ vector2dggs-0.11.0.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
14
+ vector2dggs-0.11.0.dist-info/entry_points.txt,sha256=5h8LB9L2oOE5u_N7FRGtu4JDwa553iPs4u0XhcLeLZU,52
15
+ vector2dggs-0.11.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.3
2
+ Generator: poetry-core 1.6.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,15 +0,0 @@
1
- vector2dggs/__init__.py,sha256=zkryc4Uha10GTKJDVvFVRKEySO4-gejqb9sTlyYC-EE,28
2
- vector2dggs/cli.py,sha256=d_4skD62k6pXUWgDdVHbDwpe4A4yo62ZFx8Cp_6GpBA,767
3
- vector2dggs/common.py,sha256=rQL1_rFr1VTyILffOZgdwPzZS1JThn4TBPswfCkMjbM,14471
4
- vector2dggs/constants.py,sha256=KdmBQCP_GCygzvDLtS8AMQM9i6QqOkf-9YQkh_AzrKc,1779
5
- vector2dggs/geohash.py,sha256=PVLkaaSVLgzDZNfuL0y3Xioh4pyvom845HuyLIAsLUY,10398
6
- vector2dggs/h3.py,sha256=Juvc8g4QWfDIco9RQHaX8p9S9rkW5QvusxpyO-G7eSs,7408
7
- vector2dggs/katana.py,sha256=v4BRzVCsroC6RzIYdxLfrr9eFOdmXb5S9jXBMs5tgSo,3571
8
- vector2dggs/rHP.py,sha256=UoRdidkkVGhGP85wrfBE_5BNrx1Xg5skQQe1F5X0LZ8,8109
9
- vector2dggs/s2.py,sha256=SOXMHQQq86bM88MDgBBemGiXIbuEIbrhLSgPwLKceLY,12809
10
- vector2dggs-0.10.1.dist-info/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
11
- vector2dggs-0.10.1.dist-info/COPYING.LESSER,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
12
- vector2dggs-0.10.1.dist-info/METADATA,sha256=MNgUCPkWdxUte-n8iRQUgCFAdv_rOXp-GtPvK7vaTNU,12652
13
- vector2dggs-0.10.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
14
- vector2dggs-0.10.1.dist-info/entry_points.txt,sha256=5h8LB9L2oOE5u_N7FRGtu4JDwa553iPs4u0XhcLeLZU,52
15
- vector2dggs-0.10.1.dist-info/RECORD,,