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.
Files changed (180) hide show
  1. mudm_tools-0.5.0/LICENSE +21 -0
  2. mudm_tools-0.5.0/PKG-INFO +75 -0
  3. mudm_tools-0.5.0/README.md +42 -0
  4. mudm_tools-0.5.0/pyproject.toml +62 -0
  5. mudm_tools-0.5.0/setup.cfg +4 -0
  6. mudm_tools-0.5.0/src/mudm_tools/__init__.py +29 -0
  7. mudm_tools-0.5.0/src/mudm_tools/_legacy/automodel.py +44 -0
  8. mudm_tools-0.5.0/src/mudm_tools/_legacy/roundtrip.py +225 -0
  9. mudm_tools-0.5.0/src/mudm_tools/arrow/__init__.py +5 -0
  10. mudm_tools-0.5.0/src/mudm_tools/arrow/_from_geometry.py +119 -0
  11. mudm_tools-0.5.0/src/mudm_tools/arrow/_geometry.py +145 -0
  12. mudm_tools-0.5.0/src/mudm_tools/arrow/_table_builder.py +244 -0
  13. mudm_tools-0.5.0/src/mudm_tools/arrow/models.py +15 -0
  14. mudm_tools-0.5.0/src/mudm_tools/arrow/reader.py +131 -0
  15. mudm_tools-0.5.0/src/mudm_tools/arrow/writer.py +57 -0
  16. mudm_tools-0.5.0/src/mudm_tools/converters/__init__.py +64 -0
  17. mudm_tools-0.5.0/src/mudm_tools/converters/cli.py +85 -0
  18. mudm_tools-0.5.0/src/mudm_tools/converters/geojson.py +127 -0
  19. mudm_tools-0.5.0/src/mudm_tools/converters/obj.py +125 -0
  20. mudm_tools-0.5.0/src/mudm_tools/converters/xenium.py +353 -0
  21. mudm_tools-0.5.0/src/mudm_tools/examples/__init__.py +0 -0
  22. mudm_tools-0.5.0/src/mudm_tools/examples/annotate_by_type.py +371 -0
  23. mudm_tools-0.5.0/src/mudm_tools/examples/annotate_neuron.py +407 -0
  24. mudm_tools-0.5.0/src/mudm_tools/examples/df_to_microjson.py +83 -0
  25. mudm_tools-0.5.0/src/mudm_tools/examples/load_validate.py +19 -0
  26. mudm_tools-0.5.0/src/mudm_tools/examples/neuroglancer_export.py +224 -0
  27. mudm_tools-0.5.0/src/mudm_tools/examples/neuroglancer_serve.py +158 -0
  28. mudm_tools-0.5.0/src/mudm_tools/examples/readtiles.py +29 -0
  29. mudm_tools-0.5.0/src/mudm_tools/examples/swc_to_neuroglancer.py +172 -0
  30. mudm_tools-0.5.0/src/mudm_tools/examples/tiling.py +125 -0
  31. mudm_tools-0.5.0/src/mudm_tools/examples/tiling_rust.py +193 -0
  32. mudm_tools-0.5.0/src/mudm_tools/fileutils.py +16 -0
  33. mudm_tools-0.5.0/src/mudm_tools/geojson_model.py +453 -0
  34. mudm_tools-0.5.0/src/mudm_tools/gltf/__init__.py +4 -0
  35. mudm_tools-0.5.0/src/mudm_tools/gltf/_buffers.py +124 -0
  36. mudm_tools-0.5.0/src/mudm_tools/gltf/_draco.py +197 -0
  37. mudm_tools-0.5.0/src/mudm_tools/gltf/gltf_assembler.py +568 -0
  38. mudm_tools-0.5.0/src/mudm_tools/gltf/mesh_builder.py +274 -0
  39. mudm_tools-0.5.0/src/mudm_tools/gltf/models.py +47 -0
  40. mudm_tools-0.5.0/src/mudm_tools/gltf/triangulator.py +99 -0
  41. mudm_tools-0.5.0/src/mudm_tools/gltf/writer.py +76 -0
  42. mudm_tools-0.5.0/src/mudm_tools/mudm2vt/__init__.py +5 -0
  43. mudm_tools-0.5.0/src/mudm_tools/mudm2vt/clip.py +196 -0
  44. mudm_tools-0.5.0/src/mudm_tools/mudm2vt/convert.py +206 -0
  45. mudm_tools-0.5.0/src/mudm_tools/mudm2vt/feature.py +47 -0
  46. mudm_tools-0.5.0/src/mudm_tools/mudm2vt/mudm2vt.py +490 -0
  47. mudm_tools-0.5.0/src/mudm_tools/mudm2vt/simplify.py +78 -0
  48. mudm_tools-0.5.0/src/mudm_tools/mudm2vt/tile.py +125 -0
  49. mudm_tools-0.5.0/src/mudm_tools/mudm2vt/transform.py +42 -0
  50. mudm_tools-0.5.0/src/mudm_tools/mudm2vt/utils.py +53 -0
  51. mudm_tools-0.5.0/src/mudm_tools/mudm2vt/vt2geojson.py +57 -0
  52. mudm_tools-0.5.0/src/mudm_tools/mudm2vt/wrap.py +74 -0
  53. mudm_tools-0.5.0/src/mudm_tools/neuroglancer/__init__.py +32 -0
  54. mudm_tools-0.5.0/src/mudm_tools/neuroglancer/_binary.py +38 -0
  55. mudm_tools-0.5.0/src/mudm_tools/neuroglancer/annotation_writer.py +196 -0
  56. mudm_tools-0.5.0/src/mudm_tools/neuroglancer/mesh_models.py +27 -0
  57. mudm_tools-0.5.0/src/mudm_tools/neuroglancer/mesh_writer.py +218 -0
  58. mudm_tools-0.5.0/src/mudm_tools/neuroglancer/models.py +209 -0
  59. mudm_tools-0.5.0/src/mudm_tools/neuroglancer/properties_writer.py +107 -0
  60. mudm_tools-0.5.0/src/mudm_tools/neuroglancer/skeleton_writer.py +194 -0
  61. mudm_tools-0.5.0/src/mudm_tools/neuroglancer/state.py +126 -0
  62. mudm_tools-0.5.0/src/mudm_tools/neuroglancer/writer.py +107 -0
  63. mudm_tools-0.5.0/src/mudm_tools/polygen.py +167 -0
  64. mudm_tools-0.5.0/src/mudm_tools/polygen3d.py +194 -0
  65. mudm_tools-0.5.0/src/mudm_tools/serve.py +235 -0
  66. mudm_tools-0.5.0/src/mudm_tools/swc.py +593 -0
  67. mudm_tools-0.5.0/src/mudm_tools/tilehandler.py +29 -0
  68. mudm_tools-0.5.0/src/mudm_tools/tilereader.py +154 -0
  69. mudm_tools-0.5.0/src/mudm_tools/tilewriter.py +290 -0
  70. mudm_tools-0.5.0/src/mudm_tools/tiling2d/__init__.py +29 -0
  71. mudm_tools-0.5.0/src/mudm_tools/tiling2d/parquet_prime.py +198 -0
  72. mudm_tools-0.5.0/src/mudm_tools/tiling2d/parquet_reader.py +105 -0
  73. mudm_tools-0.5.0/src/mudm_tools/tiling2d/parquet_writer.py +398 -0
  74. mudm_tools-0.5.0/src/mudm_tools/tiling2d/pbf_reader.py +31 -0
  75. mudm_tools-0.5.0/src/mudm_tools/tiling2d/pbf_writer.py +34 -0
  76. mudm_tools-0.5.0/src/mudm_tools/tiling3d/__init__.py +34 -0
  77. mudm_tools-0.5.0/src/mudm_tools/tiling3d/clip3d.py +320 -0
  78. mudm_tools-0.5.0/src/mudm_tools/tiling3d/convert3d.py +305 -0
  79. mudm_tools-0.5.0/src/mudm_tools/tiling3d/encoder3d.py +309 -0
  80. mudm_tools-0.5.0/src/mudm_tools/tiling3d/generator3d.py +455 -0
  81. mudm_tools-0.5.0/src/mudm_tools/tiling3d/gltf_encoder3d.py +181 -0
  82. mudm_tools-0.5.0/src/mudm_tools/tiling3d/morton.py +57 -0
  83. mudm_tools-0.5.0/src/mudm_tools/tiling3d/octree.py +149 -0
  84. mudm_tools-0.5.0/src/mudm_tools/tiling3d/parquet_prime.py +251 -0
  85. mudm_tools-0.5.0/src/mudm_tools/tiling3d/parquet_reader.py +112 -0
  86. mudm_tools-0.5.0/src/mudm_tools/tiling3d/parquet_writer.py +417 -0
  87. mudm_tools-0.5.0/src/mudm_tools/tiling3d/projector3d.py +38 -0
  88. mudm_tools-0.5.0/src/mudm_tools/tiling3d/proto/__init__.py +1 -0
  89. mudm_tools-0.5.0/src/mudm_tools/tiling3d/proto/mudm_3d_tile_pb2.py +53 -0
  90. mudm_tools-0.5.0/src/mudm_tools/tiling3d/reader3d.py +381 -0
  91. mudm_tools-0.5.0/src/mudm_tools/tiling3d/reader_3dtiles.py +94 -0
  92. mudm_tools-0.5.0/src/mudm_tools/tiling3d/simplify3d.py +130 -0
  93. mudm_tools-0.5.0/src/mudm_tools/tiling3d/simplify_mesh.py +137 -0
  94. mudm_tools-0.5.0/src/mudm_tools/tiling3d/tile3d.py +150 -0
  95. mudm_tools-0.5.0/src/mudm_tools/tiling3d/tilejson3d.py +60 -0
  96. mudm_tools-0.5.0/src/mudm_tools/tiling3d/tileset_json.py +171 -0
  97. mudm_tools-0.5.0/src/mudm_tools/utils.py +425 -0
  98. mudm_tools-0.5.0/src/mudm_tools/viewers/__init__.py +0 -0
  99. mudm_tools-0.5.0/src/mudm_tools/viewers/viewer2d/css/style.css +156 -0
  100. mudm_tools-0.5.0/src/mudm_tools/viewers/viewer2d/index.html +42 -0
  101. mudm_tools-0.5.0/src/mudm_tools/viewers/viewer2d/js/InfoPanel.js +57 -0
  102. mudm_tools-0.5.0/src/mudm_tools/viewers/viewer2d/js/LayerPanel.js +201 -0
  103. mudm_tools-0.5.0/src/mudm_tools/viewers/viewer2d/js/Leaflet.VectorGrid.bundled.js +2551 -0
  104. mudm_tools-0.5.0/src/mudm_tools/viewers/viewer2d/js/main.js +259 -0
  105. mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/index.html +518 -0
  106. mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/js/AxisGizmo.js +137 -0
  107. mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/js/BoundingVolume.js +29 -0
  108. mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/js/FeatureSelector.js +458 -0
  109. mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/js/InfoPanel.js +119 -0
  110. mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/js/OverviewPanel.js +826 -0
  111. mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/js/PyramidSelector.js +75 -0
  112. mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/js/ScaleBar.js +70 -0
  113. mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/js/SlicePlanePanel.js +255 -0
  114. mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/js/TileManager.js +799 -0
  115. mudm_tools-0.5.0/src/mudm_tools/viewers/viewer3d/js/main.js +827 -0
  116. mudm_tools-0.5.0/src/mudm_tools/vt2pbf/__init__.py +8 -0
  117. mudm_tools-0.5.0/src/mudm_tools/vt2pbf/config.py +2 -0
  118. mudm_tools-0.5.0/src/mudm_tools/vt2pbf/encoder.py +8 -0
  119. mudm_tools-0.5.0/src/mudm_tools/vt2pbf/exceptions.py +14 -0
  120. mudm_tools-0.5.0/src/mudm_tools/vt2pbf/mapbox/__init__.py +0 -0
  121. mudm_tools-0.5.0/src/mudm_tools/vt2pbf/mapbox/protobuf_3/__init__.py +0 -0
  122. mudm_tools-0.5.0/src/mudm_tools/vt2pbf/mapbox/protobuf_3/vector_tile_pb2.py +323 -0
  123. mudm_tools-0.5.0/src/mudm_tools/vt2pbf/mapbox/protobuf_4/__init__.py +0 -0
  124. mudm_tools-0.5.0/src/mudm_tools/vt2pbf/mapbox/protobuf_4/vector_tile_pb2.py +38 -0
  125. mudm_tools-0.5.0/src/mudm_tools/vt2pbf/mapbox/protobuf_4/vector_tile_pb2.pyi +66 -0
  126. mudm_tools-0.5.0/src/mudm_tools/vt2pbf/service/__init__.py +0 -0
  127. mudm_tools-0.5.0/src/mudm_tools/vt2pbf/service/feature.py +98 -0
  128. mudm_tools-0.5.0/src/mudm_tools/vt2pbf/service/layer.py +34 -0
  129. mudm_tools-0.5.0/src/mudm_tools/vt2pbf/service/tile.py +34 -0
  130. mudm_tools-0.5.0/src/mudm_tools.egg-info/PKG-INFO +75 -0
  131. mudm_tools-0.5.0/src/mudm_tools.egg-info/SOURCES.txt +178 -0
  132. mudm_tools-0.5.0/src/mudm_tools.egg-info/dependency_links.txt +1 -0
  133. mudm_tools-0.5.0/src/mudm_tools.egg-info/entry_points.txt +2 -0
  134. mudm_tools-0.5.0/src/mudm_tools.egg-info/requires.txt +16 -0
  135. mudm_tools-0.5.0/src/mudm_tools.egg-info/top_level.txt +1 -0
  136. mudm_tools-0.5.0/tests/test_3d_models.py +403 -0
  137. mudm_tools-0.5.0/tests/test_arrow.py +390 -0
  138. mudm_tools-0.5.0/tests/test_arrow_integration.py +387 -0
  139. mudm_tools-0.5.0/tests/test_arrow_reader.py +332 -0
  140. mudm_tools-0.5.0/tests/test_benchmark_draco.py +189 -0
  141. mudm_tools-0.5.0/tests/test_geojson_schema.py +58 -0
  142. mudm_tools-0.5.0/tests/test_gltf_assembler.py +584 -0
  143. mudm_tools-0.5.0/tests/test_gltf_buffers.py +99 -0
  144. mudm_tools-0.5.0/tests/test_gltf_draco.py +412 -0
  145. mudm_tools-0.5.0/tests/test_gltf_integration.py +119 -0
  146. mudm_tools-0.5.0/tests/test_gltf_mesh_builder.py +472 -0
  147. mudm_tools-0.5.0/tests/test_gltf_triangulator.py +89 -0
  148. mudm_tools-0.5.0/tests/test_gltf_writer.py +126 -0
  149. mudm_tools-0.5.0/tests/test_layout.py +290 -0
  150. mudm_tools-0.5.0/tests/test_mudm.py +106 -0
  151. mudm_tools-0.5.0/tests/test_neuroglancer_annotations.py +137 -0
  152. mudm_tools-0.5.0/tests/test_neuroglancer_binary.py +90 -0
  153. mudm_tools-0.5.0/tests/test_neuroglancer_mesh.py +446 -0
  154. mudm_tools-0.5.0/tests/test_neuroglancer_models.py +166 -0
  155. mudm_tools-0.5.0/tests/test_neuroglancer_multilod.py +342 -0
  156. mudm_tools-0.5.0/tests/test_neuroglancer_properties.py +90 -0
  157. mudm_tools-0.5.0/tests/test_neuroglancer_skeleton.py +218 -0
  158. mudm_tools-0.5.0/tests/test_neuroglancer_state.py +94 -0
  159. mudm_tools-0.5.0/tests/test_neuroglancer_writer.py +86 -0
  160. mudm_tools-0.5.0/tests/test_obj_to_mudm.py +341 -0
  161. mudm_tools-0.5.0/tests/test_original_schema.py +57 -0
  162. mudm_tools-0.5.0/tests/test_polygen3d.py +113 -0
  163. mudm_tools-0.5.0/tests/test_provenance.py +56 -0
  164. mudm_tools-0.5.0/tests/test_pure_python.py +60 -0
  165. mudm_tools-0.5.0/tests/test_swc.py +276 -0
  166. mudm_tools-0.5.0/tests/test_tilecut.py +105 -0
  167. mudm_tools-0.5.0/tests/test_tiled_geometry.py +236 -0
  168. mudm_tools-0.5.0/tests/test_tilejson.py +57 -0
  169. mudm_tools-0.5.0/tests/test_tiling2d_parquet.py +684 -0
  170. mudm_tools-0.5.0/tests/test_tiling2d_pbf.py +379 -0
  171. mudm_tools-0.5.0/tests/test_tiling3d.py +1360 -0
  172. mudm_tools-0.5.0/tests/test_tiling3d_3dtiles.py +488 -0
  173. mudm_tools-0.5.0/tests/test_tiling3d_feature_pbf3.py +610 -0
  174. mudm_tools-0.5.0/tests/test_tiling3d_multiprocessing.py +316 -0
  175. mudm_tools-0.5.0/tests/test_tiling3d_parquet.py +1209 -0
  176. mudm_tools-0.5.0/tests/test_tiling3d_rust.py +1227 -0
  177. mudm_tools-0.5.0/tests/test_transforms.py +252 -0
  178. mudm_tools-0.5.0/tests/test_utils.py +162 -0
  179. mudm_tools-0.5.0/tests/test_vocabulary.py +249 -0
  180. mudm_tools-0.5.0/tests/test_xenium_to_tiles.py +237 -0
@@ -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,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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,5 @@
1
+ """Arrow / GeoParquet export and import for MuDM."""
2
+
3
+ from .models import ArrowConfig # noqa: F401
4
+ from .reader import from_arrow_table, from_geoparquet # noqa: F401
5
+ from .writer import to_arrow_table, to_geoparquet # noqa: F401
@@ -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
+