use crate::geometry::{Geometry, Patch, Topology};
use crate::points::Point;
pub fn is_defined(point: &Point) -> bool {
point.iter().all(|c| c.is_finite())
}
#[derive(Debug, Clone, PartialEq)]
pub struct Compaction {
pub geometry: Geometry,
pub points: Vec<usize>,
pub cells: Vec<usize>,
pub dropped_points: usize,
pub dropped_cells: usize,
}
impl Geometry {
pub fn undefined_count(&self) -> usize {
self.patches
.iter()
.flat_map(|patch| patch.points.iter())
.filter(|point| !is_defined(point))
.count()
}
pub fn defined_only(&self) -> Option<Compaction> {
if self.undefined_count() == 0 {
return None;
}
let mut patches = Vec::with_capacity(self.patches.len());
let mut kept_points = Vec::new();
let mut kept_cells = Vec::new();
let mut point_base = 0usize;
let mut cell_base = 0usize;
let mut node_offset = 0usize;
let mut dropped_points = 0usize;
let mut dropped_cells = 0usize;
for patch in &self.patches {
let compactable = !matches!(patch.topology, Topology::Polyhedra(_));
let mut keep = Vec::with_capacity(patch.points.len());
let mut points = Vec::with_capacity(patch.points.len());
for (index, point) in patch.points.iter().enumerate() {
if !compactable || is_defined(point) {
keep.push(Some(points.len() as u32));
points.push(*point);
kept_points.push(point_base + index);
} else {
keep.push(None);
dropped_points += 1;
}
}
let (topology, kept_here, dropped_here) = compact_topology(&patch.topology, &keep, cell_base);
kept_cells.extend(kept_here);
dropped_cells += dropped_here;
let points_len = points.len();
patches.push(Patch {
index: patch.index,
node_offset,
points,
topology,
closed: Vec::new(),
});
point_base += patch.points.len();
cell_base += cells_in(&patch.topology);
node_offset += points_len;
}
Some(Compaction {
geometry: Geometry {
kind: self.kind,
patches,
},
points: kept_points,
cells: kept_cells,
dropped_points,
dropped_cells,
})
}
}
fn cells_in(topology: &Topology) -> usize {
topology.cell_count()
}
fn compact_topology(
topology: &Topology,
keep: &[Option<u32>],
cell_base: usize,
) -> (Topology, Vec<usize>, usize) {
let at = |index: u32| keep.get(index as usize).copied().flatten();
match topology {
Topology::Points => (Topology::Points, Vec::new(), 0),
Topology::Quads(quads) => {
let mut out = Vec::with_capacity(quads.len());
let mut kept = Vec::with_capacity(quads.len());
let mut dropped = 0;
for (index, q) in quads.iter().enumerate() {
let mut ring = [0u32; 4];
let mut whole = true;
for (slot, corner) in ring.iter_mut().zip(q.iter()) {
match at(*corner) {
Some(new) => *slot = new,
None => {
whole = false;
break;
}
}
}
if whole {
out.push(ring);
kept.push(cell_base + index);
} else {
dropped += 1;
}
}
(Topology::Quads(out), kept, dropped)
}
Topology::Polygons(rings) => {
let mut out = Vec::with_capacity(rings.len());
let mut kept = Vec::with_capacity(rings.len());
let mut dropped = 0;
for (index, ring) in rings.iter().enumerate() {
let renumbered: Option<Vec<u32>> = ring.iter().map(|corner| at(*corner)).collect();
match renumbered {
Some(ring) => {
out.push(ring);
kept.push(cell_base + index);
}
None => dropped += 1,
}
}
(Topology::Polygons(out), kept, dropped)
}
Topology::Triangles(triangles) => {
let mut out = Vec::with_capacity(triangles.len());
let mut kept = Vec::with_capacity(triangles.len());
let mut dropped = 0;
for (index, t) in triangles.iter().enumerate() {
match (at(t[0]), at(t[1]), at(t[2])) {
(Some(a), Some(b), Some(c)) => {
out.push([a, b, c]);
kept.push(cell_base + index);
}
_ => dropped += 1,
}
}
(Topology::Triangles(out), kept, dropped)
}
Topology::Segments(pairs) => {
let mut out = Vec::with_capacity(pairs.len());
let mut kept = Vec::with_capacity(pairs.len());
let mut dropped = 0;
for (index, pair) in pairs.iter().enumerate() {
match (at(pair[0]), at(pair[1])) {
(Some(a), Some(b)) => {
out.push([a, b]);
kept.push(cell_base + index);
}
_ => dropped += 1,
}
}
(Topology::Segments(out), kept, dropped)
}
Topology::Polylines(runs) => {
let mut out = Vec::new();
let mut start = 0u32;
let mut cut = false;
for run in runs {
let mut length = 0u32;
for offset in 0..*run {
match at(start + offset) {
Some(_) => length += 1,
None => {
if length > 0 {
out.push(length);
}
length = 0;
cut = true;
}
}
}
if length > 0 {
out.push(length);
}
start += run;
}
let dropped = if cut { runs.len() } else { 0 };
let kept = if cut {
Vec::new()
} else {
(0..runs.len()).map(|i| cell_base + i).collect()
};
(Topology::Polylines(out), kept, dropped)
}
Topology::Hexahedra {
cells,
dimensions,
index,
} => {
let mut out = Vec::with_capacity(cells.len());
let mut kept = Vec::with_capacity(cells.len());
let mut dropped = 0;
for (index, cell) in cells.iter().enumerate() {
let mut corners = [0u32; 8];
let mut whole = true;
for (slot, corner) in corners.iter_mut().zip(cell.iter()) {
match at(*corner) {
Some(new) => *slot = new,
None => {
whole = false;
break;
}
}
}
if whole {
out.push(corners);
kept.push(cell_base + index);
} else {
dropped += 1;
}
}
(
Topology::Hexahedra {
cells: out,
dimensions: *dimensions,
index: kept
.iter()
.map(|at| index.get(*at).copied().unwrap_or(*at as u32))
.collect(),
},
kept,
dropped,
)
}
Topology::Grid { fastest, slowest } => (
Topology::Points,
Vec::new(),
fastest.saturating_sub(1) * slowest.saturating_sub(1),
),
Topology::Polyhedra(cells) => (
Topology::Polyhedra(cells.clone()),
(0..cells.cell_count()).map(|i| cell_base + i).collect(),
0,
),
}
}