multimodars 0.2.2__tar.gz → 0.2.3__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 (144) hide show
  1. {multimodars-0.2.2 → multimodars-0.2.3}/.github/ISSUE_TEMPLATE/bug_report.md +8 -15
  2. {multimodars-0.2.2 → multimodars-0.2.3}/.github/PULL_REQUEST_TEMPLATE.md +1 -1
  3. {multimodars-0.2.2 → multimodars-0.2.3}/.github/workflows/CI.yml +21 -0
  4. {multimodars-0.2.2 → multimodars-0.2.3}/CHANGELOG.md +15 -0
  5. multimodars-0.2.3/CONTRIBUTING.md +164 -0
  6. {multimodars-0.2.2 → multimodars-0.2.3}/Cargo.lock +1 -1
  7. {multimodars-0.2.2 → multimodars-0.2.3}/Cargo.toml +1 -1
  8. {multimodars-0.2.2 → multimodars-0.2.3}/PKG-INFO +9 -8
  9. {multimodars-0.2.2 → multimodars-0.2.3}/README.md +7 -6
  10. multimodars-0.2.3/docs/api/adjust_ccta.rst +9 -0
  11. {multimodars-0.2.2 → multimodars-0.2.3}/docs/api/centerline.rst +2 -1
  12. {multimodars-0.2.2 → multimodars-0.2.3}/docs/api/classes/PyContour.rst +1 -1
  13. {multimodars-0.2.2 → multimodars-0.2.3}/docs/api/classes/PyGeometryPair.rst +1 -1
  14. multimodars-0.2.3/docs/api/converters_and_wrappers.rst +9 -0
  15. {multimodars-0.2.2 → multimodars-0.2.3}/docs/api/index.rst +2 -1
  16. {multimodars-0.2.2 → multimodars-0.2.3}/docs/installation.rst +1 -1
  17. {multimodars-0.2.2 → multimodars-0.2.3}/docs/tutorial_ccta.rst +12 -7
  18. {multimodars-0.2.2 → multimodars-0.2.3}/docs/tutorial_intravascular.rst +18 -38
  19. {multimodars-0.2.2 → multimodars-0.2.3}/multimodars/__init__.py +30 -8
  20. {multimodars-0.2.2 → multimodars-0.2.3}/multimodars/_converters.py +144 -89
  21. {multimodars-0.2.2 → multimodars-0.2.3}/multimodars/ccta/adjust_ccta.py +383 -65
  22. {multimodars-0.2.2 → multimodars-0.2.3}/multimodars/io/write_geometries.py +3 -2
  23. multimodars-0.2.3/multimodars/multimodars.pyi +692 -0
  24. multimodars-0.2.3/multimodars/py.typed +0 -0
  25. multimodars-0.2.3/paper/REVIEWER1.md +140 -0
  26. {multimodars-0.2.2 → multimodars-0.2.3}/paper/bibliography.bib +6 -3
  27. multimodars-0.2.3/paper/figures/Figure2.jpg +0 -0
  28. {multimodars-0.2.2 → multimodars-0.2.3}/paper/paper.md +3 -3
  29. {multimodars-0.2.2 → multimodars-0.2.3}/pyproject.toml +1 -1
  30. {multimodars-0.2.2 → multimodars-0.2.3}/src/ccta/binding/ccta_py.rs +145 -80
  31. multimodars-0.2.3/src/intravascular/binding/align.rs +335 -0
  32. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/binding/classes.rs +521 -266
  33. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/binding/mod.rs +570 -269
  34. {multimodars-0.2.2 → multimodars-0.2.3}/tests/test_wrappers.py +3 -5
  35. multimodars-0.2.2/CONTRIBUTING.md +0 -61
  36. multimodars-0.2.2/docs/api/converters_and_wrappers.rst +0 -13
  37. multimodars-0.2.2/multimodars/_wrappers.py +0 -725
  38. multimodars-0.2.2/paper/figures/Figure2.jpg +0 -0
  39. multimodars-0.2.2/src/intravascular/binding/align.rs +0 -267
  40. {multimodars-0.2.2 → multimodars-0.2.3}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  41. {multimodars-0.2.2 → multimodars-0.2.3}/.github/workflows/draft-pdf.yml +0 -0
  42. {multimodars-0.2.2 → multimodars-0.2.3}/.gitignore +0 -0
  43. {multimodars-0.2.2 → multimodars-0.2.3}/.pre-commit-config.yaml +0 -0
  44. {multimodars-0.2.2 → multimodars-0.2.3}/.readthedocs.yaml +0 -0
  45. {multimodars-0.2.2 → multimodars-0.2.3}/LICENSE +0 -0
  46. {multimodars-0.2.2 → multimodars-0.2.3}/ROADMAP.MD +0 -0
  47. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/idealized_geometry/branch_diastolic_contours.csv +0 -0
  48. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/idealized_geometry/branch_systolic_contours.csv +0 -0
  49. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/idealized_geometry/calcium_diastolic_contours.csv +0 -0
  50. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/idealized_geometry/calcium_systolic_contours.csv +0 -0
  51. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/idealized_geometry/diastolic_contours.csv +0 -0
  52. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/idealized_geometry/diastolic_reference_points.csv +0 -0
  53. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/idealized_geometry/eem_diastolic_contours.csv +0 -0
  54. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/idealized_geometry/eem_systolic_contours.csv +0 -0
  55. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/idealized_geometry/systolic_contours.csv +0 -0
  56. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/idealized_geometry/systolic_reference_points.csv +0 -0
  57. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/ivus_full/branch_diastolic_contours.csv +0 -0
  58. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/ivus_full/branch_systolic_contours.csv +0 -0
  59. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/ivus_full/calcium_diastolic_contours.csv +0 -0
  60. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/ivus_full/calcium_systolic_contours.csv +0 -0
  61. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/ivus_full/diastolic_contours.csv +0 -0
  62. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/ivus_full/diastolic_reference_points.csv +0 -0
  63. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/ivus_full/eem_diastolic_contours.csv +0 -0
  64. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/ivus_full/eem_systolic_contours.csv +0 -0
  65. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/ivus_full/systolic_contours.csv +0 -0
  66. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/ivus_full/systolic_reference_points.csv +0 -0
  67. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/ivus_rest/combined_sorted_manual.csv +0 -0
  68. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/ivus_rest/diastolic_contours.csv +0 -0
  69. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/ivus_rest/diastolic_reference_points.csv +0 -0
  70. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/ivus_rest/systolic_contours.csv +0 -0
  71. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/ivus_rest/systolic_reference_points.csv +0 -0
  72. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/ivus_stress/combined_sorted_manual.csv +0 -0
  73. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/ivus_stress/diastolic_contours.csv +0 -0
  74. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/ivus_stress/diastolic_reference_points.csv +0 -0
  75. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/ivus_stress/systolic_contours.csv +0 -0
  76. {multimodars-0.2.2 → multimodars-0.2.3}/data/fixtures/ivus_stress/systolic_reference_points.csv +0 -0
  77. {multimodars-0.2.2 → multimodars-0.2.3}/docs/Makefile +0 -0
  78. {multimodars-0.2.2 → multimodars-0.2.3}/docs/_static/.gitkeep +0 -0
  79. {multimodars-0.2.2 → multimodars-0.2.3}/docs/api/classes/PyCenterline.rst +0 -0
  80. {multimodars-0.2.2 → multimodars-0.2.3}/docs/api/classes/PyCenterlinePoint.rst +0 -0
  81. {multimodars-0.2.2 → multimodars-0.2.3}/docs/api/classes/PyContourPoint.rst +0 -0
  82. {multimodars-0.2.2 → multimodars-0.2.3}/docs/api/classes/PyFrame.rst +0 -0
  83. {multimodars-0.2.2 → multimodars-0.2.3}/docs/api/classes/PyGeometry.rst +0 -0
  84. {multimodars-0.2.2 → multimodars-0.2.3}/docs/api/classes/PyInputData.rst +0 -0
  85. {multimodars-0.2.2 → multimodars-0.2.3}/docs/api/classes/PyRecord.rst +0 -0
  86. {multimodars-0.2.2 → multimodars-0.2.3}/docs/api/classes/index.rst +0 -0
  87. {multimodars-0.2.2 → multimodars-0.2.3}/docs/api/core.rst +0 -0
  88. {multimodars-0.2.2 → multimodars-0.2.3}/docs/api/processing.rst +0 -0
  89. {multimodars-0.2.2 → multimodars-0.2.3}/docs/api/utilities.rst +0 -0
  90. {multimodars-0.2.2 → multimodars-0.2.3}/docs/build.sh +0 -0
  91. {multimodars-0.2.2 → multimodars-0.2.3}/docs/changelog.md +0 -0
  92. {multimodars-0.2.2 → multimodars-0.2.3}/docs/conf.py +0 -0
  93. {multimodars-0.2.2 → multimodars-0.2.3}/docs/figures/Alignment3p.png +0 -0
  94. {multimodars-0.2.2 → multimodars-0.2.3}/docs/figures/animation_stress_induced_systolic_deformation.gif +0 -0
  95. {multimodars-0.2.2 → multimodars-0.2.3}/docs/figures/anomalous_labeling.jpg +0 -0
  96. {multimodars-0.2.2 → multimodars-0.2.3}/docs/figures/initial_labeling.jpg +0 -0
  97. {multimodars-0.2.2 → multimodars-0.2.3}/docs/figures/scaling.jpg +0 -0
  98. {multimodars-0.2.2 → multimodars-0.2.3}/docs/index.rst +0 -0
  99. {multimodars-0.2.2 → multimodars-0.2.3}/docs/make.bat +0 -0
  100. {multimodars-0.2.2 → multimodars-0.2.3}/media/coronary_artery_disease.jpg +0 -0
  101. {multimodars-0.2.2 → multimodars-0.2.3}/media/dynamic_lumen_changes.png +0 -0
  102. {multimodars-0.2.2 → multimodars-0.2.3}/media/multimoda-rs.jpg +0 -0
  103. {multimodars-0.2.2 → multimodars-0.2.3}/multimodars/ccta/__init__.py +0 -0
  104. {multimodars-0.2.2 → multimodars-0.2.3}/multimodars/io/__init__.py +0 -0
  105. {multimodars-0.2.2 → multimodars-0.2.3}/multimodars/io/read_geometrical.py +0 -0
  106. {multimodars-0.2.2 → multimodars-0.2.3}/paper/figures/Figure1.jpg +0 -0
  107. {multimodars-0.2.2 → multimodars-0.2.3}/paper/figures/Figure3.png +0 -0
  108. {multimodars-0.2.2 → multimodars-0.2.3}/paper/figures/Figure4.jpg +0 -0
  109. {multimodars-0.2.2 → multimodars-0.2.3}/src/ccta/adjust_mesh/label_coronary.rs +0 -0
  110. {multimodars-0.2.2 → multimodars-0.2.3}/src/ccta/adjust_mesh/mod.rs +0 -0
  111. {multimodars-0.2.2 → multimodars-0.2.3}/src/ccta/adjust_mesh/scale_coronary.rs +0 -0
  112. {multimodars-0.2.2 → multimodars-0.2.3}/src/ccta/binding/mod.rs +0 -0
  113. {multimodars-0.2.2 → multimodars-0.2.3}/src/ccta/io/input.rs +0 -0
  114. {multimodars-0.2.2 → multimodars-0.2.3}/src/ccta/io/mod.rs +0 -0
  115. {multimodars-0.2.2 → multimodars-0.2.3}/src/ccta/mod.rs +0 -0
  116. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/binding/entry.rs +0 -0
  117. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/centerline_align/align_algorithms.rs +0 -0
  118. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/centerline_align/mod.rs +0 -0
  119. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/centerline_align/preprocessing.rs +0 -0
  120. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/io/geometry.rs +0 -0
  121. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/io/input.rs +0 -0
  122. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/io/integrity_check.rs +0 -0
  123. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/io/mod.rs +0 -0
  124. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/io/output.rs +0 -0
  125. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/mod.rs +0 -0
  126. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/processing/align_between.rs +0 -0
  127. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/processing/align_within.rs +0 -0
  128. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/processing/mod.rs +0 -0
  129. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/processing/postprocessing.rs +0 -0
  130. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/processing/preprocessing.rs +0 -0
  131. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/processing/process_utils.rs +0 -0
  132. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/processing/wall.rs +0 -0
  133. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/to_object/interpolation.rs +0 -0
  134. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/to_object/mod.rs +0 -0
  135. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/to_object/texture.rs +0 -0
  136. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/to_object/write_mtl.rs +0 -0
  137. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/utils/mod.rs +0 -0
  138. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/utils/test_utils.rs +0 -0
  139. {multimodars-0.2.2 → multimodars-0.2.3}/src/intravascular/utils/utils.rs +0 -0
  140. {multimodars-0.2.2 → multimodars-0.2.3}/src/lib.rs +0 -0
  141. {multimodars-0.2.2 → multimodars-0.2.3}/tests/conftest.py +0 -0
  142. {multimodars-0.2.2 → multimodars-0.2.3}/tests/test_converters.py +0 -0
  143. {multimodars-0.2.2 → multimodars-0.2.3}/tests/test_core.py +0 -0
  144. {multimodars-0.2.2 → multimodars-0.2.3}/tests/tests_todo.md +0 -0
@@ -12,27 +12,20 @@ A clear and concise description of what the bug is.
12
12
 
13
13
  **To Reproduce**
14
14
  Steps to reproduce the behavior:
15
- 1. Go to '...'
16
- 2. Click on '....'
17
- 3. Scroll down to '....'
18
- 4. See error
15
+ 1. Load data with '...'
16
+ 2. Call function '...'
17
+ 3. See error
19
18
 
20
19
  **Expected behavior**
21
20
  A clear and concise description of what you expected to happen.
22
21
 
22
+ **Environment (please complete the following information):**
23
+ - OS: [e.g. Windows, Linux, macOS]
24
+ - Python version: [e.g. 3.10]
25
+ - Package version: [e.g. 0.1.0]
26
+
23
27
  **Screenshots**
24
28
  If applicable, add screenshots to help explain your problem.
25
29
 
26
- **Desktop (please complete the following information):**
27
- - OS: [e.g. iOS]
28
- - Browser [e.g. chrome, safari]
29
- - Version [e.g. 22]
30
-
31
- **Smartphone (please complete the following information):**
32
- - Device: [e.g. iPhone6]
33
- - OS: [e.g. iOS8.1]
34
- - Browser [e.g. stock browser, safari]
35
- - Version [e.g. 22]
36
-
37
30
  **Additional context**
38
31
  Add any other context about the problem here.
@@ -1,7 +1,7 @@
1
1
  ## Pull Request Checklist
2
2
 
3
3
  - [ ] I have added tests that prove the fix is effective or that the feature works.
4
- - [ ] I ran `pytest` (or `nox` / your CI command) locally and all tests pass.
4
+ - [ ] I ran `pytest` locally and all tests pass.
5
5
  - [ ] I updated `CHANGELOG.md` (or NEWS) and bumped the package version if applicable.
6
6
  - [ ] I added/updated documentation (README, docstrings, or docs).
7
7
  - [ ] This PR is linked to an issue: fixes #<issue-number> (if applicable).
@@ -19,6 +19,27 @@ permissions:
19
19
  contents: read
20
20
 
21
21
  jobs:
22
+ python-compat:
23
+ name: Python ${{ matrix.python-version }} compatibility
24
+ runs-on: ubuntu-latest
25
+ strategy:
26
+ fail-fast: false
27
+ matrix:
28
+ python-version: ['3.10', '3.11', '3.12', '3.13']
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+ - uses: actions/setup-python@v5
32
+ with:
33
+ python-version: ${{ matrix.python-version }}
34
+ - name: Install Rust
35
+ uses: dtolnay/rust-toolchain@stable
36
+ - name: Install Python deps
37
+ run: |
38
+ python -m pip install --upgrade pip
39
+ pip install -e .[test]
40
+ - name: Run Python tests
41
+ run: pytest
42
+
22
43
  linux:
23
44
  runs-on: ${{ matrix.platform.runner }}
24
45
  strategy:
@@ -3,6 +3,21 @@
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.2.3] - 2026-03-06
7
+
8
+ ### Added
9
+ - Type stubs for the Rust-implemented interface (via maturin)
10
+ - `PyFrame.get_frame_at_z`: retrieve a frame by its z position
11
+ - `PyFrame.get_frame_at_index`: retrieve a frame by its index
12
+ - `PyFrame.replace_frame`: replace an existing frame with another
13
+
14
+ ### Changed
15
+ - CI pipeline now tests against Python 3.10 through 3.13
16
+ - Updated documentation to reflect the current interface and Python version requirements
17
+ - Added direct download links to example data in the README and documentation
18
+ - Migrated to modern NumPy-style type annotations throughout the Python codebase
19
+ - All imports are now top-level across all Python modules
20
+
6
21
  ## [0.2.2] - 2026-03-03
7
22
 
8
23
  ### Changed
@@ -0,0 +1,164 @@
1
+ # ✩°。⋆ Contributing to the project ⋆。°✩
2
+
3
+ First off, thank you for considering contributing! **ദ്ദി(˵ •̀ ᴗ - ˵ ) ✧**
4
+ Whether you’re filing a bug, proposing a new feature, improving documentation, or refactoring code, your help makes this project better for you and the whole community.
5
+
6
+ ## Code of Conduct
7
+ This project adheres to the [Contributor Covenant v2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/).
8
+ By participating, you agree to respect everyone in this community. **˗ˏˋ ♡ ˎˊ˗**
9
+
10
+ ## Table of Contents
11
+
12
+ 1. [Getting Started](#getting-started)
13
+ 2. [I Have a Question](#i-have-a-question)
14
+ 3. [Reporting Bugs](#reporting-bugs)
15
+ 4. [Suggesting Enhancements](#suggesting-enhancements)
16
+ 5. [Your First Code Contribution](#your-first-code-contribution)
17
+ 6. [Pull Request Process](#pull-request-process)
18
+ 7. [Coding Style & Tests](#coding-style--tests)
19
+ 8. [Writing Documentation](#writing-documentation)
20
+ 9. [Where to Get Help](#where-to-get-help)
21
+
22
+ ## Getting started
23
+ 1. Fork the repo and clone your fork
24
+ ```bash
25
+ git clone https://github.com/yungselm/multimoda-rs.git
26
+ cd multimoda-rs
27
+ ```
28
+ 2. Create a new branch
29
+ ```bash
30
+ git checkout -b feature/sick-feature
31
+ ```
32
+ 3. install dependencies and run tests
33
+ ```bash
34
+ pip install -e
35
+ pytest
36
+ ```
37
+ ## I have a Question
38
+ Before opening an issue:
39
+ - Read the [Documentation](https://multimoda-rs.readthedocs.io/en/latest/index.html)
40
+ - Search existing [Issues](https://github.com/yungselm/multimoda-rs/issues?q=is%3Aissue)
41
+
42
+ If you still need help:
43
+ - Open a new issue: [Click here](https://github.com/yungselm/multimoda-rs/issues/new/choose)
44
+ - Provide:
45
+ - A clear, descriptive title
46
+ - Context: what you're trying to do, expected vs. actual behaviour
47
+ - Project verion, OS/platform, Python version, and any relevant logs
48
+
49
+ ## Reporting Bugs
50
+ If you find a bug, please help us fix it by opening a [a new issue](https://github.com/yungselm/multimoda-rs/issues/new/choose) and providing:
51
+ - **Title**: A short descriptive title
52
+ - **Steps to reproduce**: Minimal code snippet or sequence to trigger the bug
53
+ - **Expected behaviour** vs **Actual behaviour**
54
+ - **Environment**:
55
+ - `multimoda-rs` version
56
+ - Python version
57
+ - OS and architecture
58
+
59
+ ## Suggesting Enhancements
60
+ Have an idea for a new feature or an improvement to existing behaviour? Open a [feature request issue](https://github.com/yungselm/multimoda-rs/issues/new/choose) and include:
61
+ - **Summary**: A concise description of the enhancement
62
+ - **Motivation**: Why would this be useful? What problem does it solve?
63
+ - **Proposed solution**: How you envision it working (API sketch, example usage, etc.)
64
+ - **Alternatives considered**: Other approaches you've thought about
65
+
66
+ We appreciate well-scoped proposals with clear use cases.
67
+
68
+ ## Your First Code Contribution
69
+ Not sure where to start? Look for issues labelled [`good first issue`](https://github.com/yungselm/multimoda-rs/issues?q=is%3Aissue+label%3A%22good+first+issue%22) or [`help wanted`](https://github.com/yungselm/multimoda-rs/issues?q=is%3Aissue+label%3A%22help+wanted%22).
70
+
71
+ **Setup** (Python + Rust hybrid via [maturin](https://github.com/PyO3/maturin)):
72
+ ```bash
73
+ # 1. Fork the repo on GitHub, then clone your fork
74
+ git clone https://github.com/<your-username>/multimoda-rs.git
75
+ cd multimoda-rs
76
+
77
+ # 2. Create and activate a virtual environment
78
+ python -m venv .venv
79
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
80
+
81
+ # 3. Install the package in development mode (compiles the Rust extension)
82
+ pip install -e ".[dev]"
83
+
84
+ # 4. Install pre-commit hooks
85
+ pre-commit install
86
+
87
+ # 5. Verify everything works
88
+ pytest
89
+ cargo test --lib
90
+ ```
91
+
92
+ ## Pull Request Process
93
+ 1. **Branch** – create a descriptive branch (`feature/my-feature`, `fix/issue-123`).
94
+ 2. **Commit** – write clear, atomic commit messages.
95
+ 3. **Tests** – add or update tests to cover your changes; all existing tests must pass.
96
+ 4. **Docs** – update docstrings and, if applicable, the RST docs under `docs/`.
97
+ 5. **Open the PR** – target the `main` branch. Fill in the PR template with a summary, motivation, and testing notes.
98
+ 6. **Review** – address reviewer comments; once approved and CI is green, a maintainer will merge.
99
+
100
+ PRs that break existing tests or skip the pre-commit hooks will not be merged.
101
+
102
+ ## Coding Style & Tests
103
+
104
+ ### Python
105
+ - **Formatter**: [Black](https://black.readthedocs.io/) (enforced automatically via pre-commit).
106
+ - **Linter**: [Ruff](https://docs.astral.sh/ruff/) with `--fix` (enforced automatically via pre-commit).
107
+ - **Docstrings**: [NumPy docstring style](https://numpydoc.readthedocs.io/en/latest/format.html).
108
+ Example:
109
+ ```python
110
+ def my_function(x: float, y: float) -> float:
111
+ """Short one-line summary.
112
+
113
+ Longer description if needed.
114
+
115
+ Parameters
116
+ ----------
117
+ x : float
118
+ Description of x.
119
+ y : float
120
+ Description of y.
121
+
122
+ Returns
123
+ -------
124
+ float
125
+ Description of the return value.
126
+ """
127
+ ```
128
+ - **Type annotations**: use `from __future__ import annotations` at the top of every module and annotate all public functions and methods.
129
+ - **Tests**: place tests under `tests/` and use [pytest](https://docs.pytest.org/). Run with `pytest`.
130
+
131
+ ### Rust
132
+ - **Formatter**: `cargo fmt --all` (enforced automatically via pre-commit).
133
+ - **Tests**: unit tests live alongside the source (`#[cfg(test)]` blocks). Run with `cargo test --lib`.
134
+
135
+ All checks are wired up via pre-commit and run automatically on every commit. You can also run them manually:
136
+ ```bash
137
+ pre-commit run --all-files
138
+ ```
139
+
140
+ ## Writing Documentation
141
+ Documentation lives under `docs/` and is built with [Sphinx](https://www.sphinx-doc.org/).
142
+
143
+ - Public API is documented via **NumPy-style docstrings** (see above) — Sphinx picks these up automatically.
144
+ - Narrative docs (tutorials, how-tos) go in `.rst` files under `docs/`.
145
+ - Build locally with:
146
+ ```bash
147
+ cd docs
148
+ make html
149
+ # open _build/html/index.html in your browser
150
+ ```
151
+ - Keep prose clear and concise. Include runnable code examples where possible.
152
+
153
+ ## Where to Get Help
154
+ | Channel | When to use |
155
+ |---------|-------------|
156
+ | [Documentation](https://multimoda-rs.readthedocs.io/en/latest/index.html) | First stop, API reference and tutorials |
157
+ | [GitHub Issues](https://github.com/yungselm/multimoda-rs/issues) | Bug reports and feature requests |
158
+ | [GitHub Discussions](https://github.com/yungselm/multimoda-rs/discussions) | Questions, ideas, and general discussion |
159
+
160
+ When asking for help, please include your `multimoda-rs` version, Python version, OS, and a minimal reproducible example.
161
+
162
+
163
+ **ฅ^>⩊<^ ฅ**
164
+ ------------------------------------------------------------------------------------
@@ -726,7 +726,7 @@ dependencies = [
726
726
 
727
727
  [[package]]
728
728
  name = "multimodars"
729
- version = "0.2.2"
729
+ version = "0.2.3"
730
730
  dependencies = [
731
731
  "anyhow",
732
732
  "approx",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "multimodars"
3
- version = "0.2.2"
3
+ version = "0.2.3"
4
4
  edition = "2021"
5
5
  license = "MIT"
6
6
  readme = "README.md"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: multimodars
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -24,7 +24,7 @@ License-File: LICENSE
24
24
  Summary: A Rust-powered cardiac multi-image modality fusion package
25
25
  Author: Anselm W. Stark
26
26
  License-Expression: MIT
27
- Requires-Python: >=3.8
27
+ Requires-Python: >=3.10
28
28
  Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
29
29
  Project-URL: Homepage, https://github.com/yungselm/multimoda-rs
30
30
  Project-URL: Issues, https://github.com/yungselm/multimoda-rs/issues
@@ -71,7 +71,7 @@ Project-URL: Issues, https://github.com/yungselm/multimoda-rs/issues
71
71
  - Centerline Alignment
72
72
  - Align registered geometries onto a vessel centerline using three‑point or manual rotation methods.
73
73
  - Geometry Utilities
74
- - Smooth contours, reorder frames to minimize spatial and index jumps, compute areas and elliptic ratios, find farthest/closest point pairs, and more.
74
+ - Smooth contours, compute areas and elliptic ratios, find farthest/closest point pairs, and more.
75
75
 
76
76
  ## Installation
77
77
 
@@ -106,7 +106,8 @@ maturin develop
106
106
 
107
107
 
108
108
  ## Quickstart Example
109
- Download the example data from the latest release and place it in your working directory. A Jupyter Notebook with step-by-step examples is available at `examples/ivus_to_centerline.ipynb`.
109
+ Download [examples.zip](https://github.com/yungselm/multimoda-rs/releases/latest/download/examples.zip) (SHA256: `d11ebc7607f43ab4571fb51c9ac9178caac57774cf5d97f4f068ace4eb070fee`) from the latest release and place it in your working directory. A Jupyter Notebook with step-by-step examples is available at `examples/ivus_to_centerline.ipynb`.
110
+ Provided you extraced examples to the project root you can just copy paste the below example to ensure proper setup:
110
111
 
111
112
  ```python
112
113
  import multimodars as mm
@@ -114,8 +115,8 @@ import numpy as np
114
115
 
115
116
  # IVUS pullbacks: full alignment of rest/stress & diastole/systole
116
117
  rest, stress, dia, sys, _ = mm.from_file_full(
117
- input_path_a="ivus_rest",
118
- input_path_b="ivus_stress",
118
+ input_path_a="examples/data/ivus_rest",
119
+ input_path_b="examples/data/ivus_stress",
119
120
  label="full",
120
121
  step_rotation_deg=0.1,
121
122
  range_rotation_deg=90,
@@ -128,12 +129,12 @@ rest, stress, dia, sys, _ = mm.from_file_full(
128
129
  output_path_b="output/stress",
129
130
  output_path_c="output/diastole",
130
131
  output_path_d="output/systole",
131
- interpolation_steps=28,
132
+ interpolation_steps=0,
132
133
  contour_types=[mm.PyContourType.Lumen, mm.PyContourType.Catheter, mm.PyContourType.Wall]
133
134
  )
134
135
 
135
136
  # Load raw centerline and align geometry onto it
136
- cl_raw = np.genfromtxt("centerline_raw.csv", delimiter=",")
137
+ cl_raw = np.genfromtxt("examples/data/centerline_raw.csv", delimiter=",")
137
138
  centerline = mm.numpy_to_centerline(cl_raw)
138
139
 
139
140
  aligned_pair, cl_resampled = mm.align_three_point(
@@ -40,7 +40,7 @@
40
40
  - Centerline Alignment
41
41
  - Align registered geometries onto a vessel centerline using three‑point or manual rotation methods.
42
42
  - Geometry Utilities
43
- - Smooth contours, reorder frames to minimize spatial and index jumps, compute areas and elliptic ratios, find farthest/closest point pairs, and more.
43
+ - Smooth contours, compute areas and elliptic ratios, find farthest/closest point pairs, and more.
44
44
 
45
45
  ## Installation
46
46
 
@@ -75,7 +75,8 @@ maturin develop
75
75
 
76
76
 
77
77
  ## Quickstart Example
78
- Download the example data from the latest release and place it in your working directory. A Jupyter Notebook with step-by-step examples is available at `examples/ivus_to_centerline.ipynb`.
78
+ Download [examples.zip](https://github.com/yungselm/multimoda-rs/releases/latest/download/examples.zip) (SHA256: `d11ebc7607f43ab4571fb51c9ac9178caac57774cf5d97f4f068ace4eb070fee`) from the latest release and place it in your working directory. A Jupyter Notebook with step-by-step examples is available at `examples/ivus_to_centerline.ipynb`.
79
+ Provided you extraced examples to the project root you can just copy paste the below example to ensure proper setup:
79
80
 
80
81
  ```python
81
82
  import multimodars as mm
@@ -83,8 +84,8 @@ import numpy as np
83
84
 
84
85
  # IVUS pullbacks: full alignment of rest/stress & diastole/systole
85
86
  rest, stress, dia, sys, _ = mm.from_file_full(
86
- input_path_a="ivus_rest",
87
- input_path_b="ivus_stress",
87
+ input_path_a="examples/data/ivus_rest",
88
+ input_path_b="examples/data/ivus_stress",
88
89
  label="full",
89
90
  step_rotation_deg=0.1,
90
91
  range_rotation_deg=90,
@@ -97,12 +98,12 @@ rest, stress, dia, sys, _ = mm.from_file_full(
97
98
  output_path_b="output/stress",
98
99
  output_path_c="output/diastole",
99
100
  output_path_d="output/systole",
100
- interpolation_steps=28,
101
+ interpolation_steps=0,
101
102
  contour_types=[mm.PyContourType.Lumen, mm.PyContourType.Catheter, mm.PyContourType.Wall]
102
103
  )
103
104
 
104
105
  # Load raw centerline and align geometry onto it
105
- cl_raw = np.genfromtxt("centerline_raw.csv", delimiter=",")
106
+ cl_raw = np.genfromtxt("examples/data/centerline_raw.csv", delimiter=",")
106
107
  centerline = mm.numpy_to_centerline(cl_raw)
107
108
 
108
109
  aligned_pair, cl_resampled = mm.align_three_point(
@@ -0,0 +1,9 @@
1
+ Adjust CCTA
2
+ ===========
3
+
4
+ .. autofunction:: multimodars.ccta.adjust_ccta.label_geometry
5
+ .. autofunction:: multimodars.ccta.adjust_ccta.label_anomalous_region
6
+ .. autofunction:: multimodars.ccta.adjust_ccta.scale_region_centerline_morphing
7
+ .. autofunction:: multimodars.ccta.adjust_ccta.compare_centerline_scaling
8
+ .. autofunction:: multimodars.ccta.adjust_ccta.find_distal_and_proximal_scaling
9
+ .. autofunction:: multimodars.ccta.adjust_ccta.find_aorta_scaling
@@ -2,4 +2,5 @@ Centerline Functions
2
2
  ====================
3
3
 
4
4
  .. autofunction:: multimodars.align_three_point
5
- .. autofunction:: multimodars.align_manual
5
+ .. autofunction:: multimodars.align_manual
6
+ .. autofunction:: multimodars.align_combined
@@ -9,4 +9,4 @@ PyContour
9
9
  :undoc-members:
10
10
  :show-inheritance:
11
11
  :inherited-members:
12
- :exclude-members: id, original_frame, points, centroid, kind
12
+ :exclude-members: id, original_frame, points, centroid, kind, aortic_thickness, pulmonary_thickness
@@ -9,4 +9,4 @@ PyGeometryPair
9
9
  :undoc-members:
10
10
  :show-inheritance:
11
11
  :inherited-members:
12
- :exclude-members: geom_a, geom_b
12
+ :exclude-members: geom_a, geom_b, label
@@ -0,0 +1,9 @@
1
+ Converters
2
+ ==========
3
+
4
+ .. autofunction:: multimodars._converters.to_array
5
+ .. autofunction:: multimodars._converters.numpy_to_inputdata
6
+ .. autofunction:: multimodars._converters.numpy_to_geometry
7
+ .. autofunction:: multimodars._converters.numpy_to_centerline
8
+ .. autofunction:: multimodars._converters.array_to_pyinputdata
9
+ .. autofunction:: multimodars._converters.geometry_to_frames_array
@@ -10,4 +10,5 @@ API Reference
10
10
  processing
11
11
  centerline
12
12
  utilities
13
- converters_and_wrappers
13
+ converters_and_wrappers
14
+ adjust_ccta
@@ -14,7 +14,7 @@ Pre-built binaries are available on PyPI for installation via pip. For the pytho
14
14
  mentioned below, wheels are automatically generated for each release of ``multimodars``, allowing you to
15
15
  install multimodars without having to compile anything.
16
16
 
17
- * Ensure that you have ``python`` installed on your machine, version 3.12 or higher (64-bits).
17
+ * Ensure that you have ``python`` installed on your machine, version 3.10 or higher (64-bits).
18
18
 
19
19
  * Install multimodars::
20
20
 
@@ -1,9 +1,14 @@
1
1
 
2
2
  .. note::
3
3
 
4
- Also download the example data and jupyter notebooks from the current release from the
5
- `Github Releases page <https://github.com/yungselm/multimoda-rs/releases>`_ to follow
6
- this tutorial step-by-step.
4
+ Also download the example data and jupyter notebooks to follow this tutorial step-by-step.
5
+ Use the direct download link:
6
+ `examples.zip <https://github.com/yungselm/multimoda-rs/releases/latest/download/examples.zip>`_
7
+ (SHA256: ``d11ebc7607f43ab4571fb51c9ac9178caac57774cf5d97f4f068ace4eb070fee``)
8
+
9
+ Alternatively, browse all releases on the
10
+ `Github Releases page <https://github.com/yungselm/multimoda-rs/releases>`_.
11
+ Specifically, the test_adjust_ccta.py allows you to also display the trimesh debug plots.
7
12
 
8
13
  Tutorial - CCTA Module
9
14
  =======================
@@ -25,10 +30,10 @@ that combines both steps, and performs several checks. Additionally is the geome
25
30
  import multimodars as mm
26
31
 
27
32
  results, (rca_cl, lca_cl, ao_cl) = mm.label_geometry(
28
- path_ccta_geometry="../data/NARCO_119.stl",
29
- path_centerline_aorta="../data/centerline_aorta.csv",
30
- path_centerline_rca="../data/centerline_rca.csv",
31
- path_centerline_lca="../data/centerline_lca.csv",
33
+ path_ccta_geometry="data/NARCO_119.stl",
34
+ path_centerline_aorta="data/centerline_aorta.csv",
35
+ path_centerline_rca="data/centerline_rca.csv",
36
+ path_centerline_lca="data/centerline_lca.csv",
32
37
  bounding_sphere_radius_mm=3.5, # rolling sphere radius for initial vessel labeling
33
38
  n_points_intramural=200, # points centerline to define end of intramural section, if unsure keep large
34
39
  anomalous_rca=True, # cleans wrongly labeled points intramural part
@@ -1,9 +1,13 @@
1
1
 
2
2
  .. note::
3
3
 
4
- Download the example data and jupyter notebooks from the current release from the
5
- `Github Releases page <https://github.com/yungselm/multimoda-rs/releases>`_ to follow
6
- this tutorial step-by-step.
4
+ Also download the example data and jupyter notebooks to follow this tutorial step-by-step.
5
+ Use the direct download link:
6
+ `examples.zip <https://github.com/yungselm/multimoda-rs/releases/latest/download/examples.zip>`_
7
+ (SHA256: ``d11ebc7607f43ab4571fb51c9ac9178caac57774cf5d97f4f068ace4eb070fee``)
8
+
9
+ Alternatively, browse all releases on the
10
+ `Github Releases page <https://github.com/yungselm/multimoda-rs/releases>`_.
7
11
 
8
12
  Tutorial - Intravascular Module
9
13
  ================================
@@ -99,52 +103,28 @@ For a single pair (e.g. only diastole/systole of one state) the simpler function
99
103
 
100
104
  2. Workflow numpy arrays and Finetuning
101
105
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
102
- Here the geometry can be directly built from arrays with the same structure as before.
103
- ``numpy_to_geometry`` accepts ``lumen_arr``, ``eem_arr``, ``catheter_arr``, ``wall_arr`` and ``reference_arr``:
106
+ To call ``from_array_singlepair`` the contours and reference point from the geometry must be packed into
107
+ a ``PyInputData`` object first. We assume that ``before_arr``, ``after_arr``, ``before_ref`` and ``after_arr``
108
+ are all Numpy arrays with N(4, ) shape:
104
109
 
105
110
  .. code-block:: python
106
111
 
107
- before_geom = mm.numpy_to_geometry(
112
+ before_input_data = mm.numpy_to_inputdata(
108
113
  lumen_arr=before_arr,
109
- eem_arr=np.array([]),
110
- catheter_arr=np.array([]),
111
- wall_arr=np.array([]),
112
- reference_arr=before_ref,
114
+ ref_point=before_ref,
115
+ record=None,
116
+ diastole=True,
117
+ label="prestent",
113
118
  )
114
119
 
115
- after_geom = mm.numpy_to_geometry(
120
+ after_input_data = mm.numpy_to_inputdata(
116
121
  lumen_arr=after_arr,
117
- eem_arr=np.array([]),
118
- catheter_arr=np.array([]),
119
- wall_arr=np.array([]),
120
- reference_arr=after_ref,
121
- )
122
-
123
- To call ``from_array_singlepair`` the contours and reference point from the geometry must be packed into
124
- a ``PyInputData`` object first:
125
-
126
- .. code-block:: python
127
-
128
- contours = []
129
- ref_pt = None
130
- for frame in before_geom.frames:
131
- contours.append(frame.lumen)
132
- if frame.reference_point is not None:
133
- ref_pt = frame.reference_point
134
-
135
- before_input_data = mm.PyInputData(
136
- lumen=contours,
137
- eem=None,
138
- calcification=None,
139
- sidebranch=None,
122
+ ref_point=after_ref,
140
123
  record=None,
141
- ref_point=ref_pt,
142
124
  diastole=True,
143
- label="before"
125
+ label="poststent",
144
126
  )
145
127
 
146
- # repeat for after_input_data ...
147
-
148
128
  pair, _ = mm.from_array_singlepair(
149
129
  input_data_a=before_input_data,
150
130
  input_data_b=after_input_data,
@@ -1,16 +1,37 @@
1
1
  from __future__ import annotations
2
2
 
3
- from .multimodars import *
3
+ from .multimodars import (
4
+ PyContourPoint,
5
+ PyContour,
6
+ PyFrame,
7
+ PyGeometry,
8
+ PyGeometryPair,
9
+ PyCenterline,
10
+ PyCenterlinePoint,
11
+ PyInputData,
12
+ PyRecord,
13
+ PyContourType,
14
+ from_file_full,
15
+ from_file_doublepair,
16
+ from_file_singlepair,
17
+ from_file_single,
18
+ from_array_full,
19
+ from_array_doublepair,
20
+ from_array_singlepair,
21
+ from_array_single,
22
+ align_three_point,
23
+ align_manual,
24
+ align_combined,
25
+ to_obj,
26
+ find_centerline_bounded_points_simple,
27
+ find_proximal_distal_scaling,
28
+ )
4
29
  from ._converters import (
5
30
  to_array,
6
31
  numpy_to_geometry,
7
32
  numpy_to_centerline,
8
33
  numpy_to_inputdata,
9
34
  )
10
- from ._wrappers import (
11
- from_file,
12
- from_array,
13
- )
14
35
  from .io import read_geometrical, write_geometries
15
36
  from .ccta.adjust_ccta import (
16
37
  label_geometry,
@@ -37,9 +58,6 @@ __all__ = [
37
58
  "numpy_to_geometry",
38
59
  "numpy_to_centerline",
39
60
  "numpy_to_inputdata",
40
- # Wrapper functions
41
- "from_file",
42
- "from_array",
43
61
  # Processing functions (from Rust)
44
62
  "from_file_full",
45
63
  "from_file_doublepair",
@@ -51,9 +69,13 @@ __all__ = [
51
69
  "from_array_single",
52
70
  "align_three_point",
53
71
  "align_manual",
72
+ "align_combined",
54
73
  "to_obj",
55
74
  "find_centerline_bounded_points_simple",
56
75
  "find_proximal_distal_scaling",
76
+ # I/O
77
+ "read_geometrical",
78
+ "write_geometries",
57
79
  # CCTA module
58
80
  "label_geometry",
59
81
  "label_anomalous_region",