use crate::linestring_3d::{Line3, PriorityDistance};
use itertools::Itertools;
use rustc_hash::FxHashMap;
use std::collections::BinaryHeap;
use vector_traits::prelude::*;
pub(super) fn simplify_rdp<T: GenericVector3>(line: &[T], distance_predicate: T::Scalar) -> Vec<T> {
if line.len() <= 2 {
return line.to_vec();
}
let mut rv: Vec<T> = Vec::with_capacity(line.len());
rv.push(line[0]);
simplify_rdp_recursive(&mut rv, line, distance_predicate * distance_predicate);
rv
}
fn simplify_rdp_recursive<T: GenericVector3>(
rv: &mut Vec<T>,
points: &[T],
distance_predicate_sq: T::Scalar,
) {
if points.len() <= 2 {
rv.push(*points.last().unwrap());
return;
}
let start_point = points[0];
let end_point = points[points.len() - 1];
let (max_dist_sq, index) = points
.iter()
.enumerate()
.skip(1)
.take(points.len() - 2)
.map(|(i, &point)| {
(
super::distance_to_line_squared_safe(start_point, end_point, point),
i,
)
})
.max_by(|(dist1, _), (dist2, _)| {
dist1
.partial_cmp(dist2)
.unwrap_or(std::cmp::Ordering::Equal)
})
.unwrap_or((-T::Scalar::ONE, 0));
if max_dist_sq <= distance_predicate_sq {
rv.push(end_point);
} else {
simplify_rdp_recursive(rv, &points[..index + 1], distance_predicate_sq);
simplify_rdp_recursive(rv, &points[index..], distance_predicate_sq);
}
}
pub(super) fn simplify_vw<T: GenericVector3>(line: &[T], points_to_delete: usize) -> Vec<T> {
if line.len() <= 2 {
return line.to_vec();
}
let mut search_tree = BinaryHeap::<PriorityDistance<T>>::new();
let mut link_tree = FxHashMap::<usize, (usize, usize, T::Scalar)>::default();
{
let mut iter_i = line.iter().enumerate();
let mut iter_j = line.iter().enumerate().skip(1);
for k in line.iter().enumerate().skip(2) {
let i = iter_i.next().unwrap();
let j = iter_j.next().unwrap();
let area = Line3::triangle_area_squared_times_4(i.1, j.1, k.1);
search_tree.push(PriorityDistance {
key: area,
index: j.0,
});
let _ = link_tree.insert(j.0, (i.0, k.0, area));
}
}
let line_points_len = line.len();
let mut deleted_nodes: usize = 0;
loop {
if search_tree.is_empty() || deleted_nodes >= points_to_delete {
break;
}
if let Some(smallest) = search_tree.pop() {
if let Some(old_links) = link_tree.get(&smallest.index).copied() {
let area = old_links.2;
if smallest.key != area {
continue;
} else {
let _ = link_tree.remove(&smallest.index);
}
deleted_nodes += 1;
let prev = old_links.0;
let next = old_links.1;
let prev_prev: Option<usize> = link_tree.get(&prev).map(|link| link.0);
let next_next: Option<usize> = link_tree.get(&next).map(|link| link.1);
if let Some(next_next) = next_next {
if let Some(prev_prev) = prev_prev {
let area = Line3::triangle_area_squared_times_4(
&line[prev],
&line[next % line_points_len],
&line[next_next % line_points_len],
);
search_tree.push(PriorityDistance {
key: area,
index: next,
});
let _ = link_tree.insert(next, (prev, next_next, area));
let area = Line3::triangle_area_squared_times_4(
&line[prev_prev],
&line[prev],
&line[next % line_points_len],
);
search_tree.push(PriorityDistance {
key: area,
index: prev,
});
let _ = link_tree.insert(prev, (prev_prev, next, area));
continue;
}
}
if let Some(prev_prev) = prev_prev {
let area = Line3::triangle_area_squared_times_4(
&line[prev_prev],
&line[prev],
&line[next % line_points_len],
);
search_tree.push(PriorityDistance {
key: area,
index: prev,
});
let _ = link_tree.insert(prev, (prev_prev, next, area));
continue;
};
if let Some(next_next) = next_next {
let area = Line3::triangle_area_squared_times_4(
&line[prev],
&line[next % line_points_len],
&line[next_next % line_points_len],
);
search_tree.push(PriorityDistance {
key: area,
index: next,
});
let _ = link_tree.insert(next, (prev, next_next, area));
continue;
};
} else {
continue;
}
}
}
[0_usize]
.iter()
.copied()
.chain(link_tree.keys().sorted_unstable().copied())
.map(|x| line[x])
.collect()
}
pub fn indexed_simplify_rdp<T: GenericVector3>(
vertices: &[T],
indices: &[u32],
distance_predicate: T::Scalar,
) -> Vec<u32> {
if vertices.len() <= 2 {
return indices.to_vec();
}
let mut simplified_indices = Vec::new();
simplified_indices.push(indices[0]);
indexed_simplify_rdp_recursive(
&mut simplified_indices,
vertices,
indices,
distance_predicate * distance_predicate,
);
simplified_indices
}
fn indexed_simplify_rdp_recursive<T: GenericVector3>(
simplified_indices: &mut Vec<u32>,
vertices: &[T],
indices: &[u32],
distance_predicate_sq: T::Scalar,
) {
if indices.len() <= 2 {
simplified_indices.push(*indices.last().unwrap());
return;
}
let start_index = indices[0];
let end_index = indices[indices.len() - 1];
let (max_dist_sq, index_index) = indices
.iter()
.enumerate()
.skip(1)
.take(indices.len() - 2)
.map(|(i, &point_i)| {
(
super::distance_to_line_squared_safe(
vertices[start_index as usize],
vertices[end_index as usize],
vertices[point_i as usize],
),
i,
)
})
.max_by(|(dist1, _), (dist2, _)| {
dist1
.partial_cmp(dist2)
.unwrap_or(std::cmp::Ordering::Equal)
})
.unwrap_or((-T::Scalar::ONE, 0)); if max_dist_sq <= distance_predicate_sq {
simplified_indices.push(end_index);
} else {
indexed_simplify_rdp_recursive(
simplified_indices,
vertices,
&indices[..=index_index],
distance_predicate_sq,
);
indexed_simplify_rdp_recursive(
simplified_indices,
vertices,
&indices[index_index..],
distance_predicate_sq,
);
}
}