use crate::{approx_eq, Indices, Pt2, Pt2s, Pt3, Pt3s};
pub fn is_ccw(pts: &[(u64, Pt2)]) -> bool {
(pts[1].1.x - pts[0].1.x) * (pts[2].1.y - pts[0].1.y)
- (pts[2].1.x - pts[0].1.x) * (pts[1].1.y - pts[0].1.y)
> 0.0
}
pub fn in_triangle(p: &(u64, Pt2), a: &(u64, Pt2), b: &(u64, Pt2), c: &(u64, Pt2)) -> bool {
let mut denom = (b.1.y - c.1.y) * (a.1.x - c.1.x) + (c.1.x - b.1.x) * (a.1.y - c.1.y);
if approx_eq(denom, 0.0, 1.0e-5) {
return true;
}
denom = 1.0 / denom;
let alpha = denom * ((b.1.y - c.1.y) * (p.1.x - c.1.x) + (c.1.x - b.1.x) * (p.1.y - c.1.y));
if alpha < 0.0 {
return false;
}
let beta = denom * ((c.1.y - a.1.y) * (p.1.x - c.1.x) + (a.1.x - c.1.x) * (p.1.y - c.1.y));
if beta < 0.0 {
return false;
}
let gamma = 1.0 - alpha - beta;
if gamma < 0.0 {
return false;
}
true
}
pub fn triangulate3d(vertices: &Pt3s, normal: Pt3) -> Indices {
assert!(vertices.len() > 3);
const PX: u8 = 1;
const NX: u8 = 2;
const PY: u8 = 3;
const NY: u8 = 4;
const PZ: u8 = 5;
const NZ: u8 = 6;
let mut nml_type = 0;
if normal.x.abs() >= normal.y.abs() && normal.x.abs() >= normal.z.abs() {
if normal.x >= 0.0 {
nml_type = PX;
} else {
nml_type = NX;
}
} else if normal.y.abs() >= normal.x.abs() && normal.y.abs() >= normal.z.abs() {
if normal.y >= 0.0 {
nml_type = PY;
} else {
nml_type = NY;
}
} else if normal.z.abs() >= normal.x.abs() && normal.z.abs() >= normal.y.abs() {
if normal.z >= 0.0 {
nml_type = PZ;
} else {
nml_type = NZ;
}
}
let mut polygon = Vec::with_capacity(vertices.len());
match nml_type {
PX => {
for (i, v) in vertices.iter().enumerate() {
polygon.push((i as u64, Pt2::new(v.y, v.z)));
}
}
NX => {
for (i, v) in vertices.iter().enumerate() {
polygon.push((i as u64, Pt2::new(-v.y, v.z)));
}
}
PY => {
for (i, v) in vertices.iter().enumerate() {
polygon.push((i as u64, Pt2::new(-v.x, v.z)));
}
}
NY => {
for (i, v) in vertices.iter().enumerate() {
polygon.push((i as u64, Pt2::new(v.x, v.z)));
}
}
PZ => {
for (i, v) in vertices.iter().enumerate() {
polygon.push((i as u64, Pt2::new(v.x, v.y)));
}
}
NZ => {
for (i, v) in vertices.iter().enumerate() {
polygon.push((i as u64, Pt2::new(-v.x, v.y)));
}
}
_ => {}
}
triangulate(polygon)
}
pub fn triangulate3d_rev(vertices: &Pt3s, normal: Pt3) -> Indices {
assert!(vertices.len() > 3);
const PX: u8 = 1;
const NX: u8 = 2;
const PY: u8 = 3;
const NY: u8 = 4;
const PZ: u8 = 5;
const NZ: u8 = 6;
let mut nml_type = 0;
if normal.x.abs() >= normal.y.abs() && normal.x.abs() >= normal.z.abs() {
if normal.x >= 0.0 {
nml_type = PX;
} else {
nml_type = NX;
}
} else if normal.y.abs() >= normal.x.abs() && normal.y.abs() >= normal.z.abs() {
if normal.y >= 0.0 {
nml_type = PY;
} else {
nml_type = NY;
}
} else if normal.z.abs() >= normal.x.abs() && normal.z.abs() >= normal.y.abs() {
if normal.z >= 0.0 {
nml_type = PZ;
} else {
nml_type = NZ;
}
}
let mut polygon = Vec::with_capacity(vertices.len());
match nml_type {
PX => {
for (i, v) in vertices.iter().enumerate() {
polygon.push((i as u64, Pt2::new(v.y, v.z)));
}
}
NX => {
for (i, v) in vertices.iter().enumerate() {
polygon.push((i as u64, Pt2::new(-v.y, v.z)));
}
}
PY => {
for (i, v) in vertices.iter().enumerate() {
polygon.push((i as u64, Pt2::new(-v.x, v.z)));
}
}
NY => {
for (i, v) in vertices.iter().enumerate() {
polygon.push((i as u64, Pt2::new(v.x, v.z)));
}
}
PZ => {
for (i, v) in vertices.iter().enumerate() {
polygon.push((i as u64, Pt2::new(v.x, v.y)));
}
}
NZ => {
for (i, v) in vertices.iter().enumerate() {
polygon.push((i as u64, Pt2::new(-v.x, v.y)));
}
}
_ => {}
}
polygon.reverse();
triangulate(polygon)
}
pub fn triangulate2d(vertices: &Pt2s) -> Indices {
assert!(vertices.len() > 3);
let mut polygon = Vec::with_capacity(vertices.len());
for (i, v) in vertices.iter().enumerate() {
polygon.push((i as u64, *v));
}
triangulate(polygon)
}
pub fn triangulate2d_rev(vertices: &Pt2s) -> Indices {
assert!(vertices.len() > 3);
let mut polygon = Vec::with_capacity(vertices.len());
for (i, v) in vertices.iter().enumerate() {
polygon.push((i as u64, *v));
}
polygon.reverse();
triangulate(polygon)
}
fn triangulate(mut polygon: Vec<(u64, Pt2)>) -> Indices {
let mut triangles = Indices::from_indices(Vec::with_capacity((polygon.len() - 2) * 3));
let mut left = polygon[0].1;
let mut index = 0usize;
(0..polygon.len()).for_each(|i| {
if polygon[i].1.x < left.x
|| (approx_eq(polygon[i].1.x, left.x, 1.0e-5) && polygon[i].1.y < left.y)
{
index = i;
left = polygon[i].1;
}
});
let tri = vec![
polygon[if index == 0 {
polygon.len() - 1
} else {
index - 1
}],
polygon[index],
polygon[if index == polygon.len() - 1 {
0
} else {
index + 1
}],
];
let ccw = is_ccw(&tri);
while polygon.len() >= 3 {
let mut eartip = -1i16;
let mut index = -1i16;
for i in &polygon {
index += 1;
if eartip >= 0 {
break;
}
let p: u16 = if index == 0 {
(polygon.len() - 1) as u16
} else {
(index - 1) as u16
};
let n: u16 = if index as usize == polygon.len() - 1 {
0
} else {
(index + 1) as u16
};
let tri = vec![polygon[p as usize], *i, polygon[n as usize]];
if is_ccw(&tri) != ccw {
continue;
}
let mut ear = true;
for j in ((index + 1) as usize)..polygon.len() {
let v = &polygon[j];
if std::ptr::eq(v, &polygon[p as usize])
|| std::ptr::eq(v, &polygon[n as usize])
|| std::ptr::eq(v, &polygon[index as usize])
{
continue;
}
if in_triangle(v, &polygon[p as usize], i, &polygon[n as usize]) {
ear = false;
break;
}
}
if ear {
eartip = index;
}
} if eartip < 0 {
break;
}
let p = if eartip == 0 {
polygon.len() - 1
} else {
eartip as usize - 1
};
let n = if eartip == (polygon.len() - 1) as i16 {
0
} else {
eartip as usize + 1
};
triangles.push(polygon[p].0);
triangles.push(polygon[eartip as usize].0);
triangles.push(polygon[n].0);
polygon.remove(eartip as usize);
}
triangles
}