pymdurs 0.1.1__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.
Files changed (64) hide show
  1. pymdurs-0.1.1/PKG-INFO +898 -0
  2. pymdurs-0.1.1/README.md +873 -0
  3. pymdurs-0.1.1/pymdurs/Cargo.lock +4656 -0
  4. pymdurs-0.1.1/pymdurs/Cargo.toml +34 -0
  5. pymdurs-0.1.1/pymdurs/MATURIN_ANALYSIS.md +86 -0
  6. pymdurs-0.1.1/pymdurs/README.md +680 -0
  7. pymdurs-0.1.1/pymdurs/__init__.py +2 -0
  8. pymdurs-0.1.1/pymdurs/src/bindings/bounding_box.rs +51 -0
  9. pymdurs-0.1.1/pymdurs/src/bindings/building.rs +201 -0
  10. pymdurs-0.1.1/pymdurs/src/bindings/cadastre.rs +82 -0
  11. pymdurs-0.1.1/pymdurs/src/bindings/cosia.rs +65 -0
  12. pymdurs-0.1.1/pymdurs/src/bindings/dem.rs +70 -0
  13. pymdurs-0.1.1/pymdurs/src/bindings/geo_core.rs +53 -0
  14. pymdurs-0.1.1/pymdurs/src/bindings/iris.rs +73 -0
  15. pymdurs-0.1.1/pymdurs/src/bindings/lcz.rs +93 -0
  16. pymdurs-0.1.1/pymdurs/src/bindings/lidar.rs +119 -0
  17. pymdurs-0.1.1/pymdurs/src/bindings/mod.rs +31 -0
  18. pymdurs-0.1.1/pymdurs/src/bindings/rnb.rs +82 -0
  19. pymdurs-0.1.1/pymdurs/src/bindings/road.rs +83 -0
  20. pymdurs-0.1.1/pymdurs/src/bindings/vegetation.rs +94 -0
  21. pymdurs-0.1.1/pymdurs/src/bindings/water.rs +86 -0
  22. pymdurs-0.1.1/pymdurs/src/lib.rs +74 -0
  23. pymdurs-0.1.1/pymdurs/tests/test_basic.py +51 -0
  24. pymdurs-0.1.1/pyproject.toml +67 -0
  25. pymdurs-0.1.1/rsmdu/Cargo.toml +68 -0
  26. pymdurs-0.1.1/rsmdu/examples/README.md +144 -0
  27. pymdurs-0.1.1/rsmdu/examples/building_complete.rs +214 -0
  28. pymdurs-0.1.1/rsmdu/examples/building_from_geojson.rs +116 -0
  29. pymdurs-0.1.1/rsmdu/examples/building_from_ign.rs +62 -0
  30. pymdurs-0.1.1/rsmdu/examples/building_from_ign_api.rs +191 -0
  31. pymdurs-0.1.1/rsmdu/examples/building_manual.rs +40 -0
  32. pymdurs-0.1.1/rsmdu/examples/cadastre_from_ign.rs +52 -0
  33. pymdurs-0.1.1/rsmdu/examples/cosia_from_ign.rs +32 -0
  34. pymdurs-0.1.1/rsmdu/examples/dem_from_ign.rs +36 -0
  35. pymdurs-0.1.1/rsmdu/examples/iris_from_ign.rs +51 -0
  36. pymdurs-0.1.1/rsmdu/examples/lcz_from_url.rs +40 -0
  37. pymdurs-0.1.1/rsmdu/examples/rnb_from_api.rs +51 -0
  38. pymdurs-0.1.1/rsmdu/examples/road_from_ign.rs +51 -0
  39. pymdurs-0.1.1/rsmdu/examples/vegetation_from_ign.rs +63 -0
  40. pymdurs-0.1.1/rsmdu/examples/water_from_ign.rs +54 -0
  41. pymdurs-0.1.1/rsmdu/src/collect/global_variables.rs +8 -0
  42. pymdurs-0.1.1/rsmdu/src/collect/ign/data/Tableau-suivi-services-web-01-08-2025.csv +1349 -0
  43. pymdurs-0.1.1/rsmdu/src/collect/ign/data/Tableau-suivi-services-web-06-02-2026.csv +1387 -0
  44. pymdurs-0.1.1/rsmdu/src/collect/ign/data/Tableau-suivi-services-web-23-05-2025.csv +1265 -0
  45. pymdurs-0.1.1/rsmdu/src/collect/ign/ign_collect.rs +596 -0
  46. pymdurs-0.1.1/rsmdu/src/collect/ign/mod.rs +2 -0
  47. pymdurs-0.1.1/rsmdu/src/collect/mod.rs +3 -0
  48. pymdurs-0.1.1/rsmdu/src/commons/basic_functions.rs +21 -0
  49. pymdurs-0.1.1/rsmdu/src/commons/mod.rs +2 -0
  50. pymdurs-0.1.1/rsmdu/src/geo_core.rs +187 -0
  51. pymdurs-0.1.1/rsmdu/src/geometric/building.rs +1162 -0
  52. pymdurs-0.1.1/rsmdu/src/geometric/cadastre.rs +167 -0
  53. pymdurs-0.1.1/rsmdu/src/geometric/cosia.rs +177 -0
  54. pymdurs-0.1.1/rsmdu/src/geometric/dem.rs +465 -0
  55. pymdurs-0.1.1/rsmdu/src/geometric/iris.rs +167 -0
  56. pymdurs-0.1.1/rsmdu/src/geometric/lcz.rs +591 -0
  57. pymdurs-0.1.1/rsmdu/src/geometric/lidar.rs +2396 -0
  58. pymdurs-0.1.1/rsmdu/src/geometric/mod.rs +11 -0
  59. pymdurs-0.1.1/rsmdu/src/geometric/rnb.rs +288 -0
  60. pymdurs-0.1.1/rsmdu/src/geometric/road.rs +167 -0
  61. pymdurs-0.1.1/rsmdu/src/geometric/vegetation.rs +518 -0
  62. pymdurs-0.1.1/rsmdu/src/geometric/water.rs +272 -0
  63. pymdurs-0.1.1/rsmdu/src/lib.rs +12 -0
  64. pymdurs-0.1.1/rsmdu/src/main.rs +7 -0
pymdurs-0.1.1/PKG-INFO ADDED
@@ -0,0 +1,898 @@
1
+ Metadata-Version: 2.4
2
+ Name: pymdurs
3
+ Version: 0.1.1
4
+ Classifier: Programming Language :: Rust
5
+ Classifier: Programming Language :: Python :: Implementation :: CPython
6
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: Topic :: Scientific/Engineering :: GIS
10
+ Requires-Dist: pandas>=2.0.0
11
+ Requires-Dist: numpy>=2.0.2
12
+ Requires-Dist: geopandas>=1.0.1
13
+ Requires-Dist: rasterio>=1.4.3
14
+ Requires-Dist: umep>=0.0.1a18
15
+ Requires-Dist: solweig>=0.1.0b55
16
+ Requires-Dist: pytest>=7.0.0 ; extra == 'dev'
17
+ Provides-Extra: dev
18
+ Summary: Rust transpilation of pymdu (Python Urban Data Model) - Python bindings
19
+ Home-Page: https://github.com/rupeelab17/rsmdu
20
+ Author-email: Boris Brangeon <boris.brangeon@plateforme-tipee.com>
21
+ License: GPL-3.0
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
24
+
25
+ # pymdurs
26
+
27
+ Rust transpilation of [pymdu](https://github.com/rupeelab17/pymdu) (Python Urban Data Model).
28
+
29
+ This project transpiles the Python pymdu library to Rust, using the [GeoRust](https://georust.org/) ecosystem for geospatial operations. It provides three deployment targets: native Rust library, Python bindings (PyO3), and WebAssembly (WASM) for browser-based applications.
30
+
31
+ ## 🎯 Project Overview
32
+
33
+ **pymdurs** is a comprehensive geospatial data processing library for urban data analysis, providing:
34
+
35
+ - **Native Rust library** (`rsmdu`) - High-performance geospatial operations
36
+ - **Python bindings** (`pymdurs`) - Pythonic API with PyO3
37
+ - **WebAssembly bindings** (`rsmdu-wasm`) - Browser-based geospatial processing
38
+
39
+ ## 📦 Project Structure
40
+
41
+ This project is organized as a **Cargo workspace** with three main crates:
42
+
43
+ ```
44
+ pymdurs/
45
+ ├── rsmdu/ # Core Rust library
46
+ │ ├── src/
47
+ │ │ ├── geometric/ # Geometric data structures
48
+ │ │ │ ├── building.rs # Building and BuildingCollection
49
+ │ │ │ ├── dem.rs # Digital Elevation Model
50
+ │ │ │ ├── cadastre.rs # Cadastral parcel data
51
+ │ │ │ ├── iris.rs # IRIS statistical units
52
+ │ │ │ ├── lcz.rs # Local Climate Zone
53
+ │ │ │ ├── road.rs # Road segments
54
+ │ │ │ ├── water.rs # Water bodies
55
+ │ │ │ └── vegetation.rs # Vegetation zones
56
+ │ │ ├── collect/ # Data collection modules
57
+ │ │ │ ├── ign/ # IGN API integration
58
+ │ │ │ │ └── ign_collect.rs
59
+ │ │ │ └── global_variables.rs
60
+ │ │ ├── geo_core.rs # Base GeoCore class
61
+ │ │ ├── commons/ # Common utilities
62
+ │ │ ├── lib.rs # Library root
63
+ │ │ └── main.rs # Binary entry point
64
+ │ └── examples/ # Rust usage examples
65
+
66
+ ├── pymdurs/ # Python bindings (PyO3)
67
+ │ ├── src/
68
+ │ │ └── bindings/ # PyO3 bindings
69
+ │ ├── examples/ # Python usage examples
70
+ │ └── tests/ # Python tests
71
+
72
+ └── rsmdu-wasm/ # WebAssembly bindings
73
+ ├── src/
74
+ │ └── lib.rs # WASM bindings
75
+ └── examples/ # Browser examples
76
+ ├── index.html # Building visualization
77
+ └── dem.html # DEM visualization
78
+ ```
79
+
80
+ ## ✨ Features
81
+
82
+ ### 🏢 Building Data Management
83
+
84
+ - **Building data collection**: Load buildings from Shapefiles, GeoJSON, or IGN API
85
+ - **Geometric operations**: Area, centroid, and height calculations
86
+ - **Data processing**: Height processing with fallback to storeys or mean district height
87
+ - **Height calculation**: Automatic height filling using:
88
+ - Number of storeys × default storey height
89
+ - Alternative height field (HAUTEUR_2)
90
+ - Mean district height (weighted by area)
91
+ - **DataFrame support**: Integration with Polars for tabular operations (equivalent to GeoDataFrame)
92
+ - **WebAssembly support**: Process building data directly in the browser
93
+
94
+ ### 🗻 Digital Elevation Model (DEM)
95
+
96
+ - **DEM collection**: Download DEM data from IGN API via WMS-R
97
+ - **Raster processing**: GeoTIFF handling and validation
98
+ - **Mask generation**: Automatic mask creation for DEM boundaries
99
+ - **Browser visualization**: Interactive DEM viewer with Leaflet.js integration
100
+ - **IGN API integration**: Direct loading from IGN WMS service in browser
101
+
102
+ ### 🗺️ Cadastral Data
103
+
104
+ - **Cadastre collection**: Download cadastral parcel data from IGN API via WFS
105
+ - **GeoJSON parsing**: Automatic parsing of IGN API responses
106
+ - **GeoJSON export**: Save cadastral data to GeoPackage format
107
+
108
+ ### 📊 IRIS Statistical Units
109
+
110
+ - **IRIS collection**: Download IRIS (statistical units) data from IGN API via WFS
111
+ - **GeoJSON parsing**: Automatic parsing of IGN API responses
112
+ - **GeoJSON export**: Save IRIS data to GeoPackage format
113
+
114
+ ### 🌡️ LCZ (Local Climate Zone)
115
+
116
+ - **LCZ collection**: Load Local Climate Zone data from external sources
117
+ - **Color mapping**: Built-in LCZ color table (17 LCZ types)
118
+ - **Spatial filtering**: Filter LCZ data by bounding box
119
+ - **Shapefile support**: Load from zip URLs (requires GDAL)
120
+
121
+ ### 🛣️ Road and Infrastructure
122
+
123
+ - **Road collection**: Download road segments from IGN API
124
+ - **Water bodies**: Download water body data from IGN API
125
+ - **Vegetation zones**: Download vegetation data from IGN API
126
+
127
+ ### 🛰️ LiDAR Processing
128
+
129
+ - **LiDAR data collection**: Download LAZ files from IGN WFS service
130
+ - **Point cloud processing**: Load and process LiDAR point clouds
131
+ - **Raster generation**: Create DSM (Digital Surface Model), DTM (Digital Terrain Model), and CHM (Canopy Height Model)
132
+ - **Classification filtering**: Filter points by classification (ground, vegetation, buildings, water, etc.)
133
+ - **Multi-band GeoTIFF export**: Export processed rasters as multi-band GeoTIFF files
134
+ - **Automatic workflow**: Points are automatically fetched and loaded when bounding box is set
135
+
136
+ ### 🌐 IGN API Integration
137
+
138
+ - **WFS (Web Feature Service)**: Vector data retrieval (buildings, roads, water, etc.)
139
+ - **WMS (Web Map Service)**: Raster data retrieval (DEM, orthoimagery, etc.)
140
+ - **WMS-R endpoint**: Optimized raster service endpoint
141
+ - **OGC compliance**: Follows OGC WFS 2.0.0 and WMS 1.3.0 standards
142
+ - **Browser support**: Direct API calls from WebAssembly
143
+
144
+ ### 🎨 WebAssembly Features
145
+
146
+ - **Building processing**: Load and process building GeoJSON in the browser
147
+ - **DEM visualization**: Interactive DEM viewer with color scales
148
+ - **IGN API integration**: Fetch data directly from IGN API in browser
149
+ - **Leaflet.js integration**: Seamless integration with Leaflet maps
150
+ - **Dynamic bbox**: Automatic bounding box updates based on map view
151
+
152
+ ## 🚀 Installation
153
+
154
+ ### Python Package
155
+
156
+ **Requirements:** Python >= 3.10, pandas >= 2.0.0, numpy >= 2.0.2
157
+
158
+ **Important:** Run maturin from the **project root** (where `pyproject.toml` is). Maturin uses `manifest-path = "pymdurs/Cargo.toml"`.
159
+
160
+ #### 1. Clone and setup
161
+
162
+ ```bash
163
+ git clone https://github.com/rupeelab17/rsmdu.git
164
+ cd rsmdu
165
+ uv venv .venv --python 3.13
166
+ source .venv/bin/activate
167
+ uv pip install maturin
168
+ uv sync
169
+ ```
170
+
171
+ #### 2. Install GDAL (prerequisite)
172
+
173
+ | Platform | Command |
174
+ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
175
+ | **macOS** | `brew install gdal` or `ARCHFLAGS="-arch arm64" uv pip install --no-cache-dir gdal` |
176
+ | **Linux** | `sudo apt-get update && sudo apt-get install -y libgdal-dev gdal-bin libclang-dev` |
177
+ | **Windows** | [OSGeo4W](https://trac.osgeo.org/osgeo4w/) (GDAL, GEOS, PROJ, SQLite3) + `choco install llvm pkgconfiglite sqlite -y` + set `GDAL_HOME`, `PKG_CONFIG_PATH`, `PATH` |
178
+
179
+ #### 3. Build (maturin develop)
180
+
181
+ | Platform | Target | Command |
182
+ | ------------------------- | --------------------------- | ------------------------------------------------------------------------ |
183
+ | **macOS** (Apple Silicon) | `aarch64-apple-darwin` | `maturin develop --target aarch64-apple-darwin` |
184
+ | **macOS** (Intel) | `x86_64-apple-darwin` | `maturin develop --target x86_64-apple-darwin` |
185
+ | **Linux** (x86_64) | `x86_64-unknown-linux-gnu` | `maturin develop --target x86_64-unknown-linux-gnu` or `maturin develop` |
186
+ | **Linux** (ARM64) | `aarch64-unknown-linux-gnu` | `maturin develop --target aarch64-unknown-linux-gnu` |
187
+ | **Windows** | `x86_64-pc-windows-msvc` | `maturin develop --target x86_64-pc-windows-msvc` |
188
+
189
+ With uv: `uv run maturin develop --target <target>`
190
+
191
+ **macOS: linker can't find GDAL / "library 'gdal' not found"**
192
+ If you upgraded GDAL or PROJ with Homebrew, the linker may still use old paths. Clean and point pkg-config at the current install, then rebuild:
193
+
194
+ ```bash
195
+ cd pymdurs && cargo clean && cd ..
196
+ export PKG_CONFIG_PATH="/opt/homebrew/lib/pkgconfig"
197
+ maturin develop --target aarch64-apple-darwin
198
+ ```
199
+
200
+ #### 4. Verify and release
201
+
202
+ ```bash
203
+ python -c "import pymdurs; print('OK')"
204
+ # Release wheel
205
+ maturin build --target <target> --release
206
+ ```
207
+
208
+ ### Installing Rust
209
+
210
+ Maturin compiles the Rust extension. If Rust is not installed, follow the instructions for your operating system:
211
+
212
+ #### Windows
213
+
214
+ 1. **Download and run rustup-init.exe:**
215
+ - Visit https://rustup.rs/
216
+ - Download `rustup-init.exe`
217
+ - Run the installer and follow the prompts
218
+
219
+ 2. **Or use PowerShell:**
220
+
221
+ ```powershell
222
+ Invoke-WebRequest -Uri https://win.rustup.rs/x86_64 -OutFile rustup-init.exe
223
+ .\rustup-init.exe
224
+ ```
225
+
226
+ 3. **Verify installation:**
227
+
228
+ ```powershell
229
+ rustc --version
230
+ cargo --version
231
+ ```
232
+
233
+ 4. **Install Visual Studio Build Tools (required for Windows):**
234
+ - Download from: https://visualstudio.microsoft.com/downloads/
235
+ - Install "Desktop development with C++" workload
236
+ - Or install the lighter "C++ build tools": https://visualstudio.microsoft.com/visual-cpp-build-tools/
237
+
238
+ **Note**: On Windows, you may need to restart your terminal after installation for PATH changes to take effect.
239
+
240
+ #### macOS
241
+
242
+ 1. **Install using Homebrew (recommended):**
243
+
244
+ ```bash
245
+ brew install rust
246
+ ```
247
+
248
+ 2. **Or use rustup (official installer):**
249
+
250
+ ```bash
251
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
252
+ ```
253
+
254
+ 3. **Follow the prompts** and restart your terminal
255
+
256
+ 4. **Verify installation:**
257
+ ```bash
258
+ rustc --version
259
+ cargo --version
260
+ ```
261
+
262
+ **Note**: On macOS, you may need to install Xcode Command Line Tools:
263
+
264
+ ```bash
265
+ xcode-select --install
266
+ ```
267
+
268
+ #### Linux
269
+
270
+ 1. **Install using your package manager:**
271
+
272
+ **Ubuntu/Debian:**
273
+
274
+ ```bash
275
+ sudo apt update
276
+ sudo apt install rustc cargo
277
+ ```
278
+
279
+ **Fedora:**
280
+
281
+ ```bash
282
+ sudo dnf install rust cargo
283
+ ```
284
+
285
+ **Arch Linux:**
286
+
287
+ ```bash
288
+ sudo pacman -S rust
289
+ ```
290
+
291
+ 2. **Or use rustup (recommended for latest version):**
292
+
293
+ ```bash
294
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
295
+ source $HOME/.cargo/env
296
+ ```
297
+
298
+ 3. **Install build dependencies (required):**
299
+
300
+ **Ubuntu/Debian:**
301
+
302
+ ```bash
303
+ sudo apt install build-essential pkg-config libssl-dev
304
+ ```
305
+
306
+ **Fedora:**
307
+
308
+ ```bash
309
+ sudo dnf install gcc pkg-config openssl-devel
310
+ ```
311
+
312
+ **Arch Linux:**
313
+
314
+ ```bash
315
+ sudo pacman -S base-devel
316
+ ```
317
+
318
+ 4. **Verify installation:**
319
+ ```bash
320
+ rustc --version
321
+ cargo --version
322
+ ```
323
+
324
+ #### Docker
325
+
326
+ When building an image that installs pymdurs with `uv pip install https://github.com/rupeelab17/rsmdu.git`, **Rust must be installed in a previous layer**. If Rust is not present, maturin installs it on the fly and can hit "Text file busy (os error 26)" when running `cargo metadata` immediately after.
327
+
328
+ **Fix:** install Rust (e.g. with rustup) **before** the step that runs `uv pip install`:
329
+
330
+ ```dockerfile
331
+ # Install Rust so maturin does not auto-install it (avoids "Text file busy")
332
+ RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable \
333
+ && . "$HOME/.cargo/env" \
334
+ && rustc --version
335
+ ENV PATH="/root/.cargo/bin:${PATH}"
336
+
337
+ # Then install pymdurs (maturin will find cargo and build the wheel)
338
+ RUN micromamba run -n umep_pymdu python -m uv pip install https://github.com/rupeelab17/rsmdu.git
339
+ ```
340
+
341
+ Adjust the environment (e.g. `micromamba run -n umep_pymdu`, or `ENV PATH` if Rust is installed for another user) to match your image.
342
+
343
+ ### WebAssembly
344
+
345
+ ```bash
346
+ # Install wasm-pack
347
+ cargo install wasm-pack
348
+
349
+ # Add WASM target
350
+ rustup target add wasm32-unknown-unknown
351
+
352
+ # Navigate to WASM package directory
353
+ cd rsmdu-wasm
354
+
355
+ # Fix WASM target (if needed)
356
+ ./fix-wasm-target.sh
357
+
358
+ # Build WASM package
359
+ ./build.sh
360
+ ```
361
+
362
+ See `rsmdu-wasm/README.md` for detailed WebAssembly setup instructions.
363
+
364
+ ## 📖 Usage
365
+
366
+ ### Rust Library
367
+
368
+ #### Building Collection
369
+
370
+ ```rust
371
+ use rsmdu::geometric::building::BuildingCollection;
372
+
373
+ // Create BuildingCollection (Python: Building(output_path='./'))
374
+ let mut buildings = BuildingCollection::new(
375
+ None, // filepath_shp (None = use IGN API)
376
+ Some("./output".to_string()), // output_path
377
+ 3.0, // defaultStoreyHeight
378
+ None, // set_crs (None = default EPSG:2154)
379
+ )?;
380
+
381
+ // Set bounding box (Python: buildings.bbox = [...])
382
+ buildings.set_bbox(-1.152704, 46.181627, -1.139893, 46.18699)?;
383
+
384
+ // Run processing (Python: buildings = buildings.run())
385
+ let buildings = buildings.run()?;
386
+
387
+ // Convert to Polars DataFrame (Python: buildings.to_gdf())
388
+ let df = buildings.to_polars_df()?;
389
+ ```
390
+
391
+ #### DEM (Digital Elevation Model)
392
+
393
+ ```rust
394
+ use rsmdu::geometric::dem::Dem;
395
+
396
+ // Create Dem instance
397
+ let mut dem = Dem::new(Some("./output".to_string()))?;
398
+
399
+ // Set bounding box
400
+ dem.set_bbox(-1.152704, 46.181627, -1.139893, 46.18699);
401
+
402
+ // Run DEM processing
403
+ let dem_result = dem.run(None)?;
404
+
405
+ // Get output paths
406
+ println!("DEM saved to: {:?}", dem_result.get_path_save_tiff());
407
+ println!("Mask: {:?}", dem_result.get_path_save_mask());
408
+ ```
409
+
410
+ ### Python Bindings
411
+
412
+ ```python
413
+ import pymdurs
414
+
415
+ # Create BuildingCollection
416
+ buildings = pymdurs.geometric.Building(
417
+ output_path="./output",
418
+ defaultStoreyHeight=3.0
419
+ )
420
+
421
+ # Set bounding box
422
+ buildings.set_bbox(-1.152704, 46.181627, -1.139893, 46.18699)
423
+
424
+ # Run processing (downloads from IGN API)
425
+ buildings = buildings.run()
426
+
427
+ # Convert to pandas DataFrame
428
+ df = buildings.to_pandas()
429
+ ```
430
+
431
+ #### LiDAR Processing
432
+
433
+ ```python
434
+ import pymdurs
435
+
436
+ # Create Lidar instance
437
+ lidar = pymdurs.geometric.Lidar(output_path="./output")
438
+
439
+ # Set bounding box (automatically fetches LAZ file URLs and loads points)
440
+ # Format: min_x, min_y, max_x, max_y (WGS84, EPSG:4326)
441
+ lidar.set_bbox(-1.154894, 46.182639, -1.148361, 46.186820)
442
+
443
+ # Set CRS (optional, defaults to EPSG:2154)
444
+ lidar.set_crs(2154)
445
+
446
+ # Process points to create rasters (DSM, DTM, CHM)
447
+ # Classification filter: 2=Ground, 3=Low Vegetation, 4=Medium, 5=High, 6=Building, 9=Water
448
+ classification_list = [3, 4, 5, 9] # Vegetation and water
449
+ output_path = lidar.run(file_name="CDSM.tif", classification_list=classification_list)
450
+
451
+ print(f"GeoTIFF saved to: {output_path}")
452
+ # File contains 3 bands: DSM, DTM, CHM
453
+ ```
454
+
455
+ ### WebAssembly (Browser)
456
+
457
+ #### Building Processing
458
+
459
+ ```javascript
460
+ import init, { WasmBuildingCollection } from "./pkg/rsmdu_wasm.js";
461
+
462
+ // Initialize WASM
463
+ await init("./pkg/rsmdu_wasm_bg.wasm");
464
+
465
+ // Load buildings from GeoJSON
466
+ const geojson = {
467
+ type: "FeatureCollection",
468
+ features: [
469
+ /* ... */
470
+ ],
471
+ };
472
+
473
+ const collection = WasmBuildingCollection.from_geojson(
474
+ JSON.stringify(geojson),
475
+ 3.0, // default storey height in meters
476
+ );
477
+
478
+ // Process heights
479
+ collection.process_heights();
480
+
481
+ // Get processed GeoJSON
482
+ const processedGeojson = collection.to_geojson();
483
+
484
+ // Get statistics
485
+ const stats = collection.get_stats();
486
+ console.log("Building count:", stats.count);
487
+ console.log("Total area:", stats.total_area);
488
+ console.log("Mean height:", stats.mean_height);
489
+ ```
490
+
491
+ #### DEM Loading
492
+
493
+ ```javascript
494
+ import init, { WasmDem } from "./pkg/rsmdu_wasm.js";
495
+
496
+ // Initialize WASM
497
+ await init("./pkg/rsmdu_wasm_bg.wasm");
498
+
499
+ // Load DEM from IGN API
500
+ const dem = await WasmDem.from_ign_api(
501
+ -1.152704, // min_x
502
+ 46.181627, // min_y
503
+ -1.139893, // max_x
504
+ 46.18699, // max_y
505
+ );
506
+
507
+ // Get DEM dimensions
508
+ console.log("Width:", dem.width());
509
+ console.log("Height:", dem.height());
510
+
511
+ // Get extent
512
+ const extent = dem.get_extent();
513
+ console.log("Extent:", extent);
514
+ ```
515
+
516
+ See `rsmdu-wasm/examples/index.html` and `rsmdu-wasm/examples/dem.html` for complete browser examples.
517
+
518
+ ## 📚 Examples
519
+
520
+ Comprehensive examples are available for all three deployment targets:
521
+
522
+ ### Rust Examples
523
+
524
+ Located in `rsmdu/examples/`:
525
+
526
+ **Building Examples:**
527
+
528
+ - **`building_manual.rs`**: Minimal example of manually creating buildings
529
+ - **`building_from_geojson.rs`**: Complete example loading from GeoJSON
530
+ - **`building_from_ign.rs`**: Example using `run()` method (Python-style)
531
+ - **`building_from_ign_api.rs`**: Detailed example loading buildings from IGN API
532
+ - **`building_complete.rs`**: Comprehensive example covering all use cases
533
+
534
+ **Other Examples:**
535
+
536
+ - **`dem_from_ign.rs`**: Downloading and processing DEM from IGN API
537
+ - **`cadastre_from_ign.rs`**: Downloading and processing cadastral data from IGN API
538
+ - **`iris_from_ign.rs`**: Downloading and processing IRIS statistical units from IGN API
539
+ - **`lcz_from_url.rs`**: Loading and processing LCZ data from URL
540
+ - **`cosia_from_ign.rs`**: Downloading COSIA landcover raster from IGN API
541
+ - **`rnb_from_api.rs`**: Downloading RNB (French National Building Reference) data from RNB API
542
+ - **`road_from_ign.rs`**: Downloading road segments from IGN API
543
+ - **`water_from_ign.rs`**: Downloading water bodies from IGN API
544
+ - **`vegetation_from_ign.rs`**: Downloading vegetation zones from IGN API
545
+
546
+ **Run Rust examples:**
547
+
548
+ ```bash
549
+ cd rsmdu
550
+ cargo run --example building_manual
551
+ cargo run --example building_from_geojson
552
+ cargo run --example building_from_ign
553
+ cargo run --example dem_from_ign
554
+ cargo run --example cadastre_from_ign
555
+ cargo run --example iris_from_ign
556
+ cargo run --example lcz_from_url
557
+ cargo run --example cosia_from_ign
558
+ cargo run --example rnb_from_api
559
+ ```
560
+
561
+ ### Python Examples
562
+
563
+ Located in `examples/` (see [examples/README.md](examples/README.md) for full documentation):
564
+
565
+ - **`building_basic.py`**: Basic Building usage
566
+ - **`building_from_ign.py`**: Load buildings from IGN API
567
+ - **`dem_from_ign.py`**: Download DEM from IGN API
568
+ - **`cadastre_from_ign.py`**: Download cadastral data from IGN API
569
+ - **`iris_from_ign.py`**: Download IRIS statistical units from IGN API
570
+ - **`lcz_from_url.py`**: Load LCZ data from URL
571
+ - **`cosia_from_ign.py`**: Complete COSIA workflow - download, vectorize and convert to UMEP format
572
+ - **`rnb_from_api.py`**: Download RNB (French National Building Reference) data from RNB API
573
+ - **`lidar_from_wfs.py`**: Download and process LiDAR data from IGN WFS service
574
+ - **`road_from_ign.py`**: Download road segments from IGN API
575
+ - **`water_from_ign.py`**: Download water bodies from IGN API
576
+ - **`vegetation_from_ign.py`**: Download vegetation zones from IGN API
577
+ - **`umep_workflow.py`**: Complete UMEP workflow for urban climate modeling (SOLWEIG, SVF, etc.)
578
+ - **`umep_workflow_new.py`**: Alternative UMEP workflow using solweig (SOLWEIG from UMEP-dev), with GIF export from preview PNGs
579
+
580
+ **Run Python examples** (from project root):
581
+
582
+ ```bash
583
+ python examples/building_basic.py
584
+ python examples/building_from_ign.py
585
+ python examples/dem_from_ign.py
586
+ python examples/cosia_from_ign.py
587
+ python examples/umep_workflow.py
588
+ python examples/umep_workflow_new.py
589
+ ```
590
+
591
+ ### WebAssembly Examples
592
+
593
+ Located in `rsmdu-wasm/examples/`:
594
+
595
+ - **`index.html`**: Interactive building visualization with Leaflet.js
596
+ - Load buildings from GeoJSON or IGN API
597
+ - Dynamic bounding box based on map view
598
+ - Building statistics and visualization
599
+ - **`dem.html`**: Interactive DEM visualization with Leaflet.js
600
+ - Load DEM from local TIFF files or IGN API
601
+ - Multiple color scales (terrain, elevation, grayscale)
602
+ - Elevation query on click
603
+ - Automatic OSM layer opacity adjustment
604
+
605
+ **Run WebAssembly examples:**
606
+
607
+ ```bash
608
+ cd rsmdu-wasm
609
+ ./build.sh
610
+ cd examples
611
+ python3 -m http.server 8000
612
+ # Open http://localhost:8000/index.html or http://localhost:8000/dem.html
613
+ ```
614
+
615
+ ## 🌐 IGN API
616
+
617
+ The library integrates with the French IGN (Institut Géographique National) Géoplateforme API.
618
+
619
+ ### Available Services
620
+
621
+ **Vector Data (WFS)**:
622
+
623
+ - `buildings`: Building footprints (BDTOPO_V3:batiment)
624
+ - `road`: Road segments (BDTOPO_V3:troncon_de_route)
625
+ - `water`: Water bodies (BDTOPO_V3:plan_d_eau)
626
+ - `cadastre`: Cadastral parcels (CADASTRALPARCELS.PARCELLAIRE_EXPRESS:parcelle)
627
+ - `iris`: IRIS statistical units (STATISTICALUNITS.IRIS:contours_iris)
628
+ - `lidar`: LiDAR point cloud data (IGNF_LIDAR-HD_TA:nuage-dalle)
629
+ - `vegetation`: Vegetation zones
630
+ - `hydrographique`: Hydrographic details
631
+
632
+ **Raster Data (WMS-R)**:
633
+
634
+ - `dem`: Digital Elevation Model (ELEVATION.ELEVATIONGRIDCOVERAGE.HIGHRES)
635
+ - `dsm`: Digital Surface Model
636
+ - `irc`: IRC orthoimagery
637
+ - `ortho`: High-resolution orthoimagery
638
+ - `cosia`: COSIA imagery
639
+
640
+ ### API Requirements
641
+
642
+ - **Internet connection**: Required for API requests
643
+ - **Rate limiting**: The API may have rate limits
644
+ - **Coordinate system**: Bounding boxes must be in WGS84 (EPSG:4326)
645
+ - **API keys**: For production use, you may need to register at https://geoservices.ign.fr/
646
+ - **CORS**: Browser-based requests require CORS support (available for IGN API)
647
+
648
+ ## 🏗️ Architecture
649
+
650
+ ### Workspace Structure
651
+
652
+ The project uses a Cargo workspace with three crates:
653
+
654
+ 1. **`rsmdu`**: Core Rust library with all geospatial functionality
655
+ - Uses feature flags (`wasm`) to conditionally compile WASM-incompatible dependencies
656
+ - Optional dependencies: `gdal`, `proj`, `geos`, `polars`, `reqwest`, etc.
657
+
658
+ 2. **`pymdurs`**: Python bindings using PyO3
659
+ - Depends on `rsmdu` crate
660
+ - Provides Pythonic API with aliases
661
+
662
+ 3. **`rsmdu-wasm`**: WebAssembly bindings
663
+ - Uses `rsmdu` with `wasm` feature flag
664
+ - Only WASM-compatible dependencies (geo, geojson, geotiff, tiff)
665
+ - Browser-specific APIs (web-sys, wasm-bindgen)
666
+
667
+ ### Inheritance Pattern (Python → Rust)
668
+
669
+ In Python, `Building` inherits from `IgnCollect`, which inherits from `GeoCore`. In Rust, we use composition:
670
+
671
+ ```rust
672
+ // Python: class Building(IgnCollect)
673
+ // Rust: BuildingCollection contains GeoCore and IgnCollect
674
+ pub struct BuildingCollection {
675
+ pub geo_core: GeoCore, // Inherits from GeoCore
676
+ ign_collect: Option<IgnCollect>, // Inherits from IgnCollect
677
+ // ...
678
+ }
679
+ ```
680
+
681
+ ### GeoCore Properties
682
+
683
+ `GeoCore` provides base functionality:
684
+
685
+ - `epsg`: Coordinate Reference System (default: 2154)
686
+ - `bbox`: Bounding box
687
+ - `output_path`: Output directory
688
+ - `output_path_shp`: Shapefile output path
689
+ - `filename_shp`: Shapefile filename
690
+
691
+ ## 📊 Status
692
+
693
+ ### ✅ Fully Implemented
694
+
695
+ **Core Features:**
696
+
697
+ - ✅ GeoJSON parsing and building collection
698
+ - ✅ IGN API integration (WFS and WMS)
699
+ - ✅ Building height processing with multiple fallback strategies
700
+ - ✅ DEM collection via WMS-R
701
+ - ✅ Cadastral data collection via WFS
702
+ - ✅ IRIS statistical units collection via WFS
703
+ - ✅ LCZ data structure with color mapping (17 LCZ types)
704
+ - ✅ Road, water, and vegetation data collection
705
+ - ✅ Polars DataFrame conversion
706
+ - ✅ GeoCore base class with all properties
707
+ - ✅ BuildingCollection with `run()` method (Python-style)
708
+ - ✅ Coordinate Reference System (CRS) transformations using Proj
709
+
710
+ **Python Bindings (PyO3):**
711
+
712
+ - ✅ Complete Python bindings installable via `pip install pymdurs`
713
+ - ✅ All geometric classes available: `Building`, `Dem`, `Cadastre`, `Iris`, `Lcz`, `Lidar`, `Road`, `Water`, `Vegetation`
714
+ - ✅ Geometric submodule (`pymdurs.geometric`) for organized class access
715
+ - ✅ Pythonic API with aliases (e.g., `pymdurs.geometric.Building` instead of `PyBuilding`)
716
+ - ✅ Pandas DataFrame conversion for Building data
717
+ - ✅ GeoJSON export/import
718
+ - ✅ LiDAR processing with automatic point loading
719
+ - ✅ Comprehensive Python examples and tests
720
+
721
+ **WebAssembly Bindings:**
722
+
723
+ - ✅ Building collection processing in browser
724
+ - ✅ DEM loading from IGN API in browser
725
+ - ✅ DEM loading from local TIFF files
726
+ - ✅ Interactive Leaflet.js visualization
727
+ - ✅ Dynamic bounding box updates
728
+ - ✅ Building statistics
729
+ - ✅ DEM visualization with color scales
730
+ - ✅ Elevation query on map click
731
+ - ✅ OSM layer opacity control
732
+
733
+ **Data Formats:**
734
+
735
+ - ✅ GeoJSON parsing and generation
736
+ - ✅ GeoTIFF reading and validation
737
+ - ✅ GeoJSON export (simplified, saves as GeoJSON temporarily)
738
+
739
+ ### 🚧 In Progress / Limitations
740
+
741
+ **Current Limitations:**
742
+
743
+ - ⚠️ GDAL Shapefile I/O temporarily disabled (API compatibility issues)
744
+ - ⚠️ Full GeoJSON export not yet implemented (saves as GeoJSON as workaround)
745
+ - ⚠️ LCZ shapefile loading from zip URLs requires full GDAL implementation
746
+ - ⚠️ Raster reprojection simplified (full resampling not yet implemented)
747
+ - ⚠️ Shapefile export for masks not yet available
748
+ - ⚠️ DEM pixel data access in WASM (currently metadata only)
749
+
750
+ **Workarounds:**
751
+
752
+ - Use GeoJSON format instead of Shapefiles for input/output
753
+ - GeoJSON export currently saves as GeoJSON (full GeoJSON support planned)
754
+ - LCZ processing structure ready but full shapefile loading pending GDAL fixes
755
+ - DEM visualization uses JavaScript libraries (GeoRasterLayer) for pixel access
756
+
757
+ ### 📋 Planned Features
758
+
759
+ **Short-term:**
760
+
761
+ - Complete GDAL integration for Shapefile I/O
762
+ - Full GeoJSON export with proper layer management
763
+ - Full raster reprojection with resampling options
764
+ - LCZ shapefile loading from zip URLs
765
+ - Full DEM pixel data access in WASM
766
+
767
+ **Long-term:**
768
+
769
+ - Additional geometric operations
770
+ - More IGN API services
771
+ - Performance optimizations
772
+ - Additional output formats
773
+ - Enhanced error handling and validation
774
+ - 3D visualization capabilities
775
+
776
+ ## 🧪 Testing
777
+
778
+ ### Rust Tests
779
+
780
+ Run Rust unit tests:
781
+
782
+ ```bash
783
+ cd rsmdu
784
+ cargo test
785
+ ```
786
+
787
+ ### Python Tests
788
+
789
+ Run Python tests:
790
+
791
+ ```bash
792
+ cd pymdurs
793
+ pytest tests/
794
+ ```
795
+
796
+ Or manually test the Python bindings:
797
+
798
+ ```bash
799
+ cd pymdurs
800
+ python -c "import pymdurs; print('✅ pymdurs imported successfully')"
801
+ python -c "import pymdurs; print('Available classes:', [x for x in dir(pymdurs.geometric) if not x.startswith('_')])"
802
+ python -c "import pymdurs; lidar = pymdurs.geometric.Lidar(output_path='./test'); print('✅ Lidar class works')"
803
+ ```
804
+
805
+ ### WebAssembly Tests
806
+
807
+ ```bash
808
+ cd rsmdu-wasm
809
+ wasm-pack test --headless --firefox
810
+ ```
811
+
812
+ ## 🤝 Contributing
813
+
814
+ Contributions are welcome! This project follows standard Rust and Python best practices.
815
+
816
+ ### Development Setup
817
+
818
+ 1. **Clone the repository:**
819
+
820
+ ```bash
821
+ git clone https://github.com/rupeelab17/pymdurs.git
822
+ cd pymdurs
823
+ ```
824
+
825
+ 2. **Set up Rust development:**
826
+
827
+ **Note**: If you haven't installed Rust yet, see the [Installing Rust](#installing-rust) section above.
828
+
829
+ ```bash
830
+ cd rsmdu
831
+ cargo build
832
+ cargo test
833
+ ```
834
+
835
+ 3. **Set up Python development:** See [Python Package](#python-package) for platform-specific build instructions.
836
+
837
+ 4. **Set up WebAssembly development:**
838
+ ```bash
839
+ cd rsmdu-wasm
840
+ rustup target add wasm32-unknown-unknown
841
+ cargo install wasm-pack
842
+ ./build.sh
843
+ ```
844
+
845
+ ### Contribution Guidelines
846
+
847
+ - Follow Rust naming conventions and style
848
+ - Add tests for new features
849
+ - Update documentation (README.md) for significant changes
850
+ - Ensure all examples still work after changes
851
+ - Test all three deployment targets (Rust, Python, WASM)
852
+ - Use feature flags for WASM-incompatible code
853
+
854
+ ### Reporting Issues
855
+
856
+ Please use GitHub Issues to report bugs or request features. Include:
857
+
858
+ - Description of the issue
859
+ - Steps to reproduce
860
+ - Expected vs actual behavior
861
+ - Environment details (OS, Rust version, Python version, browser for WASM)
862
+
863
+ ## 📄 License
864
+
865
+ GPL-3.0 (same as [pymdu](https://github.com/rupeelab17/pymdu))
866
+
867
+ ## ⚡ Performance
868
+
869
+ This Rust implementation provides significant performance improvements over the original Python version:
870
+
871
+ - **Memory efficiency**: Rust's ownership system prevents memory leaks
872
+ - **Concurrency**: Safe parallel processing capabilities
873
+ - **Speed**: Native compilation provides faster execution
874
+ - **Type safety**: Compile-time error checking reduces runtime errors
875
+ - **WebAssembly**: Near-native performance in the browser
876
+
877
+ ## 🔗 Related Projects
878
+
879
+ - [pymdu](https://github.com/rupeelab17/pymdu): Original Python implementation
880
+ - [GeoRust](https://georust.org/): Rust geospatial ecosystem
881
+ - [IGN Géoplateforme](https://geoservices.ign.fr/): French geospatial data services
882
+ - [PyO3](https://pyo3.rs/): Rust bindings for Python
883
+ - [Maturin](https://github.com/PyO3/maturin): Build tool for Python packages with Rust extensions
884
+ - [wasm-pack](https://rustwasm.github.io/wasm-pack/): Build tool for WebAssembly packages
885
+
886
+ ## 📝 Version
887
+
888
+ Current version: **0.1.1** (Alpha)
889
+
890
+ This is an early release. The API may change in future versions. See the [Status](#-status) section for implementation details.
891
+
892
+ ## 📚 Documentation
893
+
894
+ - **Rust API**: Run `cargo doc --open` in the `rsmdu` directory
895
+ - **Python API**: See `pymdurs/README.md`
896
+ - **WebAssembly API**: See `rsmdu-wasm/README.md`
897
+ - **Examples**: See [examples/README.md](examples/README.md), `rsmdu/examples/`, and `rsmdu-wasm/examples/`
898
+