use super::AsCell;
use crate::mesh::{GeoClass, Mesh, PointId};
use crate::shapes::{GeoKind, Scratchpad};
use russell_lab::Vector;
use std::collections::HashMap;
pub struct Triangulation {
pub xx: Vec<f64>,
pub yy: Vec<f64>,
pub zz: Vec<f64>,
pub triangles: Vec<Vec<PointId>>,
}
impl Triangulation {
pub fn from_surface<T: AsCell>(mesh: &Mesh, surface: &[&T]) -> Self {
let ndim = mesh.ndim;
let mut old_point_id_to_new_point_id: HashMap<PointId, PointId> = HashMap::new();
let mut pads: HashMap<GeoKind, Scratchpad> = HashMap::new();
let mut x_work = Vector::new(ndim);
let mut connectivity = vec![0; 3];
let mut res = Triangulation {
xx: Vec::new(),
yy: Vec::new(),
zz: Vec::new(),
triangles: Vec::new(),
};
for cell in surface {
let kind = cell.kind();
let class = kind.class();
let tri_or_qua = class == GeoClass::Tri || class == GeoClass::Qua;
if !tri_or_qua {
continue;
}
let points = cell.points();
let nnode = kind.nnode();
let extra_nnode = kind.triangulate_extra_nnode();
let mut extra_points = vec![usize::MAX; extra_nnode];
let pad = pads.entry(kind).or_insert_with(|| Scratchpad::new(ndim, kind).unwrap());
mesh.set_pad(pad, points);
pad.triangulate(&mut x_work, |_, i, m, x| {
let p = if m < nnode {
let p_old = points[m];
old_point_id_to_new_point_id
.entry(p_old)
.or_insert_with(|| {
let p_new = res.xx.len();
res.xx.push(x[0]);
res.yy.push(x[1]);
if ndim == 3 {
res.zz.push(x[2]);
}
p_new
})
.clone()
} else {
let k = m - nnode;
if extra_points[k] == usize::MAX {
let p_new = res.xx.len();
extra_points[k] = p_new;
res.xx.push(x[0]);
res.yy.push(x[1]);
if ndim == 3 {
res.zz.push(x[2]);
}
p_new
} else {
extra_points[k]
}
};
connectivity[i] = p;
if i == 2 {
res.triangles.push(connectivity.clone());
}
})
.unwrap();
}
res
}
}
#[cfg(test)]
mod tests {
use super::Triangulation;
use crate::mesh::Samples;
use plotpy::{Canvas, Plot};
const SAVE_FIGURE: bool = false;
#[test]
fn triangulate_surface_works_1() {
let mesh = Samples::one_qua4();
let surface: Vec<_> = mesh.cells.iter().collect();
let res = Triangulation::from_surface(&mesh, &surface);
if SAVE_FIGURE {
let mut canvas = Canvas::new();
canvas.draw_triangles(&res.xx, &res.yy, &res.triangles);
let mut plot = Plot::new();
plot.add(&canvas)
.set_equal_axes(true)
.save("/tmp/gemlab/triangulate_surface_works_1.svg")
.unwrap();
}
assert_eq!(res.xx.len(), 4);
assert_eq!(res.yy.len(), 4);
assert_eq!(res.zz.len(), 0);
assert_eq!(res.triangles.len(), 2);
}
#[test]
fn triangulate_surface_works_2() {
let mesh = Samples::qua8_tri6_lin2();
let surface: Vec<_> = mesh.cells.iter().collect();
let res = Triangulation::from_surface(&mesh, &surface);
if SAVE_FIGURE {
let mut canvas = Canvas::new();
canvas.draw_triangles(&res.xx, &res.yy, &res.triangles);
let mut plot = Plot::new();
plot.add(&canvas)
.set_equal_axes(true)
.save("/tmp/gemlab/triangulate_surface_works_2.svg")
.unwrap();
}
let npoint = mesh.points.len() + 1; assert_eq!(res.xx.len(), npoint);
assert_eq!(res.yy.len(), npoint);
assert_eq!(res.zz.len(), 0);
assert_eq!(res.triangles.len(), 8 + 4); }
#[test]
fn triangulate_surface_works_3() {
let mesh = Samples::qua8_tri6_lin2_three_dimensional();
let surface: Vec<_> = mesh.cells.iter().collect();
let res = Triangulation::from_surface(&mesh, &surface);
if SAVE_FIGURE {
let mut canvas = Canvas::new();
canvas.draw_triangles_3d(&res.xx, &res.yy, &res.zz, &res.triangles);
let mut plot = Plot::new();
plot.add(&canvas)
.set_equal_axes(true)
.set_camera(30.0, 90.0)
.set_figure_size_points(600.0, 600.0)
.save("/tmp/gemlab/triangulate_surface_works_3.svg")
.unwrap();
}
let npoint = mesh.points.len() + 1; assert_eq!(res.xx.len(), npoint);
assert_eq!(res.yy.len(), npoint);
assert_eq!(res.zz.len(), npoint);
assert_eq!(res.triangles.len(), 8 + 4); }
#[test]
fn triangulate_surface_works_4() {
let mesh = Samples::block_2d_four_qua12();
let surface: Vec<_> = mesh.cells.iter().collect();
let res = Triangulation::from_surface(&mesh, &surface);
if SAVE_FIGURE {
let mut canvas = Canvas::new();
canvas.draw_triangles(&res.xx, &res.yy, &res.triangles);
let mut plot = Plot::new();
plot.add(&canvas)
.set_equal_axes(true)
.save("/tmp/gemlab/triangulate_surface_works_4.svg")
.unwrap();
}
let ncell = 4;
let ntriangle = ncell * 18; let npoint = mesh.points.len() + 4 * ncell; assert_eq!(res.xx.len(), npoint);
assert_eq!(res.yy.len(), npoint);
assert_eq!(res.zz.len(), 0);
assert_eq!(res.triangles.len(), ntriangle);
}
}