transformez 0.2.2__tar.gz → 0.3.0__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.3.0/PKG-INFO +179 -0
- transformez-0.3.0/README.md +132 -0
- {transformez-0.2.2 → transformez-0.3.0}/pyproject.toml +34 -6
- {transformez-0.2.2 → transformez-0.3.0}/src/transformez/__init__.py +6 -35
- {transformez-0.2.2 → transformez-0.3.0}/src/transformez/_version.py +1 -1
- transformez-0.3.0/src/transformez/api.py +194 -0
- {transformez-0.2.2 → transformez-0.3.0}/src/transformez/cli.py +30 -15
- {transformez-0.2.2 → transformez-0.3.0}/src/transformez/definitions.py +4 -3
- {transformez-0.2.2 → transformez-0.3.0}/src/transformez/hooks.py +12 -5
- {transformez-0.2.2 → transformez-0.3.0}/src/transformez/htdp.py +83 -16
- {transformez-0.2.2 → transformez-0.3.0}/src/transformez/modules.py +9 -14
- {transformez-0.2.2 → transformez-0.3.0}/src/transformez/spatial.py +39 -39
- {transformez-0.2.2 → transformez-0.3.0}/src/transformez/srs.py +19 -3
- {transformez-0.2.2 → transformez-0.3.0}/src/transformez/transform.py +51 -6
- {transformez-0.2.2 → transformez-0.3.0}/tests/test_cli.py +5 -1
- transformez-0.2.2/PKG-INFO +0 -128
- transformez-0.2.2/README.md +0 -85
- {transformez-0.2.2 → transformez-0.3.0}/AUTHORS.md +0 -0
- {transformez-0.2.2 → transformez-0.3.0}/CHANGELOG.md +0 -0
- {transformez-0.2.2 → transformez-0.3.0}/CITATION.cff +0 -0
- {transformez-0.2.2 → transformez-0.3.0}/CONTRIBUTING.md +0 -0
- {transformez-0.2.2 → transformez-0.3.0}/LICENSE +0 -0
- {transformez-0.2.2 → transformez-0.3.0}/src/transformez/grid_engine.py +0 -0
- {transformez-0.2.2 → transformez-0.3.0}/src/transformez/utils.py +0 -0
- {transformez-0.2.2 → transformez-0.3.0}/src/transformez/vdatum.py +0 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: transformez
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: A standalone utility for vertical elevation datum transformations.
|
|
5
|
+
Project-URL: Homepage, https://github.com/continuous-dems/transformez
|
|
6
|
+
Project-URL: Issues, https://github.com/continuous-dems/transformez/issues
|
|
7
|
+
Author-email: Matthew Love <matthew.love@colorado.edu>, Christopher Amante <christopher.amante@colorado.edu>, Elliot Lim <elliot.lim@colorado.edu>, Michael MacFerrin <michael.macferrin@colorado.edu>, Matt Fisher <mfisher87@gmail.com>
|
|
8
|
+
Maintainer-email: Matthew Love <matthew.love@colorado.edu>
|
|
9
|
+
License: MIT License
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2010-2026 Regents of the University of Colorado
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
in the Software without restriction, including without limitation the rights
|
|
16
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
furnished to do so, subject to the following conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
|
+
SOFTWARE.
|
|
30
|
+
License-File: AUTHORS.md
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Keywords: Geospatial
|
|
33
|
+
Classifier: Operating System :: OS Independent
|
|
34
|
+
Classifier: Programming Language :: Python :: 3
|
|
35
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
36
|
+
Requires-Python: >=3.12
|
|
37
|
+
Requires-Dist: fetchez>=0.5.0
|
|
38
|
+
Requires-Dist: numpy>1.24
|
|
39
|
+
Requires-Dist: pyproj>3.6.1
|
|
40
|
+
Requires-Dist: rasterio>1.4.0
|
|
41
|
+
Requires-Dist: scipy
|
|
42
|
+
Provides-Extra: full
|
|
43
|
+
Requires-Dist: matplotlib; extra == 'full'
|
|
44
|
+
Provides-Extra: preview
|
|
45
|
+
Requires-Dist: matplotlib; extra == 'preview'
|
|
46
|
+
Description-Content-Type: text/markdown
|
|
47
|
+
|
|
48
|
+
<!-- <p align="center"> -->
|
|
49
|
+
<!-- <a href="https://github.com/continuous-dems"> -->
|
|
50
|
+
<!-- <img src="https://github.com/continuous-dems/fetchez/blob/modules/docs/source/_static/continuous_dems_logo.svg" height="80" alt="Continuous DEMs Logo"> -->
|
|
51
|
+
<!-- </a> -->
|
|
52
|
+
<!-- </p> -->
|
|
53
|
+
<h1 align="center">Transformez</h1>
|
|
54
|
+
<p align="center"><strong>Global vertical datum transformations, simplified.</strong></p>
|
|
55
|
+
|
|
56
|
+
<p align="center">
|
|
57
|
+
<a href="https://github.com/continuous-dems/transformez"><img src="https://img.shields.io/badge/version-0.3.0-blue.svg" alt="Version"></a>
|
|
58
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License"></a>
|
|
59
|
+
<a href="https://www.python.org/"><img src="https://img.shields.io/badge/python-3.12+-yellow.svg" alt="Python"></a>
|
|
60
|
+
<a href="https://badge.fury.io/py/transformez"><img src="https://badge.fury.io/py/transformez.svg" alt="PyPI version"></a>
|
|
61
|
+
<a href="https://cudem.zulip.org"><img src="https://img.shields.io/badge/zulip-join_chat-brightgreen.svg" alt="Project Chat"></a>
|
|
62
|
+
</p>
|
|
63
|
+
|
|
64
|
+
**Transformez** is a standalone Python engine for converting geospatial data between vertical datums (e.g., `MLLW` ↔ `NAVD88` ↔ `Ellipsoid`).
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+

|
|
69
|
+
*(Above: A generated vertical shift grid transforming MLLW to NAVD88)*
|
|
70
|
+
|
|
71
|
+
## Installation
|
|
72
|
+
|
|
73
|
+
### Prerequisites: HTDP
|
|
74
|
+
Transformez relies on the NGS Horizontal Time-Dependent Positioning (HTDP) software to perform highly accurate plate tectonic and frame transformations. **You must install this separately.**
|
|
75
|
+
|
|
76
|
+
**For Windows:**
|
|
77
|
+
1. Download the pre-compiled executable (`htdp.exe`) directly from the [NOAA HTDP page](https://geodesy.noaa.gov/TOOLS/Htdp/Htdp.shtml).
|
|
78
|
+
2. Place `htdp.exe` in a directory that is in your system's `PATH` (e.g., `C:\Windows\System32` or a custom scripts folder).
|
|
79
|
+
|
|
80
|
+
**For Linux / macOS:**
|
|
81
|
+
|
|
82
|
+
You will need a Fortran compiler (like `gfortran`) to compile the source code.
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# 1. Download the Fortran source code
|
|
86
|
+
wget https://geodesy.noaa.gov/TOOLS/Htdp/HTDP-download.zip
|
|
87
|
+
unzip HTDP-download.zip
|
|
88
|
+
|
|
89
|
+
# 2. Compile it
|
|
90
|
+
gfortran -o htdp htdp.f
|
|
91
|
+
|
|
92
|
+
# 3. Move it to your PATH
|
|
93
|
+
sudo mv htdp /usr/local/bin/
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Install Transformez
|
|
97
|
+
Once HTDP is accessible in your terminal, install the python package:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
pip install transformez
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Usage
|
|
104
|
+
|
|
105
|
+
**Generate a vertical shift grid for anywhere on Earth.**
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# Transform MLLW to WGS84 Ellipsoid in Norton Sound, AK
|
|
109
|
+
# (Where NOAA has no coverage!)
|
|
110
|
+
transformez -R -166/-164/63/64 -E 3s \
|
|
111
|
+
--input-datum mllw \
|
|
112
|
+
--output-datum 4979 \
|
|
113
|
+
--output shift_ak.tif
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Transform a raster directly.** Transformez reads the bounds/resolution from the file.
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
transformez --dem input_bathymetry.tif \
|
|
120
|
+
--input-datum "mllw" \
|
|
121
|
+
--output-datum "5703:geoid=geoid12b" \
|
|
122
|
+
--output output_navd88.tif
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Integrate directly into your download pipeline.**
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# Download GEBCO and shift EGM96 to WGS84 on the fly
|
|
129
|
+
fetchez gebco ... --hook transformez:datum_in=5773,datum_out=4979
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Python API
|
|
133
|
+
|
|
134
|
+
Transformez provides a high-level API for embedding transformations directly into your Python scripts, Jupyter Notebooks, or automated pipelines.
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
import transformez
|
|
138
|
+
|
|
139
|
+
# ---------------------------------------------------------
|
|
140
|
+
# Generate a Shift Grid
|
|
141
|
+
# ---------------------------------------------------------
|
|
142
|
+
# Returns a 2D numpy array. Optionally saves to a file.
|
|
143
|
+
# Requesting "mllw" in India triggers the Global Fallback (FES2014) automatically.
|
|
144
|
+
|
|
145
|
+
shift_array = transformez.generate_grid(
|
|
146
|
+
region=[80, 85, 10, 15], # [West, East, South, North]
|
|
147
|
+
increment="3s", # Grid resolution
|
|
148
|
+
datum_in="mllw",
|
|
149
|
+
datum_out="4979", # WGS84 Ellipsoid
|
|
150
|
+
out_fn="india_shift.tif" # Optional: Save to disk
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
# ---------------------------------------------------------
|
|
154
|
+
# Transform an Existing Raster
|
|
155
|
+
# ---------------------------------------------------------
|
|
156
|
+
# Applies the datum shift directly to a DEM and saves the result.
|
|
157
|
+
|
|
158
|
+
out_file = transformez.transform_raster(
|
|
159
|
+
input_raster="my_dem_mllw.tif",
|
|
160
|
+
datum_in="mllw",
|
|
161
|
+
datum_out="5703:g2012b", # NAVD88 using specific GEOID12B
|
|
162
|
+
output_raster="my_dem_navd88.tif"
|
|
163
|
+
)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Supported Datums
|
|
167
|
+
|
|
168
|
+
* **Tidal**: mllw, mhhw, msl, lat
|
|
169
|
+
|
|
170
|
+
* **Ellipsoidal**: 4979 (WGS84), 6319 (NAD83 2011)
|
|
171
|
+
|
|
172
|
+
* **Orthometric**: 5703 (NAVD88), egm2008, egm96
|
|
173
|
+
|
|
174
|
+
* **Geoids**: g2018, g2012b, geoid09, xgeoid20b
|
|
175
|
+
|
|
176
|
+
## License
|
|
177
|
+
|
|
178
|
+
This project is licensed under the MIT License - see the [LICENSE](https://github.com/ciresdem/transformez/blob/main/LICENSE) file for details.
|
|
179
|
+
Copyright (c) 2010-2026 Regents of the University of Colorado
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<!-- <p align="center"> -->
|
|
2
|
+
<!-- <a href="https://github.com/continuous-dems"> -->
|
|
3
|
+
<!-- <img src="https://github.com/continuous-dems/fetchez/blob/modules/docs/source/_static/continuous_dems_logo.svg" height="80" alt="Continuous DEMs Logo"> -->
|
|
4
|
+
<!-- </a> -->
|
|
5
|
+
<!-- </p> -->
|
|
6
|
+
<h1 align="center">Transformez</h1>
|
|
7
|
+
<p align="center"><strong>Global vertical datum transformations, simplified.</strong></p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://github.com/continuous-dems/transformez"><img src="https://img.shields.io/badge/version-0.3.0-blue.svg" alt="Version"></a>
|
|
11
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License"></a>
|
|
12
|
+
<a href="https://www.python.org/"><img src="https://img.shields.io/badge/python-3.12+-yellow.svg" alt="Python"></a>
|
|
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://cudem.zulip.org"><img src="https://img.shields.io/badge/zulip-join_chat-brightgreen.svg" alt="Project Chat"></a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
**Transformez** is a standalone Python engine for converting geospatial data between vertical datums (e.g., `MLLW` ↔ `NAVD88` ↔ `Ellipsoid`).
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+

|
|
22
|
+
*(Above: A generated vertical shift grid transforming MLLW to NAVD88)*
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
### Prerequisites: HTDP
|
|
27
|
+
Transformez relies on the NGS Horizontal Time-Dependent Positioning (HTDP) software to perform highly accurate plate tectonic and frame transformations. **You must install this separately.**
|
|
28
|
+
|
|
29
|
+
**For Windows:**
|
|
30
|
+
1. Download the pre-compiled executable (`htdp.exe`) directly from the [NOAA HTDP page](https://geodesy.noaa.gov/TOOLS/Htdp/Htdp.shtml).
|
|
31
|
+
2. Place `htdp.exe` in a directory that is in your system's `PATH` (e.g., `C:\Windows\System32` or a custom scripts folder).
|
|
32
|
+
|
|
33
|
+
**For Linux / macOS:**
|
|
34
|
+
|
|
35
|
+
You will need a Fortran compiler (like `gfortran`) to compile the source code.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# 1. Download the Fortran source code
|
|
39
|
+
wget https://geodesy.noaa.gov/TOOLS/Htdp/HTDP-download.zip
|
|
40
|
+
unzip HTDP-download.zip
|
|
41
|
+
|
|
42
|
+
# 2. Compile it
|
|
43
|
+
gfortran -o htdp htdp.f
|
|
44
|
+
|
|
45
|
+
# 3. Move it to your PATH
|
|
46
|
+
sudo mv htdp /usr/local/bin/
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Install Transformez
|
|
50
|
+
Once HTDP is accessible in your terminal, install the python package:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install transformez
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
**Generate a vertical shift grid for anywhere on Earth.**
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Transform MLLW to WGS84 Ellipsoid in Norton Sound, AK
|
|
62
|
+
# (Where NOAA has no coverage!)
|
|
63
|
+
transformez -R -166/-164/63/64 -E 3s \
|
|
64
|
+
--input-datum mllw \
|
|
65
|
+
--output-datum 4979 \
|
|
66
|
+
--output shift_ak.tif
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Transform a raster directly.** Transformez reads the bounds/resolution from the file.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
transformez --dem input_bathymetry.tif \
|
|
73
|
+
--input-datum "mllw" \
|
|
74
|
+
--output-datum "5703:geoid=geoid12b" \
|
|
75
|
+
--output output_navd88.tif
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Integrate directly into your download pipeline.**
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Download GEBCO and shift EGM96 to WGS84 on the fly
|
|
82
|
+
fetchez gebco ... --hook transformez:datum_in=5773,datum_out=4979
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Python API
|
|
86
|
+
|
|
87
|
+
Transformez provides a high-level API for embedding transformations directly into your Python scripts, Jupyter Notebooks, or automated pipelines.
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
import transformez
|
|
91
|
+
|
|
92
|
+
# ---------------------------------------------------------
|
|
93
|
+
# Generate a Shift Grid
|
|
94
|
+
# ---------------------------------------------------------
|
|
95
|
+
# Returns a 2D numpy array. Optionally saves to a file.
|
|
96
|
+
# Requesting "mllw" in India triggers the Global Fallback (FES2014) automatically.
|
|
97
|
+
|
|
98
|
+
shift_array = transformez.generate_grid(
|
|
99
|
+
region=[80, 85, 10, 15], # [West, East, South, North]
|
|
100
|
+
increment="3s", # Grid resolution
|
|
101
|
+
datum_in="mllw",
|
|
102
|
+
datum_out="4979", # WGS84 Ellipsoid
|
|
103
|
+
out_fn="india_shift.tif" # Optional: Save to disk
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# ---------------------------------------------------------
|
|
107
|
+
# Transform an Existing Raster
|
|
108
|
+
# ---------------------------------------------------------
|
|
109
|
+
# Applies the datum shift directly to a DEM and saves the result.
|
|
110
|
+
|
|
111
|
+
out_file = transformez.transform_raster(
|
|
112
|
+
input_raster="my_dem_mllw.tif",
|
|
113
|
+
datum_in="mllw",
|
|
114
|
+
datum_out="5703:g2012b", # NAVD88 using specific GEOID12B
|
|
115
|
+
output_raster="my_dem_navd88.tif"
|
|
116
|
+
)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Supported Datums
|
|
120
|
+
|
|
121
|
+
* **Tidal**: mllw, mhhw, msl, lat
|
|
122
|
+
|
|
123
|
+
* **Ellipsoidal**: 4979 (WGS84), 6319 (NAD83 2011)
|
|
124
|
+
|
|
125
|
+
* **Orthometric**: 5703 (NAVD88), egm2008, egm96
|
|
126
|
+
|
|
127
|
+
* **Geoids**: g2018, g2012b, geoid09, xgeoid20b
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
This project is licensed under the MIT License - see the [LICENSE](https://github.com/ciresdem/transformez/blob/main/LICENSE) file for details.
|
|
132
|
+
Copyright (c) 2010-2026 Regents of the University of Colorado
|
|
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
|
|
|
6
6
|
name = 'transformez'
|
|
7
7
|
description = 'A standalone utility for vertical elevation datum transformations.'
|
|
8
8
|
readme = "README.md"
|
|
9
|
-
requires-python = ">=3.
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
10
|
license = { file = "LICENSE" }
|
|
11
11
|
dynamic = ["version"]
|
|
12
12
|
authors = [
|
|
@@ -14,6 +14,7 @@ authors = [
|
|
|
14
14
|
{name = "Christopher Amante", email = "christopher.amante@colorado.edu"},
|
|
15
15
|
{name = "Elliot Lim", email = "elliot.lim@colorado.edu"},
|
|
16
16
|
{name = "Michael MacFerrin", email = "michael.macferrin@colorado.edu"},
|
|
17
|
+
{name = "Matt Fisher", email = "mfisher87@gmail.com"},
|
|
17
18
|
]
|
|
18
19
|
maintainers = [
|
|
19
20
|
{name = "Matthew Love", email = "matthew.love@colorado.edu"},
|
|
@@ -24,22 +25,30 @@ classifiers = [
|
|
|
24
25
|
'Topic :: Scientific/Engineering :: GIS',
|
|
25
26
|
]
|
|
26
27
|
dependencies = [
|
|
27
|
-
'numpy
|
|
28
|
-
'pyproj',
|
|
29
|
-
'rasterio',
|
|
30
|
-
'fetchez
|
|
28
|
+
'numpy>1.24',
|
|
29
|
+
'pyproj>3.6.1',
|
|
30
|
+
'rasterio>1.4.0',
|
|
31
|
+
'fetchez>=0.5.0',
|
|
31
32
|
'scipy',
|
|
32
33
|
]
|
|
33
34
|
|
|
34
35
|
keywords = ["Geospatial"]
|
|
35
36
|
|
|
37
|
+
[project.optional-dependencies]
|
|
38
|
+
preview = ["matplotlib"]
|
|
39
|
+
|
|
40
|
+
full = ["transformez[preview]"]
|
|
41
|
+
|
|
36
42
|
[dependency-groups]
|
|
43
|
+
dev = [
|
|
44
|
+
"mypy",
|
|
45
|
+
]
|
|
37
46
|
test = [
|
|
38
47
|
"pytest",
|
|
39
48
|
"pytest-cov",
|
|
40
49
|
]
|
|
41
50
|
|
|
42
|
-
[project.entry-points."fetchez.
|
|
51
|
+
[project.entry-points."fetchez.modules"]
|
|
43
52
|
transformez = "transformez"
|
|
44
53
|
|
|
45
54
|
[project.scripts]
|
|
@@ -73,3 +82,22 @@ exclude = [
|
|
|
73
82
|
".github",
|
|
74
83
|
]
|
|
75
84
|
|
|
85
|
+
# --- Devtools configuration ---
|
|
86
|
+
|
|
87
|
+
[tool.mypy]
|
|
88
|
+
mypy_path = "src"
|
|
89
|
+
packages = ["transformez"]
|
|
90
|
+
python_version = "3.12"
|
|
91
|
+
disable_error_code = ["import-untyped"]
|
|
92
|
+
# strict = true
|
|
93
|
+
|
|
94
|
+
[[tool.mypy.overrides]]
|
|
95
|
+
module = [
|
|
96
|
+
"matplotlib.*",
|
|
97
|
+
"rasterio.*",
|
|
98
|
+
"scipy.*",
|
|
99
|
+
"pyproj.*",
|
|
100
|
+
"fetchez.*",
|
|
101
|
+
]
|
|
102
|
+
ignore_missing_imports = true
|
|
103
|
+
follow_untyped_imports = true
|
|
@@ -5,19 +5,15 @@
|
|
|
5
5
|
transformez
|
|
6
6
|
~~~~~~~~~~~~~
|
|
7
7
|
|
|
8
|
+
Initialize the API and fetchez extension.
|
|
9
|
+
|
|
8
10
|
:copyright: (c) 2010-2026 Regents of the University of Colorado
|
|
9
11
|
:license: MIT, see LICENSE for more details.
|
|
10
12
|
"""
|
|
11
13
|
|
|
12
|
-
__author__ = "Matthew Love"
|
|
13
|
-
__credits__ = "CIRES"
|
|
14
|
-
|
|
15
14
|
try:
|
|
16
15
|
from transformez._version import __version__
|
|
17
16
|
except ImportError:
|
|
18
|
-
# Fallback when using the package from source without installing
|
|
19
|
-
# in editable mode with pip (nobody should do this):
|
|
20
|
-
# <https://pip.pypa.io/en/stable/topics/local-project-installs/#editable-installs>
|
|
21
17
|
import warnings
|
|
22
18
|
|
|
23
19
|
warnings.warn(
|
|
@@ -29,12 +25,12 @@ except ImportError:
|
|
|
29
25
|
__version__ = "dev"
|
|
30
26
|
|
|
31
27
|
|
|
28
|
+
from .api import generate_grid, transform_raster
|
|
29
|
+
|
|
32
30
|
import os
|
|
33
31
|
import glob
|
|
34
|
-
# from .hooks import TransformezHook
|
|
35
|
-
# from fetchez.hooks.registry import HookRegistry
|
|
36
|
-
from fetchez.registry import FetchezRegistry
|
|
37
32
|
|
|
33
|
+
# Expose the module for fetchez
|
|
38
34
|
from .modules import TransformezMod
|
|
39
35
|
|
|
40
36
|
def _find_proj_lib():
|
|
@@ -73,29 +69,4 @@ if "PROJ_LIB" in os.environ:
|
|
|
73
69
|
if target_proj_lib:
|
|
74
70
|
os.environ["PROJ_LIB"] = target_proj_lib
|
|
75
71
|
|
|
76
|
-
|
|
77
|
-
"""Called by fetchez when loading plugins.
|
|
78
|
-
|
|
79
|
-
Registers modules, hooks, and presets.
|
|
80
|
-
"""
|
|
81
|
-
|
|
82
|
-
registry_cls.register_module(
|
|
83
|
-
'transformez',
|
|
84
|
-
TransformezMod,
|
|
85
|
-
metadata={
|
|
86
|
-
'desc': 'Generate vertical datum shift grids on-demand.',
|
|
87
|
-
"tags": ["vdatum", "transformation", "shift-grid"],
|
|
88
|
-
"category": "Tools"
|
|
89
|
-
}
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
# HookRegistry.register_hook(TransformezHook)
|
|
93
|
-
# from fetchez.presets import register_global_preset
|
|
94
|
-
# register_global_preset(
|
|
95
|
-
# name="make-shift-grid",
|
|
96
|
-
# help_text="Download datum grids and composite them into a single shift grid.",
|
|
97
|
-
# hooks=[
|
|
98
|
-
# {"name": "transformez", "args": {}}
|
|
99
|
-
# ]
|
|
100
|
-
# )
|
|
101
|
-
setup_fetchez(FetchezRegistry)
|
|
72
|
+
__all__ = ["generate_grid", "transform_raster", "TransformezMod"]
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
transformez.api
|
|
6
|
+
~~~~~~~~~~~~~~~
|
|
7
|
+
High-level Python Interface for Transformez.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
import transformez
|
|
11
|
+
|
|
12
|
+
# Generate a shift grid (returns a numpy array)
|
|
13
|
+
shift_array = transformez.generate_grid(
|
|
14
|
+
region=[-90, -89, 29, 30],
|
|
15
|
+
increment="3s",
|
|
16
|
+
datum_in="mllw",
|
|
17
|
+
datum_out="5703"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
# Transform an existing DEM directly
|
|
21
|
+
out_file = transformez.transform_raster(
|
|
22
|
+
input_raster="my_dem_mllw.tif",
|
|
23
|
+
datum_in="mllw",
|
|
24
|
+
datum_out="5703:g2012b",
|
|
25
|
+
output_raster="my_dem_navd88.tif"
|
|
26
|
+
)
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
import os
|
|
30
|
+
import logging
|
|
31
|
+
import numpy as np
|
|
32
|
+
from typing import List, Union, Optional, Tuple
|
|
33
|
+
|
|
34
|
+
from .transform import VerticalTransform
|
|
35
|
+
from .definitions import Datums
|
|
36
|
+
from .grid_engine import GridWriter, GridEngine
|
|
37
|
+
from fetchez.spatial import parse_region, Region
|
|
38
|
+
from fetchez import utils
|
|
39
|
+
|
|
40
|
+
logger = logging.getLogger(__name__)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _parse_datum(datum_arg: str) -> Tuple[Optional[int], Optional[str]]:
|
|
44
|
+
"""Helper to parse compound datum strings (e.g. '5703:g2012b')."""
|
|
45
|
+
|
|
46
|
+
if not datum_arg:
|
|
47
|
+
return None, None
|
|
48
|
+
s = str(datum_arg)
|
|
49
|
+
if ':' in s:
|
|
50
|
+
parts = s.split(':')
|
|
51
|
+
geoid_part = parts[1]
|
|
52
|
+
geoid = (
|
|
53
|
+
geoid_part.split('=')[1] if 'geoid=' in geoid_part else geoid_part
|
|
54
|
+
)
|
|
55
|
+
return Datums.get_vdatum_by_name(parts[0]), geoid
|
|
56
|
+
return Datums.get_vdatum_by_name(s), None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def generate_grid(
|
|
60
|
+
region: Union[List[float], str, Region],
|
|
61
|
+
increment: Union[str, float],
|
|
62
|
+
datum_in: str,
|
|
63
|
+
datum_out: str,
|
|
64
|
+
out_fn: Optional[str] = None,
|
|
65
|
+
cache_dir: Optional[str] = None,
|
|
66
|
+
verbose: bool = False
|
|
67
|
+
) -> Optional[np.ndarray]:
|
|
68
|
+
"""Generate a vertical shift grid for a specific region.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
region: Bounds as [W, E, S, N], a 'loc:' string, or a Region object.
|
|
72
|
+
increment: Resolution (e.g., '3s' or 0.0008333).
|
|
73
|
+
datum_in: Source datum (e.g., 'mllw', '5703').
|
|
74
|
+
datum_out: Target datum (e.g., '4979', '6319').
|
|
75
|
+
out_fn: If provided, saves the grid to this file (.tif or .gtx).
|
|
76
|
+
cache_dir: Path to store downloaded grids.
|
|
77
|
+
verbose: Enable debug logging.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
np.ndarray: The 2D vertical shift grid, or None if failed.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
if isinstance(region, Region):
|
|
84
|
+
region_obj = region
|
|
85
|
+
else:
|
|
86
|
+
regions = parse_region(region)
|
|
87
|
+
if not regions:
|
|
88
|
+
logger.error(f"Could not parse region: {region}")
|
|
89
|
+
return None
|
|
90
|
+
region_obj = regions[0]
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
inc_val = utils.str2inc(str(increment))
|
|
94
|
+
nx = int(region_obj.width / inc_val)
|
|
95
|
+
ny = int(region_obj.height / inc_val)
|
|
96
|
+
except Exception as e:
|
|
97
|
+
logger.error(f"Invalid increment '{increment}': {e}")
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
epsg_in, geoid_in = _parse_datum(datum_in)
|
|
101
|
+
epsg_out, geoid_out = _parse_datum(datum_out)
|
|
102
|
+
|
|
103
|
+
if not epsg_in or not epsg_out:
|
|
104
|
+
logger.error(f"Invalid datum specified: {datum_in} -> {datum_out}")
|
|
105
|
+
return None
|
|
106
|
+
|
|
107
|
+
vt = VerticalTransform(
|
|
108
|
+
region=region_obj,
|
|
109
|
+
nx=nx, ny=ny,
|
|
110
|
+
epsg_in=epsg_in, epsg_out=epsg_out,
|
|
111
|
+
geoid_in=geoid_in, geoid_out=geoid_out,
|
|
112
|
+
cache_dir=cache_dir,
|
|
113
|
+
verbose=verbose
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
shift_array, _ = vt._vertical_transform(vt.epsg_in, vt.epsg_out)
|
|
117
|
+
|
|
118
|
+
if shift_array is None:
|
|
119
|
+
logger.error("Transformation failed to generate a grid.")
|
|
120
|
+
return None
|
|
121
|
+
|
|
122
|
+
if out_fn:
|
|
123
|
+
GridWriter.write(out_fn, shift_array, [region_obj.xmin, region_obj.xmax, region_obj.ymin, region_obj.ymax])
|
|
124
|
+
logger.info(f"Saved shift grid to {out_fn}")
|
|
125
|
+
|
|
126
|
+
return shift_array
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def transform_raster(
|
|
130
|
+
input_raster: str,
|
|
131
|
+
datum_in: str,
|
|
132
|
+
datum_out: str,
|
|
133
|
+
output_raster: Optional[str] = None,
|
|
134
|
+
cache_dir: Optional[str] = None,
|
|
135
|
+
verbose: bool = False
|
|
136
|
+
) -> Optional[str]:
|
|
137
|
+
"""Apply a vertical datum transformation directly to an existing raster file.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
input_raster: Path to the input DEM.
|
|
141
|
+
datum_in: Source datum of the DEM.
|
|
142
|
+
datum_out: Target datum for the output DEM.
|
|
143
|
+
output_raster: Path to save the transformed DEM. If None, auto-generates a name.
|
|
144
|
+
cache_dir: Path to store downloaded grids.
|
|
145
|
+
verbose: Enable debug logging.
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
str: The path to the transformed output raster, or None if failed.
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
import rasterio
|
|
152
|
+
|
|
153
|
+
if not os.path.exists(input_raster):
|
|
154
|
+
logger.error(f"Input raster not found: {input_raster}")
|
|
155
|
+
return None
|
|
156
|
+
|
|
157
|
+
with rasterio.open(input_raster) as src:
|
|
158
|
+
bounds = src.bounds
|
|
159
|
+
region_obj = (
|
|
160
|
+
Region(bounds.left, bounds.right, bounds.bottom, bounds.top)
|
|
161
|
+
)
|
|
162
|
+
nx, ny = src.width, src.height
|
|
163
|
+
|
|
164
|
+
epsg_in, geoid_in = _parse_datum(datum_in)
|
|
165
|
+
epsg_out, geoid_out = _parse_datum(datum_out)
|
|
166
|
+
|
|
167
|
+
if not epsg_in or not epsg_out:
|
|
168
|
+
logger.error(f"Invalid datum specified: {datum_in} -> {datum_out}")
|
|
169
|
+
return None
|
|
170
|
+
|
|
171
|
+
if not output_raster:
|
|
172
|
+
base, ext = os.path.splitext(input_raster)
|
|
173
|
+
output_raster = f"{base}_trans_{datum_out.replace(':', '_')}{ext}"
|
|
174
|
+
|
|
175
|
+
vt = VerticalTransform(
|
|
176
|
+
region=region_obj,
|
|
177
|
+
nx=nx, ny=ny,
|
|
178
|
+
epsg_in=epsg_in, epsg_out=epsg_out,
|
|
179
|
+
geoid_in=geoid_in, geoid_out=geoid_out,
|
|
180
|
+
cache_dir=cache_dir,
|
|
181
|
+
verbose=verbose
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
shift_array, _ = vt._vertical_transform(vt.epsg_in, vt.epsg_out)
|
|
185
|
+
|
|
186
|
+
if shift_array is None:
|
|
187
|
+
logger.error("Failed to generate shift array for the raster bounds.")
|
|
188
|
+
return None
|
|
189
|
+
|
|
190
|
+
success = GridEngine.apply_vertical_shift(input_raster, shift_array, output_raster)
|
|
191
|
+
|
|
192
|
+
if success:
|
|
193
|
+
return output_raster
|
|
194
|
+
return None
|