multimodars 0.4.0__tar.gz → 0.4.2__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 (155) hide show
  1. {multimodars-0.4.0 → multimodars-0.4.2}/CHANGELOG.md +17 -3
  2. {multimodars-0.4.0 → multimodars-0.4.2}/Cargo.lock +1 -1
  3. {multimodars-0.4.0 → multimodars-0.4.2}/Cargo.toml +2 -2
  4. {multimodars-0.4.0 → multimodars-0.4.2}/PKG-INFO +1 -1
  5. {multimodars-0.4.0 → multimodars-0.4.2}/src/ccta/adjust_mesh/label_coronary.rs +5 -6
  6. {multimodars-0.4.0 → multimodars-0.4.2}/src/ccta/adjust_mesh/scale_coronary.rs +10 -12
  7. multimodars-0.4.2/src/ccta/adjust_mesh.rs +12 -0
  8. {multimodars-0.4.0 → multimodars-0.4.2}/src/ccta/binding/ccta_py.rs +28 -178
  9. {multimodars-0.4.0 → multimodars-0.4.2}/src/ccta/discretizing/projecting.rs +2 -3
  10. {multimodars-0.4.0 → multimodars-0.4.2}/src/ccta/discretizing/resampling.rs +2 -4
  11. {multimodars-0.4.0 → multimodars-0.4.2}/src/ccta/discretizing/utils.rs +2 -2
  12. multimodars-0.4.2/src/ccta/discretizing/vessel_tree.rs +82 -0
  13. multimodars-0.4.0/src/ccta/discretizing/mod.rs → multimodars-0.4.2/src/ccta/discretizing.rs +3 -6
  14. {multimodars-0.4.0 → multimodars-0.4.2}/src/intravascular/binding/align.rs +3 -3
  15. {multimodars-0.4.0 → multimodars-0.4.2}/src/intravascular/binding/entry.rs +111 -67
  16. multimodars-0.4.0/src/intravascular/binding/mod.rs → multimodars-0.4.2/src/intravascular/binding/functions.rs +3 -7
  17. multimodars-0.4.2/src/intravascular/binding.rs +8 -0
  18. multimodars-0.4.0/src/intravascular/centerline_align/mod.rs → multimodars-0.4.2/src/intravascular/centerline_align/align.rs +17 -17
  19. multimodars-0.4.2/src/intravascular/centerline_align.rs +5 -0
  20. multimodars-0.4.0/src/intravascular/io/mod.rs → multimodars-0.4.2/src/intravascular/io/build.rs +4 -21
  21. multimodars-0.4.2/src/intravascular/io/geometry.rs +6 -0
  22. multimodars-0.4.2/src/intravascular/io/input.rs +7 -0
  23. multimodars-0.4.2/src/intravascular/io.rs +7 -0
  24. {multimodars-0.4.0 → multimodars-0.4.2}/src/intravascular/processing/align_between.rs +1 -17
  25. {multimodars-0.4.0 → multimodars-0.4.2}/src/intravascular/processing/align_within.rs +4 -4
  26. {multimodars-0.4.0 → multimodars-0.4.2}/src/intravascular/processing/postprocessing.rs +3 -3
  27. {multimodars-0.4.0 → multimodars-0.4.2}/src/intravascular/processing/preprocessing.rs +7 -7
  28. multimodars-0.4.0/src/intravascular/to_object/mod.rs → multimodars-0.4.2/src/intravascular/to_object/process.rs +4 -8
  29. multimodars-0.4.2/src/intravascular/to_object.rs +6 -0
  30. multimodars-0.4.2/src/lib.rs +88 -0
  31. multimodars-0.4.2/src/types/binding/py_centerline.rs +287 -0
  32. multimodars-0.4.2/src/types/binding/py_centerline_point.rs +83 -0
  33. multimodars-0.4.2/src/types/binding/py_contour.rs +432 -0
  34. multimodars-0.4.2/src/types/binding/py_contour_point.rs +129 -0
  35. multimodars-0.4.2/src/types/binding/py_discretized_vessel_tree.rs +157 -0
  36. multimodars-0.4.2/src/types/binding/py_frame.rs +201 -0
  37. multimodars-0.4.2/src/types/binding/py_geometry.rs +468 -0
  38. multimodars-0.4.2/src/types/binding/py_geometry_pair.rs +226 -0
  39. multimodars-0.4.2/src/types/binding/py_input_data.rs +258 -0
  40. multimodars-0.4.2/src/types/binding/py_record.rs +87 -0
  41. multimodars-0.4.2/src/types/binding.rs +21 -0
  42. multimodars-0.4.0/src/intravascular/io/input.rs → multimodars-0.4.2/src/types/native/centerline.rs +6 -433
  43. multimodars-0.4.2/src/types/native/centerline_point.rs +22 -0
  44. multimodars-0.4.2/src/types/native/contour.rs +963 -0
  45. multimodars-0.4.2/src/types/native/contour_point.rs +227 -0
  46. multimodars-0.4.0/src/ccta/discretizing/vessel_tree.rs → multimodars-0.4.2/src/types/native/discretized_tree.rs +7 -105
  47. multimodars-0.4.2/src/types/native/frame.rs +845 -0
  48. multimodars-0.4.2/src/types/native/geometry.rs +1234 -0
  49. multimodars-0.4.2/src/types/native/geometry_pair.rs +20 -0
  50. multimodars-0.4.2/src/types/native/input_data.rs +218 -0
  51. multimodars-0.4.2/src/types/native/record.rs +31 -0
  52. multimodars-0.4.2/src/types/native.rs +21 -0
  53. multimodars-0.4.2/src/types.rs +2 -0
  54. multimodars-0.4.0/src/ccta/adjust_mesh/mod.rs +0 -40
  55. multimodars-0.4.0/src/intravascular/binding/classes.rs +0 -2144
  56. multimodars-0.4.0/src/intravascular/io/geometry.rs +0 -3071
  57. multimodars-0.4.0/src/lib.rs +0 -83
  58. {multimodars-0.4.0 → multimodars-0.4.2}/.gitattributes +0 -0
  59. {multimodars-0.4.0 → multimodars-0.4.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  60. {multimodars-0.4.0 → multimodars-0.4.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  61. {multimodars-0.4.0 → multimodars-0.4.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  62. {multimodars-0.4.0 → multimodars-0.4.2}/.github/workflows/CI.yml +0 -0
  63. {multimodars-0.4.0 → multimodars-0.4.2}/.gitignore +0 -0
  64. {multimodars-0.4.0 → multimodars-0.4.2}/.pre-commit-config.yaml +0 -0
  65. {multimodars-0.4.0 → multimodars-0.4.2}/.readthedocs.yaml +0 -0
  66. {multimodars-0.4.0 → multimodars-0.4.2}/CITATION.cff +0 -0
  67. {multimodars-0.4.0 → multimodars-0.4.2}/CONTRIBUTING.md +0 -0
  68. {multimodars-0.4.0 → multimodars-0.4.2}/LICENSE +0 -0
  69. {multimodars-0.4.0 → multimodars-0.4.2}/README.md +0 -0
  70. {multimodars-0.4.0 → multimodars-0.4.2}/ROADMAP.MD +0 -0
  71. {multimodars-0.4.0 → multimodars-0.4.2}/benchmarks/BENCHMARK_PLAN.md +0 -0
  72. {multimodars-0.4.0 → multimodars-0.4.2}/benchmarks/benchmark_bruteforce_stepsize.py +0 -0
  73. {multimodars-0.4.0 → multimodars-0.4.2}/benchmarks/benchmark_cpu_scaling.py +0 -0
  74. {multimodars-0.4.0 → multimodars-0.4.2}/benchmarks/results/bruteforce_stepsize.png +0 -0
  75. {multimodars-0.4.0 → multimodars-0.4.2}/benchmarks/results/cpu_scaling.png +0 -0
  76. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/idealized_geometry/branch_diastolic_contours.csv +0 -0
  77. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/idealized_geometry/branch_systolic_contours.csv +0 -0
  78. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/idealized_geometry/calcium_diastolic_contours.csv +0 -0
  79. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/idealized_geometry/calcium_systolic_contours.csv +0 -0
  80. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/idealized_geometry/diastolic_contours.csv +0 -0
  81. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/idealized_geometry/diastolic_reference_points.csv +0 -0
  82. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/idealized_geometry/eem_diastolic_contours.csv +0 -0
  83. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/idealized_geometry/eem_systolic_contours.csv +0 -0
  84. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/idealized_geometry/systolic_contours.csv +0 -0
  85. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/idealized_geometry/systolic_reference_points.csv +0 -0
  86. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/ivus_full/branch_diastolic_contours.csv +0 -0
  87. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/ivus_full/branch_systolic_contours.csv +0 -0
  88. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/ivus_full/calcium_diastolic_contours.csv +0 -0
  89. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/ivus_full/calcium_systolic_contours.csv +0 -0
  90. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/ivus_full/diastolic_contours.csv +0 -0
  91. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/ivus_full/diastolic_reference_points.csv +0 -0
  92. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/ivus_full/eem_diastolic_contours.csv +0 -0
  93. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/ivus_full/eem_systolic_contours.csv +0 -0
  94. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/ivus_full/systolic_contours.csv +0 -0
  95. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/ivus_full/systolic_reference_points.csv +0 -0
  96. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/ivus_rest/combined_sorted_manual.csv +0 -0
  97. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/ivus_rest/diastolic_contours.csv +0 -0
  98. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/ivus_rest/diastolic_reference_points.csv +0 -0
  99. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/ivus_rest/systolic_contours.csv +0 -0
  100. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/ivus_rest/systolic_reference_points.csv +0 -0
  101. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/ivus_stress/combined_sorted_manual.csv +0 -0
  102. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/ivus_stress/diastolic_contours.csv +0 -0
  103. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/ivus_stress/diastolic_reference_points.csv +0 -0
  104. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/ivus_stress/systolic_contours.csv +0 -0
  105. {multimodars-0.4.0 → multimodars-0.4.2}/data/fixtures/ivus_stress/systolic_reference_points.csv +0 -0
  106. {multimodars-0.4.0 → multimodars-0.4.2}/media/coronary_artery_disease.jpg +0 -0
  107. {multimodars-0.4.0 → multimodars-0.4.2}/media/dynamic_lumen_changes.png +0 -0
  108. {multimodars-0.4.0 → multimodars-0.4.2}/media/multimoda-rs.jpg +0 -0
  109. {multimodars-0.4.0 → multimodars-0.4.2}/multimodars/__init__.py +0 -0
  110. {multimodars-0.4.0 → multimodars-0.4.2}/multimodars/_converters.py +0 -0
  111. {multimodars-0.4.0 → multimodars-0.4.2}/multimodars/_processing.py +0 -0
  112. {multimodars-0.4.0 → multimodars-0.4.2}/multimodars/ccta/__init__.py +0 -0
  113. {multimodars-0.4.0 → multimodars-0.4.2}/multimodars/ccta/debug_plots.py +0 -0
  114. {multimodars-0.4.0 → multimodars-0.4.2}/multimodars/ccta/discretization_map.py +0 -0
  115. {multimodars-0.4.0 → multimodars-0.4.2}/multimodars/ccta/fixing_functions.py +0 -0
  116. {multimodars-0.4.0 → multimodars-0.4.2}/multimodars/ccta/labeling.py +0 -0
  117. {multimodars-0.4.0 → multimodars-0.4.2}/multimodars/ccta/manipulating.py +0 -0
  118. {multimodars-0.4.0 → multimodars-0.4.2}/multimodars/io/__init__.py +0 -0
  119. {multimodars-0.4.0 → multimodars-0.4.2}/multimodars/io/read_geometrical.py +0 -0
  120. {multimodars-0.4.0 → multimodars-0.4.2}/multimodars/io/write_geometries.py +0 -0
  121. {multimodars-0.4.0 → multimodars-0.4.2}/multimodars/multimodars.pyi +0 -0
  122. {multimodars-0.4.0 → multimodars-0.4.2}/multimodars/py.typed +0 -0
  123. {multimodars-0.4.0 → multimodars-0.4.2}/paper/REVIEWER1.md +0 -0
  124. {multimodars-0.4.0 → multimodars-0.4.2}/paper/REVIEWER2.md +0 -0
  125. {multimodars-0.4.0 → multimodars-0.4.2}/paper/bibliography.bib +0 -0
  126. {multimodars-0.4.0 → multimodars-0.4.2}/paper/figures/Figure1.jpg +0 -0
  127. {multimodars-0.4.0 → multimodars-0.4.2}/paper/figures/Figure2.jpg +0 -0
  128. {multimodars-0.4.0 → multimodars-0.4.2}/paper/figures/Figure3.png +0 -0
  129. {multimodars-0.4.0 → multimodars-0.4.2}/paper/figures/Figure4.jpg +0 -0
  130. {multimodars-0.4.0 → multimodars-0.4.2}/paper/paper.md +0 -0
  131. {multimodars-0.4.0 → multimodars-0.4.2}/pyproject.toml +0 -0
  132. /multimodars-0.4.0/src/ccta/binding/mod.rs → /multimodars-0.4.2/src/ccta/binding.rs +0 -0
  133. {multimodars-0.4.0 → multimodars-0.4.2}/src/ccta/discretizing/plan.md +0 -0
  134. /multimodars-0.4.0/src/ccta/mod.rs → /multimodars-0.4.2/src/ccta.rs +0 -0
  135. {multimodars-0.4.0 → multimodars-0.4.2}/src/intravascular/centerline_align/align_algorithms.rs +0 -0
  136. {multimodars-0.4.0 → multimodars-0.4.2}/src/intravascular/centerline_align/preprocessing.rs +0 -0
  137. {multimodars-0.4.0 → multimodars-0.4.2}/src/intravascular/io/integrity_check.rs +0 -0
  138. {multimodars-0.4.0 → multimodars-0.4.2}/src/intravascular/io/output.rs +0 -0
  139. {multimodars-0.4.0 → multimodars-0.4.2}/src/intravascular/processing/process_utils.rs +0 -0
  140. {multimodars-0.4.0 → multimodars-0.4.2}/src/intravascular/processing/wall.rs +0 -0
  141. /multimodars-0.4.0/src/intravascular/processing/mod.rs → /multimodars-0.4.2/src/intravascular/processing.rs +0 -0
  142. {multimodars-0.4.0 → multimodars-0.4.2}/src/intravascular/to_object/interpolation.rs +0 -0
  143. {multimodars-0.4.0 → multimodars-0.4.2}/src/intravascular/to_object/texture.rs +0 -0
  144. {multimodars-0.4.0 → multimodars-0.4.2}/src/intravascular/to_object/write_mtl.rs +0 -0
  145. {multimodars-0.4.0 → multimodars-0.4.2}/src/intravascular/utils/general_utils.rs +0 -0
  146. {multimodars-0.4.0 → multimodars-0.4.2}/src/intravascular/utils/test_utils.rs +0 -0
  147. /multimodars-0.4.0/src/intravascular/utils/mod.rs → /multimodars-0.4.2/src/intravascular/utils.rs +0 -0
  148. /multimodars-0.4.0/src/intravascular/mod.rs → /multimodars-0.4.2/src/intravascular.rs +0 -0
  149. {multimodars-0.4.0 → multimodars-0.4.2}/tests/conftest.py +0 -0
  150. {multimodars-0.4.0 → multimodars-0.4.2}/tests/test_ccta.py +0 -0
  151. {multimodars-0.4.0 → multimodars-0.4.2}/tests/test_converters.py +0 -0
  152. {multimodars-0.4.0 → multimodars-0.4.2}/tests/test_core.py +0 -0
  153. {multimodars-0.4.0 → multimodars-0.4.2}/tests/test_intravascular.py +0 -0
  154. {multimodars-0.4.0 → multimodars-0.4.2}/tests/test_wrappers.py +0 -0
  155. {multimodars-0.4.0 → multimodars-0.4.2}/tests/tests_todo.md +0 -0
@@ -3,11 +3,26 @@
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.4.2] - 2026-06-04
7
+ Large internal refactor to improve readability and decouple modules. No behaviour change.
8
+
9
+ ### Changed
10
+ - All native types and Python bindings extracted from scattered files into a unified `src/types/native/` and
11
+ `src/types/binding/` module.
12
+ - Several large files split into focused submodules (`binding/classes.rs` removed, `io/geometry.rs`, `centerline_align.rs`, `to_object.rs` split).
13
+ - `Point3D` trait added and shared across `ContourPoint`, `CenterlinePoint`, and `(f64, f64, f64)`, simplified some functions with this.
14
+
15
+ ## [0.4.1] - 2026-06-02
16
+
17
+ ### Changed
18
+ - Rust `use` declarations now follow the idiomatic convention of importing the parent module for
19
+ functions (e.g. `use crate::ccta::discretizing;` -> `discretizing::discretize_vessel_rs(...)`)
20
+ and importing types/structs/enums directly. No behaviour change; purely internal style cleanup
21
+ across 14 source files.
22
+
6
23
  ## [0.4.0] - 2026-05-25
7
- This version introduces backwards compatibility breaking changes.
8
24
 
9
25
  ### Added
10
-
11
26
  **Vessel-tree discretization pipeline**
12
27
 
13
28
  - `prepare_centerlines(rca_cl, lca_cl, results_dict, branch_sigma, control_plot)`: one-call
@@ -47,7 +62,6 @@ the style of `label_geometry`'s control plot and working correctly in all enviro
47
62
  - `plot_results_key`, `compare_centerline_scaling`: migrated from Plotly to trimesh.
48
63
 
49
64
  ### Changed
50
-
51
65
  **Alignment reference point naming** (`align_three_point`, `align_combined`, `align_manual`)
52
66
 
53
67
  The three landmark parameters have been renamed for anatomical clarity:
@@ -665,7 +665,7 @@ dependencies = [
665
665
 
666
666
  [[package]]
667
667
  name = "multimodars"
668
- version = "0.4.0"
668
+ version = "0.4.2"
669
669
  dependencies = [
670
670
  "anyhow",
671
671
  "approx",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "multimodars"
3
- version = "0.4.0"
3
+ version = "0.4.2"
4
4
  edition = "2021"
5
5
  license = "MIT"
6
6
  readme = "README.md"
@@ -15,7 +15,7 @@ csv = "1.4.0"
15
15
  serde = { version = "1.0.228", features = ["derive"]}
16
16
  image = "0.25.10"
17
17
  nalgebra = "0.35.0"
18
- toml = "1.1.2+spec-1.1.0"
18
+ toml = "1.1.2"
19
19
  rayon = "1.12.0"
20
20
  crossbeam = "0.8.4"
21
21
  anyhow = "1.0.102"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: multimodars
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -1,5 +1,4 @@
1
- use super::calculate_squared_distance;
2
- use crate::intravascular::io::input::{Centerline, CenterlinePoint};
1
+ use crate::types::native::{Centerline, CenterlinePoint};
3
2
  use rayon::prelude::*;
4
3
  use std::collections::HashSet;
5
4
 
@@ -178,9 +177,9 @@ pub fn remove_occluded_points_ray_triangle_rust(
178
177
  }
179
178
 
180
179
  fn point_to_triangle_distance(point: &(f64, f64, f64), triangle: &Triangle) -> f64 {
181
- let dist_v0 = calculate_squared_distance(point, &triangle.v0);
182
- let dist_v1 = calculate_squared_distance(point, &triangle.v1);
183
- let dist_v2 = calculate_squared_distance(point, &triangle.v2);
180
+ let dist_v0 = super::calculate_squared_distance(point, &triangle.v0);
181
+ let dist_v1 = super::calculate_squared_distance(point, &triangle.v1);
182
+ let dist_v2 = super::calculate_squared_distance(point, &triangle.v2);
184
183
 
185
184
  dist_v0.min(dist_v1).min(dist_v2)
186
185
  }
@@ -299,7 +298,7 @@ fn find_points_inside_of_sphere(sphere: &BoundingSphere, point: &(f64, f64, f64)
299
298
  #[cfg(test)]
300
299
  mod test_find_cl_bounded_points {
301
300
  use super::*;
302
- use crate::intravascular::io::input::ContourPoint;
301
+ use crate::types::native::ContourPoint;
303
302
 
304
303
  #[test]
305
304
  fn test_find_points_simple_geometry() {
@@ -1,6 +1,4 @@
1
- use super::calculate_squared_distance;
2
- use crate::intravascular::io::geometry::Frame;
3
- use crate::intravascular::io::input::{Centerline, CenterlinePoint};
1
+ use crate::types::native::{Centerline, CenterlinePoint, Frame};
4
2
  use rayon::prelude::*;
5
3
  use std::collections::HashSet;
6
4
 
@@ -17,8 +15,8 @@ pub fn centerline_based_wall_diameter_optimization(
17
15
 
18
16
  // find closest centerline point
19
17
  let closest_cl = match centerline.points.iter().min_by(|a, b| {
20
- let dist_a = calculate_squared_distance(*a, ref_point_coronary);
21
- let dist_b = calculate_squared_distance(*b, ref_point_coronary);
18
+ let dist_a = super::calculate_squared_distance(*a, ref_point_coronary);
19
+ let dist_b = super::calculate_squared_distance(*b, ref_point_coronary);
22
20
  dist_a
23
21
  .partial_cmp(&dist_b)
24
22
  .unwrap_or(std::cmp::Ordering::Equal)
@@ -28,8 +26,8 @@ pub fn centerline_based_wall_diameter_optimization(
28
26
  };
29
27
 
30
28
  let closest_aortic: &Point3D = match aortic_points.iter().min_by(|a, b| {
31
- let dist_a = calculate_squared_distance(*a, ref_point_coronary);
32
- let dist_b = calculate_squared_distance(*b, ref_point_coronary);
29
+ let dist_a = super::calculate_squared_distance(*a, ref_point_coronary);
30
+ let dist_b = super::calculate_squared_distance(*b, ref_point_coronary);
33
31
  dist_a
34
32
  .partial_cmp(&dist_b)
35
33
  .unwrap_or(std::cmp::Ordering::Equal)
@@ -150,7 +148,7 @@ fn find_region_points(
150
148
  .map(|(i, a_pt)| {
151
149
  let min_sq = reference_points
152
150
  .iter()
153
- .map(|r_pt| calculate_squared_distance(a_pt, r_pt))
151
+ .map(|r_pt| super::calculate_squared_distance(a_pt, r_pt))
154
152
  .fold(f64::INFINITY, |m, v| if v < m { v } else { m });
155
153
  (i, min_sq)
156
154
  })
@@ -199,7 +197,7 @@ fn symmetric_nn_distance(a: &[Point3D], b: &[Point3D]) -> f64 {
199
197
  .par_iter()
200
198
  .map(|pa| {
201
199
  b.iter()
202
- .map(|pb| calculate_squared_distance(pa, pb))
200
+ .map(|pb| super::calculate_squared_distance(pa, pb))
203
201
  .fold(f64::INFINITY, |m, v| if v < m { v } else { m })
204
202
  })
205
203
  .sum();
@@ -210,7 +208,7 @@ fn symmetric_nn_distance(a: &[Point3D], b: &[Point3D]) -> f64 {
210
208
  .par_iter()
211
209
  .map(|pb| {
212
210
  a.iter()
213
- .map(|pa| calculate_squared_distance(pb, pa))
211
+ .map(|pa| super::calculate_squared_distance(pb, pa))
214
212
  .fold(f64::INFINITY, |m, v| if v < m { v } else { m })
215
213
  })
216
214
  .sum();
@@ -265,7 +263,7 @@ fn find_closest_centerline_point_optimized(
265
263
  let mut closest_point = &centerline.points[0];
266
264
 
267
265
  for centerline_point in &centerline.points {
268
- let distance_squared = calculate_squared_distance(&point, centerline_point);
266
+ let distance_squared = super::calculate_squared_distance(&point, centerline_point);
269
267
  if distance_squared < min_distance_squared {
270
268
  min_distance_squared = distance_squared;
271
269
  closest_point = centerline_point;
@@ -419,7 +417,7 @@ pub fn clean_up_non_section_points(
419
417
 
420
418
  #[cfg(test)]
421
419
  mod tests {
422
- use crate::intravascular::io::input::{CenterlinePoint, ContourPoint};
420
+ use crate::types::native::{CenterlinePoint, ContourPoint};
423
421
  use nalgebra::Vector3;
424
422
 
425
423
  use super::*;
@@ -0,0 +1,12 @@
1
+ pub mod label_coronary;
2
+ pub mod scale_coronary;
3
+ use crate::types::native::Point3D;
4
+
5
+ /// Squared Euclidean distance between any two [`Point3D`] values.
6
+ /// Use the squared form to avoid a `sqrt` when only ordering matters.
7
+ pub(super) fn calculate_squared_distance<A: Point3D, B: Point3D>(a: &A, b: &B) -> f64 {
8
+ let dx = a.x() - b.x();
9
+ let dy = a.y() - b.y();
10
+ let dz = a.z() - b.z();
11
+ dx * dx + dy * dy + dz * dz
12
+ }
@@ -1,177 +1,16 @@
1
- // src/ccta/binding/label_py.rs
1
+ // src/ccta/binding/ccta_py.rs
2
2
  use std::collections::{HashMap, HashSet};
3
3
 
4
- use crate::ccta::adjust_mesh::label_coronary::find_centerline_bounded_points;
5
- use crate::ccta::adjust_mesh::label_coronary::{
6
- remove_occluded_points_ray_triangle_rust, Triangle,
7
- };
8
- use crate::ccta::adjust_mesh::scale_coronary::{
9
- centerline_based_aortic_diameter_optimization, centerline_based_diameter_morphing,
10
- centerline_based_diameter_optimization, centerline_based_wall_diameter_optimization,
11
- clean_up_non_section_points, find_points_by_cl_region_rs,
12
- };
13
- use crate::ccta::discretizing::discretize_vessel_rs;
14
- use crate::ccta::discretizing::vessel_tree::DiscretizedVesselTree;
15
- use crate::intravascular::binding::classes::{PyCenterline, PyContour, PyFrame};
4
+ use crate::ccta::adjust_mesh::label_coronary;
5
+ use crate::ccta::adjust_mesh::label_coronary::Triangle;
6
+ use crate::ccta::adjust_mesh::scale_coronary;
7
+ use crate::ccta::discretizing;
8
+ use crate::types::binding::{PyCenterline, PyContour, PyDiscretizedVesselTree, PyFrame};
9
+ use crate::types::native::DiscretizedVesselTree;
16
10
  use pyo3::prelude::*;
17
11
 
18
12
  type Point3D = (f64, f64, f64);
19
13
  type TriangleTuple = (Point3D, Point3D, Point3D);
20
- /// (main_ref, clock_ref, counter_clock_ref) — all three as plain xyz tuples.
21
- type RefTriplet = (Point3D, Point3D, Point3D);
22
-
23
- // ─── PyDiscretizedVesselTree ──────────────────────────────────────────────────
24
-
25
- /// Fully discretized coronary vessel tree (aorta + RCA + LCA + side branches).
26
- ///
27
- /// Attributes
28
- /// ----------
29
- /// discretized_aorta : list of PyContour
30
- /// Cross-sectional contours along the aortic centerline.
31
- /// discretized_rca_main : list of PyContour
32
- /// Cross-sectional contours along the RCA main vessel.
33
- /// discretized_lca_main : list of PyContour
34
- /// Cross-sectional contours along the LCA main vessel.
35
- /// rca_branches : list of list of PyContour
36
- /// Per-side-branch contour lists for the RCA. ``rca_branches[i]``
37
- /// corresponds to RCA branch_id ``i + 1``.
38
- /// lca_branches : list of list of PyContour
39
- /// Per-side-branch contour lists for the LCA.
40
- /// rca_references : list of tuple
41
- /// Orientation triplets ``(main_ref, clock_ref, counter_clock_ref)`` along
42
- /// the RCA, sorted proximal → distal. Each element is a 3-tuple of
43
- /// ``(x, y, z)`` coordinate tuples.
44
- /// lca_references : list of tuple
45
- /// Same structure for the LCA.
46
- /// ao_rca : tuple of float
47
- /// Centroid ``(x, y, z)`` of the aorta slice closest to the RCA ostium.
48
- /// ao_lca : tuple of float
49
- /// Centroid ``(x, y, z)`` of the aorta slice closest to the LCA ostium.
50
- #[pyclass(skip_from_py_object)]
51
- #[derive(Debug, Clone)]
52
- pub struct PyDiscretizedVesselTree {
53
- #[pyo3(get, set)]
54
- pub discretized_aorta: Vec<PyContour>,
55
- #[pyo3(get, set)]
56
- pub discretized_rca_main: Vec<PyContour>,
57
- #[pyo3(get, set)]
58
- pub discretized_lca_main: Vec<PyContour>,
59
- #[pyo3(get, set)]
60
- pub rca_branches: Vec<Vec<PyContour>>,
61
- #[pyo3(get, set)]
62
- pub lca_branches: Vec<Vec<PyContour>>,
63
- #[pyo3(get)]
64
- pub rca_references: Vec<RefTriplet>,
65
- #[pyo3(get)]
66
- pub lca_references: Vec<RefTriplet>,
67
- #[pyo3(get, set)]
68
- pub ao_rca: Point3D,
69
- #[pyo3(get, set)]
70
- pub ao_lca: Point3D,
71
- }
72
-
73
- #[pymethods]
74
- impl PyDiscretizedVesselTree {
75
- fn __repr__(&self) -> String {
76
- format!(
77
- "DiscretizedVesselTree(ao={}, rca_main={}, lca_main={}, rca_branches={}, lca_branches={}, rca_refs={}, lca_refs={})",
78
- self.discretized_aorta.len(),
79
- self.discretized_rca_main.len(),
80
- self.discretized_lca_main.len(),
81
- self.rca_branches.len(),
82
- self.lca_branches.len(),
83
- self.rca_references.len(),
84
- self.lca_references.len(),
85
- )
86
- }
87
-
88
- /// Recompute orientation reference triplets and aortic ostium centroids
89
- /// from the current contour data.
90
- ///
91
- /// Call this after replacing contours (e.g. with B-spline fits) so that
92
- /// ``rca_references``, ``lca_references``, ``ao_rca``, and ``ao_lca``
93
- /// reflect the updated geometry.
94
- pub fn calculate_ref_pts(&mut self) -> PyResult<()> {
95
- let convert =
96
- |contours: &[PyContour]| -> PyResult<Vec<crate::intravascular::io::geometry::Contour>> {
97
- contours.iter().map(|c| c.to_rust_contour()).collect()
98
- };
99
-
100
- let rust_aorta = convert(&self.discretized_aorta)?;
101
- let rust_rca = convert(&self.discretized_rca_main)?;
102
- let rust_lca = convert(&self.discretized_lca_main)?;
103
- let rust_rca_branches: PyResult<Vec<Vec<_>>> =
104
- self.rca_branches.iter().map(|b| convert(b)).collect();
105
- let rust_lca_branches: PyResult<Vec<Vec<_>>> =
106
- self.lca_branches.iter().map(|b| convert(b)).collect();
107
-
108
- let tree = DiscretizedVesselTree {
109
- discretized_aorta: rust_aorta,
110
- discretized_rca_main: rust_rca,
111
- discretized_lca_main: rust_lca,
112
- rca_branches: rust_rca_branches?,
113
- lca_branches: rust_lca_branches?,
114
- spacing: 1.0,
115
- rca_references: vec![],
116
- lca_references: vec![],
117
- ao_rca: (0.0, 0.0, 0.0),
118
- ao_lca: (0.0, 0.0, 0.0),
119
- pts_cusp_rcc: None,
120
- pts_cusp_lcc: None,
121
- pts_cusp_acc: None,
122
- index_stj_slice: None,
123
- index_aa: None,
124
- };
125
-
126
- let updated = tree.calculate_ref_pts();
127
- self.rca_references = updated
128
- .rca_references
129
- .into_iter()
130
- .map(|r| (r.main_ref, r.clock_ref, r.counter_clock_ref))
131
- .collect();
132
- self.lca_references = updated
133
- .lca_references
134
- .into_iter()
135
- .map(|r| (r.main_ref, r.clock_ref, r.counter_clock_ref))
136
- .collect();
137
- self.ao_rca = updated.ao_rca;
138
- self.ao_lca = updated.ao_lca;
139
-
140
- Ok(())
141
- }
142
- }
143
-
144
- impl From<DiscretizedVesselTree> for PyDiscretizedVesselTree {
145
- fn from(t: DiscretizedVesselTree) -> Self {
146
- Self {
147
- discretized_aorta: t.discretized_aorta.iter().map(PyContour::from).collect(),
148
- discretized_rca_main: t.discretized_rca_main.iter().map(PyContour::from).collect(),
149
- discretized_lca_main: t.discretized_lca_main.iter().map(PyContour::from).collect(),
150
- rca_branches: t
151
- .rca_branches
152
- .iter()
153
- .map(|b| b.iter().map(PyContour::from).collect())
154
- .collect(),
155
- lca_branches: t
156
- .lca_branches
157
- .iter()
158
- .map(|b| b.iter().map(PyContour::from).collect())
159
- .collect(),
160
- rca_references: t
161
- .rca_references
162
- .into_iter()
163
- .map(|r| (r.main_ref, r.clock_ref, r.counter_clock_ref))
164
- .collect(),
165
- lca_references: t
166
- .lca_references
167
- .into_iter()
168
- .map(|r| (r.main_ref, r.clock_ref, r.counter_clock_ref))
169
- .collect(),
170
- ao_rca: t.ao_rca,
171
- ao_lca: t.ao_lca,
172
- }
173
- }
174
- }
175
14
 
176
15
  /// Find points bounded by spheres along a coronary vessel centerline.
177
16
  ///
@@ -211,7 +50,8 @@ pub fn find_centerline_bounded_points_simple(
211
50
  let rust_centerline = centerline.to_rust_centerline();
212
51
 
213
52
  // Call Rust function directly - no complex conversions needed
214
- let result_points = find_centerline_bounded_points(rust_centerline, &points, radius);
53
+ let result_points =
54
+ label_coronary::find_centerline_bounded_points(rust_centerline, &points, radius);
215
55
 
216
56
  Ok(result_points)
217
57
  }
@@ -257,7 +97,7 @@ pub fn remove_occluded_points_ray_triangle(
257
97
  .map(|(v0, v1, v2)| Triangle::new(v0, v1, v2))
258
98
  .collect();
259
99
 
260
- let result = remove_occluded_points_ray_triangle_rust(
100
+ let result = label_coronary::remove_occluded_points_ray_triangle_rust(
261
101
  &rust_centerline_coronary,
262
102
  &rust_centerline_aorta,
263
103
  range_coronary,
@@ -291,8 +131,11 @@ pub fn adjust_diameter_centerline_morphing_simple(
291
131
  ) -> PyResult<Vec<Point3D>> {
292
132
  let rust_centerline = centerline.to_rust_centerline();
293
133
 
294
- let result_points =
295
- centerline_based_diameter_morphing(&rust_centerline, &points, diameter_adjustment_mm);
134
+ let result_points = scale_coronary::centerline_based_diameter_morphing(
135
+ &rust_centerline,
136
+ &points,
137
+ diameter_adjustment_mm,
138
+ );
296
139
 
297
140
  Ok(result_points)
298
141
  }
@@ -332,7 +175,8 @@ pub fn find_points_by_cl_region(
332
175
  .map(|f| f.to_rust_frame())
333
176
  .collect::<Result<_, _>>()?;
334
177
 
335
- let result_points = find_points_by_cl_region_rs(&rust_centerline, &rust_frames, &points);
178
+ let result_points =
179
+ scale_coronary::find_points_by_cl_region_rs(&rust_centerline, &rust_frames, &points);
336
180
 
337
181
  Ok(result_points)
338
182
  }
@@ -367,7 +211,7 @@ pub fn clean_outlier_points(
367
211
  neighborhood_radius: f64,
368
212
  min_neigbor_ratio: f64,
369
213
  ) -> PyResult<(Vec<Point3D>, Vec<Point3D>)> {
370
- let result_points = clean_up_non_section_points(
214
+ let result_points = scale_coronary::clean_up_non_section_points(
371
215
  points_to_cleanup,
372
216
  reference_points,
373
217
  neighborhood_radius,
@@ -414,7 +258,7 @@ pub fn find_proximal_distal_scaling(
414
258
  distal_reference: Vec<Point3D>,
415
259
  ) -> PyResult<(f64, f64)> {
416
260
  let rust_centerline = centerline.to_rust_centerline();
417
- let (prox_dist, distal_dist) = centerline_based_diameter_optimization(
261
+ let (prox_dist, distal_dist) = scale_coronary::centerline_based_diameter_optimization(
418
262
  &anomalous_points,
419
263
  n_proximal,
420
264
  n_distal,
@@ -451,7 +295,7 @@ pub fn find_aortic_scaling(
451
295
  centerline: PyCenterline,
452
296
  ) -> PyResult<f64> {
453
297
  let rust_centerline = centerline.to_rust_centerline();
454
- let dist = centerline_based_aortic_diameter_optimization(
298
+ let dist = scale_coronary::centerline_based_aortic_diameter_optimization(
455
299
  &intramural_points,
456
300
  &reference_points,
457
301
  &rust_centerline,
@@ -490,7 +334,7 @@ pub fn find_aortic_wall_scaling(
490
334
  aortic_pts: Vec<Point3D>,
491
335
  ) -> PyResult<f64> {
492
336
  let rust_centerline = cl_aorta.to_rust_centerline();
493
- let dist = centerline_based_wall_diameter_optimization(
337
+ let dist = scale_coronary::centerline_based_wall_diameter_optimization(
494
338
  &rust_centerline,
495
339
  &ref_pt_coronary,
496
340
  &aortic_pts,
@@ -586,7 +430,13 @@ pub fn discretize_vessel(
586
430
  n_points: usize,
587
431
  ) -> PyResult<Vec<PyContour>> {
588
432
  let rust_centerline = centerline.to_rust_centerline();
589
- let contours = discretize_vessel_rs(&rust_centerline, &points, branch_id, step_size, n_points);
433
+ let contours = discretizing::discretize_vessel_rs(
434
+ &rust_centerline,
435
+ &points,
436
+ branch_id,
437
+ step_size,
438
+ n_points,
439
+ );
590
440
  Ok(contours.iter().map(PyContour::from).collect())
591
441
  }
592
442
 
@@ -1,5 +1,4 @@
1
- use crate::intravascular::io::geometry::{Contour, ContourType};
2
- use crate::intravascular::io::input::{Centerline, CenterlinePoint, ContourPoint};
1
+ use crate::types::native::{Centerline, CenterlinePoint, Contour, ContourPoint, ContourType};
3
2
  use nalgebra::Vector3;
4
3
 
5
4
  /// Walks branch `branch_id` at uniform arc-length steps of `step_size`, assigns each mesh point
@@ -206,7 +205,7 @@ fn interpolate_branch_at_s(
206
205
  #[cfg(test)]
207
206
  mod tests {
208
207
  use super::*;
209
- use crate::intravascular::io::input::{Centerline, CenterlinePoint, ContourPoint};
208
+ use crate::types::native::{Centerline, CenterlinePoint, ContourPoint};
210
209
  use nalgebra::Vector3;
211
210
 
212
211
  fn cp(idx: u32, x: f64, y: f64, z: f64) -> ContourPoint {
@@ -1,5 +1,4 @@
1
- use crate::intravascular::io::geometry::Contour;
2
- use crate::intravascular::io::input::ContourPoint;
1
+ use crate::types::native::{Contour, ContourPoint};
3
2
  use nalgebra::Vector3;
4
3
 
5
4
  /// Filters and resamples raw projected slices from `walk_centerline_slices`:
@@ -230,8 +229,7 @@ fn catmull_rom(
230
229
  #[cfg(test)]
231
230
  mod tests {
232
231
  use super::*;
233
- use crate::intravascular::io::geometry::{Contour, ContourType};
234
- use crate::intravascular::io::input::ContourPoint;
232
+ use crate::types::native::{Contour, ContourPoint, ContourType};
235
233
 
236
234
  fn make_point(x: f64, y: f64, z: f64) -> ContourPoint {
237
235
  ContourPoint {
@@ -1,4 +1,4 @@
1
- use crate::intravascular::io::input::{Centerline, CenterlinePoint, ContourPoint};
1
+ use crate::types::native::{Centerline, CenterlinePoint, ContourPoint};
2
2
  use nalgebra::Vector3;
3
3
 
4
4
  /// Smooths centerline positions with a Gaussian kernel (per branch) and recomputes normals.
@@ -149,7 +149,7 @@ pub fn smooth_centerline(centerline: &Centerline, sigma: f64) -> Centerline {
149
149
  #[cfg(test)]
150
150
  mod tests {
151
151
  use super::*;
152
- use crate::intravascular::io::input::ContourPoint;
152
+ use crate::types::native::ContourPoint;
153
153
 
154
154
  fn make_centerline(pts: &[(f64, f64, f64)]) -> Centerline {
155
155
  let contour_pts: Vec<ContourPoint> = pts
@@ -0,0 +1,82 @@
1
+ use crate::types::native::{Centerline, Contour, DiscretizedVesselTree};
2
+ use anyhow::Result;
3
+
4
+ impl DiscretizedVesselTree {
5
+ /// Discretize the full vessel tree from pre-labelled point sets.
6
+ ///
7
+ /// Smooths all three centerlines with a Gaussian (σ = 2.5 points) before
8
+ /// discretizing, then processes:
9
+ /// - aorta (branch 0)
10
+ /// - RCA main vessel (`branch_id_rca`, usually 0)
11
+ /// - LCA main vessel (`branch_id_lca`, usually 0)
12
+ /// - every RCA side branch: `side_branches_rca[i]` → branch_id `i + 1`
13
+ /// - every LCA side branch: `side_branches_lca[i]` → branch_id `i + 1`
14
+ ///
15
+ /// `side_branches_rca` / `side_branches_lca` come from `label_branches` results:
16
+ /// `results["rca_points_side_1"]`, `results["rca_points_side_2"]`, …, in order.
17
+ pub fn from_results_dict(
18
+ ao_cl: &Centerline,
19
+ rca_cl: &Centerline,
20
+ lca_cl: &Centerline,
21
+ points_ao: &[(f64, f64, f64)],
22
+ points_rca_main: &[(f64, f64, f64)],
23
+ points_lca_main: &[(f64, f64, f64)],
24
+ side_branches_rca: Vec<Vec<(f64, f64, f64)>>,
25
+ side_branches_lca: Vec<Vec<(f64, f64, f64)>>,
26
+ branch_id_rca: u32,
27
+ branch_id_lca: u32,
28
+ step_size: f64,
29
+ n_points: usize,
30
+ ) -> Result<DiscretizedVesselTree> {
31
+ let discretized_aorta =
32
+ super::discretize_vessel_rs(ao_cl, points_ao, 0, step_size, n_points);
33
+ let discretized_rca_main = super::discretize_vessel_rs(
34
+ rca_cl,
35
+ points_rca_main,
36
+ branch_id_rca,
37
+ step_size,
38
+ n_points,
39
+ );
40
+ let discretized_lca_main = super::discretize_vessel_rs(
41
+ lca_cl,
42
+ points_lca_main,
43
+ branch_id_lca,
44
+ step_size,
45
+ n_points,
46
+ );
47
+
48
+ let rca_branches: Vec<Vec<Contour>> = side_branches_rca
49
+ .iter()
50
+ .enumerate()
51
+ .map(|(i, pts)| {
52
+ super::discretize_vessel_rs(rca_cl, pts, (i + 1) as u32, step_size, n_points)
53
+ })
54
+ .collect();
55
+
56
+ let lca_branches: Vec<Vec<Contour>> = side_branches_lca
57
+ .iter()
58
+ .enumerate()
59
+ .map(|(i, pts)| {
60
+ super::discretize_vessel_rs(lca_cl, pts, (i + 1) as u32, step_size, n_points)
61
+ })
62
+ .collect();
63
+
64
+ Ok(DiscretizedVesselTree {
65
+ discretized_aorta,
66
+ discretized_rca_main,
67
+ discretized_lca_main,
68
+ spacing: step_size,
69
+ rca_branches,
70
+ lca_branches,
71
+ rca_references: vec![],
72
+ lca_references: vec![],
73
+ ao_lca: (0.0, 0.0, 0.0),
74
+ ao_rca: (0.0, 0.0, 0.0),
75
+ pts_cusp_rcc: None,
76
+ pts_cusp_lcc: None,
77
+ pts_cusp_acc: None,
78
+ index_stj_slice: None,
79
+ index_aa: None,
80
+ })
81
+ }
82
+ }
@@ -3,10 +3,7 @@ pub mod resampling;
3
3
  mod utils;
4
4
  pub mod vessel_tree;
5
5
 
6
- use crate::ccta::discretizing::projecting::walk_centerline_slices;
7
- use crate::ccta::discretizing::resampling::create_uniform_contours;
8
- use crate::intravascular::io::geometry::Contour;
9
- use crate::intravascular::io::input::Centerline;
6
+ use crate::types::native::{Centerline, Contour};
10
7
 
11
8
  /// Walk `branch_id` of `centerline` at uniform `step_size` intervals, project the supplied
12
9
  /// mesh `points` onto each perpendicular cross-section, filter incomplete slices, and
@@ -21,6 +18,6 @@ pub fn discretize_vessel_rs(
21
18
  const SMOOTH_SIGMA: f64 = 2.5;
22
19
 
23
20
  let cl_smooth = utils::smooth_centerline(centerline, SMOOTH_SIGMA);
24
- let raw = walk_centerline_slices(&cl_smooth, points, branch_id, step_size);
25
- create_uniform_contours(raw, n_points)
21
+ let raw = projecting::walk_centerline_slices(&cl_smooth, points, branch_id, step_size);
22
+ resampling::create_uniform_contours(raw, n_points)
26
23
  }
@@ -1,7 +1,7 @@
1
- use crate::intravascular::{
2
- binding::classes::{PyCenterline, PyContourType, PyGeometry, PyGeometryPair},
3
- centerline_align::{align_combined_rs, align_manual_rs, align_three_point_rs},
1
+ use crate::intravascular::centerline_align::{
2
+ align_combined_rs, align_manual_rs, align_three_point_rs,
4
3
  };
4
+ use crate::types::binding::{PyCenterline, PyContourType, PyGeometry, PyGeometryPair};
5
5
  use pyo3::prelude::*;
6
6
 
7
7
  /// Align a geometry (or geometry pair) to the centerline using three reference points.