use crate::cad_topology::CadTopology;
use nalgebra;
pub struct Vertex {
pub pos: nalgebra::Vector2<f64>,
}
impl Vertex {
fn new(x: f64, y: f64) -> Self {
Self { pos: nalgebra::Vector2::<f64>::new(x, y) }
}
}
pub struct Edge {
pub p0: nalgebra::Vector2<f64>,
pub p1: nalgebra::Vector2<f64>,
}
impl Edge {
fn new() -> Self {
Self {
p0: nalgebra::Vector2::<f64>::new(0., 0.),
p1: nalgebra::Vector2::<f64>::new(0., 0.),
}
}
pub fn arc_length(&self) -> f64 {
(self.p0 - self.p1).norm()
}
pub fn get_area_arc_origin(&self) -> f64 {
del_geo::tri2::area(&[0., 0.], self.p0.as_slice(), self.p1.as_slice())
}
pub fn get_position(&self, ratio: f64) -> nalgebra::Vector2::<f64> {
self.p0.scale(1_f64 - ratio) + self.p1.scale(ratio)
}
pub fn get_winding_number(&self, po: &nalgebra::Vector2<f64>) -> f64 {
del_geo::edge2::winding_number(&self.p0, &self.p1, po)
}
pub fn gen_mesh(&self, ndiv: usize) -> Vec<f64> {
let mut xyw = Vec::<f64>::new();
assert!(ndiv > 0);
for ip in 1..ndiv {
let r2 = ip as f64 / ndiv as f64;
let v2: nalgebra::Vector2::<f64> = (1_f64 - r2) * self.p0 + r2 * self.p1;
xyw.push(v2.x);
xyw.push(v2.y);
xyw.push(r2);
}
xyw
}
}
pub struct Loop<'a> {
idx_loop: usize,
cad: &'a Cad2,
}
impl<'a> Loop<'a> {
pub fn area(&self) -> f64 {
let mut area = 0_f64;
for &(ie, r) in self.cad.topology.loops[self.idx_loop].idx2edge_dir.iter() {
let a0 = self.cad.edges[ie].get_area_arc_origin();
if r { area += a0; } else { area -= a0; }
}
area
}
pub fn winding_number_at_edge(
&self,
idx_edge: usize,
ratio: f64) -> f64 {
let p0 = self.cad.edges[idx_edge].get_position(ratio);
let mut wn: f64 = 0.0;
let lp = &self.cad.topology.loops[self.idx_loop];
if lp.v != usize::MAX {
assert_ne!(self.idx_loop, 0);
} else {
for &edge_dir1 in lp.idx2edge_dir.iter() {
if edge_dir1.0 == idx_edge {
wn += 0.5;
} else {
wn += self.cad.edges[edge_dir1.0].get_winding_number(&p0);
}
}
}
wn
}
pub fn check_if_winding_number_is_constant(&self) {
let mut wns = vec!(0_f64; 0);
let lp = &self.cad.topology.loops[self.idx_loop];
if lp.v != usize::MAX {
assert_ne!(self.idx_loop, 0); } else {
for &edge_dir0 in lp.idx2edge_dir.iter() {
let wn = self.winding_number_at_edge(
edge_dir0.0, 0.5_f64);
wns.push(wn);
}
}
let ave: f64 = wns.iter().sum::<f64>() / wns.len() as f64;
for &x in wns.iter() {
assert!((x - ave).abs() < 1.0e-5);
}
}
}
pub struct Face<'a> {
idx_face: usize,
cad: &'a Cad2,
}
impl<'a> Face<'a> {
pub fn area(&self) -> f64 {
let mut area = 0_f64;
for &idx_lp in self.cad.topology.faces[self.idx_face].idx2loop.iter() {
area += self.cad.get_loop(idx_lp).area();
}
area
}
pub fn winding_number_at_edge(
&self,
idx_edge: usize,
ratio: f64) -> f64 {
let mut wn: f64 = 0.0;
for &idx_loop in self.cad.topology.faces[self.idx_face].idx2loop.iter() {
wn += self.cad.get_loop(idx_loop).winding_number_at_edge(idx_edge, ratio);
}
wn
}
}
pub struct Cad2 {
pub topology: CadTopology,
pub vertices: Vec<Vertex>,
pub edges: Vec<Edge>,
}
impl Cad2 {
pub fn new() -> Self {
Self {
topology: CadTopology::new(),
vertices: vec!(),
edges: vec!(),
}
}
pub fn get_face(&self, idx_face: usize) -> Face {
Face { idx_face: idx_face, cad: self }
}
pub fn get_loop(&self, idx_loop: usize) -> Loop {
Loop { idx_loop: idx_loop, cad: self }
}
pub fn num_edge(&self) -> usize {
self.edges.len()
}
pub fn check(&self) -> bool {
assert!(self.topology.check());
if self.vertices.len() != self.topology.num_vertex {
return false;
}
if self.edges.len() != self.topology.edges.len() {
return false;
}
for idx_loop in 0..self.topology.loops.len() {
self.get_loop(idx_loop).check_if_winding_number_is_constant();
}
return true;
}
pub fn add_polygon(
&mut self,
vtx2xy: &[f64]) -> usize {
let np = vtx2xy.len() / 2;
let idx_loop = self.topology.add_polygon(np);
for ip in 0..np {
self.vertices.push(Vertex::new(vtx2xy[ip * 2 + 0], vtx2xy[ip * 2 + 1]));
}
for _ie in 0..np {
self.edges.push(Edge::new());
}
self.copy_vertex_positions_to_edges();
debug_assert!(self.check());
idx_loop
}
pub fn add_vertex_to_face(
&mut self,
x0: f64,
y0: f64,
ifc_add: usize) {
if ifc_add >= self.topology.faces.len() { return; }
self.topology.add_vertex_to_face(ifc_add);
debug_assert!(self.topology.check());
self.vertices.push(Vertex::new(x0, y0));
self.copy_vertex_positions_to_edges();
debug_assert!(self.check());
}
pub fn add_new_vertex_to_edge(
&mut self,
x: f64, y: f64, idx_edge: usize) -> usize {
if idx_edge >= self.topology.edges.len() { return usize::MAX; }
let idx_vtx_new = self.topology.add_new_vertex_to_edge(idx_edge);
debug_assert!(self.topology.check());
self.vertices.push(Vertex::new(x, y));
self.edges.push(Edge::new());
self.copy_vertex_positions_to_edges();
debug_assert!(self.check());
idx_vtx_new
}
pub fn add_vertex_to_edge(
&mut self,
idx_vtx: usize,
idx_edge: usize) -> bool {
if idx_edge >= self.topology.edges.len() { return false; }
if idx_vtx >= self.topology.num_vertex { return false; }
let res = self.topology.add_existing_vertex_to_edge(idx_vtx, idx_edge);
if !res { return false; }
self.edges.push(Edge::new());
self.copy_vertex_positions_to_edges();
debug_assert!(self.check());
true
}
fn copy_vertex_positions_to_edges(&mut self) {
for ie in 0..self.topology.edges.len() {
let iv0 = self.topology.edges[ie].v0;
let iv1 = self.topology.edges[ie].v1;
self.edges[ie].p0 = self.vertices[iv0].pos;
self.edges[ie].p1 = self.vertices[iv1].pos;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let mut cad2 = Cad2::new();
let i0_face = cad2.add_polygon(&[
0., 0.,
1., 0.,
1., 1.]);
assert!(cad2.check());
assert!((cad2.get_face(i0_face).area() - 0.5).abs() < 1.0e-5);
let i1_face = cad2.add_polygon(&[
1.1, 0.2,
2.1, 0.2,
2.1, 1.2,
1.1, 1.2]);
assert!(cad2.check());
assert!((cad2.get_face(i1_face).area() - 1.0).abs() < 1.0e-5);
}
}