mudm-tools 0.5.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.
- mudm_tools-0.5.0/LICENSE +21 -0
- mudm_tools-0.5.0/PKG-INFO +75 -0
- mudm_tools-0.5.0/README.md +42 -0
- mudm_tools-0.5.0/pyproject.toml +62 -0
- mudm_tools-0.5.0/setup.cfg +4 -0
- mudm_tools-0.5.0/src/mudm_tools/__init__.py +29 -0
- mudm_tools-0.5.0/src/mudm_tools/_legacy/automodel.py +44 -0
- mudm_tools-0.5.0/src/mudm_tools/_legacy/roundtrip.py +225 -0
- mudm_tools-0.5.0/src/mudm_tools/arrow/__init__.py +5 -0
- mudm_tools-0.5.0/src/mudm_tools/arrow/_from_geometry.py +119 -0
- mudm_tools-0.5.0/src/mudm_tools/arrow/_geometry.py +145 -0
- mudm_tools-0.5.0/src/mudm_tools/arrow/_table_builder.py +244 -0
- mudm_tools-0.5.0/src/mudm_tools/arrow/models.py +15 -0
- mudm_tools-0.5.0/src/mudm_tools/arrow/reader.py +131 -0
- mudm_tools-0.5.0/src/mudm_tools/arrow/writer.py +57 -0
- mudm_tools-0.5.0/src/mudm_tools/converters/__init__.py +64 -0
- mudm_tools-0.5.0/src/mudm_tools/converters/cli.py +85 -0
- mudm_tools-0.5.0/src/mudm_tools/converters/geojson.py +127 -0
- mudm_tools-0.5.0/src/mudm_tools/converters/obj.py +125 -0
- mudm_tools-0.5.0/src/mudm_tools/converters/xenium.py +353 -0
- mudm_tools-0.5.0/src/mudm_tools/examples/__init__.py +0 -0
- mudm_tools-0.5.0/src/mudm_tools/examples/annotate_by_type.py +371 -0
- mudm_tools-0.5.0/src/mudm_tools/examples/annotate_neuron.py +407 -0
- mudm_tools-0.5.0/src/mudm_tools/examples/df_to_microjson.py +83 -0
- mudm_tools-0.5.0/src/mudm_tools/examples/load_validate.py +19 -0
- mudm_tools-0.5.0/src/mudm_tools/examples/neuroglancer_export.py +224 -0
- mudm_tools-0.5.0/src/mudm_tools/examples/neuroglancer_serve.py +158 -0
- mudm_tools-0.5.0/src/mudm_tools/examples/readtiles.py +29 -0
- mudm_tools-0.5.0/src/mudm_tools/examples/swc_to_neuroglancer.py +172 -0
- mudm_tools-0.5.0/src/mudm_tools/examples/tiling.py +125 -0
- mudm_tools-0.5.0/src/mudm_tools/examples/tiling_rust.py +193 -0
- mudm_tools-0.5.0/src/mudm_tools/fileutils.py +16 -0
- mudm_tools-0.5.0/src/mudm_tools/geojson_model.py +453 -0
- mudm_tools-0.5.0/src/mudm_tools/gltf/__init__.py +4 -0
- mudm_tools-0.5.0/src/mudm_tools/gltf/_buffers.py +124 -0
- mudm_tools-0.5.0/src/mudm_tools/gltf/_draco.py +197 -0
- mudm_tools-0.5.0/src/mudm_tools/gltf/gltf_assembler.py +568 -0
- mudm_tools-0.5.0/src/mudm_tools/gltf/mesh_builder.py +274 -0
- mudm_tools-0.5.0/src/mudm_tools/gltf/models.py +47 -0
- mudm_tools-0.5.0/src/mudm_tools/gltf/triangulator.py +99 -0
- mudm_tools-0.5.0/src/mudm_tools/gltf/writer.py +76 -0
- mudm_tools-0.5.0/src/mudm_tools/mudm2vt/__init__.py +5 -0
- mudm_tools-0.5.0/src/mudm_tools/mudm2vt/clip.py +196 -0
- mudm_tools-0.5.0/src/mudm_tools/mudm2vt/convert.py +206 -0
- mudm_tools-0.5.0/src/mudm_tools/mudm2vt/feature.py +47 -0
- mudm_tools-0.5.0/src/mudm_tools/mudm2vt/mudm2vt.py +490 -0
- mudm_tools-0.5.0/src/mudm_tools/mudm2vt/simplify.py +78 -0
- mudm_tools-0.5.0/src/mudm_tools/mudm2vt/tile.py +125 -0
- mudm_tools-0.5.0/src/mudm_tools/mudm2vt/transform.py +42 -0
- mudm_tools-0.5.0/src/mudm_tools/mudm2vt/utils.py +53 -0
- mudm_tools-0.5.0/src/mudm_tools/mudm2vt/vt2geojson.py +57 -0
- mudm_tools-0.5.0/src/mudm_tools/mudm2vt/wrap.py +74 -0
- mudm_tools-0.5.0/src/mudm_tools/neuroglancer/__init__.py +32 -0
- mudm_tools-0.5.0/src/mudm_tools/neuroglancer/_binary.py +38 -0
- mudm_tools-0.5.0/src/mudm_tools/neuroglancer/annotation_writer.py +196 -0
- mudm_tools-0.5.0/src/mudm_tools/neuroglancer/mesh_models.py +27 -0
- mudm_tools-0.5.0/src/mudm_tools/neuroglancer/mesh_writer.py +218 -0
- mudm_tools-0.5.0/src/mudm_tools/neuroglancer/models.py +209 -0
- mudm_tools-0.5.0/src/mudm_tools/neuroglancer/properties_writer.py +107 -0
- mudm_tools-0.5.0/src/mudm_tools/neuroglancer/skeleton_writer.py +194 -0
- mudm_tools-0.5.0/src/mudm_tools/neuroglancer/state.py +126 -0
- mudm_tools-0.5.0/src/mudm_tools/neuroglancer/writer.py +107 -0
- mudm_tools-0.5.0/src/mudm_tools/polygen.py +167 -0
- mudm_tools-0.5.0/src/mudm_tools/polygen3d.py +194 -0
- mudm_tools-0.5.0/src/mudm_tools/serve.py +235 -0
- mudm_tools-0.5.0/src/mudm_tools/swc.py +593 -0
- mudm_tools-0.5.0/src/mudm_tools/tilehandler.py +29 -0
- mudm_tools-0.5.0/src/mudm_tools/tilereader.py +154 -0
- mudm_tools-0.5.0/src/mudm_tools/tilewriter.py +290 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling2d/__init__.py +29 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling2d/parquet_prime.py +198 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling2d/parquet_reader.py +105 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling2d/parquet_writer.py +398 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling2d/pbf_reader.py +31 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling2d/pbf_writer.py +34 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/__init__.py +34 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/clip3d.py +320 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/convert3d.py +305 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/encoder3d.py +309 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/generator3d.py +455 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/gltf_encoder3d.py +181 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/morton.py +57 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/octree.py +149 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/parquet_prime.py +251 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/parquet_reader.py +112 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/parquet_writer.py +417 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/projector3d.py +38 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/proto/__init__.py +1 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/proto/mudm_3d_tile_pb2.py +53 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/reader3d.py +381 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/reader_3dtiles.py +94 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/simplify3d.py +130 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/simplify_mesh.py +137 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/tile3d.py +150 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/tilejson3d.py +60 -0
- mudm_tools-0.5.0/src/mudm_tools/tiling3d/tileset_json.py +171 -0
- mudm_tools-0.5.0/src/mudm_tools/utils.py +425 -0
- mudm_tools-0.5.0/src/mudm_tools/viewers/__init__.py +0 -0
- mudm_tools-0.5.0/src/mudm_tools/viewers/viewer2d/css/style.css +156 -0
- mudm_tools-0.5.0/src/mudm_tools/viewers/viewer2d/index.html +42 -0
- mudm_tools-0.5.0/src/mudm_tools/viewers/viewer2d/js/InfoPanel.js +57 -0
- mudm_tools-0.5.0/src/mudm_tools/viewers/viewer2d/js/LayerPanel.js +201 -0
- mudm_tools-0.5.0/src/mudm_tools/viewers/viewer2d/js/Leaflet.VectorGrid.bundled.js +2551 -0
- mudm_tools-0.5.0/src/mudm_tools/viewers/viewer2d/js/main.js +259 -0
- mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/index.html +518 -0
- mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/js/AxisGizmo.js +137 -0
- mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/js/BoundingVolume.js +29 -0
- mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/js/FeatureSelector.js +458 -0
- mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/js/InfoPanel.js +119 -0
- mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/js/OverviewPanel.js +826 -0
- mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/js/PyramidSelector.js +75 -0
- mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/js/ScaleBar.js +70 -0
- mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/js/SlicePlanePanel.js +255 -0
- mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/js/TileManager.js +799 -0
- mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/js/main.js +827 -0
- mudm_tools-0.5.0/src/mudm_tools/vt2pbf/__init__.py +8 -0
- mudm_tools-0.5.0/src/mudm_tools/vt2pbf/config.py +2 -0
- mudm_tools-0.5.0/src/mudm_tools/vt2pbf/encoder.py +8 -0
- mudm_tools-0.5.0/src/mudm_tools/vt2pbf/exceptions.py +14 -0
- mudm_tools-0.5.0/src/mudm_tools/vt2pbf/mapbox/__init__.py +0 -0
- mudm_tools-0.5.0/src/mudm_tools/vt2pbf/mapbox/protobuf_3/__init__.py +0 -0
- mudm_tools-0.5.0/src/mudm_tools/vt2pbf/mapbox/protobuf_3/vector_tile_pb2.py +323 -0
- mudm_tools-0.5.0/src/mudm_tools/vt2pbf/mapbox/protobuf_4/__init__.py +0 -0
- mudm_tools-0.5.0/src/mudm_tools/vt2pbf/mapbox/protobuf_4/vector_tile_pb2.py +38 -0
- mudm_tools-0.5.0/src/mudm_tools/vt2pbf/mapbox/protobuf_4/vector_tile_pb2.pyi +66 -0
- mudm_tools-0.5.0/src/mudm_tools/vt2pbf/service/__init__.py +0 -0
- mudm_tools-0.5.0/src/mudm_tools/vt2pbf/service/feature.py +98 -0
- mudm_tools-0.5.0/src/mudm_tools/vt2pbf/service/layer.py +34 -0
- mudm_tools-0.5.0/src/mudm_tools/vt2pbf/service/tile.py +34 -0
- mudm_tools-0.5.0/src/mudm_tools.egg-info/PKG-INFO +75 -0
- mudm_tools-0.5.0/src/mudm_tools.egg-info/SOURCES.txt +178 -0
- mudm_tools-0.5.0/src/mudm_tools.egg-info/dependency_links.txt +1 -0
- mudm_tools-0.5.0/src/mudm_tools.egg-info/entry_points.txt +2 -0
- mudm_tools-0.5.0/src/mudm_tools.egg-info/requires.txt +16 -0
- mudm_tools-0.5.0/src/mudm_tools.egg-info/top_level.txt +1 -0
- mudm_tools-0.5.0/tests/test_3d_models.py +403 -0
- mudm_tools-0.5.0/tests/test_arrow.py +390 -0
- mudm_tools-0.5.0/tests/test_arrow_integration.py +387 -0
- mudm_tools-0.5.0/tests/test_arrow_reader.py +332 -0
- mudm_tools-0.5.0/tests/test_benchmark_draco.py +189 -0
- mudm_tools-0.5.0/tests/test_geojson_schema.py +58 -0
- mudm_tools-0.5.0/tests/test_gltf_assembler.py +584 -0
- mudm_tools-0.5.0/tests/test_gltf_buffers.py +99 -0
- mudm_tools-0.5.0/tests/test_gltf_draco.py +412 -0
- mudm_tools-0.5.0/tests/test_gltf_integration.py +119 -0
- mudm_tools-0.5.0/tests/test_gltf_mesh_builder.py +472 -0
- mudm_tools-0.5.0/tests/test_gltf_triangulator.py +89 -0
- mudm_tools-0.5.0/tests/test_gltf_writer.py +126 -0
- mudm_tools-0.5.0/tests/test_layout.py +290 -0
- mudm_tools-0.5.0/tests/test_mudm.py +106 -0
- mudm_tools-0.5.0/tests/test_neuroglancer_annotations.py +137 -0
- mudm_tools-0.5.0/tests/test_neuroglancer_binary.py +90 -0
- mudm_tools-0.5.0/tests/test_neuroglancer_mesh.py +446 -0
- mudm_tools-0.5.0/tests/test_neuroglancer_models.py +166 -0
- mudm_tools-0.5.0/tests/test_neuroglancer_multilod.py +342 -0
- mudm_tools-0.5.0/tests/test_neuroglancer_properties.py +90 -0
- mudm_tools-0.5.0/tests/test_neuroglancer_skeleton.py +218 -0
- mudm_tools-0.5.0/tests/test_neuroglancer_state.py +94 -0
- mudm_tools-0.5.0/tests/test_neuroglancer_writer.py +86 -0
- mudm_tools-0.5.0/tests/test_obj_to_mudm.py +341 -0
- mudm_tools-0.5.0/tests/test_original_schema.py +57 -0
- mudm_tools-0.5.0/tests/test_polygen3d.py +113 -0
- mudm_tools-0.5.0/tests/test_provenance.py +56 -0
- mudm_tools-0.5.0/tests/test_pure_python.py +60 -0
- mudm_tools-0.5.0/tests/test_swc.py +276 -0
- mudm_tools-0.5.0/tests/test_tilecut.py +105 -0
- mudm_tools-0.5.0/tests/test_tiled_geometry.py +236 -0
- mudm_tools-0.5.0/tests/test_tilejson.py +57 -0
- mudm_tools-0.5.0/tests/test_tiling2d_parquet.py +684 -0
- mudm_tools-0.5.0/tests/test_tiling2d_pbf.py +379 -0
- mudm_tools-0.5.0/tests/test_tiling3d.py +1360 -0
- mudm_tools-0.5.0/tests/test_tiling3d_3dtiles.py +488 -0
- mudm_tools-0.5.0/tests/test_tiling3d_feature_pbf3.py +610 -0
- mudm_tools-0.5.0/tests/test_tiling3d_multiprocessing.py +316 -0
- mudm_tools-0.5.0/tests/test_tiling3d_parquet.py +1209 -0
- mudm_tools-0.5.0/tests/test_tiling3d_rust.py +1227 -0
- mudm_tools-0.5.0/tests/test_transforms.py +252 -0
- mudm_tools-0.5.0/tests/test_utils.py +162 -0
- mudm_tools-0.5.0/tests/test_vocabulary.py +249 -0
- mudm_tools-0.5.0/tests/test_xenium_to_tiles.py +237 -0
mudm_tools-0.5.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 NovaGen Research Fund
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mudm-tools
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: Processing pipelines, tiling engines, and format converters for muDM spatial data.
|
|
5
|
+
Author-email: Bengt Ljungquist <bengt.ljungquist@nih.gov>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Documentation, https://github.com/NovagenResearch/mudm-tools
|
|
8
|
+
Project-URL: Source, https://github.com/NovagenResearch/mudm-tools
|
|
9
|
+
Keywords: microscopy,mudm,tiling,spatial-data,vector-tiles
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Rust
|
|
14
|
+
Requires-Python: <3.14,>=3.11
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: mudm>=0.5.0
|
|
18
|
+
Requires-Dist: pydantic>=2.3.0
|
|
19
|
+
Requires-Dist: geojson-pydantic>=1.2.0
|
|
20
|
+
Requires-Dist: geojson2vt>=1.0.1
|
|
21
|
+
Requires-Dist: protobuf>=5.29.3
|
|
22
|
+
Requires-Dist: geojson>=3.1.0
|
|
23
|
+
Requires-Dist: shapely>=2.0.6
|
|
24
|
+
Requires-Dist: mapbox-vector-tile>=2.1.0
|
|
25
|
+
Requires-Dist: pyarrow>=19.0.1
|
|
26
|
+
Requires-Dist: geopandas>=1.0.1
|
|
27
|
+
Requires-Dist: jsonschema>=4.23.0
|
|
28
|
+
Requires-Dist: pygltflib>=1.16
|
|
29
|
+
Requires-Dist: numpy>=1.26
|
|
30
|
+
Provides-Extra: draco
|
|
31
|
+
Requires-Dist: DracoPy>=1.4; extra == "draco"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# mudm-tools
|
|
35
|
+
|
|
36
|
+
Processing pipelines, tiling engines, and format converters for [muDM](https://github.com/NovagenResearch/mudm) spatial data. Includes optional Rust acceleration via prebuilt wheels.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install mudm-tools
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
On supported platforms (Linux x86_64, macOS x86_64/arm64, Windows x86_64), this automatically includes the Rust-accelerated tiling engine. On other platforms, a pure-Python fallback is used.
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
import mudm_tools
|
|
48
|
+
print(mudm_tools.RUST_AVAILABLE) # True with prebuilt wheel
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Features
|
|
52
|
+
|
|
53
|
+
- **2D tiling**: Rust-accelerated quadtree pipeline (StreamingTileGenerator2D) + legacy Python pipeline
|
|
54
|
+
- **3D tiling**: Octree-based mesh tiling with meshopt/Draco compression (StreamingTileGenerator)
|
|
55
|
+
- **Format converters**: Xenium spatial transcriptomics, OBJ meshes, GeoJSON
|
|
56
|
+
- **GeoParquet/Arrow**: Import and export via Apache Arrow
|
|
57
|
+
- **glTF/GLB export**: 3D mesh export with optional Draco compression
|
|
58
|
+
- **Neuroglancer**: Precomputed format for browser-based 3D visualization
|
|
59
|
+
- **Multiple output formats**: PBF (MVT), 3D Tiles (GLB), tiled Parquet (ZSTD), Neuroglancer precomputed
|
|
60
|
+
|
|
61
|
+
## Quick start
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from mudm import MuDM # core data model (separate package)
|
|
65
|
+
from mudm_tools._rs import StreamingTileGenerator2D # Rust-accelerated
|
|
66
|
+
from mudm_tools.tiling2d import generate_pbf
|
|
67
|
+
|
|
68
|
+
gen = StreamingTileGenerator2D(min_zoom=0, max_zoom=7, buffer=64/4096)
|
|
69
|
+
gen.add_geojson(open("data.json").read(), bounds)
|
|
70
|
+
generate_pbf(gen, "tiles/", bounds)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## License
|
|
74
|
+
|
|
75
|
+
MIT
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# mudm-tools
|
|
2
|
+
|
|
3
|
+
Processing pipelines, tiling engines, and format converters for [muDM](https://github.com/NovagenResearch/mudm) spatial data. Includes optional Rust acceleration via prebuilt wheels.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install mudm-tools
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
On supported platforms (Linux x86_64, macOS x86_64/arm64, Windows x86_64), this automatically includes the Rust-accelerated tiling engine. On other platforms, a pure-Python fallback is used.
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
import mudm_tools
|
|
15
|
+
print(mudm_tools.RUST_AVAILABLE) # True with prebuilt wheel
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Features
|
|
19
|
+
|
|
20
|
+
- **2D tiling**: Rust-accelerated quadtree pipeline (StreamingTileGenerator2D) + legacy Python pipeline
|
|
21
|
+
- **3D tiling**: Octree-based mesh tiling with meshopt/Draco compression (StreamingTileGenerator)
|
|
22
|
+
- **Format converters**: Xenium spatial transcriptomics, OBJ meshes, GeoJSON
|
|
23
|
+
- **GeoParquet/Arrow**: Import and export via Apache Arrow
|
|
24
|
+
- **glTF/GLB export**: 3D mesh export with optional Draco compression
|
|
25
|
+
- **Neuroglancer**: Precomputed format for browser-based 3D visualization
|
|
26
|
+
- **Multiple output formats**: PBF (MVT), 3D Tiles (GLB), tiled Parquet (ZSTD), Neuroglancer precomputed
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from mudm import MuDM # core data model (separate package)
|
|
32
|
+
from mudm_tools._rs import StreamingTileGenerator2D # Rust-accelerated
|
|
33
|
+
from mudm_tools.tiling2d import generate_pbf
|
|
34
|
+
|
|
35
|
+
gen = StreamingTileGenerator2D(min_zoom=0, max_zoom=7, buffer=64/4096)
|
|
36
|
+
gen.add_geojson(open("data.json").read(), bounds)
|
|
37
|
+
generate_pbf(gen, "tiles/", bounds)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## License
|
|
41
|
+
|
|
42
|
+
MIT
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "mudm-tools"
|
|
7
|
+
version = "0.5.0"
|
|
8
|
+
description = "Processing pipelines, tiling engines, and format converters for muDM spatial data."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [
|
|
11
|
+
{ name = "Bengt Ljungquist", email = "bengt.ljungquist@nih.gov" },
|
|
12
|
+
]
|
|
13
|
+
license = { text = "MIT" }
|
|
14
|
+
requires-python = ">=3.11,<3.14"
|
|
15
|
+
classifiers = [
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Programming Language :: Python",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Rust",
|
|
20
|
+
]
|
|
21
|
+
keywords = ["microscopy", "mudm", "tiling", "spatial-data", "vector-tiles"]
|
|
22
|
+
dependencies = [
|
|
23
|
+
"mudm>=0.5.0",
|
|
24
|
+
"pydantic>=2.3.0",
|
|
25
|
+
"geojson-pydantic>=1.2.0",
|
|
26
|
+
"geojson2vt>=1.0.1",
|
|
27
|
+
"protobuf>=5.29.3",
|
|
28
|
+
"geojson>=3.1.0",
|
|
29
|
+
"shapely>=2.0.6",
|
|
30
|
+
"mapbox-vector-tile>=2.1.0",
|
|
31
|
+
"pyarrow>=19.0.1",
|
|
32
|
+
"geopandas>=1.0.1",
|
|
33
|
+
"jsonschema>=4.23.0",
|
|
34
|
+
"pygltflib>=1.16",
|
|
35
|
+
"numpy>=1.26",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.optional-dependencies]
|
|
39
|
+
draco = ["DracoPy>=1.4"]
|
|
40
|
+
|
|
41
|
+
[project.scripts]
|
|
42
|
+
mudm-serve = "mudm_tools.serve:main"
|
|
43
|
+
|
|
44
|
+
[project.urls]
|
|
45
|
+
Documentation = "https://github.com/NovagenResearch/mudm-tools"
|
|
46
|
+
Source = "https://github.com/NovagenResearch/mudm-tools"
|
|
47
|
+
|
|
48
|
+
[tool.maturin]
|
|
49
|
+
manifest-path = "rust/Cargo.toml"
|
|
50
|
+
python-source = "src"
|
|
51
|
+
module-name = "mudm_tools._rs"
|
|
52
|
+
features = ["pyo3/extension-module"]
|
|
53
|
+
|
|
54
|
+
[tool.setuptools.packages.find]
|
|
55
|
+
where = ["src"]
|
|
56
|
+
|
|
57
|
+
[tool.setuptools.package-data]
|
|
58
|
+
"mudm_tools.viewers" = ["**/*.html", "**/*.js", "**/*.css"]
|
|
59
|
+
|
|
60
|
+
[tool.pytest.ini_options]
|
|
61
|
+
testpaths = ["tests/"]
|
|
62
|
+
pythonpath = ["src/", "scripts/"]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""mudm-tools — processing pipelines, tiling, and format converters for muDM."""
|
|
2
|
+
|
|
3
|
+
from .mudm2vt.mudm2vt import mudm2vt # noqa: F401
|
|
4
|
+
from .neuroglancer import ( # noqa: F401
|
|
5
|
+
to_neuroglancer,
|
|
6
|
+
write_annotations,
|
|
7
|
+
)
|
|
8
|
+
from .gltf import to_gltf, to_glb, GltfConfig # noqa: F401
|
|
9
|
+
from .arrow import to_arrow_table, to_geoparquet, ArrowConfig # noqa: F401
|
|
10
|
+
from .arrow import from_arrow_table, from_geoparquet # noqa: F401
|
|
11
|
+
from .tiling3d import ( # noqa: F401
|
|
12
|
+
TileGenerator3D,
|
|
13
|
+
OctreeConfig,
|
|
14
|
+
TileReader3D,
|
|
15
|
+
TileModel3D,
|
|
16
|
+
)
|
|
17
|
+
from .tiling3d.tilejson3d import ( # noqa: F401
|
|
18
|
+
TileEncoding,
|
|
19
|
+
KnownTileFormat,
|
|
20
|
+
KnownCompression,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
from ._rs import StreamingTileGenerator, StreamingTileGenerator2D # noqa: F401
|
|
25
|
+
RUST_AVAILABLE = True
|
|
26
|
+
except ImportError:
|
|
27
|
+
RUST_AVAILABLE = False
|
|
28
|
+
|
|
29
|
+
__version__ = "0.5.0"
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Microjson using manual MuDM pydantic models,
|
|
2
|
+
but autogenerated GeoJSON models."""
|
|
3
|
+
from typing import Optional, Union
|
|
4
|
+
from pydantic import BaseModel, StrictInt, StrictStr
|
|
5
|
+
from geojson.Feature import GeojsonFeature
|
|
6
|
+
from geojson.FeatureCollection import GeojsonFeaturecollection
|
|
7
|
+
from geojson.Geometry import GeojsonGeometry
|
|
8
|
+
from geojson.GeometryCollection import GeojsonGeometrycollection
|
|
9
|
+
from mudm.model import Multiscale
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class GeoJSONAuto(BaseModel):
|
|
13
|
+
"""The root object of a GeoJSON file"""
|
|
14
|
+
|
|
15
|
+
__root__: Union[
|
|
16
|
+
GeojsonFeature,
|
|
17
|
+
GeojsonFeaturecollection,
|
|
18
|
+
GeojsonGeometry,
|
|
19
|
+
GeojsonGeometrycollection,
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class MuDMFeature(GeojsonFeature):
|
|
24
|
+
"""A MuDM feature, which is a GeoJSON feature with additional
|
|
25
|
+
metadata"""
|
|
26
|
+
|
|
27
|
+
multiscale: Optional[Multiscale]
|
|
28
|
+
ref: Optional[Union[StrictStr, StrictInt]]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class MuDMFeatureCollection(GeojsonFeaturecollection):
|
|
32
|
+
"""A MuDM feature collection, which is a GeoJSON feature
|
|
33
|
+
collection with additional metadata"""
|
|
34
|
+
|
|
35
|
+
multiscale: Optional[Multiscale]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class MuDMAuto(BaseModel):
|
|
39
|
+
"""The root object of a MuDM file"""
|
|
40
|
+
|
|
41
|
+
__root__: Union[
|
|
42
|
+
MuDMFeature, MuDMFeatureCollection,
|
|
43
|
+
GeojsonGeometry, GeojsonGeometrycollection
|
|
44
|
+
]
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"""MuDM Roundtrip for GeoJSON, generated automatically
|
|
2
|
+
by datamodel-codegen from models exported from
|
|
3
|
+
Pydantic models"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from enum import Enum
|
|
8
|
+
from typing import Any, Dict, List, Optional, Union
|
|
9
|
+
|
|
10
|
+
from pydantic.v1 import BaseModel, Field
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Type(Enum):
|
|
14
|
+
point = 'Point'
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Point(BaseModel):
|
|
18
|
+
bbox: Optional[List[float]] = Field(None, min_length=4, title='Bbox')
|
|
19
|
+
type: Type = Field(..., title='Type')
|
|
20
|
+
coordinates: List[float] = Field(...,
|
|
21
|
+
max_length=3,
|
|
22
|
+
min_length=2,
|
|
23
|
+
title='Coordinates')
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Type1(Enum):
|
|
27
|
+
multi_point = 'MultiPoint'
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class MultiPoint(BaseModel):
|
|
31
|
+
bbox: Optional[List[float]] = Field(None, min_length=4, title='Bbox')
|
|
32
|
+
type: Type1 = Field(..., title='Type')
|
|
33
|
+
coordinates: List[List[float]] = Field(..., title='Coordinates')
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Type2(Enum):
|
|
37
|
+
line_string = 'LineString'
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class LineString(BaseModel):
|
|
41
|
+
bbox: Optional[List[float]] = Field(None, min_length=4, title='Bbox')
|
|
42
|
+
type: Type2 = Field(..., title='Type')
|
|
43
|
+
coordinates: List[List[float]] = Field(..., title='Coordinates')
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class Type3(Enum):
|
|
47
|
+
multi_line_string = 'MultiLineString'
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class MultiLineString(BaseModel):
|
|
51
|
+
bbox: Optional[List[float]] = Field(None, min_length=4, title='Bbox')
|
|
52
|
+
type: Type3 = Field(..., title='Type')
|
|
53
|
+
coordinates: List[List[List[float]]] = Field(..., title='Coordinates')
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class Type4(Enum):
|
|
57
|
+
polygon = 'Polygon'
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class Polygon(BaseModel):
|
|
61
|
+
bbox: Optional[List[float]] = Field(None, min_length=4, title='Bbox')
|
|
62
|
+
type: Type4 = Field(..., title='Type')
|
|
63
|
+
coordinates: List[List[List[float]]] = Field(..., title='Coordinates')
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class Type5(Enum):
|
|
67
|
+
multi_polygon = 'MultiPolygon'
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class MultiPolygon(BaseModel):
|
|
71
|
+
bbox: Optional[List[float]] = Field(None, min_length=4, title='Bbox')
|
|
72
|
+
type: Type5 = Field(..., title='Type')
|
|
73
|
+
coordinates: List[List[List[List[float]]]] = Field(...,
|
|
74
|
+
title='Coordinates')
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class Type6(Enum):
|
|
78
|
+
geometry_collection = 'GeometryCollection'
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class GeometryCollection(BaseModel):
|
|
82
|
+
bbox: Optional[List[float]] = Field(None, min_length=4, title='Bbox')
|
|
83
|
+
type: Type6 = Field(..., title='Type')
|
|
84
|
+
geometries: List[
|
|
85
|
+
Union[Point,
|
|
86
|
+
MultiPoint,
|
|
87
|
+
LineString,
|
|
88
|
+
MultiLineString,
|
|
89
|
+
Polygon,
|
|
90
|
+
MultiPolygon]
|
|
91
|
+
] = Field(..., title='Geometries')
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class Properties(BaseModel):
|
|
95
|
+
descriptive: Optional[Dict[str, str]] = Field(None, title='Descriptive')
|
|
96
|
+
numerical: Optional[Dict[str, float]] = Field(None, title='Numerical')
|
|
97
|
+
multiNumerical: Optional[Dict[str, List[float]]] = Field(
|
|
98
|
+
None, title='Multi Numerical'
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class Unit(Enum):
|
|
103
|
+
angstrom = 'angstrom'
|
|
104
|
+
attometer = 'attometer'
|
|
105
|
+
centimeter = 'centimeter'
|
|
106
|
+
decimeter = 'decimeter'
|
|
107
|
+
exameter = 'exameter'
|
|
108
|
+
femtometer = 'femtometer'
|
|
109
|
+
foot = 'foot'
|
|
110
|
+
gigameter = 'gigameter'
|
|
111
|
+
hectometer = 'hectometer'
|
|
112
|
+
inch = 'inch'
|
|
113
|
+
kilometer = 'kilometer'
|
|
114
|
+
megameter = 'megameter'
|
|
115
|
+
meter = 'meter'
|
|
116
|
+
micrometer = 'micrometer'
|
|
117
|
+
mile = 'mile'
|
|
118
|
+
millimeter = 'millimeter'
|
|
119
|
+
nanometer = 'nanometer'
|
|
120
|
+
parsec = 'parsec'
|
|
121
|
+
petameter = 'petameter'
|
|
122
|
+
picometer = 'picometer'
|
|
123
|
+
terameter = 'terameter'
|
|
124
|
+
yard = 'yard'
|
|
125
|
+
yoctometer = 'yoctometer'
|
|
126
|
+
yottameter = 'yottameter'
|
|
127
|
+
zeptometer = 'zeptometer'
|
|
128
|
+
zettameter = 'zettameter'
|
|
129
|
+
pixel = 'pixel'
|
|
130
|
+
radian = 'radian'
|
|
131
|
+
degree = 'degree'
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class Axe(Enum):
|
|
135
|
+
x = 'x'
|
|
136
|
+
y = 'y'
|
|
137
|
+
z = 'z'
|
|
138
|
+
r = 'r'
|
|
139
|
+
theta = 'theta'
|
|
140
|
+
phi = 'phi'
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class Multiscale(BaseModel):
|
|
144
|
+
axes: List[Axe] = Field(..., title='Axes')
|
|
145
|
+
units: Optional[List[Unit]] = None
|
|
146
|
+
pixelsPerUnit: Optional[List[float]] = Field(
|
|
147
|
+
None, alias='pixelsPerUnit', title='Pixelsperunit'
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class Type7(Enum):
|
|
152
|
+
feature = 'Feature'
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class MuDMFeature(BaseModel):
|
|
156
|
+
bbox: Optional[List[float]] = Field(None, min_length=4, title='Bbox')
|
|
157
|
+
type: Type7 = Field(..., title='Type')
|
|
158
|
+
geometry: Union[
|
|
159
|
+
Point,
|
|
160
|
+
MultiPoint,
|
|
161
|
+
LineString,
|
|
162
|
+
MultiLineString,
|
|
163
|
+
Polygon,
|
|
164
|
+
MultiPolygon,
|
|
165
|
+
GeometryCollection,
|
|
166
|
+
] = Field(
|
|
167
|
+
...,
|
|
168
|
+
description='The geometry of the feature',
|
|
169
|
+
title='Geometry',
|
|
170
|
+
)
|
|
171
|
+
properties: Properties
|
|
172
|
+
id: Optional[Union[str, int]] = Field(None, title='Id')
|
|
173
|
+
multiscale: Optional[Multiscale] = None
|
|
174
|
+
ref: Optional[Union[str, int]] = Field(None, title='Ref')
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class Feature(BaseModel):
|
|
178
|
+
bbox: Optional[List[float]] = Field(None, min_length=4, title='Bbox')
|
|
179
|
+
type: Type7 = Field(..., title='Type')
|
|
180
|
+
geometry: Union[
|
|
181
|
+
Point,
|
|
182
|
+
MultiPoint,
|
|
183
|
+
LineString,
|
|
184
|
+
MultiLineString,
|
|
185
|
+
Polygon,
|
|
186
|
+
MultiPolygon,
|
|
187
|
+
GeometryCollection,
|
|
188
|
+
] = Field(
|
|
189
|
+
...,
|
|
190
|
+
description='The geometry of the feature',
|
|
191
|
+
title='Geometry',
|
|
192
|
+
)
|
|
193
|
+
properties: Dict[str, Any] = Field(
|
|
194
|
+
...,
|
|
195
|
+
description='Properties of the feature',
|
|
196
|
+
title='Properties',
|
|
197
|
+
)
|
|
198
|
+
id: Optional[Union[str, int]] = Field(None, title='Id')
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
class Type9(Enum):
|
|
202
|
+
feature_collection = 'FeatureCollection'
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
class MuDMFeatureCollection(BaseModel):
|
|
206
|
+
bbox: Optional[List[float]] = Field(None, min_length=4, title='Bbox')
|
|
207
|
+
type: Type9 = Field(..., title='Type')
|
|
208
|
+
features: List[Feature] = Field(..., title='Features')
|
|
209
|
+
multiscale: Optional[Multiscale] = None
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class MuDM(BaseModel):
|
|
213
|
+
__root__: Union[
|
|
214
|
+
MuDMFeature,
|
|
215
|
+
MuDMFeatureCollection,
|
|
216
|
+
Point,
|
|
217
|
+
MultiPoint,
|
|
218
|
+
LineString,
|
|
219
|
+
MultiLineString,
|
|
220
|
+
Polygon,
|
|
221
|
+
MultiPolygon,
|
|
222
|
+
GeometryCollection,
|
|
223
|
+
] = Field(...,
|
|
224
|
+
description='The root object of a MuDM file',
|
|
225
|
+
title='MuDM')
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""Shapely → MuDM/GeoJSON geometry conversion (reverse of _geometry.py)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import shapely
|
|
8
|
+
from shapely.geometry import (
|
|
9
|
+
GeometryCollection as ShapelyGeometryCollection,
|
|
10
|
+
LineString as ShapelyLineString,
|
|
11
|
+
MultiLineString as ShapelyMultiLineString,
|
|
12
|
+
MultiPoint as ShapelyMultiPoint,
|
|
13
|
+
MultiPolygon as ShapelyMultiPolygon,
|
|
14
|
+
Point as ShapelyPoint,
|
|
15
|
+
Polygon as ShapelyPolygon,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from geojson_pydantic import (
|
|
19
|
+
GeometryCollection,
|
|
20
|
+
LineString,
|
|
21
|
+
MultiLineString,
|
|
22
|
+
MultiPoint,
|
|
23
|
+
MultiPolygon,
|
|
24
|
+
Point,
|
|
25
|
+
Polygon,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
from mudm.model import (
|
|
29
|
+
TIN,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _pos(coord: tuple) -> tuple:
|
|
34
|
+
"""Convert a Shapely coordinate tuple to a GeoJSON position."""
|
|
35
|
+
return tuple(float(c) for c in coord)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _is_tin(geom: ShapelyMultiPolygon) -> bool:
|
|
39
|
+
"""Check if a MultiPolygon is a TIN (all polygons are 3D triangles)."""
|
|
40
|
+
if not geom.has_z:
|
|
41
|
+
return False
|
|
42
|
+
for poly in geom.geoms:
|
|
43
|
+
if len(poly.interiors) != 0:
|
|
44
|
+
return False
|
|
45
|
+
coords = list(poly.exterior.coords)
|
|
46
|
+
if len(coords) != 4: # closed triangle = 4 coords
|
|
47
|
+
return False
|
|
48
|
+
return True
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _multipolygon_to_tin(geom: ShapelyMultiPolygon) -> TIN:
|
|
52
|
+
"""Convert a triangle-only 3D MultiPolygon to a TIN."""
|
|
53
|
+
faces = []
|
|
54
|
+
for poly in geom.geoms:
|
|
55
|
+
ring = [_pos(c) for c in poly.exterior.coords]
|
|
56
|
+
faces.append([ring])
|
|
57
|
+
return TIN(type="TIN", coordinates=faces)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _ring_coords(ring) -> list[tuple]:
|
|
61
|
+
"""Extract ring coordinates from a Shapely LinearRing or coord sequence."""
|
|
62
|
+
return [_pos(c) for c in ring.coords]
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def shapely_to_microjson(geom: Any) -> Any:
|
|
66
|
+
"""Convert a Shapely geometry to a GeoJSON-pydantic model.
|
|
67
|
+
|
|
68
|
+
Returns None for None input.
|
|
69
|
+
"""
|
|
70
|
+
if geom is None:
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
if isinstance(geom, ShapelyPoint):
|
|
74
|
+
return Point(type="Point", coordinates=_pos(geom.coords[0]))
|
|
75
|
+
|
|
76
|
+
if isinstance(geom, ShapelyMultiPoint):
|
|
77
|
+
return MultiPoint(
|
|
78
|
+
type="MultiPoint",
|
|
79
|
+
coordinates=[_pos(p.coords[0]) for p in geom.geoms],
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
if isinstance(geom, ShapelyLineString):
|
|
83
|
+
return LineString(
|
|
84
|
+
type="LineString",
|
|
85
|
+
coordinates=[_pos(c) for c in geom.coords],
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
if isinstance(geom, ShapelyMultiLineString):
|
|
89
|
+
return MultiLineString(
|
|
90
|
+
type="MultiLineString",
|
|
91
|
+
coordinates=[
|
|
92
|
+
[_pos(c) for c in line.coords] for line in geom.geoms
|
|
93
|
+
],
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
if isinstance(geom, ShapelyPolygon):
|
|
97
|
+
rings = [_ring_coords(geom.exterior)]
|
|
98
|
+
for interior in geom.interiors:
|
|
99
|
+
rings.append(_ring_coords(interior))
|
|
100
|
+
return Polygon(type="Polygon", coordinates=rings)
|
|
101
|
+
|
|
102
|
+
if isinstance(geom, ShapelyMultiPolygon):
|
|
103
|
+
if _is_tin(geom):
|
|
104
|
+
return _multipolygon_to_tin(geom)
|
|
105
|
+
polys = []
|
|
106
|
+
for poly in geom.geoms:
|
|
107
|
+
rings = [_ring_coords(poly.exterior)]
|
|
108
|
+
for interior in poly.interiors:
|
|
109
|
+
rings.append(_ring_coords(interior))
|
|
110
|
+
polys.append(rings)
|
|
111
|
+
return MultiPolygon(type="MultiPolygon", coordinates=polys)
|
|
112
|
+
|
|
113
|
+
if isinstance(geom, ShapelyGeometryCollection):
|
|
114
|
+
parts = [shapely_to_microjson(g) for g in geom.geoms]
|
|
115
|
+
return GeometryCollection(type="GeometryCollection", geometries=parts)
|
|
116
|
+
|
|
117
|
+
raise TypeError(f"Unsupported Shapely geometry type: {type(geom)}")
|
|
118
|
+
|
|
119
|
+
|