transformez 0.5.0__tar.gz → 0.5.2__tar.gz
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.
- {transformez-0.5.0 → transformez-0.5.2}/PKG-INFO +5 -3
- {transformez-0.5.0 → transformez-0.5.2}/README.md +2 -1
- {transformez-0.5.0 → transformez-0.5.2}/pyproject.toml +2 -1
- {transformez-0.5.0 → transformez-0.5.2}/src/transformez/_version.py +1 -1
- {transformez-0.5.0 → transformez-0.5.2}/src/transformez/cli.py +12 -11
- {transformez-0.5.0 → transformez-0.5.2}/src/transformez/grid_engine.py +20 -11
- {transformez-0.5.0 → transformez-0.5.2}/src/transformez/srs.py +80 -17
- {transformez-0.5.0 → transformez-0.5.2}/AUTHORS.md +0 -0
- {transformez-0.5.0 → transformez-0.5.2}/CHANGELOG.md +0 -0
- {transformez-0.5.0 → transformez-0.5.2}/CITATION.cff +0 -0
- {transformez-0.5.0 → transformez-0.5.2}/CONTRIBUTING.md +0 -0
- {transformez-0.5.0 → transformez-0.5.2}/LICENSE +0 -0
- {transformez-0.5.0 → transformez-0.5.2}/src/transformez/__init__.py +0 -0
- {transformez-0.5.0 → transformez-0.5.2}/src/transformez/_spatial.py +0 -0
- {transformez-0.5.0 → transformez-0.5.2}/src/transformez/api.py +0 -0
- {transformez-0.5.0 → transformez-0.5.2}/src/transformez/definitions.py +0 -0
- {transformez-0.5.0 → transformez-0.5.2}/src/transformez/hooks.py +0 -0
- {transformez-0.5.0 → transformez-0.5.2}/src/transformez/htdp.py +0 -0
- {transformez-0.5.0 → transformez-0.5.2}/src/transformez/modules.py +0 -0
- {transformez-0.5.0 → transformez-0.5.2}/src/transformez/transform.py +0 -0
- {transformez-0.5.0 → transformez-0.5.2}/src/transformez/utils.py +0 -0
- {transformez-0.5.0 → transformez-0.5.2}/src/transformez/vdatum.py +0 -0
- {transformez-0.5.0 → transformez-0.5.2}/tests/test_cli.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: transformez
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.2
|
|
4
4
|
Summary: A standalone utility for vertical elevation datum transformations.
|
|
5
5
|
Project-URL: Homepage, https://github.com/continuous-dems/transformez
|
|
6
6
|
Project-URL: Issues, https://github.com/continuous-dems/transformez/issues
|
|
@@ -36,11 +36,12 @@ Classifier: Topic :: Scientific/Engineering :: GIS
|
|
|
36
36
|
Requires-Python: >=3.12
|
|
37
37
|
Requires-Dist: click
|
|
38
38
|
Requires-Dist: fetchez>=0.6.0
|
|
39
|
-
Requires-Dist: fiona
|
|
40
39
|
Requires-Dist: numpy>1.24
|
|
40
|
+
Requires-Dist: pyogrio>=0.7.0
|
|
41
41
|
Requires-Dist: pyproj>3.6.1
|
|
42
42
|
Requires-Dist: rasterio>1.4.0
|
|
43
43
|
Requires-Dist: scipy
|
|
44
|
+
Requires-Dist: shapely>=2.0.0
|
|
44
45
|
Provides-Extra: full
|
|
45
46
|
Requires-Dist: matplotlib; extra == 'full'
|
|
46
47
|
Provides-Extra: preview
|
|
@@ -56,10 +57,11 @@ Description-Content-Type: text/markdown
|
|
|
56
57
|
<p align="center"><strong>Global vertical datum transformations, simplified.</strong></p>
|
|
57
58
|
|
|
58
59
|
<p align="center">
|
|
59
|
-
<a href="https://github.com/continuous-dems/transformez"><img src="https://img.shields.io/badge/version-0.5.
|
|
60
|
+
<a href="https://github.com/continuous-dems/transformez"><img src="https://img.shields.io/badge/version-0.5.1-blue.svg" alt="Version"></a>
|
|
60
61
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License"></a>
|
|
61
62
|
<a href="https://www.python.org/"><img src="https://img.shields.io/badge/python-3.12+-yellow.svg" alt="Python"></a>
|
|
62
63
|
<a href="https://badge.fury.io/py/transformez"><img src="https://badge.fury.io/py/transformez.svg" alt="PyPI version"></a>
|
|
64
|
+
<a href="https://anaconda.org/conda-forge/transformez"><img src="https://img.shields.io/conda/vn/conda-forge/transformez.svg" alt="Conda Version"></a>
|
|
63
65
|
<a href="https://cudem.zulip.org"><img src="https://img.shields.io/badge/zulip-join_chat-brightgreen.svg" alt="Project Chat"></a>
|
|
64
66
|
</p>
|
|
65
67
|
|
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
<p align="center"><strong>Global vertical datum transformations, simplified.</strong></p>
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
10
|
-
<a href="https://github.com/continuous-dems/transformez"><img src="https://img.shields.io/badge/version-0.5.
|
|
10
|
+
<a href="https://github.com/continuous-dems/transformez"><img src="https://img.shields.io/badge/version-0.5.1-blue.svg" alt="Version"></a>
|
|
11
11
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License"></a>
|
|
12
12
|
<a href="https://www.python.org/"><img src="https://img.shields.io/badge/python-3.12+-yellow.svg" alt="Python"></a>
|
|
13
13
|
<a href="https://badge.fury.io/py/transformez"><img src="https://badge.fury.io/py/transformez.svg" alt="PyPI version"></a>
|
|
14
|
+
<a href="https://anaconda.org/conda-forge/transformez"><img src="https://img.shields.io/conda/vn/conda-forge/transformez.svg" alt="Conda Version"></a>
|
|
14
15
|
<a href="https://cudem.zulip.org"><img src="https://img.shields.io/badge/zulip-join_chat-brightgreen.svg" alt="Project Chat"></a>
|
|
15
16
|
</p>
|
|
16
17
|
|
|
@@ -29,17 +29,18 @@ TRANSFORMEZ_COMMANDS = {
|
|
|
29
29
|
class TransformezMainGroup(FetchezMainGroup):
|
|
30
30
|
"""A custom Click Group that handles deprecated aliases."""
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
32
|
+
pass
|
|
33
|
+
# def get_command(self, ctx, cmd_name):
|
|
34
|
+
# if cmd_name == "run":
|
|
35
|
+
# click.secho(
|
|
36
|
+
# " DEPRECATION WARNING: 'transformez run' is deprecated and will be removed in a future release.\n"
|
|
37
|
+
# "Please use 'transformez grid' to generate shift grids or 'transformez raster' to shift a raster.",
|
|
38
|
+
# fg="yellow",
|
|
39
|
+
# err=True,
|
|
40
|
+
# )
|
|
41
|
+
# return click.Group.get_command(self, ctx, "run")
|
|
42
|
+
|
|
43
|
+
# return click.Group.get_command(self, ctx, cmd_name)
|
|
43
44
|
|
|
44
45
|
# def format_commands(self, ctx, formatter):
|
|
45
46
|
# commands = []
|
|
@@ -79,18 +79,19 @@ def plot_grid(grid_array, region, title="Vertical Shift Preview"):
|
|
|
79
79
|
|
|
80
80
|
class GridEngine:
|
|
81
81
|
@staticmethod
|
|
82
|
-
def create_land_mask(region, nx, ny,
|
|
83
|
-
"""Reads a list of vector
|
|
82
|
+
def create_land_mask(region, nx, ny, vector_files):
|
|
83
|
+
"""Reads a list of vector files and rasterizes them into a boolean land mask.
|
|
84
84
|
Returns a numpy boolean array where True = Land, False = Ocean.
|
|
85
85
|
"""
|
|
86
86
|
|
|
87
87
|
try:
|
|
88
|
-
import
|
|
88
|
+
from pyogrio.raw import read
|
|
89
|
+
import shapely
|
|
89
90
|
from rasterio.features import rasterize
|
|
90
91
|
|
|
91
92
|
except ImportError:
|
|
92
93
|
logger.warning(
|
|
93
|
-
"
|
|
94
|
+
"pyogrio and shapely are required for vector coastline masking."
|
|
94
95
|
)
|
|
95
96
|
return None
|
|
96
97
|
|
|
@@ -99,16 +100,24 @@ class GridEngine:
|
|
|
99
100
|
)
|
|
100
101
|
|
|
101
102
|
geoms = []
|
|
102
|
-
for
|
|
103
|
+
for vec_path in vector_files:
|
|
103
104
|
try:
|
|
104
|
-
# Use bbox filtering in
|
|
105
|
+
# Use bbox filtering in pyogrio to speed up reading vectors
|
|
105
106
|
bbox = (region.xmin, region.ymin, region.xmax, region.ymax)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
|
|
108
|
+
# pyogrio raw read returns a tuple: (meta, geometry_wkb, field_data)
|
|
109
|
+
meta, fids, geometry_wkb, fields = read(vec_path, bbox=bbox)
|
|
110
|
+
|
|
111
|
+
if len(geometry_wkb) > 0:
|
|
112
|
+
# Convert WKB directly to shapely geometries
|
|
113
|
+
# We also filter out any None/Null geometries
|
|
114
|
+
valid_geoms = [
|
|
115
|
+
g for g in shapely.from_wkb(geometry_wkb) if g is not None
|
|
116
|
+
]
|
|
117
|
+
geoms.extend(valid_geoms)
|
|
118
|
+
|
|
110
119
|
except Exception as e:
|
|
111
|
-
logger.warning(f"Failed reading coastline
|
|
120
|
+
logger.warning(f"Failed reading coastline vector {vec_path}: {e}")
|
|
112
121
|
|
|
113
122
|
if not geoms:
|
|
114
123
|
return None
|
|
@@ -16,6 +16,10 @@ import os
|
|
|
16
16
|
import logging
|
|
17
17
|
from pyproj import CRS, Transformer
|
|
18
18
|
|
|
19
|
+
import numpy as np
|
|
20
|
+
from rasterio.warp import transform_bounds, reproject, Resampling
|
|
21
|
+
from rasterio.transform import from_bounds
|
|
22
|
+
|
|
19
23
|
from fetchez.spatial import Region
|
|
20
24
|
from .definitions import Datums
|
|
21
25
|
from .transform import VerticalTransform
|
|
@@ -145,7 +149,7 @@ class SRSParser:
|
|
|
145
149
|
self.tc["want_vertical"] = has_src_vert or has_dst_vert
|
|
146
150
|
|
|
147
151
|
def set_vertical_transform(self):
|
|
148
|
-
"""Generates the vertical shift grid using VerticalTransform."""
|
|
152
|
+
"""Generates the vertical shift grid using VerticalTransform, aligned to src_crs."""
|
|
149
153
|
|
|
150
154
|
if not self.region or not self.tc["want_vertical"]:
|
|
151
155
|
return
|
|
@@ -162,7 +166,6 @@ class SRSParser:
|
|
|
162
166
|
|
|
163
167
|
if not s_ident and self.tc["src_geoid"]:
|
|
164
168
|
s_ident = 6319
|
|
165
|
-
|
|
166
169
|
if not d_ident and self.tc["dst_geoid"]:
|
|
167
170
|
d_ident = 6319
|
|
168
171
|
|
|
@@ -178,10 +181,32 @@ class SRSParser:
|
|
|
178
181
|
logger.info(
|
|
179
182
|
f"Generating vertical grid: {s_ident} -> {d_ident} : {self.tc['trans_fn']} :"
|
|
180
183
|
)
|
|
184
|
+
|
|
185
|
+
# Determine Native WGS84 Region for Transformez
|
|
186
|
+
src_is_projected = self.tc["src_crs"].is_projected
|
|
187
|
+
if src_is_projected:
|
|
188
|
+
# Transform the native bounding box to WGS84 to query the shift models
|
|
189
|
+
w, s, e, n = transform_bounds(
|
|
190
|
+
self.tc["src_crs"],
|
|
191
|
+
"EPSG:4326",
|
|
192
|
+
proc_region.xmin,
|
|
193
|
+
proc_region.ymin,
|
|
194
|
+
proc_region.xmax,
|
|
195
|
+
proc_region.ymax,
|
|
196
|
+
)
|
|
197
|
+
vt_region = Region(w, e, s, n)
|
|
198
|
+
else:
|
|
199
|
+
vt_region = proc_region
|
|
200
|
+
|
|
201
|
+
# Generate grid resolution based on WGS84 bounds (approx 3 arc-seconds)
|
|
202
|
+
inc_deg = 3.0 / 3600.0
|
|
203
|
+
vt_nx = max(10, int(vt_region.width / inc_deg))
|
|
204
|
+
vt_ny = max(10, int(vt_region.height / inc_deg))
|
|
205
|
+
|
|
181
206
|
vt = VerticalTransform(
|
|
182
|
-
|
|
183
|
-
nx=
|
|
184
|
-
ny=
|
|
207
|
+
vt_region,
|
|
208
|
+
nx=vt_nx,
|
|
209
|
+
ny=vt_ny,
|
|
185
210
|
epsg_in=s_ident,
|
|
186
211
|
epsg_out=d_ident,
|
|
187
212
|
geoid_in=self.tc["src_geoid"],
|
|
@@ -189,27 +214,65 @@ class SRSParser:
|
|
|
189
214
|
cache_dir=self.cache_dir,
|
|
190
215
|
)
|
|
191
216
|
shift_arr, _ = vt._vertical_transform(vt.epsg_in, vt.epsg_out)
|
|
217
|
+
|
|
218
|
+
# Warp the Grid Back to the Source CRS
|
|
219
|
+
if src_is_projected:
|
|
220
|
+
logger.info(
|
|
221
|
+
f"Warping shift grid to native input CRS ({self.tc['src_crs'].name})..."
|
|
222
|
+
)
|
|
223
|
+
wgs_transform = from_bounds(
|
|
224
|
+
vt_region.xmin,
|
|
225
|
+
vt_region.ymin,
|
|
226
|
+
vt_region.xmax,
|
|
227
|
+
vt_region.ymax,
|
|
228
|
+
vt_nx,
|
|
229
|
+
vt_ny,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
# Output grid dimensions for the native projection
|
|
233
|
+
out_nx = max(10, int(proc_region.width / (proc_region.width / vt_nx)))
|
|
234
|
+
out_ny = max(10, int(proc_region.height / (proc_region.height / vt_ny)))
|
|
235
|
+
native_transform = from_bounds(
|
|
236
|
+
proc_region.xmin,
|
|
237
|
+
proc_region.ymin,
|
|
238
|
+
proc_region.xmax,
|
|
239
|
+
proc_region.ymax,
|
|
240
|
+
out_nx,
|
|
241
|
+
out_ny,
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
native_shift_array = np.zeros((out_ny, out_nx), dtype=np.float32)
|
|
245
|
+
|
|
246
|
+
reproject(
|
|
247
|
+
source=shift_arr,
|
|
248
|
+
destination=native_shift_array,
|
|
249
|
+
src_transform=wgs_transform,
|
|
250
|
+
src_crs="EPSG:4326",
|
|
251
|
+
dst_transform=native_transform,
|
|
252
|
+
dst_crs=self.tc["src_crs"],
|
|
253
|
+
resampling=Resampling.bilinear,
|
|
254
|
+
)
|
|
255
|
+
shift_arr = native_shift_array
|
|
256
|
+
|
|
257
|
+
# We artificially inject the native transform into proc_region to satisfy GridWriter
|
|
258
|
+
proc_region.transform = native_transform
|
|
259
|
+
|
|
260
|
+
# Write the natively-aligned grid to disk!
|
|
192
261
|
GridWriter.write(self.tc["trans_fn"], shift_arr, proc_region)
|
|
193
262
|
|
|
194
263
|
self.manual_vert_grid = self.tc["trans_fn"]
|
|
195
264
|
|
|
196
265
|
def get_components(self):
|
|
197
266
|
"""Returns the components:
|
|
198
|
-
|
|
199
|
-
-
|
|
200
|
-
- Transformer: Hub -> Dest (2D)
|
|
201
|
-
- Grid Path (str) or None
|
|
267
|
+
- Transformer: Source -> Dest (Single Pass Horizontal)
|
|
268
|
+
- Grid Path (str) or None (Aligned to Source)
|
|
202
269
|
"""
|
|
203
270
|
|
|
204
271
|
if self.tc["want_vertical"] and not self.manual_vert_grid:
|
|
205
272
|
self.set_vertical_transform()
|
|
206
273
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
# only build 2D transformer (for proj). We'll apply the vertical grid ourselves,
|
|
211
|
-
# as pyproj seems finicky when it comes to this.
|
|
212
|
-
t_to_hub = Transformer.from_crs(self.tc["src_crs"], hub_crs, always_xy=True)
|
|
213
|
-
t_from_hub = Transformer.from_crs(hub_crs, self.tc["dst_crs"], always_xy=True)
|
|
274
|
+
horz_transformer = Transformer.from_crs(
|
|
275
|
+
self.tc["src_crs"], self.tc["dst_crs"], always_xy=True
|
|
276
|
+
)
|
|
214
277
|
|
|
215
|
-
return
|
|
278
|
+
return horz_transformer, self.manual_vert_grid
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|