multimodars 0.2.3__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. {multimodars-0.2.3 → multimodars-0.3.0}/.github/workflows/CI.yml +1 -1
  2. multimodars-0.3.0/.pre-commit-config.yaml +52 -0
  3. {multimodars-0.2.3 → multimodars-0.3.0}/CHANGELOG.md +55 -0
  4. {multimodars-0.2.3 → multimodars-0.3.0}/Cargo.lock +1 -27
  5. {multimodars-0.2.3 → multimodars-0.3.0}/Cargo.toml +1 -2
  6. {multimodars-0.2.3 → multimodars-0.3.0}/PKG-INFO +7 -2
  7. multimodars-0.3.0/ROADMAP.MD +90 -0
  8. multimodars-0.3.0/docs/api/adjust_ccta.rst +9 -0
  9. {multimodars-0.2.3 → multimodars-0.3.0}/docs/conf.py +4 -10
  10. multimodars-0.3.0/docs/figures/dataprep.jpg +0 -0
  11. multimodars-0.3.0/docs/index.rst +82 -0
  12. multimodars-0.3.0/docs/tutorial_ccta.rst +485 -0
  13. multimodars-0.3.0/docs/tutorial_intravascular.rst +621 -0
  14. {multimodars-0.2.3 → multimodars-0.3.0}/multimodars/__init__.py +50 -2
  15. {multimodars-0.2.3 → multimodars-0.3.0}/multimodars/_converters.py +82 -6
  16. multimodars-0.3.0/multimodars/_processing.py +1426 -0
  17. multimodars-0.3.0/multimodars/ccta/__init__.py +466 -0
  18. multimodars-0.3.0/multimodars/ccta/debug_plots.py +207 -0
  19. multimodars-0.3.0/multimodars/ccta/fixing_functions.py +239 -0
  20. multimodars-0.3.0/multimodars/ccta/labeling.py +561 -0
  21. multimodars-0.3.0/multimodars/ccta/manipulating.py +977 -0
  22. {multimodars-0.2.3 → multimodars-0.3.0}/multimodars/multimodars.pyi +184 -169
  23. {multimodars-0.2.3 → multimodars-0.3.0}/pyproject.toml +9 -2
  24. {multimodars-0.2.3 → multimodars-0.3.0}/src/ccta/adjust_mesh/label_coronary.rs +1 -3
  25. {multimodars-0.2.3 → multimodars-0.3.0}/src/ccta/adjust_mesh/scale_coronary.rs +97 -42
  26. {multimodars-0.2.3 → multimodars-0.3.0}/src/ccta/binding/ccta_py.rs +114 -23
  27. {multimodars-0.2.3 → multimodars-0.3.0}/src/ccta/mod.rs +0 -1
  28. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/binding/align.rs +6 -6
  29. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/binding/classes.rs +85 -10
  30. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/binding/entry.rs +186 -195
  31. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/binding/mod.rs +256 -319
  32. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/centerline_align/align_algorithms.rs +1 -1
  33. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/centerline_align/mod.rs +13 -13
  34. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/io/geometry.rs +91 -26
  35. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/io/input.rs +10 -13
  36. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/io/integrity_check.rs +18 -21
  37. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/io/mod.rs +2 -5
  38. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/io/output.rs +1 -1
  39. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/processing/align_between.rs +16 -11
  40. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/processing/align_within.rs +18 -20
  41. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/processing/postprocessing.rs +3 -9
  42. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/processing/preprocessing.rs +55 -22
  43. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/processing/process_utils.rs +2 -4
  44. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/processing/wall.rs +11 -19
  45. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/to_object/interpolation.rs +8 -8
  46. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/to_object/mod.rs +2 -0
  47. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/to_object/texture.rs +1 -1
  48. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/to_object/write_mtl.rs +5 -5
  49. multimodars-0.2.3/src/intravascular/utils/utils.rs → multimodars-0.3.0/src/intravascular/utils/general_utils.rs +4 -4
  50. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/utils/mod.rs +1 -1
  51. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/utils/test_utils.rs +11 -11
  52. {multimodars-0.2.3 → multimodars-0.3.0}/src/lib.rs +5 -2
  53. multimodars-0.3.0/tests/test_ccta.py +657 -0
  54. multimodars-0.2.3/.pre-commit-config.yaml +0 -38
  55. multimodars-0.2.3/ROADMAP.MD +0 -63
  56. multimodars-0.2.3/docs/api/adjust_ccta.rst +0 -9
  57. multimodars-0.2.3/docs/index.rst +0 -69
  58. multimodars-0.2.3/docs/tutorial_ccta.rst +0 -163
  59. multimodars-0.2.3/docs/tutorial_intravascular.rst +0 -391
  60. multimodars-0.2.3/multimodars/ccta/__init__.py +0 -1
  61. multimodars-0.2.3/multimodars/ccta/adjust_ccta.py +0 -1007
  62. multimodars-0.2.3/src/ccta/io/input.rs +0 -220
  63. multimodars-0.2.3/src/ccta/io/mod.rs +0 -1
  64. {multimodars-0.2.3 → multimodars-0.3.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  65. {multimodars-0.2.3 → multimodars-0.3.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  66. {multimodars-0.2.3 → multimodars-0.3.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  67. {multimodars-0.2.3 → multimodars-0.3.0}/.github/workflows/draft-pdf.yml +0 -0
  68. {multimodars-0.2.3 → multimodars-0.3.0}/.gitignore +0 -0
  69. {multimodars-0.2.3 → multimodars-0.3.0}/.readthedocs.yaml +0 -0
  70. {multimodars-0.2.3 → multimodars-0.3.0}/CONTRIBUTING.md +0 -0
  71. {multimodars-0.2.3 → multimodars-0.3.0}/LICENSE +0 -0
  72. {multimodars-0.2.3 → multimodars-0.3.0}/README.md +0 -0
  73. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/idealized_geometry/branch_diastolic_contours.csv +0 -0
  74. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/idealized_geometry/branch_systolic_contours.csv +0 -0
  75. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/idealized_geometry/calcium_diastolic_contours.csv +0 -0
  76. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/idealized_geometry/calcium_systolic_contours.csv +0 -0
  77. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/idealized_geometry/diastolic_contours.csv +0 -0
  78. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/idealized_geometry/diastolic_reference_points.csv +0 -0
  79. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/idealized_geometry/eem_diastolic_contours.csv +0 -0
  80. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/idealized_geometry/eem_systolic_contours.csv +0 -0
  81. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/idealized_geometry/systolic_contours.csv +0 -0
  82. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/idealized_geometry/systolic_reference_points.csv +0 -0
  83. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/ivus_full/branch_diastolic_contours.csv +0 -0
  84. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/ivus_full/branch_systolic_contours.csv +0 -0
  85. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/ivus_full/calcium_diastolic_contours.csv +0 -0
  86. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/ivus_full/calcium_systolic_contours.csv +0 -0
  87. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/ivus_full/diastolic_contours.csv +0 -0
  88. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/ivus_full/diastolic_reference_points.csv +0 -0
  89. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/ivus_full/eem_diastolic_contours.csv +0 -0
  90. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/ivus_full/eem_systolic_contours.csv +0 -0
  91. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/ivus_full/systolic_contours.csv +0 -0
  92. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/ivus_full/systolic_reference_points.csv +0 -0
  93. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/ivus_rest/combined_sorted_manual.csv +0 -0
  94. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/ivus_rest/diastolic_contours.csv +0 -0
  95. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/ivus_rest/diastolic_reference_points.csv +0 -0
  96. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/ivus_rest/systolic_contours.csv +0 -0
  97. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/ivus_rest/systolic_reference_points.csv +0 -0
  98. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/ivus_stress/combined_sorted_manual.csv +0 -0
  99. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/ivus_stress/diastolic_contours.csv +0 -0
  100. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/ivus_stress/diastolic_reference_points.csv +0 -0
  101. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/ivus_stress/systolic_contours.csv +0 -0
  102. {multimodars-0.2.3 → multimodars-0.3.0}/data/fixtures/ivus_stress/systolic_reference_points.csv +0 -0
  103. {multimodars-0.2.3 → multimodars-0.3.0}/docs/Makefile +0 -0
  104. {multimodars-0.2.3 → multimodars-0.3.0}/docs/_static/.gitkeep +0 -0
  105. {multimodars-0.2.3 → multimodars-0.3.0}/docs/api/centerline.rst +0 -0
  106. {multimodars-0.2.3 → multimodars-0.3.0}/docs/api/classes/PyCenterline.rst +0 -0
  107. {multimodars-0.2.3 → multimodars-0.3.0}/docs/api/classes/PyCenterlinePoint.rst +0 -0
  108. {multimodars-0.2.3 → multimodars-0.3.0}/docs/api/classes/PyContour.rst +0 -0
  109. {multimodars-0.2.3 → multimodars-0.3.0}/docs/api/classes/PyContourPoint.rst +0 -0
  110. {multimodars-0.2.3 → multimodars-0.3.0}/docs/api/classes/PyFrame.rst +0 -0
  111. {multimodars-0.2.3 → multimodars-0.3.0}/docs/api/classes/PyGeometry.rst +0 -0
  112. {multimodars-0.2.3 → multimodars-0.3.0}/docs/api/classes/PyGeometryPair.rst +0 -0
  113. {multimodars-0.2.3 → multimodars-0.3.0}/docs/api/classes/PyInputData.rst +0 -0
  114. {multimodars-0.2.3 → multimodars-0.3.0}/docs/api/classes/PyRecord.rst +0 -0
  115. {multimodars-0.2.3 → multimodars-0.3.0}/docs/api/classes/index.rst +0 -0
  116. {multimodars-0.2.3 → multimodars-0.3.0}/docs/api/converters_and_wrappers.rst +0 -0
  117. {multimodars-0.2.3 → multimodars-0.3.0}/docs/api/core.rst +0 -0
  118. {multimodars-0.2.3 → multimodars-0.3.0}/docs/api/index.rst +0 -0
  119. {multimodars-0.2.3 → multimodars-0.3.0}/docs/api/processing.rst +0 -0
  120. {multimodars-0.2.3 → multimodars-0.3.0}/docs/api/utilities.rst +0 -0
  121. {multimodars-0.2.3 → multimodars-0.3.0}/docs/build.sh +0 -0
  122. {multimodars-0.2.3 → multimodars-0.3.0}/docs/changelog.md +0 -0
  123. {multimodars-0.2.3 → multimodars-0.3.0}/docs/figures/Alignment3p.png +0 -0
  124. {multimodars-0.2.3 → multimodars-0.3.0}/docs/figures/animation_stress_induced_systolic_deformation.gif +0 -0
  125. {multimodars-0.2.3 → multimodars-0.3.0}/docs/figures/anomalous_labeling.jpg +0 -0
  126. {multimodars-0.2.3 → multimodars-0.3.0}/docs/figures/initial_labeling.jpg +0 -0
  127. {multimodars-0.2.3 → multimodars-0.3.0}/docs/figures/scaling.jpg +0 -0
  128. {multimodars-0.2.3 → multimodars-0.3.0}/docs/installation.rst +0 -0
  129. {multimodars-0.2.3 → multimodars-0.3.0}/docs/make.bat +0 -0
  130. {multimodars-0.2.3 → multimodars-0.3.0}/media/coronary_artery_disease.jpg +0 -0
  131. {multimodars-0.2.3 → multimodars-0.3.0}/media/dynamic_lumen_changes.png +0 -0
  132. {multimodars-0.2.3 → multimodars-0.3.0}/media/multimoda-rs.jpg +0 -0
  133. {multimodars-0.2.3 → multimodars-0.3.0}/multimodars/io/__init__.py +0 -0
  134. {multimodars-0.2.3 → multimodars-0.3.0}/multimodars/io/read_geometrical.py +0 -0
  135. {multimodars-0.2.3 → multimodars-0.3.0}/multimodars/io/write_geometries.py +0 -0
  136. {multimodars-0.2.3 → multimodars-0.3.0}/multimodars/py.typed +0 -0
  137. {multimodars-0.2.3 → multimodars-0.3.0}/paper/REVIEWER1.md +0 -0
  138. {multimodars-0.2.3 → multimodars-0.3.0}/paper/bibliography.bib +0 -0
  139. {multimodars-0.2.3 → multimodars-0.3.0}/paper/figures/Figure1.jpg +0 -0
  140. {multimodars-0.2.3 → multimodars-0.3.0}/paper/figures/Figure2.jpg +0 -0
  141. {multimodars-0.2.3 → multimodars-0.3.0}/paper/figures/Figure3.png +0 -0
  142. {multimodars-0.2.3 → multimodars-0.3.0}/paper/figures/Figure4.jpg +0 -0
  143. {multimodars-0.2.3 → multimodars-0.3.0}/paper/paper.md +0 -0
  144. {multimodars-0.2.3 → multimodars-0.3.0}/src/ccta/adjust_mesh/mod.rs +0 -0
  145. {multimodars-0.2.3 → multimodars-0.3.0}/src/ccta/binding/mod.rs +0 -0
  146. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/centerline_align/preprocessing.rs +0 -0
  147. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/mod.rs +0 -0
  148. {multimodars-0.2.3 → multimodars-0.3.0}/src/intravascular/processing/mod.rs +0 -0
  149. {multimodars-0.2.3 → multimodars-0.3.0}/tests/conftest.py +0 -0
  150. {multimodars-0.2.3 → multimodars-0.3.0}/tests/test_converters.py +0 -0
  151. {multimodars-0.2.3 → multimodars-0.3.0}/tests/test_core.py +0 -0
  152. {multimodars-0.2.3 → multimodars-0.3.0}/tests/test_wrappers.py +0 -0
  153. {multimodars-0.2.3 → multimodars-0.3.0}/tests/tests_todo.md +0 -0
@@ -226,7 +226,7 @@ jobs:
226
226
  name: Release
227
227
  runs-on: ubuntu-latest
228
228
  if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }}
229
- needs: [linux, musllinux, windows, macos, sdist]
229
+ needs: [linux, musllinux, windows, macos, sdist, python-compat]
230
230
  permissions:
231
231
  id-token: write
232
232
  contents: write
@@ -0,0 +1,52 @@
1
+ repos:
2
+ - repo: local
3
+ hooks:
4
+ # - id: pytest
5
+ # name: Run pytest
6
+ # entry: pytest
7
+ # language: system
8
+ # types: [python]
9
+ # pass_filenames: false
10
+
11
+ - id: rust-fmt
12
+ name: Rust format
13
+ entry: cargo fmt --all
14
+ language: system
15
+ types: [rust]
16
+ pass_filenames: false
17
+
18
+ - id: rust-clippy
19
+ name: Rust clippy
20
+ entry: cargo clippy --all-targets --all-features -- -D warnings
21
+ language: system
22
+ types: [rust]
23
+ pass_filenames: false
24
+
25
+ # - id: rust-test
26
+ # name: Rust unit tests
27
+ # entry: cargo test --lib # --quiet
28
+ # language: system
29
+ # types: [rust]
30
+ # pass_filenames: false
31
+
32
+ - id: python-black
33
+ name: Black formatting
34
+ entry: black
35
+ language: system
36
+ types: [python]
37
+ require_serial: true
38
+ args: [--quiet, --target-version, py312]
39
+
40
+ - id: python-ruff
41
+ name: Ruff linting
42
+ entry: ruff check
43
+ language: system
44
+ types: [python]
45
+ args: [--fix]
46
+
47
+ - id: python-mypy
48
+ name: Mypy type checking
49
+ entry: mypy multimodars --ignore-missing-imports
50
+ language: system
51
+ types: [python]
52
+ pass_filenames: false
@@ -3,6 +3,61 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  This project adheres to [Semantic Versioning](https://semver.org/).
5
5
 
6
+ ## [0.3.0] - 2026-04-30
7
+
8
+ ### Added
9
+ - `stitch_ccta_to_intravascular()`: fuses an aligned intravascular `PyGeometry` with a CCTA
10
+ trimesh by triangulating a patch between the open boundary ring of the CCTA mesh and the
11
+ proximal/distal contour of the intravascular geometry. Supports two boundary-ring alignment
12
+ modes (`"nearest_iv"` and `"highest_z"`) for proximal and distal ends independently.
13
+ - `fix_and_remesh_stitched_mesh()`: repairs the stitched surface (non-manifold edges/vertices,
14
+ open holes) and applies isotropic remeshing via `pymeshlab`. Requires the optional
15
+ `multimodars[meshlab]` extra.
16
+ - `manual_hole_fill()`: flat-fills remaining open holes in a trimesh after automatic repair.
17
+ - `remove_labeled_points_from_mesh()`: deletes one or more labeled vertex regions from the mesh, remaps faces, and returns the open boundary ring as `"boundary_points"` for downstream stitching.
18
+ - `keep_labeled_points_from_mesh()`: retains only the vertices of a specified labeled region,
19
+ discarding all others.
20
+ - `sync_results_to_mesh()`: refreshes all coordinate lists in the results dictionary after
21
+ `scale_region_centerline_morphing()` moves vertices, keeping labels consistent with the
22
+ updated mesh.
23
+ - `find_aortic_wall_scaling()`: computes the optimal radial scaling factor for the aortic wall
24
+ region by minimising the distance to the first intravascular frame whose lumen elliptic ratio
25
+ drops below 1.3 (transition from intramural to free-segment lumen).
26
+ - `export_section_stl()`: exports the full mesh or a labeled sub-region (`"all"`, `"aorta"`,
27
+ `"rca"`, `"lca"`) as an STL file.
28
+ - `plot_results_key()`: opens an interactive 3-D trimesh scene visualising selected labeled
29
+ regions with colour coding (yellow = aorta, blue = RCA, green = LCA, red = removed/intramural,
30
+ cyan = proximal, magenta = distal, orange = anomalous).
31
+ - Tests for all new CCTA functions.
32
+ - `mypy` added to pre-commit hooks for static type checking.
33
+
34
+ ### Changed
35
+ - Rust-side CCTA STL reader (`src/ccta/io/input.rs`) removed; mesh I/O is now handled
36
+ entirely via Python `trimesh`, eliminating the `stl_io` dependency.
37
+ - `pymeshlab` and `pyglet` are now optional dependencies; the core package installs without
38
+ them. Install extras with `pip install 'multimodars[meshlab]'`.
39
+ - Debug-plot helpers moved to a dedicated `ccta.debug_plots` module.
40
+ - CCTA Python module refactored into focused sub-modules (`labeling`, `manipulating`,
41
+ `fixing_functions`, `debug_plots`).
42
+ - Parameter order updated in several CCTA API calls for consistency.
43
+ - `diastole` argument removed from functions where it was not used.
44
+ - Labeling of aorta boundary points improved to avoid incorrect assignment at mesh edges.
45
+ - Type stubs updated and extended to cover all new public functions.
46
+ - Clippy lints applied across the Rust codebase (non-breaking).
47
+
48
+ ### Fixed
49
+ - 3-D area and elliptic ratio calculation corrected for non-planar contours.
50
+ - Mesh face normals corrected after stitching to ensure consistent outward orientation.
51
+
52
+ ### Documentation
53
+ - CCTA tutorial completely rewritten to cover the full stitching workflow:
54
+ `remove_labeled_points_from_mesh` → `stitch_ccta_to_intravascular` →
55
+ `fix_and_remesh_stitched_mesh` → Taubin smoothing → `export_section_stl` → re-labeling.
56
+ - Intravascular tutorial reviewed and completed: section numbering corrected (1–7),
57
+ CSV-vs-numpy workflow note added, column descriptions with units added to data tables,
58
+ Sphinx cross-references added throughout, `translate()` tuple-argument bug fixed.
59
+
60
+
6
61
  ## [0.2.3] - 2026-03-06
7
62
 
8
63
  ### Added
@@ -161,12 +161,6 @@ version = "1.23.1"
161
161
  source = "registry+https://github.com/rust-lang/crates.io-index"
162
162
  checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422"
163
163
 
164
- [[package]]
165
- name = "byteorder"
166
- version = "1.5.0"
167
- source = "registry+https://github.com/rust-lang/crates.io-index"
168
- checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
169
-
170
164
  [[package]]
171
165
  name = "byteorder-lite"
172
166
  version = "0.1.0"
@@ -390,15 +384,6 @@ dependencies = [
390
384
  "miniz_oxide",
391
385
  ]
392
386
 
393
- [[package]]
394
- name = "float-cmp"
395
- version = "0.10.0"
396
- source = "registry+https://github.com/rust-lang/crates.io-index"
397
- checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8"
398
- dependencies = [
399
- "num-traits",
400
- ]
401
-
402
387
  [[package]]
403
388
  name = "getrandom"
404
389
  version = "0.3.4"
@@ -726,7 +711,7 @@ dependencies = [
726
711
 
727
712
  [[package]]
728
713
  name = "multimodars"
729
- version = "0.2.3"
714
+ version = "0.3.0"
730
715
  dependencies = [
731
716
  "anyhow",
732
717
  "approx",
@@ -737,7 +722,6 @@ dependencies = [
737
722
  "pyo3",
738
723
  "rayon",
739
724
  "serde",
740
- "stl_io",
741
725
  "toml",
742
726
  ]
743
727
 
@@ -1255,16 +1239,6 @@ version = "1.2.1"
1255
1239
  source = "registry+https://github.com/rust-lang/crates.io-index"
1256
1240
  checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
1257
1241
 
1258
- [[package]]
1259
- name = "stl_io"
1260
- version = "0.10.0"
1261
- source = "registry+https://github.com/rust-lang/crates.io-index"
1262
- checksum = "da63e75b86345156b191c021b3ce2a13b973941ecdb8c70d6f00cbbfe0076ed7"
1263
- dependencies = [
1264
- "byteorder",
1265
- "float-cmp",
1266
- ]
1267
-
1268
1242
  [[package]]
1269
1243
  name = "syn"
1270
1244
  version = "2.0.104"
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "multimodars"
3
- version = "0.2.3"
3
+ version = "0.3.0"
4
4
  edition = "2021"
5
5
  license = "MIT"
6
6
  readme = "README.md"
@@ -20,4 +20,3 @@ rayon = "1.7.1"
20
20
  crossbeam = "0.8.4"
21
21
  anyhow = "1.0.100"
22
22
  approx = "0.5"
23
- stl_io = "0.10.0"
@@ -1,25 +1,30 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: multimodars
3
- Version: 0.2.3
3
+ Version: 0.3.0
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
7
7
  Classifier: License :: OSI Approved :: MIT License
8
8
  Requires-Dist: numpy>=2.0.0,<3.0.0
9
9
  Requires-Dist: trimesh>=4.8.0
10
- Requires-Dist: pyglet<2
10
+ Requires-Dist: scipy>=1.15.0
11
11
  Requires-Dist: sphinx>=8.0,<9.0 ; extra == 'docs'
12
12
  Requires-Dist: sphinx-rtd-theme ; extra == 'docs'
13
13
  Requires-Dist: sphinx-autodoc-typehints ; extra == 'docs'
14
14
  Requires-Dist: myst-parser ; extra == 'docs'
15
15
  Requires-Dist: maturin>=1.7,<2.0 ; extra == 'docs'
16
16
  Requires-Dist: furo ; extra == 'docs'
17
+ Requires-Dist: pymeshlab>=2023.12 ; extra == 'meshlab'
17
18
  Requires-Dist: pytest>=9.0.2 ; extra == 'test'
18
19
  Requires-Dist: pytest-cov ; extra == 'test'
19
20
  Requires-Dist: ruff ; extra == 'test'
20
21
  Requires-Dist: black ; extra == 'test'
22
+ Requires-Dist: mypy ; extra == 'test'
23
+ Requires-Dist: pyglet<2 ; extra == 'viz'
21
24
  Provides-Extra: docs
25
+ Provides-Extra: meshlab
22
26
  Provides-Extra: test
27
+ Provides-Extra: viz
23
28
  License-File: LICENSE
24
29
  Summary: A Rust-powered cardiac multi-image modality fusion package
25
30
  Author: Anselm W. Stark
@@ -0,0 +1,90 @@
1
+ # Python package that has one purpose: Combining any intravascular image modality with CCTA meshes.
2
+
3
+ # Centerline alignment module
4
+ (- [] Create Centerline directly from mesh) (v1.0.0)
5
+
6
+ # Mesh combination (v0.3.0)
7
+ - [] Write a more stable function to find intramural points on aorta (for now works with excluded RCA points)
8
+ - [] fix centerline resampling
9
+ - [] Create an aortic and coronary wall with a consistent connection
10
+
11
+ # CCTA clinical assessment (v0.4.0)
12
+ - [] automatically find the required reference points for alignment
13
+ - [] automatically assess lumen area, minor-, major axis, mla, intramural length etc. from the CCTA mesh.
14
+ - [] return hausdorff distances per point between aligned ivus mesh and ccta mesh.
15
+ - [] function to automatically assign wall thickness to ccta and combined ivus/ccta mesh
16
+ - [] helper function to automatically export only certain points on mesh (e.g. RCA or LCA)
17
+ - [] function to combine anomalous section only with the distal part
18
+
19
+ # Miscellaneous
20
+ - [] Improve print statements in the whole package
21
+
22
+ # Prepublish checklist (JOSS review feedback — open until resolved):
23
+
24
+ ## Data & archival
25
+ - [] Upload example data (`examples.zip`) to a persistent archive (Zenodo or similar) with a DOI.
26
+ Upload the source code snapshot there as well, either in the same record or a separate one linked from the paper.
27
+ Leave open until the DOI is minted and cited in the paper/README.
28
+ - [] Clarify whether the sample data (repo + examples.zip) is real human data or synthetic data.
29
+ If real, add a statement on ethical approval / data-use conformity per JOSS policy
30
+ (https://joss.readthedocs.io/en/latest/policies.html#joss-policies).
31
+
32
+ ## Dependencies / packaging
33
+ - [] Add `scipy` as an explicit runtime dependency in `pyproject.toml` (required by `mm.label_geometry()`).
34
+ - [] Convert `optional-dependencies` groups that are not user-facing extras (docs, test, dev)
35
+ to PEP 735 `dependency-groups` so they are not shipped with the package on PyPI.
36
+ Move notebook runtime deps (`trimesh`, `plotly`, `scipy`, `nbformat`, `ipykernel`) into a
37
+ `[dependency-groups.dev]` group so `uv` installs them automatically during development.
38
+
39
+ ## Examples / notebooks
40
+ - [] Include the `examples/` folder (with data) directly in the repository so users can clone
41
+ and run without a separate download, and so CI can execute the notebooks as tests.
42
+ - [] Fix `ivus_to_centerline.ipynb`: create `output/` and `output/unprocessed/` directories
43
+ on-the-fly with `os.makedirs(..., exist_ok=True)` so the notebook does not error on a fresh clone.
44
+ - [] Add a unit test that runs the example notebook end-to-end (e.g. using `nbmake` or `pytest-notebook`)
45
+ so regressions are caught automatically.
46
+
47
+ ## Performance claim
48
+ - [] Provide reproducible code + sample data for the performance claim in the paper (lines 102-104):
49
+ "Empirical performance on a 16-core CPU: an OCT pullback with 280 frames and a rotation search range
50
+ of ±3° (final accuracy 0.01°) saw alignment time reduced from 150 s to 18 s with the optimized
51
+ multiscale search."
52
+ Add a benchmark script or notebook to `examples/` so the claim can be independently reproduced.
53
+
54
+ ## Documentation — Tutorial Intravascular
55
+ - [x] Section "1. Workflow csv files": add column descriptions with units after the data table,
56
+ and add header names to the first data table — done (frame_index, x (mm), y (mm), z (mm)
57
+ headers present; "Column descriptions:" bullet block added).
58
+ - [x] Section "1. Workflow csv files": add `:func:` / `:class:` Sphinx cross-references —
59
+ done throughout section 2 and the rest of the tutorial.
60
+ - [x] Section "3. Workflow numpy arrays": explain how CSV and numpy workflows differ — done via
61
+ `.. note:: **CSV vs. numpy workflow** …` block at the top of section 3.
62
+ - [x] Fix section numbering — done: sections run 1–7 with no duplicates.
63
+ - [x] Section "6. Utility functions / to_array": clarify Returns block — done with prose
64
+ descriptions and typed bullet list per return type; `:func:` cross-reference present.
65
+ - [x] Fix `translate((0.0, 1.0, 2.0))` tuple bug — done: all three call-sites use positional
66
+ args `translate(0.0, 1.0, 2.0)`.
67
+ - [] Fix remaining undefined variables in tutorial snippets (reviewer: "cannot be run due to
68
+ undefined variables"):
69
+ - `stress` (section 6, to_array snippet, line ~392) — only defined if the user followed the
70
+ `from_file_full` path; breaks on the `singlepair` path. Change to `rest` or add a note.
71
+ - `cl_resampled` (section 6, to_array snippet, line ~394) — variable returned in section 4
72
+ is named `resampled_cl`; rename to match.
73
+ - `results["rca_points"]` (section 4, align_combined code block, line ~358) — `results` is
74
+ never defined in this tutorial. Add an inline comment: `# from mm.label_geometry() — see
75
+ CCTA tutorial` and a placeholder assignment above the block.
76
+ - `geometry` (section 5, to_obj code block, line ~374) — undefined at that point; replace
77
+ with `aligned` (returned from align_combined in section 4).
78
+
79
+ ## Documentation — general
80
+ - [] Consider converting tutorials to Jupyter notebooks rendered via `nbsphinx` or `myst-nb`
81
+ so outputs are visible, results are verifiable, and documentation build failures reveal
82
+ broken code early. (Non-blocking suggestion from reviewer crnh / richardkoehler.)
83
+ - [] Cite the case-report paper in the Research impact statement (it is cited elsewhere but
84
+ not in that section).
85
+
86
+ ## CI / quality
87
+ - [] Integrate coverage measurement (`pytest-cov`) and upload reports to Coveralls or Codecov.
88
+ - [] Add a coverage status badge to the README.
89
+ - [] Add `mypy` to pre-commit hooks.
90
+ - [] Add `scipy` to pre-commit / lint hooks.
@@ -0,0 +1,9 @@
1
+ Adjust CCTA
2
+ ===========
3
+
4
+ .. autofunction:: multimodars.ccta.labeling.label_geometry
5
+ .. autofunction:: multimodars.ccta.labeling.label_anomalous_region
6
+ .. autofunction:: multimodars.ccta.manipulating.scale_region_centerline_morphing
7
+ .. autofunction:: multimodars.ccta.manipulating.find_distal_and_proximal_scaling
8
+ .. autofunction:: multimodars.ccta.manipulating.find_aorta_scaling
9
+ .. autofunction:: multimodars.ccta.debug_plots.compare_centerline_scaling
@@ -3,12 +3,13 @@ import sys
3
3
  import re
4
4
 
5
5
  try:
6
- import multimodars
6
+ import multimodars # noqa: F401
7
7
  except ImportError:
8
8
  from unittest.mock import MagicMock
9
9
 
10
10
  sys.modules["multimodars"] = MagicMock()
11
11
 
12
+
12
13
  # Get the version from Cargo.toml
13
14
  def get_version():
14
15
  with open(os.path.join("..", "Cargo.toml"), "r") as f:
@@ -19,6 +20,7 @@ def get_version():
19
20
  return match.group(1)
20
21
  return "0.0.0"
21
22
 
23
+
22
24
  # Add project to path
23
25
  sys.path.insert(0, os.path.abspath(".."))
24
26
  sys.path.insert(0, os.path.abspath("../src"))
@@ -62,12 +64,4 @@ autodoc_default_options = {
62
64
  "special-members": "__init__",
63
65
  }
64
66
  autodoc_typehints = "description"
65
-
66
- # Workaround for PyO3 modules
67
- try:
68
- import multimodars
69
- except ImportError:
70
- from unittest.mock import MagicMock
71
-
72
- sys.modules["multimodars"] = MagicMock()
73
- print("Warning: multimodars module not found, using mocks for documentation")
67
+ numfig = True
@@ -0,0 +1,82 @@
1
+ .. multimodars documentation master file, created by
2
+ sphinx-quickstart on Wed Jul 23 22:38:42 2025.
3
+ You can adapt this file completely to your liking, but it should at least
4
+ contain the root `toctree` directive.
5
+
6
+
7
+ Welcome to multimodars documentation!
8
+ =====================================
9
+
10
+ *multimodars: A Rust-powered cardiac multi-image modality fusion package.*
11
+
12
+ .. warning::
13
+
14
+ Not intended for clinical use.
15
+
16
+ This package aims to combine different cardiac imaging modalities to combined 3D models. A particular focus is on the fusion of intravascular
17
+ imaging (either intravascular ultrasound [IVUS] or optical coherence tomography [OCT]) with a 3D geometry created from computed coronary tomography angiography (CCTA).
18
+
19
+ The main functionalities are organized into two major categories:
20
+
21
+ 1. **Intravascular Alignment**: This category addresses the co-registration of intravascular frames through translation and rotation to minimize the distance between adjacent frames.
22
+ This approach is particularly useful for correcting misalignments introduced by cardiac motion during intravascular image acquisition. It further encompasses the alignment of
23
+ separate intravascular pullbacks (e.g., acquired under rest and stress conditions) as well as the co-registration of systolic and diastolic frames within the same pullback.
24
+
25
+ 2. **CCTA-Intravascular Fusion**: This category covers the fusion of intravascular frames with a three-dimensional geometry reconstructed from coronary computed tomography angiography (CCTA).
26
+ This is particularly valuable for generating high-resolution three-dimensional models of coronary arteries by combining the high spatial resolution of intravascular imaging with the
27
+ three-dimensional geometry provided by CCTA. Functionalities in this category include the anatomical labeling of CCTA geometries based on centerlines, the registration of intravascular
28
+ frames onto a centerline, and the subsequent fusion of the resulting geometry with the CCTA reconstruction.
29
+
30
+ Intravascular image data are accepted either as CSV files following the output format of
31
+ `AIVUS <https://github.com/AI-in-Cardiovascular-Medicine/AIVUS-CAA>`_, an open-source tool for automated intravascular ultrasound analysis,
32
+ or directly as NumPy arrays, affording greater flexibility for integration with custom pipelines.
33
+
34
+ Table of Contents
35
+ -----------------
36
+
37
+ .. toctree::
38
+ :hidden:
39
+
40
+ Home <self>
41
+
42
+ .. toctree::
43
+ :maxdepth: 2
44
+
45
+ installation
46
+ Intravascular Alignment Tutorial <tutorial_intravascular>
47
+ CCTA Intravascular Fusion Tutorial <tutorial_ccta>
48
+ api/index
49
+ changelog
50
+
51
+ License
52
+ -------
53
+
54
+ This package is covered by the open source `MIT License <https://github.com/yungselm/multimoda-rs/blob/main/LICENSE>`_.
55
+
56
+ Developers
57
+ ----------
58
+
59
+ - `Anselm Stark <https://github.com/yugnselm>`_:sup:`1,2`
60
+ - `Marc Ilic <https://github.com/cicram>`_:sup:`1,2`
61
+ - `Ali Mokthari <https://github.com/alimokh91>`_:sup:`1,2`
62
+ - `Pooya Mohammadi Kazaj <https://github.com/pooya-mohammadi>`_:sup:`1,2`
63
+ - `Isaac Shiri <https://github.com/Isaacshiri>`_:sup:`1`
64
+
65
+ :sup:`1`\ Department of Cardiology, Inselspital, Bern University Hospital, University of Bern, Switzerland
66
+ :sup:`2`\ Graduate School for Cellular and Biomedical Sciences, University of Bern, Bern, Switzerland
67
+
68
+ Contributing
69
+ ------------
70
+ We'd welcome your contributions to multimodars. Please read the
71
+ `contributing guidelines <https://github.com/yungselm/multimoda-rs/blob/main/CONTRIBUTING.md>`_ on how to contribute to ``multimodars``.
72
+
73
+ Changelog
74
+ ---------
75
+
76
+ * :doc:`changelog`
77
+
78
+ Indices and tables
79
+ ==================
80
+
81
+ * :ref:`genindex`
82
+ * :ref:`search`