multimodars 0.7.2__tar.gz → 0.7.4__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.
- {multimodars-0.7.2 → multimodars-0.7.4}/CHANGELOG.md +68 -1
- {multimodars-0.7.2 → multimodars-0.7.4}/Cargo.lock +1 -1
- {multimodars-0.7.2 → multimodars-0.7.4}/Cargo.toml +1 -1
- {multimodars-0.7.2 → multimodars-0.7.4}/PKG-INFO +3 -3
- {multimodars-0.7.2 → multimodars-0.7.4}/README.md +2 -2
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/_processing.py +63 -20
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/ccta/__init__.py +19 -13
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/ccta/stitching/boundary.py +337 -168
- multimodars-0.7.4/multimodars/ccta/stitching/core.py +459 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/io/read_geometrical.py +9 -25
- {multimodars-0.7.2 → multimodars-0.7.4}/src/ccta/discretizing/resampling.rs +2 -11
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/binding/align.rs +12 -3
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/centerline_align/align.rs +20 -123
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/centerline_align/align_algorithms.rs +94 -42
- multimodars-0.7.4/src/intravascular/centerline_align/preprocessing.rs +316 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/io/input.rs +6 -7
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types/native/centerline.rs +117 -32
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types/native/geometry.rs +38 -6
- multimodars-0.7.4/src/types/native.rs +111 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/tests/test_ccta.py +369 -29
- multimodars-0.7.4/uv.lock +4004 -0
- multimodars-0.7.2/.claude/debug_meshes/stitched_after_fix.stl +0 -0
- multimodars-0.7.2/multimodars/ccta/stitching/core.py +0 -366
- multimodars-0.7.2/src/intravascular/centerline_align/preprocessing.rs +0 -605
- multimodars-0.7.2/src/types/native.rs +0 -52
- {multimodars-0.7.2 → multimodars-0.7.4}/.gitattributes +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/.github/workflows/CI.yml +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/.gitignore +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/.pre-commit-config.yaml +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/.readthedocs.yaml +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/CITATION.cff +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/CONTRIBUTING.md +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/LICENSE +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/ROADMAP.MD +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/benchmarks/BENCHMARK_PLAN.md +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/benchmarks/benchmark_bruteforce_stepsize.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/benchmarks/benchmark_cpu_scaling.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/benchmarks/results/bruteforce_stepsize.png +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/benchmarks/results/cpu_scaling.png +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/idealized_geometry/branch_diastolic_contours.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/idealized_geometry/branch_systolic_contours.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/idealized_geometry/calcium_diastolic_contours.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/idealized_geometry/calcium_systolic_contours.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/idealized_geometry/diastolic_contours.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/idealized_geometry/diastolic_reference_points.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/idealized_geometry/eem_diastolic_contours.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/idealized_geometry/eem_systolic_contours.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/idealized_geometry/systolic_contours.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/idealized_geometry/systolic_reference_points.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/ivus_full/branch_diastolic_contours.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/ivus_full/branch_systolic_contours.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/ivus_full/calcium_diastolic_contours.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/ivus_full/calcium_systolic_contours.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/ivus_full/diastolic_contours.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/ivus_full/diastolic_reference_points.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/ivus_full/eem_diastolic_contours.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/ivus_full/eem_systolic_contours.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/ivus_full/systolic_contours.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/ivus_full/systolic_reference_points.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/ivus_rest/combined_sorted_manual.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/ivus_rest/diastolic_contours.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/ivus_rest/diastolic_reference_points.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/ivus_rest/systolic_contours.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/ivus_rest/systolic_reference_points.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/ivus_stress/combined_sorted_manual.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/ivus_stress/diastolic_contours.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/ivus_stress/diastolic_reference_points.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/ivus_stress/systolic_contours.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/data/fixtures/ivus_stress/systolic_reference_points.csv +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/media/coronary_artery_disease.jpg +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/media/dynamic_lumen_changes.png +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/media/multimoda-rs.jpg +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/__init__.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/_converters.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/ccta/centerline_prep.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/ccta/debug_plots.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/ccta/discretization_map.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/ccta/labeling/__init__.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/ccta/labeling/core.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/ccta/labeling/helpers.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/ccta/mesh_regions.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/ccta/postprocessing.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/ccta/scaling.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/ccta/scaling_helpers.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/ccta/stitching/__init__.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/ccta/stitching/helpers.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/io/__init__.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/io/write_geometries.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/multimodars.pyi +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/multimodars/py.typed +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/paper/REVIEWER1.md +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/paper/REVIEWER2.md +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/paper/bibliography.bib +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/paper/figures/Figure1.jpg +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/paper/figures/Figure2.jpg +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/paper/figures/Figure3.png +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/paper/figures/Figure4.jpg +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/paper/paper.md +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/pyproject.toml +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/ccta/adjust_mesh/label_coronary.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/ccta/adjust_mesh/scale_coronary.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/ccta/adjust_mesh.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/ccta/binding/ccta_py.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/ccta/binding.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/ccta/discretizing/plan.md +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/ccta/discretizing/projecting.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/ccta/discretizing/vessel_tree.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/ccta/discretizing.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/ccta.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/binding/entry.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/binding/functions.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/binding.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/centerline_align.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/io/build.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/io/integrity_check.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/io/output.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/io.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/processing/align_between.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/processing/align_within.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/processing/postprocessing.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/processing/preprocessing.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/processing/process_utils.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/processing/wall.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/processing.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/to_object/interpolation.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/to_object/process.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/to_object/texture.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/to_object/write_mtl.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/to_object.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/utils/general_utils.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/utils/test_utils.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular/utils.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/intravascular.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/lib.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types/binding/py_centerline.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types/binding/py_centerline_point.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types/binding/py_contour.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types/binding/py_contour_point.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types/binding/py_discretized_vessel_tree.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types/binding/py_frame.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types/binding/py_geometry.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types/binding/py_geometry_pair.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types/binding/py_input_data.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types/binding/py_record.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types/binding.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types/native/centerline_point.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types/native/contour.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types/native/contour_point.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types/native/discretized_tree.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types/native/frame.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types/native/geometry_pair.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types/native/record.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/src/types.rs +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/tests/conftest.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/tests/test_converters.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/tests/test_core.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/tests/test_intravascular.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/tests/test_wrappers.py +0 -0
- {multimodars-0.7.2 → multimodars-0.7.4}/tests/tests_todo.md +0 -0
|
@@ -3,6 +3,73 @@
|
|
|
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.7.4] - 2026-10-02
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
- Alignment: the reference point is found on the full-resolution centerline and the resampling
|
|
10
|
+
is anchored on it, instead of snapping to the nearest frame-spaced sample (up to half a spacing).
|
|
11
|
+
- Alignment: the reference frame, not frame 0, is placed on the reference point, matching the
|
|
12
|
+
rotation search. Frames off either end of the centerline no longer shift the rest.
|
|
13
|
+
- `find_ref_frame_idx` returns the frame's position instead of its `id`.
|
|
14
|
+
- Alignment: centerlines given in ascending z kept backwards tangents after being reversed, so
|
|
15
|
+
frames were rotated to face against the centerline.
|
|
16
|
+
- Alignment: the resampled centerline no longer drops up to one spacing at its distal end.
|
|
17
|
+
- `Centerline.resample` no longer adds a near-duplicate point before the end through float drift.
|
|
18
|
+
|
|
19
|
+
### Internal
|
|
20
|
+
- Alignment preprocessing uses `Centerline::resample_anchored` instead of its own copy. Shared
|
|
21
|
+
`cumulative_arc_length` / `mean_spacing` helpers replace the hand-written versions.
|
|
22
|
+
|
|
23
|
+
## [0.7.3] - 2026-09-28
|
|
24
|
+
Smoother anomalous ostium. The two halves of the ostial ring now meet in smooth arcs instead of
|
|
25
|
+
sharp kinks, the ring's correction is faded into the aortic mesh all the way round, and the fillet
|
|
26
|
+
only rounds the aorta-facing half - towards the aorta rather than back into the vessel. On
|
|
27
|
+
`examples/data` the raw stitched mesh goes from 220 to 81 self-intersecting faces at the ostium
|
|
28
|
+
(235 to 47 after `fix_and_remesh_stitched_mesh`). Still to do: most of the rest sit at one tip of
|
|
29
|
+
the slit-like ostium, where the aortic wall touches the first millimetres of the intravascular tube.
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
- `stitch_ccta_to_intravascular` gained `seam_points_a` / `seam_points_b` (default 2 / 4). At both
|
|
33
|
+
seams where the ostium's aorta-facing Half A meets its coronary-facing Half B, that many Half A /
|
|
34
|
+
Half B points are replaced by a smooth arc that follows each half's own direction. Everything
|
|
35
|
+
outside those ranges stays exactly in place, so Half A's mid-section keeps its wall-thickness
|
|
36
|
+
offset from the intravascular ostium. The counts are points on the CCTA ring as cut from the
|
|
37
|
+
mesh, before it is densified; more than a half can give are reduced with a warning. Only used
|
|
38
|
+
with `prox_start_mode="highest_z"` and `proximal_is_ostium=True`.
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
- `fillet_bulge` now only rounds the ostium's Half A, fading out along the seam arcs; Half B and
|
|
42
|
+
the distal seam stay direct strips (0.7.2 rounded every strut of both seams). It needs
|
|
43
|
+
`prox_start_mode="highest_z"` with `proximal_is_ostium=True`, otherwise a warning is printed and
|
|
44
|
+
the direct strip is used.
|
|
45
|
+
- The two-half ostium's IV-plane clamp now runs before the seam arcs are built, so it cannot
|
|
46
|
+
flatten them back into a kink. What triggers it (ring and IV plane at least 45° apart) is
|
|
47
|
+
unchanged.
|
|
48
|
+
|
|
49
|
+
### Fixed
|
|
50
|
+
- The fillet's arcs bulged away from the combined centroid of both rings, which on an anomalous
|
|
51
|
+
ostium sent many of them back into the vessel (47 of 100 on `examples/data`). They now bulge
|
|
52
|
+
away from the intravascular geometry, along the ostial frame's outward normal.
|
|
53
|
+
- Only Half A's displacement was faded into the surrounding aortic mesh, so the faces behind
|
|
54
|
+
Half B's moved rim folded through the intravascular tube. The whole ring's displacement is now
|
|
55
|
+
faded in.
|
|
56
|
+
- A zero-length strut no longer misaligns the fillet's intermediate rings.
|
|
57
|
+
- `stitch` (the one-call wrapper) failed with its default regions: it removed them with
|
|
58
|
+
`target_boundaries=1`, merging the two rims into one ring, which stitching then rejected. It now
|
|
59
|
+
keeps both rims.
|
|
60
|
+
- `read_mesh` no longer falls back to face-cleanup methods that trimesh 4 removed; they could only
|
|
61
|
+
hide an error.
|
|
62
|
+
|
|
63
|
+
### Internal
|
|
64
|
+
- `_redistribute_ring_evenly`'s arc-length sampling moved into `_even_arclength_samples`, so
|
|
65
|
+
per-point values (the Half A weights) resample with the points.
|
|
66
|
+
- `_condition_ostium_ring_two_half` and `_prepare_prox_dist_boundary_pts` also return the Half A
|
|
67
|
+
weights; `_carry_ring_weights` keeps them with their points through densification, start-point
|
|
68
|
+
rotation and winding fixes.
|
|
69
|
+
- `_bulge_arc_points` is replaced by the vectorised `_fillet_arc_layers`.
|
|
70
|
+
`_taper_ring_displacement` lost `protected_pts` / `seam_damping`, which fading the whole ring
|
|
71
|
+
no longer needs.
|
|
72
|
+
|
|
6
73
|
## [0.7.2] - 2026-09-19
|
|
7
74
|
More anatomical approach in creating the anomalous ostium. Takes the wall measurement to create
|
|
8
75
|
and offset. This ensures that the ostium is represented like the ostium from the intravascular
|
|
@@ -162,7 +229,7 @@ kind of a dome on top of this plane.
|
|
|
162
229
|
### Fixed
|
|
163
230
|
- `align_manual` no explicitly states `rotation_angle_deg` instead of `rotation_angle`
|
|
164
231
|
|
|
165
|
-
|
|
232
|
+
### Changed
|
|
166
233
|
- `align_manual`, `align_combined` and `align_three_points` all return their rotation angle now.
|
|
167
234
|
|
|
168
235
|
## [0.5.4] - 2026-08-03 Hotfix
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: multimodars
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.4
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
6
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
@@ -36,7 +36,7 @@ Project-URL: Issues, https://github.com/yungselm/multimoda-rs/issues
|
|
|
36
36
|
> Brace for breaking changes!
|
|
37
37
|
|
|
38
38
|
[](https://pypi.org/project/multimodars)
|
|
39
|
-
[](https://pepy.tech/project/multimodars)
|
|
39
|
+
<!-- [](https://pepy.tech/project/multimodars) -->
|
|
40
40
|
[](LICENSE)
|
|
41
41
|
[](https://multimoda-rs.readthedocs.io)
|
|
42
42
|
[](https://github.com/yungselm/multimoda-rs/actions/workflows/CI.yml)
|
|
@@ -104,7 +104,7 @@ rest, stress, dia, sys, _ = mm.from_file_full(
|
|
|
104
104
|
# Align geometry onto a CCTA-derived centerline
|
|
105
105
|
cl_raw = np.genfromtxt("examples/data/centerline_raw.csv", delimiter=",")
|
|
106
106
|
centerline = mm.numpy_to_centerline(cl_raw)
|
|
107
|
-
aligned_pair,
|
|
107
|
+
aligned_pair, spacing_mm, total_rotation_deg = mm.align_three_point(
|
|
108
108
|
centerline, rest,
|
|
109
109
|
main_ref_pt=(12.2605, -201.3643, 1751.0554),
|
|
110
110
|
counterclockwise_ref_pt=(11.7567, -202.1920, 1754.7975),
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
> Brace for breaking changes!
|
|
13
13
|
|
|
14
14
|
[](https://pypi.org/project/multimodars)
|
|
15
|
-
[](https://pepy.tech/project/multimodars)
|
|
15
|
+
<!-- [](https://pepy.tech/project/multimodars) -->
|
|
16
16
|
[](LICENSE)
|
|
17
17
|
[](https://multimoda-rs.readthedocs.io)
|
|
18
18
|
[](https://github.com/yungselm/multimoda-rs/actions/workflows/CI.yml)
|
|
@@ -80,7 +80,7 @@ rest, stress, dia, sys, _ = mm.from_file_full(
|
|
|
80
80
|
# Align geometry onto a CCTA-derived centerline
|
|
81
81
|
cl_raw = np.genfromtxt("examples/data/centerline_raw.csv", delimiter=",")
|
|
82
82
|
centerline = mm.numpy_to_centerline(cl_raw)
|
|
83
|
-
aligned_pair,
|
|
83
|
+
aligned_pair, spacing_mm, total_rotation_deg = mm.align_three_point(
|
|
84
84
|
centerline, rest,
|
|
85
85
|
main_ref_pt=(12.2605, -201.3643, 1751.0554),
|
|
86
86
|
counterclockwise_ref_pt=(11.7567, -202.1920, 1754.7975),
|
|
@@ -1,31 +1,65 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from .multimodars import (
|
|
4
|
+
PyCenterline,
|
|
4
5
|
PyContour,
|
|
5
6
|
PyContourType,
|
|
7
|
+
PyDiscretizedVesselTree, # noqa: F401 — re-exported for type annotations
|
|
6
8
|
PyGeometry,
|
|
7
9
|
PyGeometryPair,
|
|
8
10
|
PyInputData,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
from_file_full as _from_file_full,
|
|
12
|
-
from_file_doublepair as _from_file_doublepair,
|
|
13
|
-
from_file_singlepair as _from_file_singlepair,
|
|
14
|
-
from_file_single as _from_file_single,
|
|
15
|
-
from_array_full as _from_array_full,
|
|
16
|
-
from_array_doublepair as _from_array_doublepair,
|
|
17
|
-
from_array_singlepair as _from_array_singlepair,
|
|
18
|
-
from_array_single as _from_array_single,
|
|
19
|
-
align_three_point as _align_three_point,
|
|
20
|
-
align_manual as _align_manual,
|
|
11
|
+
)
|
|
12
|
+
from .multimodars import (
|
|
21
13
|
align_combined as _align_combined,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
14
|
+
)
|
|
15
|
+
from .multimodars import (
|
|
16
|
+
align_manual as _align_manual,
|
|
17
|
+
)
|
|
18
|
+
from .multimodars import (
|
|
19
|
+
align_three_point as _align_three_point,
|
|
20
|
+
)
|
|
21
|
+
from .multimodars import (
|
|
26
22
|
build_adjacency_map as _build_adjacency_map,
|
|
23
|
+
)
|
|
24
|
+
from .multimodars import (
|
|
27
25
|
discretize_vessel as _discretize_vessel,
|
|
28
26
|
)
|
|
27
|
+
from .multimodars import (
|
|
28
|
+
find_centerline_bounded_points_simple as _find_centerline_bounded_points_simple,
|
|
29
|
+
)
|
|
30
|
+
from .multimodars import (
|
|
31
|
+
find_proximal_distal_scaling as _find_proximal_distal_scaling,
|
|
32
|
+
)
|
|
33
|
+
from .multimodars import (
|
|
34
|
+
from_array_doublepair as _from_array_doublepair,
|
|
35
|
+
)
|
|
36
|
+
from .multimodars import (
|
|
37
|
+
from_array_full as _from_array_full,
|
|
38
|
+
)
|
|
39
|
+
from .multimodars import (
|
|
40
|
+
from_array_single as _from_array_single,
|
|
41
|
+
)
|
|
42
|
+
from .multimodars import (
|
|
43
|
+
from_array_singlepair as _from_array_singlepair,
|
|
44
|
+
)
|
|
45
|
+
from .multimodars import (
|
|
46
|
+
from_file_doublepair as _from_file_doublepair,
|
|
47
|
+
)
|
|
48
|
+
from .multimodars import (
|
|
49
|
+
from_file_full as _from_file_full,
|
|
50
|
+
)
|
|
51
|
+
from .multimodars import (
|
|
52
|
+
from_file_single as _from_file_single,
|
|
53
|
+
)
|
|
54
|
+
from .multimodars import (
|
|
55
|
+
from_file_singlepair as _from_file_singlepair,
|
|
56
|
+
)
|
|
57
|
+
from .multimodars import (
|
|
58
|
+
read_centerline_vtp as _read_centerline_vtp,
|
|
59
|
+
)
|
|
60
|
+
from .multimodars import (
|
|
61
|
+
to_obj as _to_obj,
|
|
62
|
+
)
|
|
29
63
|
|
|
30
64
|
_AlignLog = list[tuple[int, int, float, float, float, float, float]]
|
|
31
65
|
|
|
@@ -1035,7 +1069,10 @@ def align_three_point(
|
|
|
1035
1069
|
geometry : PyGeometryPair or PyGeometry
|
|
1036
1070
|
Single geometry or diastolic/systolic geometry pair to align.
|
|
1037
1071
|
main_ref_pt : tuple of float
|
|
1038
|
-
``(x, y, z)`` reference point at the aortic ostium.
|
|
1072
|
+
``(x, y, z)`` reference point at the aortic ostium. The geometry's reference
|
|
1073
|
+
frame (the first frame with a reference point) is placed on the closest
|
|
1074
|
+
centerline point; frames that do not fit on the centerline are left
|
|
1075
|
+
unaligned and reported in a warning.
|
|
1039
1076
|
counterclockwise_ref_pt : tuple of float
|
|
1040
1077
|
``(x, y, z)`` counterclockwise reference point (viewed proximal → distal).
|
|
1041
1078
|
clockwise_ref_pt : tuple of float
|
|
@@ -1131,7 +1168,10 @@ def align_manual(
|
|
|
1131
1168
|
rotation_angle_deg : float
|
|
1132
1169
|
Rotation angle in degrees to apply.
|
|
1133
1170
|
ref_point : tuple of float
|
|
1134
|
-
``(x, y, z)`` reference point on the centerline.
|
|
1171
|
+
``(x, y, z)`` reference point on the centerline. The geometry's reference
|
|
1172
|
+
frame (the first frame with a reference point, else frame 0) is placed on
|
|
1173
|
+
the closest centerline point; frames that do not fit on the centerline are
|
|
1174
|
+
left unaligned and reported in a warning.
|
|
1135
1175
|
write : bool, optional
|
|
1136
1176
|
Whether to write the aligned meshes to OBJ files. Default is ``False``.
|
|
1137
1177
|
watertight : bool, optional
|
|
@@ -1219,7 +1259,10 @@ def align_combined(
|
|
|
1219
1259
|
geometry : PyGeometryPair or PyGeometry
|
|
1220
1260
|
Single geometry or diastolic/systolic geometry pair to align.
|
|
1221
1261
|
main_ref_pt : tuple of float
|
|
1222
|
-
``(x, y, z)`` reference point at the aortic ostium.
|
|
1262
|
+
``(x, y, z)`` reference point at the aortic ostium. The geometry's reference
|
|
1263
|
+
frame (the first frame with a reference point) is placed on the closest
|
|
1264
|
+
centerline point; frames that do not fit on the centerline are left
|
|
1265
|
+
unaligned and reported in a warning.
|
|
1223
1266
|
counterclockwise_ref_pt : tuple of float
|
|
1224
1267
|
``(x, y, z)`` counterclockwise reference point (viewed proximal → distal).
|
|
1225
1268
|
clockwise_ref_pt : tuple of float
|
|
@@ -1505,7 +1548,7 @@ def build_adjacency_map(
|
|
|
1505
1548
|
|
|
1506
1549
|
|
|
1507
1550
|
def discretize_vessel(
|
|
1508
|
-
centerline:
|
|
1551
|
+
centerline: PyCenterline,
|
|
1509
1552
|
points: list[tuple[float, float, float]],
|
|
1510
1553
|
branch_id: int = 0,
|
|
1511
1554
|
step_size: float = 0.5,
|
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from . import stitching
|
|
4
|
-
from . import scaling
|
|
5
|
-
from . import labeling
|
|
6
|
-
from . import centerline_prep
|
|
7
|
-
from . import debug_plots as debug_plots
|
|
8
|
-
from . import mesh_regions
|
|
9
|
-
from . import postprocessing as _postprocessing
|
|
10
|
-
|
|
11
3
|
from pathlib import Path
|
|
12
4
|
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
13
6
|
import numpy as np
|
|
14
7
|
import trimesh
|
|
15
8
|
|
|
16
9
|
from ..io.write_geometries import export_section_stl as export_section_stl
|
|
10
|
+
from . import centerline_prep, labeling, mesh_regions, scaling, stitching
|
|
11
|
+
from . import debug_plots as debug_plots
|
|
12
|
+
from . import postprocessing as _postprocessing
|
|
17
13
|
|
|
18
14
|
if TYPE_CHECKING:
|
|
19
15
|
from ..multimodars import PyCenterline, PyFrame, PyGeometry
|
|
@@ -264,7 +260,7 @@ def scale(
|
|
|
264
260
|
def stitch(
|
|
265
261
|
results: dict,
|
|
266
262
|
geometry: PyGeometry,
|
|
267
|
-
region_remove: list[str] | str =
|
|
263
|
+
region_remove: list[str] | str | None = None,
|
|
268
264
|
prox_start_mode: str = "highest_z",
|
|
269
265
|
dist_start_mode: str = "nearest_iv",
|
|
270
266
|
) -> dict:
|
|
@@ -291,12 +287,18 @@ def stitch(
|
|
|
291
287
|
geometry : PyGeometry
|
|
292
288
|
Intravascular imaging geometry whose contours define the vessel lumen
|
|
293
289
|
used as the stitching target.
|
|
290
|
+
region_remove : str or list of str, optional
|
|
291
|
+
Labeled regions cut out of the CCTA mesh before stitching (default
|
|
292
|
+
``["anomalous_points", "proximal_points"]``).
|
|
294
293
|
prox_start_mode : str, optional
|
|
295
294
|
How to choose index 0 of the proximal boundary ring before stitching.
|
|
296
|
-
``"
|
|
297
|
-
|
|
295
|
+
``"highest_z"`` (default here) rotates to the point with the largest
|
|
296
|
+
z-coordinate and treats the ostium as two halves (see
|
|
297
|
+
:func:`~multimodars.ccta.stitching.stitch_ccta_to_intravascular`);
|
|
298
|
+
``"nearest_iv"`` rotates to the point closest to IV point 0.
|
|
298
299
|
dist_start_mode : str, optional
|
|
299
|
-
Same as *prox_start_mode* but for the distal boundary ring
|
|
300
|
+
Same as *prox_start_mode* but for the distal boundary ring (default
|
|
301
|
+
``"nearest_iv"``).
|
|
300
302
|
|
|
301
303
|
Returns
|
|
302
304
|
-------
|
|
@@ -304,8 +306,12 @@ def stitch(
|
|
|
304
306
|
Stitched results dictionary with the same structure as *results*, where
|
|
305
307
|
``"mesh"`` is the stitched, hole-filled surface.
|
|
306
308
|
"""
|
|
309
|
+
if region_remove is None:
|
|
310
|
+
region_remove = ["anomalous_points", "proximal_points"]
|
|
311
|
+
# Cutting a segment out of the vessel opens a rim at each end, and the
|
|
312
|
+
# stitch needs both as separate rings.
|
|
307
313
|
updated_results = mesh_regions.remove_labeled_points_from_mesh(
|
|
308
|
-
results, region_remove
|
|
314
|
+
results, region_remove, target_boundaries=2
|
|
309
315
|
)
|
|
310
316
|
|
|
311
317
|
stitched = stitching.stitch_ccta_to_intravascular(
|