use super::InitialMesh;
use super::TriangleFacet;
use crate::math::Real;
use crate::transformation::convex_hull_utils::indexed_support_point_nth;
use crate::transformation::convex_hull_utils::{indexed_support_point_id, normalize};
use crate::utils;
use na::{self, Point3};
pub fn convex_hull(points: &[Point3<Real>]) -> (Vec<Point3<Real>>, Vec<[u32; 3]>) {
if points.is_empty() {
return (Vec::new(), Vec::new());
}
let mut normalized_points = points.to_vec();
let _ = normalize(&mut normalized_points[..]);
let mut undecidable_points = Vec::new();
let mut silhouette_loop_facets_and_idx = Vec::new();
let mut removed_facets = Vec::new();
let mut triangles;
match super::get_initial_mesh(points, &mut normalized_points[..], &mut undecidable_points) {
InitialMesh::Facets(facets) => {
triangles = facets;
}
InitialMesh::ResultMesh(vertices, indices) => {
return (vertices, indices);
}
}
let mut i = 0;
while i != triangles.len() {
silhouette_loop_facets_and_idx.clear();
if !triangles[i].valid || triangles[i].affinely_dependent {
i = i + 1;
continue;
}
let pt_id = indexed_support_point_id(
&triangles[i].normal,
&normalized_points[..],
triangles[i].visible_points[..].iter().copied(),
);
if let Some(point) = pt_id {
triangles[i].valid = false;
removed_facets.clear();
removed_facets.push(i);
for j in 0usize..3 {
compute_silhouette(
triangles[i].adj[j],
triangles[i].indirect_adj_id[j],
point,
&mut silhouette_loop_facets_and_idx,
&normalized_points[..],
&mut removed_facets,
&mut triangles[..],
);
}
fix_silhouette_topology(
&normalized_points,
&mut silhouette_loop_facets_and_idx,
&mut removed_facets,
&mut triangles[..],
);
if silhouette_loop_facets_and_idx.is_empty() {
let mut any_valid = false;
for j in i + 1..triangles.len() {
if triangles[j].valid && !triangles[j].affinely_dependent {
any_valid = true;
}
}
if any_valid {
panic!(
"Warning: exitting an unfinished work: {}, {}",
normalized_points[point],
triangles.len()
);
}
triangles[i].valid = true;
break;
}
attach_and_push_facets(
&silhouette_loop_facets_and_idx[..],
point,
&normalized_points[..],
&mut triangles,
&removed_facets[..],
&mut undecidable_points,
);
}
i = i + 1;
}
let mut idx = Vec::new();
for facet in triangles.iter() {
if facet.valid {
idx.push([
facet.pts[0] as u32,
facet.pts[1] as u32,
facet.pts[2] as u32,
]);
}
}
let mut points = points.to_vec();
utils::remove_unused_points(&mut points, &mut idx[..]);
assert!(points.len() != 0, "Internal error: empty output mesh.");
(points, idx)
}
fn compute_silhouette(
facet: usize,
indirect_id: usize,
point: usize,
out_facets_and_idx: &mut Vec<(usize, usize)>,
points: &[Point3<Real>],
removed_facets: &mut Vec<usize>,
triangles: &mut [TriangleFacet],
) {
if triangles[facet].valid {
if !triangles[facet].order_independent_can_be_seen_by_point(point, points) {
out_facets_and_idx.push((facet, indirect_id));
} else {
triangles[facet].valid = false;
removed_facets.push(facet);
compute_silhouette(
triangles[facet].adj[(indirect_id + 1) % 3],
triangles[facet].indirect_adj_id[(indirect_id + 1) % 3],
point,
out_facets_and_idx,
points,
removed_facets,
triangles,
);
compute_silhouette(
triangles[facet].adj[(indirect_id + 2) % 3],
triangles[facet].indirect_adj_id[(indirect_id + 2) % 3],
point,
out_facets_and_idx,
points,
removed_facets,
triangles,
);
}
} else {
}
}
fn fix_silhouette_topology(
points: &[Point3<Real>],
out_facets_and_idx: &mut Vec<(usize, usize)>,
removed_facets: &mut Vec<usize>,
triangles: &mut [TriangleFacet],
) {
let mut workspace = vec![0; points.len()];
let mut needs_fixing = false;
for (facet, adj_id) in &*out_facets_and_idx {
let p = triangles[*facet].second_point_from_edge(*adj_id);
workspace[p] += 1;
if workspace[p] > 1 {
needs_fixing = true;
}
}
if needs_fixing {
let mut loop_start = 0;
for (facet, adj_id) in &*out_facets_and_idx {
let p1 = points[triangles[*facet].second_point_from_edge(*adj_id)];
let p2 = points[triangles[*facet].first_point_from_edge(*adj_id)];
let supp = indexed_support_point_nth(
&(p2 - p1),
points,
out_facets_and_idx
.iter()
.map(|(f, ai)| triangles[*f].second_point_from_edge(*ai)),
)
.unwrap();
let selected = &out_facets_and_idx[supp];
if workspace[triangles[selected.0].second_point_from_edge(selected.1)] == 1 {
loop_start = supp;
break;
}
}
let mut removing = None;
let old_facets_and_idx = std::mem::replace(out_facets_and_idx, Vec::new());
for i in 0..old_facets_and_idx.len() {
let facet_id = (loop_start + i) % old_facets_and_idx.len();
let (facet, adj_id) = old_facets_and_idx[facet_id];
match removing {
Some(p) => {
let p1 = triangles[facet].second_point_from_edge(adj_id);
if p == p1 {
removing = None;
}
}
_ => {
let p1 = triangles[facet].second_point_from_edge(adj_id);
if workspace[p1] > 1 {
removing = Some(p1);
}
}
}
if removing.is_some() {
if triangles[facet].valid {
triangles[facet].valid = false;
removed_facets.push(facet);
}
} else {
out_facets_and_idx.push((facet, adj_id));
}
}
}
}
fn attach_and_push_facets(
silhouette_loop_facets_and_idx: &[(usize, usize)],
point: usize,
points: &[Point3<Real>],
triangles: &mut Vec<TriangleFacet>,
removed_facets: &[usize],
undecidable: &mut Vec<usize>,
) {
let mut new_facets = Vec::with_capacity(silhouette_loop_facets_and_idx.len());
let mut adj_facet: usize;
let mut indirect_id: usize;
for i in 0..silhouette_loop_facets_and_idx.len() {
adj_facet = silhouette_loop_facets_and_idx[i].0;
indirect_id = silhouette_loop_facets_and_idx[i].1;
let facet = TriangleFacet::new(
point,
triangles[adj_facet].second_point_from_edge(indirect_id),
triangles[adj_facet].first_point_from_edge(indirect_id),
points,
);
new_facets.push(facet);
}
for i in 0..silhouette_loop_facets_and_idx.len() {
let prev_facet;
if i == 0 {
prev_facet = triangles.len() + silhouette_loop_facets_and_idx.len() - 1;
} else {
prev_facet = triangles.len() + i - 1;
}
let (middle_facet, middle_id) = silhouette_loop_facets_and_idx[i];
let next_facet = triangles.len() + (i + 1) % silhouette_loop_facets_and_idx.len();
new_facets[i].set_facets_adjascency(prev_facet, middle_facet, next_facet, 2, middle_id, 0);
assert!(!triangles[triangles[middle_facet].adj[middle_id]].valid);
triangles[middle_facet].adj[middle_id] = triangles.len() + i;
triangles[middle_facet].indirect_adj_id[middle_id] = 1;
}
for curr_facet in removed_facets.iter() {
for visible_point in triangles[*curr_facet].visible_points.iter() {
if points[*visible_point] == points[point] {
continue;
}
let mut furthest = usize::max_value();
let mut furthest_dist = 0.0;
for (i, curr_facet) in new_facets.iter_mut().enumerate() {
if !curr_facet.affinely_dependent {
let distance = curr_facet.distance_to_point(*visible_point, points);
if distance > furthest_dist {
furthest = i;
furthest_dist = distance;
}
}
}
if furthest != usize::max_value() {
if new_facets[furthest].can_see_point(*visible_point, points) {
new_facets[furthest].add_visible_point(*visible_point, points);
}
}
}
}
let mut i = 0;
while i != undecidable.len() {
let mut furthest = usize::max_value();
let mut furthest_dist = 0.0;
let undecidable_point = undecidable[i];
for (j, curr_facet) in new_facets.iter_mut().enumerate() {
if curr_facet.can_see_point(undecidable_point, points) {
let distance = curr_facet.distance_to_point(undecidable_point, points);
if distance > furthest_dist {
furthest = j;
furthest_dist = distance;
}
}
}
if furthest != usize::max_value() {
new_facets[furthest].add_visible_point(undecidable_point, points);
let _ = undecidable.swap_remove(i);
} else {
i = i + 1;
}
}
triangles.append(&mut new_facets);
}
#[cfg(test)]
mod test {
use crate::transformation;
#[cfg(feature = "dim2")]
use na::Point2;
#[cfg(feature = "dim2")]
#[test]
fn test_simple_convex_hull() {
let points = [
Point2::new(4.723881f32, 3.597233),
Point2::new(3.333363, 3.429991),
Point2::new(3.137215, 2.812263),
];
let chull = transformation::convex_hull(points.as_slice());
assert!(chull.coords.len() == 3);
}
#[cfg(feature = "dim3")]
#[test]
fn test_ball_convex_hull() {
use crate::shape::Ball;
let (points, _) = Ball::new(0.4).to_trimesh(20, 20);
let (vertices, _) = transformation::convex_hull(points.as_slice());
assert!(vertices.len() == vertices.len());
}
}