pub mod geom;
pub mod interpolation;
#[cfg(feature = "c_api")]
mod c_interface;
use rand::prelude::thread_rng;
use rand::Rng;
use serde_json::Map;
use serde_json::json;
use serde_json::Value;
use std::fmt;
use std::fs::File;
use std::io::Write;
#[derive(Debug, PartialEq)]
pub enum StartinError {
EmptyTriangulation,
OutsideConvexHull,
SearchCircleEmpty,
TriangleNotPresent,
VertexInfinite,
VertexRemoved,
VertexUnknown,
TinHasNoAttributes,
WrongAttribute,
}
pub enum InsertionStrategy {
AsIs,
BBox,
}
pub enum DuplicateHandling {
First,
Last,
Highest,
Lowest,
}
impl fmt::Display for DuplicateHandling {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
DuplicateHandling::First => write!(f, "First"),
DuplicateHandling::Last => write!(f, "Last"),
DuplicateHandling::Highest => write!(f, "Highest"),
DuplicateHandling::Lowest => write!(f, "Lowest"),
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct Triangle {
pub v: [usize; 3],
}
impl Triangle {
fn is_infinite(&self) -> bool {
if self.v[0] == 0 || self.v[1] == 0 || self.v[2] == 0 {
return true;
}
false
}
}
impl fmt::Display for Triangle {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {}, {})", self.v[0], self.v[1], self.v[2])
}
}
#[repr(C)]
#[derive(Debug, Clone)]
struct Link(Vec<usize>);
impl Link {
fn new() -> Link {
Link(Vec::with_capacity(8))
}
fn len(&self) -> usize {
self.0.len()
}
fn is_empty(&self) -> bool {
self.0.len() == 0
}
fn add(&mut self, v: usize) {
self.0.push(v);
}
fn insert_after_v(&mut self, v: usize, after: usize) {
let pos = self.0.iter().position(|&x| x == after).unwrap();
self.0.insert(pos + 1, v);
}
fn delete(&mut self, v: usize) {
let re = self.0.iter().position(|&x| x == v);
if re.is_some() {
self.0.remove(re.unwrap());
}
}
fn replace(&mut self, v: usize, newv: usize) {
let re = self.0.iter().position(|&x| x == v);
if re.is_some() {
self.0[re.unwrap()] = newv;
}
}
fn infinite_first(&mut self) {
let re = self.0.iter().position(|&x| x == 0);
if re.is_some() {
let posinf = re.unwrap();
if posinf == 0 {
return;
}
let mut newstar: Vec<usize> = Vec::new();
for j in posinf..self.0.len() {
newstar.push(self.0[j]);
}
for j in 0..posinf {
newstar.push(self.0[j]);
}
self.0 = newstar;
}
}
fn clear(&mut self) {
self.0.clear();
}
fn contains_infinite_vertex(&self) -> bool {
let pos = self.0.iter().position(|&x| x == 0);
pos.is_some()
}
fn next_index(&self, i: usize) -> usize {
if i == (self.0.len() - 1) {
0
} else {
i + 1
}
}
fn prev_index(&self, i: usize) -> usize {
if i == 0 {
self.0.len() - 1
} else {
i - 1
}
}
fn get_index(&self, v: usize) -> Option<usize> {
return self.0.iter().position(|&x| x == v);
}
fn get_next_vertex(&self, v: usize) -> Option<usize> {
let re = self.get_index(v);
re?;
let pos = re.unwrap();
if pos == (self.0.len() - 1) {
Some(self.0[0])
} else {
Some(self.0[pos + 1])
}
}
fn get_prev_vertex(&self, v: usize) -> Option<usize> {
let re = self.get_index(v);
re?;
let pos = re.unwrap();
if pos == 0 {
Some(self.0[self.0.len() - 1])
} else {
Some(self.0[pos - 1])
}
}
fn iter(&self) -> Iter {
Iter(Box::new(self.0.iter()))
}
}
struct Iter<'a>(Box<dyn Iterator<Item = &'a usize> + 'a>);
impl<'a> Iterator for Iter<'a> {
type Item = &'a usize;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl std::ops::Index<usize> for Link {
type Output = usize;
fn index(&self, idx: usize) -> &usize {
&self.0[idx]
}
}
impl fmt::Display for Link {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(&format!("link: {:?}\n", self.0))?;
Ok(())
}
}
#[repr(C)]
struct Star {
pt: [f64; 3],
link: Link,
}
impl Star {
fn new(x: f64, y: f64, z: f64) -> Star {
let l = Link::new();
Star {
pt: [x, y, z],
link: l,
}
}
fn is_deleted(&self) -> bool {
self.link.is_empty()
}
}
#[repr(C)]
pub struct Triangulation {
stars: Vec<Star>,
attributes: Option<Vec<Value>>,
attributes_schema: Vec<(String, String)>,
snaptol: f64,
cur: usize,
is_init: bool,
jump_and_walk: bool,
robust_predicates: bool,
removed_indices: Vec<usize>,
duplicates_handling: DuplicateHandling,
}
impl Default for Triangulation {
fn default() -> Self {
Self::new()
}
}
impl Triangulation {
pub fn new() -> Triangulation {
let l: Vec<Star> = vec![Star::new(f64::INFINITY, f64::INFINITY, f64::INFINITY)];
let es: Vec<usize> = Vec::new();
Triangulation {
stars: l,
attributes: None,
attributes_schema: Vec::new(),
snaptol: 0.001,
cur: 0,
is_init: false,
jump_and_walk: false,
robust_predicates: true,
removed_indices: es,
duplicates_handling: DuplicateHandling::First,
}
}
fn insert_one_pt_init_phase(&mut self, x: f64, y: f64, z: f64) -> Result<usize, (usize, bool)> {
let p: [f64; 3] = [x, y, z];
for i in 1..self.stars.len() {
if geom::distance2d_squared(&self.stars[i].pt, &p) <= (self.snaptol * self.snaptol) {
return Err((i, self.update_z_value_duplicate(i, z)));
}
}
self.collect_garbage();
self.stars.push(Star::new(x, y, z));
let l = self.stars.len();
if l >= 4 {
let a = l - 3;
let b = l - 2;
let c = l - 1;
let re = geom::orient2d(
&self.stars[a].pt,
&self.stars[b].pt,
&self.stars[c].pt,
self.robust_predicates,
);
if re == 1 {
self.stars[0].link.add(a);
self.stars[0].link.add(c);
self.stars[0].link.add(b);
self.stars[a].link.add(0);
self.stars[a].link.add(b);
self.stars[a].link.add(c);
self.stars[b].link.add(0);
self.stars[b].link.add(c);
self.stars[b].link.add(a);
self.stars[c].link.add(0);
self.stars[c].link.add(a);
self.stars[c].link.add(b);
self.is_init = true;
} else if re == -1 {
self.stars[0].link.add(a);
self.stars[0].link.add(b);
self.stars[0].link.add(c);
self.stars[a].link.add(0);
self.stars[a].link.add(c);
self.stars[a].link.add(b);
self.stars[b].link.add(0);
self.stars[b].link.add(a);
self.stars[b].link.add(c);
self.stars[c].link.add(0);
self.stars[c].link.add(b);
self.stars[c].link.add(a);
self.is_init = true;
}
}
self.cur = l - 1;
if self.is_init {
for j in 1..(l - 3) {
let tr = self.walk(&self.stars[j].pt);
self.flip13(j, &tr);
self.update_dt(j);
}
}
match &mut self.attributes {
Some(x) => x.push(json!({})),
_ => (),
};
Ok(self.cur)
}
pub fn set_snap_tolerance(&mut self, snaptol: f64) -> f64 {
if snaptol > 0.0 {
self.snaptol = snaptol;
}
self.snaptol
}
pub fn get_snap_tolerance(&self) -> f64 {
self.snaptol
}
pub fn set_jump_and_walk(&mut self, b: bool) {
self.jump_and_walk = b;
}
pub fn get_jump_and_walk(&self) -> bool {
self.jump_and_walk
}
pub fn is_using_robust_predicates(&self) -> bool {
self.robust_predicates
}
pub fn use_robust_predicates(&mut self, b: bool) {
self.robust_predicates = b;
}
pub fn set_duplicates_handling(&mut self, method: DuplicateHandling) {
self.duplicates_handling = method;
}
pub fn get_duplicates_handling(&self) -> String {
self.duplicates_handling.to_string()
}
pub fn insert(&mut self, pts: &Vec<[f64; 3]>, strategy: InsertionStrategy) {
let mut mystrategy = strategy;
if pts.is_empty() {
mystrategy = InsertionStrategy::AsIs;
}
match mystrategy {
InsertionStrategy::BBox => {
let mut bbox = geom::bbox2d(&pts);
if (bbox[0] == std::f64::MAX)
|| (bbox[1] == std::f64::MAX)
|| (bbox[2] == std::f64::MIN)
|| (bbox[3] == std::f64::MIN)
{
for each in pts {
let _re = self.insert_one_pt(each[0], each[1], each[2]);
}
} else {
bbox[0] -= 10.0;
bbox[1] -= 10.0;
bbox[2] += 10.0;
bbox[3] += 10.0;
self.insert_with_bbox(&pts, &bbox);
}
}
InsertionStrategy::AsIs => {
for each in pts {
let _re = self.insert_one_pt(each[0], each[1], each[2]);
}
} }
}
fn insert_with_bbox(&mut self, pts: &Vec<[f64; 3]>, bbox: &[f64; 4]) {
let mut c4: Vec<usize> = Vec::new();
c4.push(self.insert_one_pt(bbox[0], bbox[1], 0.0).unwrap());
c4.push(self.insert_one_pt(bbox[2], bbox[1], 0.0).unwrap());
c4.push(self.insert_one_pt(bbox[2], bbox[3], 0.0).unwrap());
c4.push(self.insert_one_pt(bbox[0], bbox[3], 0.0).unwrap());
for each in pts {
let _re = self.insert_one_pt(each[0], each[1], each[2]);
}
for each in &c4 {
let _re = self.remove(*each);
}
self.collect_garbage();
}
pub fn insert_one_pt(&mut self, px: f64, py: f64, pz: f64) -> Result<usize, (usize, bool)> {
self.insert_one_pt_z_handling(px, py, pz, true)
}
fn insert_one_pt_interpol(&mut self, px: f64, py: f64) -> Result<usize, (usize, bool)> {
self.insert_one_pt_z_handling(px, py, 0.0, false)
}
fn insert_one_pt_z_handling(
&mut self,
px: f64,
py: f64,
pz: f64,
zupdate: bool,
) -> Result<usize, (usize, bool)> {
if !self.is_init {
return self.insert_one_pt_init_phase(px, py, pz);
}
let p: [f64; 3] = [px, py, pz];
let tr = self.walk(&p);
if geom::distance2d_squared(&self.stars[tr.v[0]].pt, &p) <= (self.snaptol * self.snaptol) {
if zupdate {
return Err((tr.v[0], self.update_z_value_duplicate(tr.v[0], pz)));
} else {
return Err((tr.v[0], false));
}
}
if geom::distance2d_squared(&self.stars[tr.v[1]].pt, &p) <= (self.snaptol * self.snaptol) {
if zupdate {
return Err((tr.v[1], self.update_z_value_duplicate(tr.v[1], pz)));
} else {
return Err((tr.v[1], false));
}
}
if geom::distance2d_squared(&self.stars[tr.v[2]].pt, &p) <= (self.snaptol * self.snaptol) {
if zupdate {
return Err((tr.v[2], self.update_z_value_duplicate(tr.v[2], pz)));
} else {
return Err((tr.v[2], false));
}
}
let pi: usize;
if self.removed_indices.is_empty() {
self.stars.push(Star::new(px, py, pz));
pi = self.stars.len() - 1;
} else {
pi = self.removed_indices.pop().unwrap();
self.stars[pi].pt[0] = px;
self.stars[pi].pt[1] = py;
self.stars[pi].pt[2] = pz;
}
self.flip13(pi, &tr);
self.update_dt(pi);
self.cur = pi;
match &mut self.attributes {
Some(x) => x.push(json!({})),
_ => (),
}
Ok(pi)
}
fn update_z_value_duplicate(&mut self, vi: usize, newz: f64) -> bool {
let mut re = false;
match self.duplicates_handling {
DuplicateHandling::Last => {
self.stars[vi].pt[2] = newz;
re = true;
}
DuplicateHandling::Highest => {
if newz > self.stars[vi].pt[2] {
self.stars[vi].pt[2] = newz;
re = true;
}
}
DuplicateHandling::Lowest => {
if newz < self.stars[vi].pt[2] {
self.stars[vi].pt[2] = newz;
re = true;
}
}
DuplicateHandling::First => (),
}
re
}
fn update_dt(&mut self, pi: usize) {
let mut mystack: Vec<Triangle> = Vec::new();
mystack.push(Triangle {
v: [pi, self.stars[pi].link[0], self.stars[pi].link[1]],
});
mystack.push(Triangle {
v: [pi, self.stars[pi].link[1], self.stars[pi].link[2]],
});
mystack.push(Triangle {
v: [pi, self.stars[pi].link[2], self.stars[pi].link[0]],
});
loop {
let tr = match mystack.pop() {
None => break,
Some(x) => x,
};
let opposite = self.get_opposite_vertex(&tr);
if tr.is_infinite() {
let mut a: i8 = 0;
if tr.v[0] == 0 {
a = geom::orient2d(
&self.stars[opposite].pt,
&self.stars[tr.v[1]].pt,
&self.stars[tr.v[2]].pt,
self.robust_predicates,
);
} else if tr.v[1] == 0 {
a = geom::orient2d(
&self.stars[tr.v[0]].pt,
&self.stars[opposite].pt,
&self.stars[tr.v[2]].pt,
self.robust_predicates,
);
} else if tr.v[2] == 0 {
a = geom::orient2d(
&self.stars[tr.v[0]].pt,
&self.stars[tr.v[1]].pt,
&self.stars[opposite].pt,
self.robust_predicates,
);
}
if a > 0 {
let (ret0, ret1) = self.flip22(&tr, opposite);
mystack.push(ret0);
mystack.push(ret1);
}
} else {
if opposite == 0 {
if geom::orient2d(
&self.stars[tr.v[0]].pt,
&self.stars[tr.v[1]].pt,
&self.stars[tr.v[2]].pt,
self.robust_predicates,
) == 0
{
let (ret0, ret1) = self.flip22(&tr, 0);
mystack.push(ret0);
mystack.push(ret1);
}
} else {
if geom::incircle(
&self.stars[tr.v[0]].pt,
&self.stars[tr.v[1]].pt,
&self.stars[tr.v[2]].pt,
&self.stars[opposite].pt,
self.robust_predicates,
) > 0
{
let (ret0, ret1) = self.flip22(&tr, opposite);
mystack.push(ret0);
mystack.push(ret1);
}
}
}
}
}
fn flip13(&mut self, pi: usize, tr: &Triangle) {
self.stars[pi].link.add(tr.v[0]);
self.stars[pi].link.add(tr.v[1]);
self.stars[pi].link.add(tr.v[2]);
self.stars[tr.v[0]].link.insert_after_v(pi, tr.v[1]);
self.stars[tr.v[1]].link.insert_after_v(pi, tr.v[2]);
self.stars[tr.v[2]].link.insert_after_v(pi, tr.v[0]);
self.stars[pi].link.infinite_first();
}
fn flip31(&mut self, vi: usize) {
let mut ns: Vec<usize> = Vec::new();
for each in self.stars[vi].link.iter() {
ns.push(*each);
}
for n in ns.iter() {
self.stars[*n].link.delete(vi);
}
self.stars[vi].link.clear();
self.stars[vi].pt[0] = f64::NAN;
self.stars[vi].pt[1] = f64::NAN;
self.stars[vi].pt[2] = f64::NAN;
self.removed_indices.push(vi);
if self.attributes.is_some() {
let _ = self.reset_vertex_attributes(vi);
}
if ns[0] != 0 {
self.cur = ns[0];
} else if ns[1] != 0 {
self.cur = ns[1];
} else if ns[2] != 0 {
self.cur = ns[2];
}
}
pub fn get_point(&self, vi: usize) -> Result<Vec<f64>, StartinError> {
match self.is_vertex_removed(vi) {
Err(why) => Err(why),
Ok(b) => match b {
true => Err(StartinError::VertexRemoved),
false => Ok(self.stars[vi].pt.to_vec()),
},
}
}
pub fn get_attributes_schema(&self) -> Vec<(String, String)> {
self.attributes_schema.clone()
}
pub fn set_attributes_schema(
&mut self,
att_schema: Vec<(String, String)>,
) -> Result<(), StartinError> {
let dtypes_allowed: Vec<String> = vec![
"f64".to_string(),
"i64".to_string(),
"u64".to_string(),
"bool".to_string(),
"String".to_string(),
];
for each in &att_schema {
if dtypes_allowed.iter().any(|e| *e == *each.1) {
self.attributes_schema
.push((each.0.clone(), each.1.clone()));
} else {
return Err(StartinError::WrongAttribute);
}
}
self.attributes = Some(vec![json!({}); self.stars.len()]);
Ok(())
}
pub fn get_vertex_attributes(&self, vi: usize) -> Result<Value, StartinError> {
match self.is_vertex_removed(vi) {
Err(why) => Err(why),
Ok(b) => match b {
true => Err(StartinError::VertexRemoved),
false => match &self.attributes {
Some(x) => Ok(x.get(vi).unwrap().clone()),
None => Err(StartinError::TinHasNoAttributes),
},
},
}
}
fn reset_vertex_attributes(&mut self, vi: usize) -> Result<bool, StartinError> {
match self.is_vertex_removed(vi) {
Err(why) => Err(why),
Ok(_b) => match &mut self.attributes {
Some(x) => {
*x.get_mut(vi).unwrap() = json!({});
return Ok(true);
}
None => {
return Err(StartinError::TinHasNoAttributes);
}
},
}
}
pub fn add_vertex_attributes(&mut self, vi: usize, a: Value) -> Result<bool, StartinError> {
match self.is_vertex_removed(vi) {
Err(why) => Err(why),
Ok(_b) => match &mut self.attributes {
Some(x) => {
if a.is_object() == false {
return Ok(false);
}
let mut a2: Map<String, Value> = Map::new();
let a1 = a.as_object().unwrap();
for (p, v2) in a1 {
let c = self
.attributes_schema
.iter()
.position(|(first, _)| first == p);
if c.is_some() {
match self.attributes_schema.get(c.unwrap()).unwrap().1.as_ref() {
"f64" => {
if v2.is_number() {
a2.insert(p.to_string(), v2.clone());
}
}
"i64" => {
if v2.is_i64() {
a2.insert(p.to_string(), v2.clone());
}
}
"u64" => {
if v2.is_u64() {
a2.insert(p.to_string(), v2.clone());
}
}
"String" => {
if v2.is_string() {
a2.insert(p.to_string(), v2.clone());
}
}
"bool" => {
if v2.is_boolean() {
a2.insert(p.to_string(), v2.clone());
}
}
_ => continue,
}
}
}
let v = x.get_mut(vi).unwrap();
let vo = v.as_object_mut().unwrap();
vo.append(&mut a2);
Ok(true)
}
None => {
return Err(StartinError::TinHasNoAttributes);
}
},
}
}
pub fn all_attributes(&self) -> Option<Vec<Value>> {
self.attributes.clone()
}
pub fn adjacent_triangles_to_triangle(
&self,
tr: &Triangle,
) -> Result<Vec<Triangle>, StartinError> {
if !self.is_triangle(&tr) || tr.is_infinite() {
return Err(StartinError::TriangleNotPresent);
}
let mut trs: Vec<Triangle> = Vec::new();
let mut opp = self.stars[tr.v[2]].link.get_next_vertex(tr.v[1]).unwrap();
trs.push(Triangle {
v: [tr.v[1], opp, tr.v[2]],
});
opp = self.stars[tr.v[0]].link.get_next_vertex(tr.v[2]).unwrap();
trs.push(Triangle {
v: [tr.v[2], opp, tr.v[0]],
});
opp = self.stars[tr.v[1]].link.get_next_vertex(tr.v[0]).unwrap();
trs.push(Triangle {
v: [tr.v[0], opp, tr.v[1]],
});
Ok(trs)
}
pub fn incident_triangles_to_vertex(&self, vi: usize) -> Result<Vec<Triangle>, StartinError> {
match self.is_vertex_removed(vi) {
Err(why) => Err(why),
Ok(b) => match b {
true => Err(StartinError::VertexRemoved),
false => {
let mut trs: Vec<Triangle> = Vec::new();
for (i, each) in self.stars[vi].link.iter().enumerate() {
let j = self.stars[vi].link.next_index(i);
trs.push(Triangle {
v: [vi, *each, self.stars[vi].link[j]],
});
}
Ok(trs)
}
},
}
}
pub fn normal_vertex(&self, vi: usize) -> Result<Vec<f64>, StartinError> {
match self.incident_triangles_to_vertex(vi) {
Err(why) => Err(why),
Ok(trs) => {
let mut avgns: Vec<f64> = vec![0.0, 0.0, 0.0];
let mut no_finite_tr = 0;
for tr in &trs {
if self.is_finite(tr) == false {
continue;
}
no_finite_tr += 1;
let n = geom::normal_triangle(
&self.stars[tr.v[0]].pt,
&self.stars[tr.v[1]].pt,
&self.stars[tr.v[2]].pt,
true,
);
for j in 0..3 {
avgns[j] += n[j];
}
}
for j in 0..3 {
avgns[j] /= no_finite_tr as f64;
}
let norm =
((avgns[0] * avgns[0]) + (avgns[1] * avgns[1]) + (avgns[2] * avgns[2])).sqrt();
Ok(vec![avgns[0] / norm, avgns[1] / norm, avgns[2] / norm])
}
}
}
pub fn normal_triangle(&self, tr: &Triangle) -> Result<Vec<f64>, StartinError> {
match self.is_triangle(tr) {
false => Err(StartinError::TriangleNotPresent),
true => Ok(geom::normal_triangle(
&self.stars[tr.v[0]].pt,
&self.stars[tr.v[1]].pt,
&self.stars[tr.v[2]].pt,
true,
)),
}
}
pub fn area2d_triangle(&self, tr: &Triangle) -> Result<f64, StartinError> {
match self.is_triangle(tr) {
false => Err(StartinError::TriangleNotPresent),
true => Ok(geom::area2d_triangle(
&self.stars[tr.v[0]].pt,
&self.stars[tr.v[1]].pt,
&self.stars[tr.v[2]].pt,
)),
}
}
pub fn area3d_triangle(&self, tr: &Triangle) -> Result<f64, StartinError> {
match self.is_triangle(tr) {
false => Err(StartinError::TriangleNotPresent),
true => Ok(geom::area3d_triangle(
&self.stars[tr.v[0]].pt,
&self.stars[tr.v[1]].pt,
&self.stars[tr.v[2]].pt,
)),
}
}
pub fn volume_triangle(&self, tr: &Triangle, planez: f64) -> Result<f64, StartinError> {
match self.is_triangle(tr) {
false => Err(StartinError::TriangleNotPresent),
true => Ok(geom::volume_triangle_from_base(
&self.stars[tr.v[0]].pt,
&self.stars[tr.v[1]].pt,
&self.stars[tr.v[2]].pt,
planez,
)),
}
}
pub fn degree(&self, vi: usize) -> Result<usize, StartinError> {
match self.is_vertex_removed(vi) {
Err(why) => Err(why),
Ok(b) => match b {
true => Err(StartinError::VertexRemoved),
false => Ok(self.stars[vi].link.len()),
},
}
}
pub fn adjacent_vertices_to_vertex(&self, vi: usize) -> Result<Vec<usize>, StartinError> {
match self.is_vertex_removed(vi) {
Err(why) => Err(why),
Ok(b) => match b {
true => Err(StartinError::VertexRemoved),
false => {
let mut adjs: Vec<usize> = Vec::new();
for each in self.stars[vi].link.iter() {
adjs.push(*each);
}
Ok(adjs)
}
},
}
}
pub fn is_triangle(&self, tr: &Triangle) -> bool {
if tr.v[0] >= self.stars.len() || tr.v[1] >= self.stars.len() || tr.v[2] >= self.stars.len()
{
return false;
}
let re = self.stars[tr.v[0]].link.get_next_vertex(tr.v[1]);
if re.is_none() {
return false;
} else {
if re.unwrap() == tr.v[2] {
return true;
} else {
return false;
}
}
}
pub fn is_finite(&self, tr: &Triangle) -> bool {
return !tr.is_infinite();
}
pub fn statistics_degree(&self) -> (f64, usize, usize) {
let mut total: f64 = 0.0;
let mut min: usize = usize::max_value();
let mut max: usize = usize::min_value();
for i in 1..self.stars.len() {
total += self.stars[i].link.len() as f64;
if self.stars[i].link.len() > max {
max = self.stars[i].link.len();
}
if self.stars[i].link.len() < min {
min = self.stars[i].link.len();
}
}
total /= (self.stars.len() - 2) as f64;
(total, min, max)
}
pub fn number_of_vertices(&self) -> usize {
self.stars.len() - 1 - self.removed_indices.len()
}
pub fn number_of_triangles(&self) -> usize {
let mut count: usize = 0;
for (i, star) in self.stars.iter().enumerate() {
for (j, value) in star.link.iter().enumerate() {
if i < *value {
let k = star.link[star.link.next_index(j)];
if i < k {
let tr = Triangle { v: [i, *value, k] };
if !tr.is_infinite() {
count += 1;
}
}
}
}
}
count
}
pub fn number_of_removed_vertices(&self) -> usize {
self.removed_indices.len()
}
pub fn is_vertex_removed(&self, vi: usize) -> Result<bool, StartinError> {
if vi >= self.stars.len() {
return Err(StartinError::VertexUnknown);
}
Ok(self.stars[vi].is_deleted())
}
pub fn convex_hull(&self) -> Vec<usize> {
let mut re: Vec<usize> = Vec::new();
for x in self.stars[0].link.iter() {
re.push(*x);
}
re.reverse();
re
}
pub fn number_of_vertices_on_convex_hull(&self) -> usize {
if !self.is_init {
return 0;
}
self.stars[0].link.len()
}
pub fn is_vertex_convex_hull(&self, vi: usize) -> bool {
if vi == 0 {
return false;
}
if !self.is_vertex_valid(vi) {
return false;
}
self.stars[vi].link.contains_infinite_vertex()
}
pub fn locate(&mut self, px: f64, py: f64) -> Result<Triangle, StartinError> {
if !self.is_init {
return Err(StartinError::EmptyTriangulation);
}
let p: [f64; 3] = [px, py, 0.0];
let re = self.walk(&p);
match re.is_infinite() {
true => Err(StartinError::OutsideConvexHull),
false => {
self.cur = re.v[0];
return Ok(re);
}
}
}
pub fn closest_point(&mut self, px: f64, py: f64) -> Result<usize, StartinError> {
let re = self.locate(px, py);
if re.is_err() {
return Err(re.err().unwrap());
}
let p: [f64; 3] = [px, py, 0.0];
let tr = re.unwrap();
let mut d = std::f64::MAX;
let mut closest: usize = 0;
for each in tr.v.iter() {
let dtmp = geom::distance2d_squared(&self.stars[*each].pt, &p);
if dtmp < d {
d = dtmp;
closest = *each;
}
}
loop {
let mut found_one_closer = false;
for each in self.stars[closest].link.iter() {
let dtmp = geom::distance2d_squared(&self.stars[*each].pt, &p);
if dtmp < d {
d = dtmp;
closest = *each;
found_one_closer = true;
break;
}
}
if !found_one_closer {
break;
}
}
Ok(closest)
}
fn walk(&self, x: &[f64]) -> Triangle {
let mut cur = self.cur;
if self.jump_and_walk {
let mut rng = thread_rng();
let mut d: f64 = geom::distance2d_squared(&self.stars[self.cur].pt, x);
let n = (self.stars.len() as f64).powf(0.25);
for _i in 0..n as i32 {
let re: usize = rng.gen_range(1, self.stars.len());
if self.stars[re].is_deleted() {
continue;
}
let dtemp = geom::distance2d_squared(&self.stars[re].pt, x);
if dtemp < d {
cur = re;
d = dtemp;
}
}
}
let mut tr = Triangle { v: [0, 0, 0] };
tr.v[0] = cur;
let l = &self.stars[cur].link;
for i in 0..(l.len() - 1) {
if (l[i] != 0) && (l[i + 1] != 0) {
tr.v[1] = l[i];
tr.v[2] = l[i + 1];
break;
}
}
if geom::orient2d(
&self.stars[tr.v[0]].pt,
&self.stars[tr.v[1]].pt,
x,
self.robust_predicates,
) == -1
{
if geom::orient2d(
&self.stars[tr.v[1]].pt,
&self.stars[tr.v[2]].pt,
x,
self.robust_predicates,
) != -1
{
let tmp: usize = tr.v[0];
tr.v[0] = tr.v[1];
tr.v[1] = tr.v[2];
tr.v[2] = tmp;
} else {
let tmp: usize = tr.v[1];
tr.v[1] = tr.v[0];
tr.v[0] = tr.v[2];
tr.v[2] = tmp;
}
}
loop {
if tr.is_infinite() {
break;
}
if geom::orient2d(
&self.stars[tr.v[1]].pt,
&self.stars[tr.v[2]].pt,
x,
self.robust_predicates,
) != -1
{
if geom::orient2d(
&self.stars[tr.v[2]].pt,
&self.stars[tr.v[0]].pt,
x,
self.robust_predicates,
) != -1
{
break;
} else {
let prev = self.stars[tr.v[2]].link.get_prev_vertex(tr.v[0]).unwrap();
tr.v[1] = tr.v[2];
tr.v[2] = prev;
}
} else {
let prev = self.stars[tr.v[1]].link.get_prev_vertex(tr.v[2]).unwrap();
tr.v[0] = tr.v[2];
tr.v[2] = prev;
}
}
tr
}
fn flip22(&mut self, tr: &Triangle, opposite: usize) -> (Triangle, Triangle) {
self.stars[tr.v[0]].link.insert_after_v(opposite, tr.v[1]);
self.stars[tr.v[1]].link.delete(tr.v[2]);
self.stars[opposite].link.insert_after_v(tr.v[0], tr.v[2]);
self.stars[tr.v[2]].link.delete(tr.v[1]);
let ret0 = Triangle {
v: [tr.v[0], tr.v[1], opposite],
};
let ret1 = Triangle {
v: [tr.v[0], opposite, tr.v[2]],
};
(ret0, ret1)
}
fn get_opposite_vertex(&self, tr: &Triangle) -> usize {
self.stars[tr.v[2]].link.get_next_vertex(tr.v[1]).unwrap()
}
pub fn all_vertices(&self) -> Vec<Vec<f64>> {
let mut pts: Vec<Vec<f64>> = Vec::with_capacity(self.stars.len() - 1);
for i in 0..self.stars.len() {
pts.push(self.stars[i].pt.to_vec());
}
pts
}
pub fn all_finite_edges(&self) -> Vec<usize> {
let mut edges: Vec<usize> = Vec::new();
for i in 1..self.stars.len() {
for value in self.stars[i].link.iter() {
if (*value != 0) && (i < *value) {
edges.push(i);
edges.push(*value);
}
}
}
edges
}
pub fn all_triangles(&self) -> Vec<Triangle> {
let mut trs: Vec<Triangle> = Vec::new();
for (i, star) in self.stars.iter().enumerate() {
for (j, value) in star.link.iter().enumerate() {
if i < *value {
let k = star.link[star.link.next_index(j)];
if i < k {
trs.push(Triangle { v: [i, *value, k] });
}
}
}
}
trs
}
pub fn all_finite_triangles(&self) -> Vec<Triangle> {
let alltrs = self.all_triangles();
let mut re: Vec<Triangle> = Vec::new();
for t in &alltrs {
if !t.is_infinite() {
re.push(t.clone());
}
}
re
}
pub fn is_valid(&self) -> bool {
self.is_valid_ch_convex() && self.is_valid_circumcircle()
}
fn is_valid_circumcircle(&self) -> bool {
let mut re = true;
let trs = self.all_finite_triangles();
for tr in trs.iter() {
for i in 1..self.stars.len() {
if !self.stars[i].is_deleted()
&& geom::incircle(
&self.stars[tr.v[0]].pt,
&self.stars[tr.v[1]].pt,
&self.stars[tr.v[2]].pt,
&self.stars[i].pt,
self.robust_predicates,
) > 0
{
println!("NOT DELAUNAY FFS!");
println!("{} with {}", tr, i);
re = false
}
}
}
re
}
fn is_valid_ch_convex(&self) -> bool {
let mut re = true;
let ch = self.convex_hull();
for i in 0..ch.len() {
if geom::orient2d(
&self.stars[ch[i % ch.len()]].pt,
&self.stars[ch[(i + 1) % ch.len()]].pt,
&self.stars[ch[(i + 2) % ch.len()]].pt,
self.robust_predicates,
) == -1
{
re = false;
break;
}
}
if !re {
println!("CONVEX NOT CONVEX");
}
re
}
fn remove_on_convex_hull(&mut self, v: usize) -> Result<usize, StartinError> {
let mut adjs: Vec<usize> = Vec::new();
self.stars[v].link.infinite_first();
for each in self.stars[v].link.iter() {
adjs.push(*each);
}
let mut cur: usize = 0;
let mut nadjs = adjs.len();
let mut steps = 0;
while adjs.len() > 3 {
if steps == nadjs {
break;
}
if adjs.len() == nadjs {
steps += 1;
} else {
nadjs = adjs.len();
steps = 0;
}
let a = cur % adjs.len();
let b = (cur + 1) % adjs.len();
let c = (cur + 2) % adjs.len();
if adjs[a] == 0 || adjs[b] == 0 || adjs[c] == 0 {
cur += 1;
continue;
}
if (geom::orient2d(
&self.stars[adjs[a]].pt,
&self.stars[adjs[b]].pt,
&self.stars[adjs[c]].pt,
self.robust_predicates,
) == 1)
&& (geom::orient2d(
&self.stars[adjs[a]].pt,
&self.stars[adjs[c]].pt,
&self.stars[v].pt,
self.robust_predicates,
) >= 0)
{
let cur2 = cur + 3;
let mut isdel = true;
for i in 0..adjs.len() - 3 {
if adjs[(cur2 + i) % adjs.len()] != 0
&& geom::incircle(
&self.stars[adjs[a]].pt,
&self.stars[adjs[b]].pt,
&self.stars[adjs[c]].pt,
&self.stars[adjs[(cur2 + i) % adjs.len()]].pt,
self.robust_predicates,
) > 0
{
isdel = false;
break;
}
}
if isdel {
let t = Triangle {
v: [adjs[a], adjs[b], v],
};
self.flip22(&t, adjs[c]);
adjs.remove((cur + 1) % adjs.len());
}
}
cur += 1;
}
if adjs.len() == 3 {
self.flip31(v);
if self.number_of_vertices() < 3 {
for i in 0..self.stars.len() {
self.stars[i].link.clear();
}
self.stars[v].pt[0] = f64::NAN;
self.stars[v].pt[1] = f64::NAN;
self.stars[v].pt[2] = f64::NAN;
self.is_init = false;
}
Ok(self.stars.len() - 1)
} else {
self.stars[adjs[1]].link.delete(v);
self.stars[*(adjs.last().unwrap())].link.delete(v);
for i in 2..(adjs.len() - 1) {
if self.is_vertex_convex_hull(adjs[i]) {
for i in 0..self.stars.len() {
self.stars[i].link.clear();
}
self.stars[v].pt[0] = f64::NAN;
self.stars[v].pt[1] = f64::NAN;
self.stars[v].pt[2] = f64::NAN;
self.removed_indices.push(v);
self.is_init = false;
return Ok(self.stars.len() - 1);
}
self.stars[adjs[i]].link.replace(v, 0);
self.stars[adjs[i]].link.infinite_first();
}
let mut prev = v;
for i in 2..(adjs.len() - 1) {
self.stars[0].link.insert_after_v(adjs[i], prev);
prev = adjs[i];
}
self.stars[adjs[0]].link.delete(v);
self.stars[v].link.clear();
self.stars[v].pt[0] = f64::NAN;
self.stars[v].pt[1] = f64::NAN;
self.stars[v].pt[2] = f64::NAN;
self.removed_indices.push(v);
for i in 0..1000 {
if adjs[i] != 0 {
self.cur = adjs[i];
break;
}
}
Ok(self.stars.len() - 1)
}
}
pub fn remove(&mut self, vi: usize) -> Result<usize, StartinError> {
if vi == 0 {
return Err(StartinError::VertexInfinite);
}
if !self.is_init {
self.stars[vi].pt[0] = f64::NAN;
self.stars[vi].pt[1] = f64::NAN;
self.stars[vi].pt[2] = f64::NAN;
self.removed_indices.push(vi);
if self.attributes.is_some() {
let _ = self.reset_vertex_attributes(vi);
}
}
match self.is_vertex_removed(vi) {
Err(why) => return Err(why),
Ok(b) => {
if b {
return Err(StartinError::VertexRemoved);
}
}
}
if self.is_vertex_convex_hull(vi) {
return self.remove_on_convex_hull(vi);
}
let mut adjs: Vec<usize> = Vec::new();
for each in self.stars[vi].link.iter() {
adjs.push(*each);
}
let mut cur: usize = 0;
while adjs.len() > 3 {
let a = cur % adjs.len();
let b = (cur + 1) % adjs.len();
let c = (cur + 2) % adjs.len();
if (geom::orient2d(
&self.stars[adjs[a]].pt,
&self.stars[adjs[b]].pt,
&self.stars[adjs[c]].pt,
self.robust_predicates,
) == 1)
&& (geom::orient2d(
&self.stars[adjs[a]].pt,
&self.stars[adjs[c]].pt,
&self.stars[vi].pt,
self.robust_predicates,
) >= 0)
{
let cur2 = cur + 3;
let mut isdel = true;
for i in 0..adjs.len() - 3 {
if geom::incircle(
&self.stars[adjs[a]].pt,
&self.stars[adjs[b]].pt,
&self.stars[adjs[c]].pt,
&self.stars[adjs[(cur2 + i) % adjs.len()]].pt,
self.robust_predicates,
) > 0
{
isdel = false;
break;
}
}
if isdel {
let t = Triangle {
v: [adjs[a], adjs[b], vi],
};
self.flip22(&t, adjs[c]);
adjs.remove((cur + 1) % adjs.len());
}
}
cur += 1;
}
self.flip31(vi);
Ok(self.stars.len() - 1)
}
pub fn write_obj(&self, path: String) -> std::io::Result<()> {
let trs = self.all_finite_triangles();
let mut f = File::create(path)?;
let mut s = String::new();
let mut onegoodpt = [1.0, 1.0, 1.0];
for i in 1..self.stars.len() {
if !self.stars[i].is_deleted() {
onegoodpt[0] = self.stars[i].pt[0];
onegoodpt[1] = self.stars[i].pt[1];
onegoodpt[2] = self.stars[i].pt[2];
break;
}
}
for i in 1..self.stars.len() {
if self.stars[i].is_deleted() {
s.push_str(&format!(
"v {} {} {}\n",
onegoodpt[0], onegoodpt[1], onegoodpt[2]
));
continue;
}
s.push_str(&format!(
"v {} {} {}\n",
self.stars[i].pt[0], self.stars[i].pt[1], self.stars[i].pt[2]
));
}
write!(f, "{}", s).unwrap();
let mut s = String::new();
for tr in trs.iter() {
s.push_str(&format!("f {} {} {}\n", tr.v[0], tr.v[1], tr.v[2]));
}
write!(f, "{}", s).unwrap();
Ok(())
}
pub fn write_ply(&self, path: String) -> std::io::Result<()> {
let trs = self.all_finite_triangles();
let mut f = File::create(path)?;
writeln!(f, "ply").unwrap();
writeln!(f, "format ascii 1.0").unwrap();
writeln!(f, "comment made by startin").unwrap();
writeln!(f, "element vertex {}", self.stars.len() - 1).unwrap();
writeln!(f, "property double x").unwrap();
writeln!(f, "property double y").unwrap();
writeln!(f, "property double z").unwrap();
for each in &self.attributes_schema {
match each.1.as_ref() {
"f64" => {
writeln!(f, "property double {}", each.0).unwrap();
}
"i64" => {
writeln!(f, "property int {}", each.0).unwrap();
}
"u64" => {
writeln!(f, "property uint {}", each.0).unwrap();
}
"bool" => {
writeln!(f, "property uint {}", each.0).unwrap();
}
_ => (),
}
}
writeln!(f, "element face {}", trs.len()).unwrap();
writeln!(f, "property list uchar int vertex_indices").unwrap();
writeln!(f, "end_header").unwrap();
let mut onegoodpt = [1.0, 1.0, 1.0];
for i in 1..self.stars.len() {
if !self.stars[i].is_deleted() {
onegoodpt[0] = self.stars[i].pt[0];
onegoodpt[1] = self.stars[i].pt[1];
onegoodpt[2] = self.stars[i].pt[2];
break;
}
}
let mut s = String::new();
for i in 1..self.stars.len() {
if self.stars[i].is_deleted() {
s.push_str(&format!(
"{} {} {}",
onegoodpt[0], onegoodpt[1], onegoodpt[2]
));
} else {
s.push_str(&format!(
"{} {} {}",
self.stars[i].pt[0], self.stars[i].pt[1], self.stars[i].pt[2]
));
}
for each in &self.attributes_schema {
match each.1.as_ref() {
"f64" | "i64" | "u64" => {
let a = self.attributes.as_ref().unwrap();
let b = &a[i];
let c = &b[&each.0];
s.push_str(&format!(" {}", c));
}
"bool" => {
let a = self.attributes.as_ref().unwrap();
let b = &a[i];
let c = &b[&each.0];
if c == true {
s.push_str(" 1");
} else {
s.push_str(" 0");
}
}
_ => (),
}
}
s.push_str("\n");
}
write!(f, "{}", s).unwrap();
let mut s = String::new();
for tr in trs.iter() {
s.push_str(&format!(
"3 {} {} {}\n",
tr.v[0] - 1,
tr.v[1] - 1,
tr.v[2] - 1
));
}
write!(f, "{}", s).unwrap();
Ok(())
}
pub fn printme(&self, withxyz: bool) -> String {
let mut s = String::from("**********\n");
for (i, p) in self.stars.iter().enumerate() {
s.push_str(&format!("{}: [", i));
for each in p.link.iter() {
s.push_str(&format!("{} - ", each));
}
s.push_str(&"]\n".to_string());
if withxyz {
s.push_str(&format!("\t{:?}\n", self.stars[i].pt));
}
}
s.push_str("**********\n");
s
}
pub fn voronoi_cell_area(&self, vi: usize, ignore_infinity: bool) -> Option<f64> {
if !self.is_vertex_valid(vi) {
return None;
}
if !ignore_infinity && self.is_vertex_convex_hull(vi) {
return Some(f64::INFINITY);
}
let mut centres: Vec<Vec<f64>> = Vec::new();
let mut l = self.stars[vi].link.clone();
if l.contains_infinite_vertex() {
l.delete(0);
}
for (i, n) in l.iter().enumerate() {
let j = l.next_index(i);
centres.push(geom::circle_centre(
&self.stars[vi].pt,
&self.stars[*n].pt,
&self.stars[l[j]].pt,
));
}
centres.push(vec![centres[0][0], centres[0][1]]);
let mut totalarea = 0.0_f64;
for c in centres.windows(2) {
totalarea += geom::area2d_triangle(&self.stars[vi].pt, &c[0], &c[1]);
}
Some(totalarea)
}
fn is_vertex_valid(&self, v: usize) -> bool {
let mut re = true;
if v >= self.stars.len() || self.stars[v].is_deleted() {
re = false;
}
re
}
pub fn get_bbox(&self) -> Vec<f64> {
let mut minx: f64 = std::f64::MAX;
let mut miny: f64 = std::f64::MAX;
let mut maxx: f64 = std::f64::MIN;
let mut maxy: f64 = std::f64::MIN;
if self.stars.len() == 1 {
minx = std::f64::NEG_INFINITY;
miny = std::f64::NEG_INFINITY;
maxx = std::f64::INFINITY;
maxy = std::f64::INFINITY;
} else {
for i in 1..self.stars.len() {
if self.is_vertex_removed(i).unwrap() {
continue;
}
if self.stars[i].pt[0] < minx {
minx = self.stars[i].pt[0];
}
if self.stars[i].pt[1] < miny {
miny = self.stars[i].pt[1];
}
if self.stars[i].pt[0] > maxx {
maxx = self.stars[i].pt[0];
}
if self.stars[i].pt[1] > maxy {
maxy = self.stars[i].pt[1];
}
}
}
vec![minx, miny, maxx, maxy]
}
pub fn vertical_exaggeration(&mut self, factor: f64) {
let mut minz: f64 = std::f64::MAX;
for i in 1..self.stars.len() {
if self.stars[i].is_deleted() {
continue;
}
if self.stars[i].pt[2] < minz {
minz = self.stars[i].pt[2];
}
}
for i in 1..self.stars.len() {
if self.stars[i].is_deleted() {
continue;
}
let z2 = ((self.stars[i].pt[2] - minz) * factor) + minz;
self.stars[i].pt[2] = z2;
}
}
pub fn update_vertex_z_value(&mut self, vi: usize, z: f64) -> Result<bool, StartinError> {
if vi == 0 {
return Ok(false);
}
match self.is_vertex_removed(vi) {
Err(why) => Err(why),
Ok(_b) => {
self.stars[vi].pt[2] = z;
Ok(true)
}
}
}
pub fn has_garbage(&self) -> bool {
self.number_of_removed_vertices() > 0
}
pub fn collect_garbage(&mut self) {
self.removed_indices.sort_unstable();
for star in self.stars.iter_mut() {
for value in star.link.0.iter_mut() {
let pos = self.removed_indices.binary_search(value).unwrap_err();
let newv = *value - pos;
*value = newv;
}
}
let mut offset = 0;
for each in &self.removed_indices {
self.stars.remove(each - offset);
match &mut self.attributes {
Some(x) => {
let _ = x.remove(each - offset);
}
None => (),
};
offset += 1;
}
self.removed_indices.clear();
self.cur = 1;
}
}
impl fmt::Display for Triangulation {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str("======== TRIANGULATION ========\n")?;
fmt.write_str(&format!("# vertices: {:19}\n", self.number_of_vertices()))?;
fmt.write_str(&format!("# triangles: {:18}\n", self.number_of_triangles()))?;
fmt.write_str(&format!(
"# convex hull: {:16}\n",
self.number_of_vertices_on_convex_hull()
))?;
fmt.write_str("---\n")?;
fmt.write_str(&format!(
"extra_attributes: {:>13}\n",
self.attributes.is_some()
))?;
fmt.write_str(&format!("snap_tolerance: {:>15}\n", self.snaptol))?;
fmt.write_str(&format!("jump_and_walk: {:>16}\n", self.jump_and_walk))?;
fmt.write_str(&format!(
"duplicates_handling: {:>10}\n",
self.duplicates_handling.to_string()
))?;
fmt.write_str("===============================\n")?;
Ok(())
}
}