use std::collections::BTreeMap;
use crate::linalg::{Vec2, Vec3, Vec4, Mat3, Mat3x4};
use crate::math;
pub const K_PI: f64 = std::f64::consts::PI;
pub const K_TWO_PI: f64 = std::f64::consts::TAU;
pub const K_HALF_PI: f64 = std::f64::consts::FRAC_PI_2;
pub const K_PRECISION: f64 = 1e-12;
pub const DEFAULT_SEGMENTS: i32 = 0;
pub const DEFAULT_ANGLE: f64 = 10.0;
pub const DEFAULT_LENGTH: f64 = 1.0;
#[inline]
pub fn radians(a: f64) -> f64 {
a * K_PI / 180.0
}
#[inline]
pub fn degrees(a: f64) -> f64 {
a * 180.0 / K_PI
}
#[inline]
pub fn smoothstep(edge0: f64, edge1: f64, a: f64) -> f64 {
let x = ((a - edge0) / (edge1 - edge0)).clamp(0.0, 1.0);
x * x * (3.0 - 2.0 * x)
}
pub fn sind(x: f64) -> f64 {
if !x.is_finite() {
return f64::NAN;
}
if x < 0.0 {
return -sind(-x);
}
let mut quo = (x / 90.0).round_ties_even() as i64;
let mut r = x - quo as f64 * 90.0;
if r > 45.0 {
quo += 1;
r -= 90.0;
} else if r < -45.0 {
quo -= 1;
r += 90.0;
} else if r == 45.0 && quo % 2 != 0 {
quo += 1;
r = -45.0;
} else if r == -45.0 && quo % 2 != 0 {
quo -= 1;
r = 45.0;
}
match ((quo % 4) + 4) % 4 {
0 => math::sin(radians(r)),
1 => math::cos(radians(r)),
2 => -math::sin(radians(r)),
3 => -math::cos(radians(r)),
_ => 0.0,
}
}
#[inline]
pub fn cosd(x: f64) -> f64 {
sind(x + 90.0)
}
pub type SimplePolygon = Vec<Vec2>;
pub type Polygons = Vec<SimplePolygon>;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct PolyVert {
pub pos: Vec2,
pub idx: i32,
}
pub type SimplePolygonIdx = Vec<PolyVert>;
pub type PolygonsIdx = Vec<SimplePolygonIdx>;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Box {
pub min: Vec3,
pub max: Vec3,
}
impl Default for Box {
fn default() -> Self {
Box {
min: Vec3::splat(f64::INFINITY),
max: Vec3::splat(f64::NEG_INFINITY),
}
}
}
impl Box {
pub fn new() -> Self {
Self::default()
}
pub fn from_points(p1: Vec3, p2: Vec3) -> Self {
Box {
min: Vec3::new(p1.x.min(p2.x), p1.y.min(p2.y), p1.z.min(p2.z)),
max: Vec3::new(p1.x.max(p2.x), p1.y.max(p2.y), p1.z.max(p2.z)),
}
}
pub fn from_point(p: Vec3) -> Self {
Box { min: p, max: p }
}
pub fn is_empty(&self) -> bool {
self.min.x > self.max.x || self.min.y > self.max.y || self.min.z > self.max.z
}
pub fn size(&self) -> Vec3 {
self.max - self.min
}
pub fn center(&self) -> Vec3 {
(self.max + self.min) * 0.5
}
pub fn scale(&self) -> f64 {
let abs_min = Vec3::new(self.min.x.abs(), self.min.y.abs(), self.min.z.abs());
let abs_max = Vec3::new(self.max.x.abs(), self.max.y.abs(), self.max.z.abs());
let m = Vec3::new(
abs_min.x.max(abs_max.x),
abs_min.y.max(abs_max.y),
abs_min.z.max(abs_max.z),
);
m.x.max(m.y).max(m.z)
}
pub fn contains_point(&self, p: Vec3) -> bool {
p.x >= self.min.x && p.x <= self.max.x
&& p.y >= self.min.y && p.y <= self.max.y
&& p.z >= self.min.z && p.z <= self.max.z
}
pub fn contains_box(&self, other: &Box) -> bool {
other.min.x >= self.min.x && other.max.x <= self.max.x
&& other.min.y >= self.min.y && other.max.y <= self.max.y
&& other.min.z >= self.min.z && other.max.z <= self.max.z
}
pub fn union_point(&mut self, p: Vec3) {
self.min.x = self.min.x.min(p.x);
self.min.y = self.min.y.min(p.y);
self.min.z = self.min.z.min(p.z);
self.max.x = self.max.x.max(p.x);
self.max.y = self.max.y.max(p.y);
self.max.z = self.max.z.max(p.z);
}
pub fn union_box(&self, other: &Box) -> Box {
Box {
min: Vec3::new(
self.min.x.min(other.min.x),
self.min.y.min(other.min.y),
self.min.z.min(other.min.z),
),
max: Vec3::new(
self.max.x.max(other.max.x),
self.max.y.max(other.max.y),
self.max.z.max(other.max.z),
),
}
}
pub fn transform(&self, t: &Mat3x4) -> Box {
use crate::linalg::Vec4 as V4;
let min_t = *t * V4::new(self.min.x, self.min.y, self.min.z, 1.0);
let max_t = *t * V4::new(self.max.x, self.max.y, self.max.z, 1.0);
Box {
min: Vec3::new(min_t.x.min(max_t.x), min_t.y.min(max_t.y), min_t.z.min(max_t.z)),
max: Vec3::new(min_t.x.max(max_t.x), min_t.y.max(max_t.y), min_t.z.max(max_t.z)),
}
}
pub fn does_overlap_box(&self, other: &Box) -> bool {
self.min.x <= other.max.x && self.min.y <= other.max.y && self.min.z <= other.max.z
&& self.max.x >= other.min.x && self.max.y >= other.min.y && self.max.z >= other.min.z
}
pub fn does_overlap_point_xy(&self, p: Vec3) -> bool {
p.x >= self.min.x && p.x <= self.max.x && p.y >= self.min.y && p.y <= self.max.y
}
pub fn is_finite(&self) -> bool {
self.min.x.is_finite() && self.min.y.is_finite() && self.min.z.is_finite()
&& self.max.x.is_finite() && self.max.y.is_finite() && self.max.z.is_finite()
}
}
impl std::ops::Add<Vec3> for Box {
type Output = Box;
fn add(self, shift: Vec3) -> Box {
Box { min: self.min + shift, max: self.max + shift }
}
}
impl std::ops::AddAssign<Vec3> for Box {
fn add_assign(&mut self, shift: Vec3) {
self.min = self.min + shift;
self.max = self.max + shift;
}
}
impl std::ops::Mul<Vec3> for Box {
type Output = Box;
fn mul(self, scale: Vec3) -> Box {
Box { min: self.min * scale, max: self.max * scale }
}
}
impl std::ops::MulAssign<Vec3> for Box {
fn mul_assign(&mut self, scale: Vec3) {
self.min = self.min * scale;
self.max = self.max * scale;
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Rect {
pub min: Vec2,
pub max: Vec2,
}
impl Default for Rect {
fn default() -> Self {
Rect {
min: Vec2::splat(f64::INFINITY),
max: Vec2::splat(f64::NEG_INFINITY),
}
}
}
impl Rect {
pub fn new() -> Self {
Self::default()
}
pub fn from_points(a: Vec2, b: Vec2) -> Self {
Rect {
min: Vec2::new(a.x.min(b.x), a.y.min(b.y)),
max: Vec2::new(a.x.max(b.x), a.y.max(b.y)),
}
}
pub fn size(&self) -> Vec2 {
self.max - self.min
}
pub fn area(&self) -> f64 {
let sz = self.size();
sz.x * sz.y
}
pub fn scale(&self) -> f64 {
let abs_min = Vec2::new(self.min.x.abs(), self.min.y.abs());
let abs_max = Vec2::new(self.max.x.abs(), self.max.y.abs());
let m = Vec2::new(abs_min.x.max(abs_max.x), abs_min.y.max(abs_max.y));
m.x.max(m.y)
}
pub fn center(&self) -> Vec2 {
(self.max + self.min) * 0.5
}
pub fn contains_point(&self, p: Vec2) -> bool {
p.x >= self.min.x && p.x <= self.max.x && p.y >= self.min.y && p.y <= self.max.y
}
pub fn contains_rect(&self, other: &Rect) -> bool {
other.min.x >= self.min.x && other.max.x <= self.max.x
&& other.min.y >= self.min.y && other.max.y <= self.max.y
}
pub fn does_overlap(&self, other: &Rect) -> bool {
self.min.x <= other.max.x && self.min.y <= other.max.y
&& self.max.x >= other.min.x && self.max.y >= other.min.y
}
pub fn is_empty(&self) -> bool {
self.max.y <= self.min.y || self.max.x <= self.min.x
}
pub fn is_finite(&self) -> bool {
self.min.x.is_finite() && self.min.y.is_finite()
&& self.max.x.is_finite() && self.max.y.is_finite()
}
pub fn union_point(&mut self, p: Vec2) {
self.min.x = self.min.x.min(p.x);
self.min.y = self.min.y.min(p.y);
self.max.x = self.max.x.max(p.x);
self.max.y = self.max.y.max(p.y);
}
pub fn union_rect(&self, other: &Rect) -> Rect {
Rect {
min: Vec2::new(self.min.x.min(other.min.x), self.min.y.min(other.min.y)),
max: Vec2::new(self.max.x.max(other.max.x), self.max.y.max(other.max.y)),
}
}
}
impl std::ops::Add<Vec2> for Rect {
type Output = Rect;
fn add(self, shift: Vec2) -> Rect {
Rect { min: self.min + shift, max: self.max + shift }
}
}
impl std::ops::AddAssign<Vec2> for Rect {
fn add_assign(&mut self, shift: Vec2) {
self.min = self.min + shift;
self.max = self.max + shift;
}
}
impl std::ops::Mul<Vec2> for Rect {
type Output = Rect;
fn mul(self, scale: Vec2) -> Rect {
Rect { min: self.min * scale, max: self.max * scale }
}
}
impl std::ops::MulAssign<Vec2> for Rect {
fn mul_assign(&mut self, scale: Vec2) {
self.min = self.min * scale;
self.max = self.max * scale;
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum OpType {
Add,
Subtract,
Intersect,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Error {
NoError,
NonFiniteVertex,
NotManifold,
VertexOutOfBounds,
PropertiesWrongLength,
MissingPositionProperties,
MergeVectorsDifferentLengths,
MergeIndexOutOfBounds,
TransformWrongLength,
RunIndexWrongLength,
FaceIdWrongLength,
InvalidConstruction,
ResultTooLarge,
InvalidTangents,
}
impl Error {
pub fn to_str(self) -> &'static str {
match self {
Error::NoError => "No Error",
Error::NonFiniteVertex => "Non-Finite Vertex",
Error::NotManifold => "Not Manifold",
Error::VertexOutOfBounds => "Vertex Out of Bounds",
Error::PropertiesWrongLength => "Properties Wrong Length",
Error::MissingPositionProperties => "Missing Position Properties",
Error::MergeVectorsDifferentLengths => "Merge Vectors Different Lengths",
Error::MergeIndexOutOfBounds => "Merge Index Out of Bounds",
Error::TransformWrongLength => "Transform Wrong Length",
Error::RunIndexWrongLength => "Run Index Wrong Length",
Error::FaceIdWrongLength => "Face ID Wrong Length",
Error::InvalidConstruction => "Invalid Construction",
Error::ResultTooLarge => "Result Too Large",
Error::InvalidTangents => "Invalid Tangents",
}
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_str())
}
}
use std::sync::OnceLock;
use std::sync::Mutex;
struct QualityState {
min_circular_angle: f64,
min_circular_edge_length: f64,
circular_segments: i32,
}
static QUALITY_STATE: OnceLock<Mutex<QualityState>> = OnceLock::new();
fn quality_state() -> &'static Mutex<QualityState> {
QUALITY_STATE.get_or_init(|| {
Mutex::new(QualityState {
min_circular_angle: DEFAULT_ANGLE,
min_circular_edge_length: DEFAULT_LENGTH,
circular_segments: DEFAULT_SEGMENTS,
})
})
}
pub struct Quality;
impl Quality {
pub fn set_min_circular_angle(angle: f64) {
quality_state().lock().unwrap().min_circular_angle = angle;
}
pub fn set_min_circular_edge_length(length: f64) {
quality_state().lock().unwrap().min_circular_edge_length = length;
}
pub fn set_circular_segments(n: i32) {
quality_state().lock().unwrap().circular_segments = n;
}
pub fn get_circular_segments(radius: f64) -> i32 {
let q = quality_state().lock().unwrap();
if q.circular_segments > 0 {
return q.circular_segments;
}
let n_seg_a = (360.0 / q.min_circular_angle) as i32;
let n_seg_l = (2.0 * radius.abs() * K_PI / q.min_circular_edge_length) as i32;
let mut n_seg = n_seg_a.min(n_seg_l) + 3;
n_seg -= n_seg % 4;
n_seg.max(4)
}
pub fn reset_to_defaults() {
let mut q = quality_state().lock().unwrap();
q.min_circular_angle = DEFAULT_ANGLE;
q.min_circular_edge_length = DEFAULT_LENGTH;
q.circular_segments = DEFAULT_SEGMENTS;
}
}
#[derive(Clone, Debug)]
pub struct ExecutionParams {
pub intermediate_checks: bool,
pub self_intersection_checks: bool,
pub process_overlaps: bool,
pub suppress_errors: bool,
pub cleanup_triangles: bool,
pub verbose: i32,
}
impl Default for ExecutionParams {
fn default() -> Self {
ExecutionParams {
intermediate_checks: false,
self_intersection_checks: false,
process_overlaps: true,
suppress_errors: false,
cleanup_triangles: true,
verbose: 0,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Smoothness {
pub halfedge: usize,
pub smoothness: f64,
}
#[derive(Clone, Debug, Default)]
pub struct MeshGLP<P: Copy + Default, I: Copy + Default = u32> {
pub num_prop: I,
pub vert_properties: Vec<P>,
pub tri_verts: Vec<I>,
pub merge_from_vert: Vec<I>,
pub merge_to_vert: Vec<I>,
pub run_index: Vec<I>,
pub run_original_id: Vec<u32>,
pub run_transform: Vec<P>,
pub face_id: Vec<I>,
pub halfedge_tangent: Vec<P>,
pub run_flags: Vec<u8>,
pub tolerance: P,
}
impl MeshGLP<f32, u32> {
pub fn num_vert(&self) -> usize {
if self.num_prop == 0 { 0 } else { self.vert_properties.len() / self.num_prop as usize }
}
pub fn num_tri(&self) -> usize {
self.tri_verts.len() / 3
}
pub fn get_vert_pos(&self, v: usize) -> [f32; 3] {
let offset = v * self.num_prop as usize;
[self.vert_properties[offset], self.vert_properties[offset + 1], self.vert_properties[offset + 2]]
}
pub fn get_tri_verts(&self, t: usize) -> [u32; 3] {
let offset = 3 * t;
[self.tri_verts[offset], self.tri_verts[offset + 1], self.tri_verts[offset + 2]]
}
pub fn get_tangent(&self, h: usize) -> [f32; 4] {
let offset = 4 * h;
[
self.halfedge_tangent[offset],
self.halfedge_tangent[offset + 1],
self.halfedge_tangent[offset + 2],
self.halfedge_tangent[offset + 3],
]
}
pub fn merge(&mut self) -> bool {
use crate::collider::Collider;
use crate::disjoint_sets::DisjointSets;
use crate::sort::morton_code;
use std::collections::BTreeSet;
let num_vert = self.num_vert();
let num_tri = self.num_tri();
let mut merge_map: Vec<usize> = (0..num_vert).collect();
for i in 0..self.merge_from_vert.len() {
merge_map[self.merge_from_vert[i] as usize] = self.merge_to_vert[i] as usize;
}
let next = [1usize, 2, 0];
let mut open_edges: BTreeSet<(usize, usize)> = BTreeSet::new();
for tri in 0..num_tri {
for i in 0..3 {
let a = merge_map[self.tri_verts[3 * tri + next[i]] as usize];
let b = merge_map[self.tri_verts[3 * tri + i] as usize];
let edge = (a, b);
let rev = (b, a);
if open_edges.contains(&rev) {
open_edges.remove(&rev);
} else {
open_edges.insert(edge);
}
}
}
if open_edges.is_empty() {
return false;
}
let open_verts: Vec<usize> = {
let mut vset = std::collections::BTreeSet::new();
for (_a, b) in &open_edges {
vset.insert(*b);
}
vset.into_iter().collect()
};
let num_open = open_verts.len();
let mut bbox = Box::default();
for v in 0..num_vert {
let pos = self.get_vert_pos(v);
let p = Vec3::new(pos[0] as f64, pos[1] as f64, pos[2] as f64);
bbox.union_point(p);
}
let tolerance = f64::max(
self.tolerance as f64,
f32::EPSILON as f64 * bbox.scale(),
);
let mut vert_box: Vec<Box> = Vec::with_capacity(num_open);
let mut vert_morton: Vec<u32> = Vec::with_capacity(num_open);
for &v in &open_verts {
let pos = self.get_vert_pos(v);
let center = Vec3::new(pos[0] as f64, pos[1] as f64, pos[2] as f64);
let half_tol = tolerance / 2.0;
let bx = Box::from_points(
center - Vec3::new(half_tol, half_tol, half_tol),
center + Vec3::new(half_tol, half_tol, half_tol),
);
vert_box.push(bx);
vert_morton.push(morton_code(center, &bbox));
}
let mut order: Vec<usize> = (0..num_open).collect();
order.sort_by_key(|&i| vert_morton[i]);
let sorted_box: Vec<Box> = order.iter().map(|&i| vert_box[i]).collect();
let sorted_morton: Vec<u32> = order.iter().map(|&i| vert_morton[i]).collect();
let sorted_verts: Vec<usize> = order.iter().map(|&i| open_verts[i]).collect();
let collider = Collider::new(sorted_box.clone(), sorted_morton);
let uf = DisjointSets::new(num_vert as u32);
collider.collisions_with_boxes(&sorted_box, false, |a, b| {
uf.unite(sorted_verts[a] as u32, sorted_verts[b] as u32);
});
for i in 0..self.merge_from_vert.len() {
uf.unite(self.merge_from_vert[i], self.merge_to_vert[i]);
}
self.merge_from_vert.clear();
self.merge_to_vert.clear();
for v in 0..num_vert {
let merge_to = uf.find(v as u32) as usize;
if merge_to != v {
self.merge_from_vert.push(v as u32);
self.merge_to_vert.push(merge_to as u32);
}
}
true
}
pub fn backside(&self, run: usize) -> bool {
run < self.run_flags.len() && (self.run_flags[run] & 1) != 0
}
pub fn has_normals(&self, run: usize) -> bool {
run < self.run_flags.len() && (self.run_flags[run] & 2) != 0
}
pub fn update_normals(&mut self, normal_idx: usize) {
if normal_idx < 3 || normal_idx + 3 > self.num_prop as usize {
return;
}
let num_vert = self.num_vert();
let num_run = self.run_original_id.len();
let np = self.num_prop as usize;
let mut vert_updated = vec![false; num_vert];
for run in 0..num_run {
let offset = 12 * run;
let has_transform = offset + 12 <= self.run_transform.len();
let (m00, m01, m02,
m10, m11, m12,
m20, m21, m22) = if has_transform {
let t = &self.run_transform[offset..offset + 12];
(t[0] as f64, t[3] as f64, t[6] as f64,
t[1] as f64, t[4] as f64, t[7] as f64,
t[2] as f64, t[5] as f64, t[8] as f64)
} else {
(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
};
let det = m00*(m11*m22 - m12*m21) - m01*(m10*m22 - m12*m20) + m02*(m10*m21 - m11*m20);
let (n00, n01, n02, n10, n11, n12, n20, n21, n22) = if det.abs() < 1e-30 {
(1.0f64, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
} else {
let inv = 1.0 / det;
let a00 = (m11*m22 - m12*m21) * inv;
let a01 = (m02*m21 - m01*m22) * inv;
let a02 = (m01*m12 - m02*m11) * inv;
let a10 = (m12*m20 - m10*m22) * inv;
let a11 = (m00*m22 - m02*m20) * inv;
let a12 = (m02*m10 - m00*m12) * inv;
let a20 = (m10*m21 - m11*m20) * inv;
let a21 = (m01*m20 - m00*m21) * inv;
let a22 = (m00*m11 - m01*m10) * inv;
(a00, a01, a02, a10, a11, a12, a20, a21, a22)
};
let sign = if self.backside(run) { -1.0f64 } else { 1.0 };
let start = if run < self.run_index.len() { self.run_index[run] as usize } else { 0 };
let end = if run + 1 < self.run_index.len() { self.run_index[run + 1] as usize } else { self.tri_verts.len() };
for idx in (start..end).step_by(1) {
let vert = self.tri_verts[idx] as usize;
if vert >= num_vert || vert_updated[vert] { continue; }
vert_updated[vert] = true;
let prop_start = vert * np + normal_idx;
let nx = self.vert_properties[prop_start] as f64;
let ny = self.vert_properties[prop_start + 1] as f64;
let nz = self.vert_properties[prop_start + 2] as f64;
let tx = n00*nx + n01*ny + n02*nz;
let ty = n10*nx + n11*ny + n12*nz;
let tz = n20*nx + n21*ny + n22*nz;
let len = (tx*tx + ty*ty + tz*tz).sqrt();
let (tx, ty, tz) = if len > 0.0 {
(sign * tx / len, sign * ty / len, sign * tz / len)
} else {
(0.0, 0.0, 0.0)
};
self.vert_properties[prop_start] = tx as f32;
self.vert_properties[prop_start + 1] = ty as f32;
self.vert_properties[prop_start + 2] = tz as f32;
}
}
self.run_transform.clear();
self.run_flags.clear();
}
}
impl MeshGLP<f64, u64> {
pub fn num_vert(&self) -> usize {
if self.num_prop == 0 { 0 } else { self.vert_properties.len() / self.num_prop as usize }
}
pub fn num_tri(&self) -> usize {
self.tri_verts.len() / 3
}
pub fn get_vert_pos(&self, v: usize) -> [f64; 3] {
let offset = v * self.num_prop as usize;
[self.vert_properties[offset], self.vert_properties[offset + 1], self.vert_properties[offset + 2]]
}
pub fn get_tri_verts(&self, t: usize) -> [u64; 3] {
let offset = 3 * t;
[self.tri_verts[offset], self.tri_verts[offset + 1], self.tri_verts[offset + 2]]
}
pub fn get_tangent(&self, h: usize) -> [f64; 4] {
let offset = 4 * h;
[
self.halfedge_tangent[offset],
self.halfedge_tangent[offset + 1],
self.halfedge_tangent[offset + 2],
self.halfedge_tangent[offset + 3],
]
}
}
pub type MeshGL = MeshGLP<f32, u32>;
pub type MeshGL64 = MeshGLP<f64, u64>;
#[derive(Clone, Debug, Default)]
pub struct RayHit {
pub face_id: u64,
pub distance: f64,
pub position: crate::linalg::Vec3,
pub normal: crate::linalg::Vec3,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct Halfedge {
pub start_vert: i32,
pub end_vert: i32,
pub paired_halfedge: i32,
pub prop_vert: i32,
}
impl Halfedge {
pub fn is_forward(&self) -> bool {
self.start_vert < self.end_vert
}
}
impl PartialOrd for Halfedge {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Halfedge {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
if self.start_vert == other.start_vert {
self.end_vert.cmp(&other.end_vert)
} else {
self.start_vert.cmp(&other.start_vert)
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Barycentric {
pub tri: i32,
pub uvw: Vec4,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct TriRef {
pub mesh_id: i32,
pub original_id: i32,
pub face_id: i32,
pub coplanar_id: i32,
}
impl TriRef {
pub fn same_face(&self, other: &TriRef) -> bool {
self.mesh_id == other.mesh_id
&& self.coplanar_id == other.coplanar_id
&& self.face_id == other.face_id
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct TmpEdge {
pub first: i32,
pub second: i32,
pub halfedge_idx: i32,
}
impl TmpEdge {
pub fn new(start: i32, end: i32, idx: i32) -> Self {
TmpEdge {
first: start.min(end),
second: start.max(end),
halfedge_idx: idx,
}
}
}
impl PartialOrd for TmpEdge {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for TmpEdge {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
if self.first == other.first {
self.second.cmp(&other.second)
} else {
self.first.cmp(&other.first)
}
}
}
#[derive(Clone, Debug)]
pub struct Relation {
pub original_id: i32,
pub transform: Mat3x4,
pub back_side: bool,
pub has_normals: bool,
}
impl Default for Relation {
fn default() -> Self {
Relation {
original_id: -1,
transform: Mat3x4::identity(),
back_side: false,
has_normals: false,
}
}
}
impl Relation {
pub fn get_normal_transform(&self) -> Mat3 {
let sign = if self.back_side { -1.0 } else { 1.0 };
self.transform.rotation().transpose().inverse() * sign
}
pub fn get_inverse_normal_transform(&self) -> Mat3 {
let sign = if self.back_side { -1.0 } else { 1.0 };
self.transform.rotation().transpose() * sign
}
}
#[derive(Clone, Debug, Default)]
pub struct MeshRelationD {
pub original_id: i32,
pub mesh_id_transform: BTreeMap<i32, Relation>,
pub tri_ref: Vec<TriRef>,
}
impl MeshRelationD {
pub fn new() -> Self {
MeshRelationD {
original_id: -1,
mesh_id_transform: BTreeMap::new(),
tri_ref: Vec::new(),
}
}
}
#[inline]
pub fn next_halfedge(current: i32) -> i32 {
let n = current + 1;
if n % 3 == 0 { n - 3 } else { n }
}
pub fn prev_halfedge(current: i32) -> i32 {
let base = current - (current % 3);
let pos = (current % 3 + 2) % 3;
base + pos
}
#[inline]
pub fn next3(i: i32) -> i32 {
let n = i + 1;
if n == 3 { 0 } else { n }
}
#[cfg(test)]
#[path = "types_tests.rs"]
mod tests;