use crate::linestring_2d::{Line2, LineString2, PriorityDistance};
use itertools::Itertools;
use std::collections::BinaryHeap;
use vector_traits::prelude::*;
pub(super) fn simplify_rdp_recursive<T: GenericVector2>(
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 fn indexed_simplify_rdp<T: GenericVector2>(
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: GenericVector2>(
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,
);
}
}
pub(super) fn simplify_vw<T: GenericVector2>(line: &Vec<T>, points_to_delete: usize) -> Vec<T> {
let connected = line.is_connected();
if line.len() <= 2 {
return line.clone();
}
let mut search_tree = BinaryHeap::<PriorityDistance<T>>::new();
let mut link_tree = rustc_hash::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 = Line2::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));
}
}
if connected {
let i = line.len() - 2;
let j = line.len() - 1;
let k = line.len();
let area = Line2::triangle_area_squared_times_4(line[i], line[j], line[0]);
search_tree.push(PriorityDistance {
key: area,
index: j,
});
let _ = link_tree.insert(j, (i, k, area));
}
let line_points_len = line.len();
let mut deleted_nodes: usize = 0;
loop {
if search_tree.is_empty() || link_tree.len() == 2 || 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 = Line2::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 = Line2::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 = Line2::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 = Line2::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;
}
}
}
if !connected {
[0_usize]
.iter()
.copied()
.chain(
link_tree
.keys()
.sorted_unstable()
.copied()
.chain([line.len() - 1].iter().copied()),
)
.map(|x| line[x])
.collect()
} else {
[0_usize]
.iter()
.copied()
.chain(link_tree.keys().sorted_unstable().copied())
.map(|x| line[x])
.collect()
}
}