use crate::{
DoubleMapper, Feature,
geometry::{DISTANCE_EPSILON, Point},
measured_polygon::ProgressableFeature,
util::{progress_distance, progress_in_range},
};
#[derive(Default)]
struct MappingHelper<'a> {
mapping: Vec<(f32, f32)>,
used_f1: Vec<&'a ProgressableFeature>,
used_f2: Vec<&'a ProgressableFeature>,
}
impl<'a> MappingHelper<'a> {
fn add_mapping(&mut self, f1: &'a ProgressableFeature, f2: &'a ProgressableFeature) {
if self.used_f1.contains(&f1) || self.used_f2.contains(&f2) {
return;
}
if let Err(insertion_index) = self.mapping.binary_search_by(|it| it.0.total_cmp(&f1.progress)) {
let n = self.mapping.len();
if n >= 1 {
let (before1, before2) = self.mapping[(insertion_index + n - 1) % n];
let (after1, after2) = self.mapping[insertion_index % n];
if progress_distance(f1.progress, before1) < DISTANCE_EPSILON
|| progress_distance(f1.progress, after1) < DISTANCE_EPSILON
|| progress_distance(f2.progress, before2) < DISTANCE_EPSILON
|| progress_distance(f2.progress, after2) < DISTANCE_EPSILON
{
return;
}
if n > 1 && !progress_in_range(f2.progress, before2, after2) {
return;
}
}
self.mapping.insert(insertion_index, (f1.progress, f2.progress));
self.used_f1.push(f1);
self.used_f2.push(f2);
} else {
panic!("There can't be two features with the same progress");
}
}
}
impl DoubleMapper {
pub fn from_features(features1: &[ProgressableFeature], features2: &[ProgressableFeature]) -> Self {
let mut filtered_features1 = Vec::new();
let mut filtered_features2 = Vec::new();
for feature in features1 {
if feature.feature.is_corner() {
filtered_features1.push(feature);
}
}
for feature in features2 {
if feature.feature.is_corner() {
filtered_features2.push(feature);
}
}
let mut distance_vertex_list = Vec::new();
for f1 in filtered_features1 {
for &f2 in &filtered_features2 {
let distance = feature_dist_squared(&f1.feature, &f2.feature);
if distance != f32::MAX {
distance_vertex_list.push(DistanceVertex { distance, f1, f2 });
}
}
}
distance_vertex_list.sort_by(|a, b| a.distance.total_cmp(&b.distance));
Self::new(match distance_vertex_list.len() {
0 => vec![(0.0, 0.0), (0.5, 0.5)],
1 => {
let f1 = distance_vertex_list[0].f1.progress;
let f2 = distance_vertex_list[0].f2.progress;
vec![(f1, f2), ((f1 + 0.5) % 1.0, (f2 + 0.5) % 1.0)]
}
_ => {
let mut helper = MappingHelper::default();
for dv in distance_vertex_list {
helper.add_mapping(dv.f1, dv.f2);
}
helper.mapping
}
})
}
}
struct DistanceVertex<'a> {
distance: f32,
f1: &'a ProgressableFeature,
f2: &'a ProgressableFeature,
}
fn feature_representative_point(feature: &Feature) -> Point {
(feature.cubics[0].anchor0() + feature.cubics[feature.cubics.len() - 1].anchor1().to_vector()) / 2.0
}
fn feature_dist_squared(f1: &Feature, f2: &Feature) -> f32 {
if f1.is_corner_and(|f1_convex| f2.is_corner_and(|f2_convex| f1_convex != f2_convex)) {
f32::MAX
} else {
(feature_representative_point(f1) - feature_representative_point(f2)).square_length()
}
}