multimodars 0.4.2__tar.gz → 0.4.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.
- {multimodars-0.4.2 → multimodars-0.4.3}/CHANGELOG.md +7 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/Cargo.lock +1 -1
- {multimodars-0.4.2 → multimodars-0.4.3}/Cargo.toml +1 -1
- {multimodars-0.4.2 → multimodars-0.4.3}/PKG-INFO +1 -1
- {multimodars-0.4.2 → multimodars-0.4.3}/src/ccta/adjust_mesh/scale_coronary.rs +28 -28
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/binding/entry.rs +4 -28
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/centerline_align/align_algorithms.rs +4 -4
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/processing/align_between.rs +4 -4
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/processing/align_within.rs +8 -17
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/processing/postprocessing.rs +5 -5
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/processing/process_utils.rs +25 -74
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/to_object/write_mtl.rs +3 -28
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/binding/py_geometry.rs +2 -3
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/native/contour_point.rs +73 -1
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/native.rs +1 -1
- {multimodars-0.4.2 → multimodars-0.4.3}/.gitattributes +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/.github/workflows/CI.yml +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/.gitignore +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/.pre-commit-config.yaml +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/.readthedocs.yaml +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/CITATION.cff +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/CONTRIBUTING.md +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/LICENSE +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/README.md +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/ROADMAP.MD +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/benchmarks/BENCHMARK_PLAN.md +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/benchmarks/benchmark_bruteforce_stepsize.py +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/benchmarks/benchmark_cpu_scaling.py +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/benchmarks/results/bruteforce_stepsize.png +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/benchmarks/results/cpu_scaling.png +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/idealized_geometry/branch_diastolic_contours.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/idealized_geometry/branch_systolic_contours.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/idealized_geometry/calcium_diastolic_contours.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/idealized_geometry/calcium_systolic_contours.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/idealized_geometry/diastolic_contours.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/idealized_geometry/diastolic_reference_points.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/idealized_geometry/eem_diastolic_contours.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/idealized_geometry/eem_systolic_contours.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/idealized_geometry/systolic_contours.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/idealized_geometry/systolic_reference_points.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/ivus_full/branch_diastolic_contours.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/ivus_full/branch_systolic_contours.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/ivus_full/calcium_diastolic_contours.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/ivus_full/calcium_systolic_contours.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/ivus_full/diastolic_contours.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/ivus_full/diastolic_reference_points.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/ivus_full/eem_diastolic_contours.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/ivus_full/eem_systolic_contours.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/ivus_full/systolic_contours.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/ivus_full/systolic_reference_points.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/ivus_rest/combined_sorted_manual.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/ivus_rest/diastolic_contours.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/ivus_rest/diastolic_reference_points.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/ivus_rest/systolic_contours.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/ivus_rest/systolic_reference_points.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/ivus_stress/combined_sorted_manual.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/ivus_stress/diastolic_contours.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/ivus_stress/diastolic_reference_points.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/ivus_stress/systolic_contours.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/data/fixtures/ivus_stress/systolic_reference_points.csv +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/media/coronary_artery_disease.jpg +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/media/dynamic_lumen_changes.png +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/media/multimoda-rs.jpg +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/multimodars/__init__.py +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/multimodars/_converters.py +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/multimodars/_processing.py +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/multimodars/ccta/__init__.py +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/multimodars/ccta/debug_plots.py +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/multimodars/ccta/discretization_map.py +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/multimodars/ccta/fixing_functions.py +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/multimodars/ccta/labeling.py +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/multimodars/ccta/manipulating.py +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/multimodars/io/__init__.py +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/multimodars/io/read_geometrical.py +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/multimodars/io/write_geometries.py +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/multimodars/multimodars.pyi +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/multimodars/py.typed +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/paper/REVIEWER1.md +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/paper/REVIEWER2.md +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/paper/bibliography.bib +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/paper/figures/Figure1.jpg +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/paper/figures/Figure2.jpg +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/paper/figures/Figure3.png +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/paper/figures/Figure4.jpg +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/paper/paper.md +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/pyproject.toml +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/ccta/adjust_mesh/label_coronary.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/ccta/adjust_mesh.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/ccta/binding/ccta_py.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/ccta/binding.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/ccta/discretizing/plan.md +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/ccta/discretizing/projecting.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/ccta/discretizing/resampling.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/ccta/discretizing/utils.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/ccta/discretizing/vessel_tree.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/ccta/discretizing.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/ccta.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/binding/align.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/binding/functions.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/binding.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/centerline_align/align.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/centerline_align/preprocessing.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/centerline_align.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/io/build.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/io/geometry.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/io/input.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/io/integrity_check.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/io/output.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/io.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/processing/preprocessing.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/processing/wall.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/processing.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/to_object/interpolation.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/to_object/process.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/to_object/texture.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/to_object.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/utils/general_utils.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/utils/test_utils.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/utils.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/lib.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/binding/py_centerline.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/binding/py_centerline_point.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/binding/py_contour.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/binding/py_contour_point.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/binding/py_discretized_vessel_tree.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/binding/py_frame.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/binding/py_geometry_pair.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/binding/py_input_data.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/binding/py_record.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/binding.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/native/centerline.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/native/centerline_point.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/native/contour.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/native/discretized_tree.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/native/frame.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/native/geometry.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/native/geometry_pair.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/native/input_data.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types/native/record.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/src/types.rs +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/tests/conftest.py +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/tests/test_ccta.py +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/tests/test_converters.py +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/tests/test_core.py +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/tests/test_intravascular.py +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/tests/test_wrappers.py +0 -0
- {multimodars-0.4.2 → multimodars-0.4.3}/tests/tests_todo.md +0 -0
|
@@ -3,6 +3,13 @@
|
|
|
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.3] - 2026-06-04
|
|
7
|
+
Small refactor based on cargo modules analysis (https://github.com/regexident/cargo-modules)
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- Moved downsample points to top layer module `types`
|
|
11
|
+
- Renamed duplicate functions and names
|
|
12
|
+
|
|
6
13
|
## [0.4.2] - 2026-06-04
|
|
7
14
|
Large internal refactor to improve readability and decouple modules. No behaviour change.
|
|
8
15
|
|
|
@@ -2,12 +2,12 @@ use crate::types::native::{Centerline, CenterlinePoint, Frame};
|
|
|
2
2
|
use rayon::prelude::*;
|
|
3
3
|
use std::collections::HashSet;
|
|
4
4
|
|
|
5
|
-
type
|
|
5
|
+
type Coords3 = (f64, f64, f64);
|
|
6
6
|
|
|
7
7
|
pub fn centerline_based_wall_diameter_optimization(
|
|
8
8
|
centerline: &Centerline,
|
|
9
|
-
ref_point_coronary: &
|
|
10
|
-
aortic_points: &[
|
|
9
|
+
ref_point_coronary: &Coords3,
|
|
10
|
+
aortic_points: &[Coords3],
|
|
11
11
|
) -> f64 {
|
|
12
12
|
if centerline.points.is_empty() || aortic_points.is_empty() {
|
|
13
13
|
return 0.0;
|
|
@@ -25,7 +25,7 @@ pub fn centerline_based_wall_diameter_optimization(
|
|
|
25
25
|
None => return 0.0,
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
let closest_aortic: &
|
|
28
|
+
let closest_aortic: &Coords3 = match aortic_points.iter().min_by(|a, b| {
|
|
29
29
|
let dist_a = super::calculate_squared_distance(*a, ref_point_coronary);
|
|
30
30
|
let dist_b = super::calculate_squared_distance(*b, ref_point_coronary);
|
|
31
31
|
dist_a
|
|
@@ -66,8 +66,8 @@ pub fn centerline_based_wall_diameter_optimization(
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
pub fn centerline_based_aortic_diameter_optimization(
|
|
69
|
-
intramural_points: &[
|
|
70
|
-
reference_points: &[
|
|
69
|
+
intramural_points: &[Coords3],
|
|
70
|
+
reference_points: &[Coords3],
|
|
71
71
|
centerline: &Centerline,
|
|
72
72
|
) -> f64 {
|
|
73
73
|
let start = -2.0f64;
|
|
@@ -91,12 +91,12 @@ pub fn centerline_based_aortic_diameter_optimization(
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
pub fn centerline_based_diameter_optimization(
|
|
94
|
-
anomalous_points: &[
|
|
94
|
+
anomalous_points: &[Coords3],
|
|
95
95
|
n_proximal: usize,
|
|
96
96
|
n_distal: usize,
|
|
97
97
|
centerline: &Centerline,
|
|
98
|
-
proximal_reference: &[
|
|
99
|
-
distal_reference: &[
|
|
98
|
+
proximal_reference: &[Coords3],
|
|
99
|
+
distal_reference: &[Coords3],
|
|
100
100
|
) -> (f64, f64) {
|
|
101
101
|
let (proximal_points, anomalous_points_new) =
|
|
102
102
|
find_region_points(anomalous_points, proximal_reference, n_proximal);
|
|
@@ -134,10 +134,10 @@ pub fn centerline_based_diameter_optimization(
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
fn find_region_points(
|
|
137
|
-
anomalous_points: &[
|
|
138
|
-
reference_points: &[
|
|
137
|
+
anomalous_points: &[Coords3],
|
|
138
|
+
reference_points: &[Coords3],
|
|
139
139
|
n_points: usize,
|
|
140
|
-
) -> (Vec<
|
|
140
|
+
) -> (Vec<Coords3>, Vec<Coords3>) {
|
|
141
141
|
if anomalous_points.is_empty() || reference_points.is_empty() || n_points == 0 {
|
|
142
142
|
return (Vec::new(), anomalous_points.to_vec());
|
|
143
143
|
}
|
|
@@ -165,12 +165,12 @@ fn find_region_points(
|
|
|
165
165
|
|
|
166
166
|
let selected_indices: HashSet<usize> = selected_slice.iter().map(|(i, _)| *i).collect();
|
|
167
167
|
|
|
168
|
-
let selected_points: Vec<
|
|
168
|
+
let selected_points: Vec<Coords3> = selected_slice
|
|
169
169
|
.iter()
|
|
170
170
|
.map(|(i, _)| anomalous_points[*i])
|
|
171
171
|
.collect();
|
|
172
172
|
|
|
173
|
-
let remaining_points: Vec<
|
|
173
|
+
let remaining_points: Vec<Coords3> = anomalous_points
|
|
174
174
|
.iter()
|
|
175
175
|
.enumerate()
|
|
176
176
|
.filter_map(|(i, pt)| {
|
|
@@ -188,7 +188,7 @@ fn find_region_points(
|
|
|
188
188
|
/// Symmetric average nearest-neighbor distance between two point sets.
|
|
189
189
|
/// Returns sqrt of average squared distance for readability (i.e., RMS of nearest neighbor distances).
|
|
190
190
|
/// If either set is empty returns f64::INFINITY.
|
|
191
|
-
fn symmetric_nn_distance(a: &[
|
|
191
|
+
fn symmetric_nn_distance(a: &[Coords3], b: &[Coords3]) -> f64 {
|
|
192
192
|
if a.is_empty() || b.is_empty() {
|
|
193
193
|
return f64::INFINITY;
|
|
194
194
|
}
|
|
@@ -220,9 +220,9 @@ fn symmetric_nn_distance(a: &[Point3D], b: &[Point3D]) -> f64 {
|
|
|
220
220
|
|
|
221
221
|
pub fn centerline_based_diameter_morphing(
|
|
222
222
|
centerline: &Centerline,
|
|
223
|
-
points: &[
|
|
223
|
+
points: &[Coords3],
|
|
224
224
|
diameter_adjustment_mm: f64,
|
|
225
|
-
) -> Vec<
|
|
225
|
+
) -> Vec<Coords3> {
|
|
226
226
|
points
|
|
227
227
|
.par_iter()
|
|
228
228
|
.map(|point| {
|
|
@@ -257,7 +257,7 @@ pub fn centerline_based_diameter_morphing(
|
|
|
257
257
|
|
|
258
258
|
fn find_closest_centerline_point_optimized(
|
|
259
259
|
centerline: &Centerline,
|
|
260
|
-
point:
|
|
260
|
+
point: Coords3,
|
|
261
261
|
) -> &CenterlinePoint {
|
|
262
262
|
let mut min_distance_squared = f64::MAX;
|
|
263
263
|
let mut closest_point = ¢erline.points[0];
|
|
@@ -276,24 +276,24 @@ fn find_closest_centerline_point_optimized(
|
|
|
276
276
|
pub fn find_points_by_cl_region_rs(
|
|
277
277
|
centerline: &Centerline,
|
|
278
278
|
frames: &[Frame],
|
|
279
|
-
points: &[
|
|
280
|
-
) -> (Vec<
|
|
279
|
+
points: &[Coords3],
|
|
280
|
+
) -> (Vec<Coords3>, Vec<Coords3>, Vec<Coords3>) {
|
|
281
281
|
let mut cumulative_z_dist_frames = 0.0;
|
|
282
282
|
for i in 1..frames.len() {
|
|
283
283
|
cumulative_z_dist_frames += (frames[i].centroid.2 - frames[i - 1].centroid.2).abs();
|
|
284
284
|
}
|
|
285
285
|
cumulative_z_dist_frames /= (frames.len() - 1) as f64;
|
|
286
286
|
|
|
287
|
-
let centroids_to_match = frames.iter().map(|f| f.centroid).collect::<Vec<
|
|
287
|
+
let centroids_to_match = frames.iter().map(|f| f.centroid).collect::<Vec<Coords3>>();
|
|
288
288
|
let cl_points_indices: Vec<usize> =
|
|
289
289
|
find_cl_points_in_range(centerline, ¢roids_to_match, cumulative_z_dist_frames);
|
|
290
290
|
|
|
291
291
|
// needed for proximal/distal classification
|
|
292
292
|
let dist_ref = centroids_to_match[centroids_to_match.len() - 1];
|
|
293
293
|
|
|
294
|
-
let mut proximal_points: Vec<
|
|
295
|
-
let mut distal_points: Vec<
|
|
296
|
-
let mut points_between: Vec<
|
|
294
|
+
let mut proximal_points: Vec<Coords3> = Vec::new();
|
|
295
|
+
let mut distal_points: Vec<Coords3> = Vec::new();
|
|
296
|
+
let mut points_between: Vec<Coords3> = Vec::new();
|
|
297
297
|
|
|
298
298
|
let mut remaining_points = points.to_vec();
|
|
299
299
|
|
|
@@ -327,7 +327,7 @@ pub fn find_points_by_cl_region_rs(
|
|
|
327
327
|
|
|
328
328
|
fn find_cl_points_in_range(
|
|
329
329
|
centerline: &Centerline,
|
|
330
|
-
points: &[
|
|
330
|
+
points: &[Coords3],
|
|
331
331
|
search_radius: f64,
|
|
332
332
|
) -> Vec<usize> {
|
|
333
333
|
let mut selected_points = Vec::new();
|
|
@@ -355,11 +355,11 @@ fn find_cl_points_in_range(
|
|
|
355
355
|
}
|
|
356
356
|
|
|
357
357
|
pub fn clean_up_non_section_points(
|
|
358
|
-
points_to_cleanup: Vec<
|
|
359
|
-
reference_points: Vec<
|
|
358
|
+
points_to_cleanup: Vec<Coords3>,
|
|
359
|
+
reference_points: Vec<Coords3>,
|
|
360
360
|
neighborhood_radius: f64,
|
|
361
361
|
min_neigbor_ratio: f64,
|
|
362
|
-
) -> (Vec<
|
|
362
|
+
) -> (Vec<Coords3>, Vec<Coords3>) {
|
|
363
363
|
let neighborhood_radius_sq = neighborhood_radius * neighborhood_radius;
|
|
364
364
|
|
|
365
365
|
let mut cleaned_points = Vec::new();
|
|
@@ -4,7 +4,7 @@ use std::fs::File;
|
|
|
4
4
|
use std::io::Write;
|
|
5
5
|
use std::path::Path;
|
|
6
6
|
|
|
7
|
-
use crate::intravascular::io::geometry::{
|
|
7
|
+
use crate::intravascular::io::geometry::{ContourType, Geometry};
|
|
8
8
|
use crate::intravascular::io::input::InputData;
|
|
9
9
|
use crate::intravascular::io::output;
|
|
10
10
|
use crate::intravascular::processing::align_between;
|
|
@@ -778,33 +778,9 @@ pub fn single_processing_rs(
|
|
|
778
778
|
Ok((geom, logs))
|
|
779
779
|
}
|
|
780
780
|
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
ContourType::Lumen => geometry
|
|
785
|
-
.frames
|
|
786
|
-
.iter()
|
|
787
|
-
.map(|frame| frame.lumen.clone())
|
|
788
|
-
.collect(),
|
|
789
|
-
_ => geometry
|
|
790
|
-
.frames
|
|
791
|
-
.iter()
|
|
792
|
-
.filter_map(|frame| frame.extras.get(&contour_type).cloned())
|
|
793
|
-
.collect(),
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
/// Helper function to get contour type name for file naming
|
|
798
|
-
pub fn get_contour_type_name(contour_type: ContourType) -> &'static str {
|
|
799
|
-
match contour_type {
|
|
800
|
-
ContourType::Lumen => "lumen",
|
|
801
|
-
ContourType::Eem => "eem",
|
|
802
|
-
ContourType::Calcification => "calcification",
|
|
803
|
-
ContourType::Sidebranch => "sidebranch",
|
|
804
|
-
ContourType::Catheter => "catheter",
|
|
805
|
-
ContourType::Wall => "wall",
|
|
806
|
-
}
|
|
807
|
-
}
|
|
781
|
+
pub use crate::intravascular::processing::process_utils::{
|
|
782
|
+
extract_contours_by_type, get_contour_type_name,
|
|
783
|
+
};
|
|
808
784
|
|
|
809
785
|
/// Helper function to create appropriate MTL file for each contour type
|
|
810
786
|
pub fn create_mtl_for_contour_type(
|
{multimodars-0.4.2 → multimodars-0.4.3}/src/intravascular/centerline_align/align_algorithms.rs
RENAMED
|
@@ -2,9 +2,8 @@ use crate::intravascular::io::geometry::{Contour, Geometry};
|
|
|
2
2
|
use crate::intravascular::io::input::ContourPoint;
|
|
3
3
|
use crate::intravascular::io::input::{Centerline, CenterlinePoint};
|
|
4
4
|
use crate::intravascular::processing::align_between::GeometryPair;
|
|
5
|
-
use crate::intravascular::processing::process_utils::
|
|
6
|
-
|
|
7
|
-
};
|
|
5
|
+
use crate::intravascular::processing::process_utils::hausdorff_distance;
|
|
6
|
+
use crate::types::native;
|
|
8
7
|
use nalgebra::{Point3, Rotation3, Unit, Vector3};
|
|
9
8
|
|
|
10
9
|
/// Allows alignment algorithms to operate on either a single [`Geometry`] or a [`GeometryPair`].
|
|
@@ -408,7 +407,8 @@ pub fn refine_alignment_hausdorff<T: AlignTarget>(
|
|
|
408
407
|
|
|
409
408
|
for frame in frames.iter() {
|
|
410
409
|
if n_downsample < n_points_per_frame {
|
|
411
|
-
let downsampled =
|
|
410
|
+
let downsampled =
|
|
411
|
+
native::downsample_contour_points(&frame.lumen.points, n_downsample);
|
|
412
412
|
nested.push(downsampled);
|
|
413
413
|
} else {
|
|
414
414
|
nested.push(frame.lumen.points.clone());
|
|
@@ -3,9 +3,8 @@ use rayon::prelude::*;
|
|
|
3
3
|
|
|
4
4
|
use crate::intravascular::io::geometry::Geometry;
|
|
5
5
|
use crate::intravascular::io::input::ContourPoint;
|
|
6
|
-
use crate::intravascular::processing::process_utils::{
|
|
7
|
-
|
|
8
|
-
};
|
|
6
|
+
use crate::intravascular::processing::process_utils::{hausdorff_distance, search_range};
|
|
7
|
+
use crate::types::native;
|
|
9
8
|
|
|
10
9
|
pub use crate::types::native::GeometryPair;
|
|
11
10
|
|
|
@@ -163,7 +162,8 @@ fn extract_geometry_points_with_frame_info(
|
|
|
163
162
|
let mut all_points = Vec::new();
|
|
164
163
|
for frame in &geometry.frames {
|
|
165
164
|
let frame_sample_size = (frame.lumen.points.len() as f64 * sample_ratio).ceil() as usize;
|
|
166
|
-
let sampled =
|
|
165
|
+
let sampled =
|
|
166
|
+
native::downsample_contour_points(&frame.lumen.points, frame_sample_size.max(1));
|
|
167
167
|
|
|
168
168
|
for point in sampled {
|
|
169
169
|
all_points.push(PointWithFrameInfo {
|
|
@@ -5,9 +5,8 @@ use std::sync::{Arc, Mutex};
|
|
|
5
5
|
use super::wall;
|
|
6
6
|
use crate::intravascular::io::geometry::{Contour, ContourType, Frame, Geometry};
|
|
7
7
|
use crate::intravascular::io::input::ContourPoint;
|
|
8
|
-
use crate::intravascular::processing::process_utils::{
|
|
9
|
-
|
|
10
|
-
};
|
|
8
|
+
use crate::intravascular::processing::process_utils::{hausdorff_distance, search_range};
|
|
9
|
+
use crate::types::native;
|
|
11
10
|
|
|
12
11
|
#[derive(Debug)]
|
|
13
12
|
pub struct AlignLog {
|
|
@@ -170,10 +169,11 @@ fn catheter_lumen_vec_from_frames(
|
|
|
170
169
|
sample_size_lumen: usize,
|
|
171
170
|
sample_size_catheter: Option<usize>,
|
|
172
171
|
) -> Vec<ContourPoint> {
|
|
173
|
-
let mut lumen_points =
|
|
172
|
+
let mut lumen_points =
|
|
173
|
+
native::downsample_contour_points(&frame.lumen.points, sample_size_lumen);
|
|
174
174
|
let mut catheter_points = if let Some(sample_size_catheter) = sample_size_catheter {
|
|
175
175
|
if let Some(catheter_contour) = frame.extras.get(&ContourType::Catheter) {
|
|
176
|
-
downsample_contour_points(&catheter_contour.points, sample_size_catheter)
|
|
176
|
+
native::downsample_contour_points(&catheter_contour.points, sample_size_catheter)
|
|
177
177
|
} else {
|
|
178
178
|
Vec::new()
|
|
179
179
|
}
|
|
@@ -562,13 +562,7 @@ fn interp_point(
|
|
|
562
562
|
}
|
|
563
563
|
}
|
|
564
564
|
|
|
565
|
-
fn
|
|
566
|
-
c1: &Contour,
|
|
567
|
-
c2: &Contour,
|
|
568
|
-
t: f64,
|
|
569
|
-
id: u32,
|
|
570
|
-
original_frame: u32,
|
|
571
|
-
) -> Contour {
|
|
565
|
+
fn fill_frame_gap(c1: &Contour, c2: &Contour, t: f64, id: u32, original_frame: u32) -> Contour {
|
|
572
566
|
let len = c1.points.len().min(c2.points.len());
|
|
573
567
|
let points: Vec<ContourPoint> = (0..len)
|
|
574
568
|
.map(|i| interp_point(&c1.points[i], &c2.points[i], t, original_frame, i as u32))
|
|
@@ -601,7 +595,7 @@ fn create_interpolated_frame(frame_1: &Frame, frame_2: &Frame, t: f64) -> Frame
|
|
|
601
595
|
frame_1.centroid.2 + (frame_2.centroid.2 - frame_1.centroid.2) * t,
|
|
602
596
|
);
|
|
603
597
|
|
|
604
|
-
let lumen =
|
|
598
|
+
let lumen = fill_frame_gap(
|
|
605
599
|
&frame_1.lumen,
|
|
606
600
|
&frame_2.lumen,
|
|
607
601
|
t,
|
|
@@ -616,10 +610,7 @@ fn create_interpolated_frame(frame_1: &Frame, frame_2: &Frame, t: f64) -> Frame
|
|
|
616
610
|
}
|
|
617
611
|
match (frame_1.extras.get(key), frame_2.extras.get(key)) {
|
|
618
612
|
(Some(c1), Some(c2)) => {
|
|
619
|
-
extras.insert(
|
|
620
|
-
*key,
|
|
621
|
-
interpolate_contour(c1, c2, t, c2.id, c2.original_frame),
|
|
622
|
-
);
|
|
613
|
+
extras.insert(*key, fill_frame_gap(c1, c2, t, c2.id, c2.original_frame));
|
|
623
614
|
}
|
|
624
615
|
(Some(c1), None) => {
|
|
625
616
|
extras.insert(*key, c1.clone());
|
|
@@ -226,7 +226,7 @@ fn new_frames_by_sample_rate(geometry: &Geometry, mut z_coords: Vec<f64>) -> Geo
|
|
|
226
226
|
let t = (z_coord - lower.centroid.2) / (upper.centroid.2 - lower.centroid.2);
|
|
227
227
|
|
|
228
228
|
// Interpolate lumen contour
|
|
229
|
-
let new_lumen =
|
|
229
|
+
let new_lumen = blend_contour(&lower.lumen, &upper.lumen, t);
|
|
230
230
|
|
|
231
231
|
// Interpolate extra contours
|
|
232
232
|
let mut new_extras = HashMap::new();
|
|
@@ -241,7 +241,7 @@ fn new_frames_by_sample_rate(geometry: &Geometry, mut z_coords: Vec<f64>) -> Geo
|
|
|
241
241
|
{
|
|
242
242
|
if let (Some(l_extra), Some(u_extra)) = (lower.extras.get(kind), upper.extras.get(kind))
|
|
243
243
|
{
|
|
244
|
-
new_extras.insert(*kind,
|
|
244
|
+
new_extras.insert(*kind, blend_contour(l_extra, u_extra, t));
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
247
|
|
|
@@ -297,7 +297,7 @@ fn new_frames_by_sample_rate(geometry: &Geometry, mut z_coords: Vec<f64>) -> Geo
|
|
|
297
297
|
}
|
|
298
298
|
}
|
|
299
299
|
|
|
300
|
-
fn
|
|
300
|
+
fn blend_contour(c1: &Contour, c2: &Contour, t: f64) -> Contour {
|
|
301
301
|
let new_points: Vec<ContourPoint> = c1
|
|
302
302
|
.points
|
|
303
303
|
.iter()
|
|
@@ -716,7 +716,7 @@ mod tests {
|
|
|
716
716
|
}
|
|
717
717
|
|
|
718
718
|
#[test]
|
|
719
|
-
fn
|
|
719
|
+
fn test_blend_contour() {
|
|
720
720
|
let contour1 = create_test_contour(0, 0.0, None, ContourType::Lumen);
|
|
721
721
|
let mut contour2 = create_test_contour(1, 2.0, None, ContourType::Lumen);
|
|
722
722
|
|
|
@@ -726,7 +726,7 @@ mod tests {
|
|
|
726
726
|
contour2.points[1].x = 7.0;
|
|
727
727
|
contour2.points[1].y = 8.0;
|
|
728
728
|
|
|
729
|
-
let interpolated =
|
|
729
|
+
let interpolated = blend_contour(&contour1, &contour2, 0.5);
|
|
730
730
|
|
|
731
731
|
// Points should be interpolated - using the correct calculation
|
|
732
732
|
// p1.x = 1.0, p2.x = 5.0, t=0.5 → 1.0 + 0.5*(5.0-1.0) = 3.0
|
|
@@ -1,20 +1,35 @@
|
|
|
1
|
+
use crate::intravascular::io::geometry::{Contour, ContourType, Geometry};
|
|
1
2
|
use crate::intravascular::io::input::ContourPoint;
|
|
2
3
|
use rayon::prelude::*;
|
|
3
4
|
use std::f64::consts::PI;
|
|
4
5
|
|
|
5
|
-
pub fn
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
pub fn extract_contours_by_type(geometry: &Geometry, contour_type: ContourType) -> Vec<Contour> {
|
|
7
|
+
match contour_type {
|
|
8
|
+
ContourType::Lumen => geometry
|
|
9
|
+
.frames
|
|
10
|
+
.iter()
|
|
11
|
+
.map(|frame| frame.lumen.clone())
|
|
12
|
+
.collect(),
|
|
13
|
+
_ => geometry
|
|
14
|
+
.frames
|
|
15
|
+
.iter()
|
|
16
|
+
.filter_map(|frame| frame.extras.get(&contour_type).cloned())
|
|
17
|
+
.collect(),
|
|
8
18
|
}
|
|
9
|
-
let step = points.len() as f64 / n as f64;
|
|
10
|
-
(0..n)
|
|
11
|
-
.map(|i| {
|
|
12
|
-
let index = (i as f64 * step) as usize;
|
|
13
|
-
points[index]
|
|
14
|
-
})
|
|
15
|
-
.collect()
|
|
16
19
|
}
|
|
17
20
|
|
|
21
|
+
pub fn get_contour_type_name(contour_type: ContourType) -> &'static str {
|
|
22
|
+
match contour_type {
|
|
23
|
+
ContourType::Lumen => "lumen",
|
|
24
|
+
ContourType::Eem => "eem",
|
|
25
|
+
ContourType::Calcification => "calcification",
|
|
26
|
+
ContourType::Sidebranch => "sidebranch",
|
|
27
|
+
ContourType::Catheter => "catheter",
|
|
28
|
+
ContourType::Wall => "wall",
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
18
33
|
pub fn search_range<F>(
|
|
19
34
|
cost_fn: F,
|
|
20
35
|
step_deg: f64,
|
|
@@ -110,72 +125,8 @@ fn directed_hausdorff(contour_a: &[ContourPoint], contour_b: &[ContourPoint]) ->
|
|
|
110
125
|
#[cfg(test)]
|
|
111
126
|
mod process_utils_tests {
|
|
112
127
|
use super::*;
|
|
113
|
-
use crate::intravascular::utils::test_utils::dummy_geometry;
|
|
114
128
|
use approx::assert_relative_eq;
|
|
115
129
|
|
|
116
|
-
#[test]
|
|
117
|
-
fn test_downsample_geometry() {
|
|
118
|
-
let dummy = dummy_geometry();
|
|
119
|
-
let cont_points = dummy.frames[0].lumen.points.clone();
|
|
120
|
-
let downsampled_contour = downsample_contour_points(&cont_points, 3);
|
|
121
|
-
|
|
122
|
-
assert_eq!(downsampled_contour.len(), 3);
|
|
123
|
-
assert_eq!(downsampled_contour[0].point_index, 0);
|
|
124
|
-
assert_eq!(downsampled_contour[1].point_index, 2);
|
|
125
|
-
|
|
126
|
-
let downsampled_contour = downsample_contour_points(&cont_points, 6);
|
|
127
|
-
|
|
128
|
-
assert_eq!(downsampled_contour.len(), 6);
|
|
129
|
-
assert_eq!(downsampled_contour[0].point_index, 0);
|
|
130
|
-
assert_eq!(downsampled_contour[1].point_index, 1);
|
|
131
|
-
|
|
132
|
-
let downsampled_contour = downsample_contour_points(&cont_points, 5);
|
|
133
|
-
let n = downsampled_contour.len();
|
|
134
|
-
assert_eq!(downsampled_contour[n - 1].point_index, 4);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// tests from here are AI generated!!
|
|
138
|
-
#[test]
|
|
139
|
-
fn test_downsample_edge_cases() {
|
|
140
|
-
let points = vec![
|
|
141
|
-
ContourPoint {
|
|
142
|
-
frame_index: 1,
|
|
143
|
-
point_index: 0,
|
|
144
|
-
x: 1.0,
|
|
145
|
-
y: 2.0,
|
|
146
|
-
z: 0.0,
|
|
147
|
-
aortic: false,
|
|
148
|
-
},
|
|
149
|
-
ContourPoint {
|
|
150
|
-
frame_index: 1,
|
|
151
|
-
point_index: 1,
|
|
152
|
-
x: 3.0,
|
|
153
|
-
y: 4.0,
|
|
154
|
-
z: 0.0,
|
|
155
|
-
aortic: false,
|
|
156
|
-
},
|
|
157
|
-
];
|
|
158
|
-
|
|
159
|
-
// Test n > points.len()
|
|
160
|
-
let result = downsample_contour_points(&points, 5);
|
|
161
|
-
assert_eq!(result.len(), 2);
|
|
162
|
-
assert_eq!(result[0].point_index, 0);
|
|
163
|
-
assert_eq!(result[1].point_index, 1);
|
|
164
|
-
|
|
165
|
-
// Test n == points.len()
|
|
166
|
-
let result = downsample_contour_points(&points, 2);
|
|
167
|
-
assert_eq!(result.len(), 2);
|
|
168
|
-
|
|
169
|
-
// Test n == 0
|
|
170
|
-
let result = downsample_contour_points(&points, 0);
|
|
171
|
-
assert_eq!(result.len(), 0);
|
|
172
|
-
|
|
173
|
-
// Test empty input
|
|
174
|
-
let empty: Vec<ContourPoint> = Vec::new();
|
|
175
|
-
let result = downsample_contour_points(&empty, 3);
|
|
176
|
-
assert_eq!(result.len(), 0);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
130
|
#[test]
|
|
180
131
|
fn test_search_range_quadratic_function() {
|
|
181
132
|
// Test with a simple quadratic cost function: (angle - 0.5)^2
|
|
@@ -3,6 +3,9 @@ use super::texture::{
|
|
|
3
3
|
create_displacement_texture, create_transparent_texture,
|
|
4
4
|
};
|
|
5
5
|
use crate::intravascular::io::geometry::{Contour, ContourType, Geometry};
|
|
6
|
+
use crate::intravascular::processing::process_utils::{
|
|
7
|
+
extract_contours_by_type, get_contour_type_name,
|
|
8
|
+
};
|
|
6
9
|
use ::std::fs::File;
|
|
7
10
|
use ::std::io::Write;
|
|
8
11
|
use std::collections::HashMap;
|
|
@@ -246,22 +249,6 @@ fn write_transparent_texture(
|
|
|
246
249
|
uv_coords
|
|
247
250
|
}
|
|
248
251
|
|
|
249
|
-
/// Extracts contours of a specific type from a geometry
|
|
250
|
-
fn extract_contours_by_type(geometry: &Geometry, contour_type: ContourType) -> Vec<Contour> {
|
|
251
|
-
match contour_type {
|
|
252
|
-
ContourType::Lumen => geometry
|
|
253
|
-
.frames
|
|
254
|
-
.iter()
|
|
255
|
-
.map(|frame| frame.lumen.clone())
|
|
256
|
-
.collect(),
|
|
257
|
-
_ => geometry
|
|
258
|
-
.frames
|
|
259
|
-
.iter()
|
|
260
|
-
.filter_map(|frame| frame.extras.get(&contour_type).cloned())
|
|
261
|
-
.collect(),
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
252
|
/// Computes displacements between two sets of contours (alternative implementation)
|
|
266
253
|
/// This is used for max displacement calculation since the texture.rs version only works on Geometry
|
|
267
254
|
fn compute_displacements_for_contours(reference: &[Contour], target: &[Contour]) -> Vec<f64> {
|
|
@@ -283,15 +270,3 @@ fn compute_displacements_for_contours(reference: &[Contour], target: &[Contour])
|
|
|
283
270
|
})
|
|
284
271
|
.collect()
|
|
285
272
|
}
|
|
286
|
-
|
|
287
|
-
/// Gets the string name for a contour type for file naming
|
|
288
|
-
fn get_contour_type_name(contour_type: ContourType) -> &'static str {
|
|
289
|
-
match contour_type {
|
|
290
|
-
ContourType::Lumen => "lumen",
|
|
291
|
-
ContourType::Eem => "eem",
|
|
292
|
-
ContourType::Calcification => "calcification",
|
|
293
|
-
ContourType::Sidebranch => "sidebranch",
|
|
294
|
-
ContourType::Catheter => "catheter",
|
|
295
|
-
ContourType::Wall => "wall",
|
|
296
|
-
}
|
|
297
|
-
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
use super::py_contour::{PyContour, PyContourType};
|
|
2
2
|
use super::py_contour_point::PyContourPoint;
|
|
3
3
|
use super::py_frame::PyFrame;
|
|
4
|
-
use crate::
|
|
5
|
-
use crate::types::native::{ContourPoint, ContourType, Geometry};
|
|
4
|
+
use crate::types::native::{self as native, ContourPoint, ContourType, Geometry};
|
|
6
5
|
use pyo3::prelude::*;
|
|
7
6
|
|
|
8
7
|
type GeomSummary = (f64, f64, f64);
|
|
@@ -400,7 +399,7 @@ impl PyGeometry {
|
|
|
400
399
|
let downsample_contour = |contour: &PyContour| -> PyContour {
|
|
401
400
|
let rust_points: Vec<ContourPoint> =
|
|
402
401
|
contour.points.iter().map(ContourPoint::from).collect();
|
|
403
|
-
let downsampled =
|
|
402
|
+
let downsampled = native::downsample_contour_points(&rust_points, n_points);
|
|
404
403
|
PyContour {
|
|
405
404
|
points: downsampled.iter().map(PyContourPoint::from).collect(),
|
|
406
405
|
..contour.clone()
|