1use std::collections::BTreeMap;
5use crate::linalg::{Vec2, Vec3, Vec4, Mat3, Mat3x4};
6use crate::math;
7
8pub const K_PI: f64 = std::f64::consts::PI;
13pub const K_TWO_PI: f64 = std::f64::consts::TAU;
14pub const K_HALF_PI: f64 = std::f64::consts::FRAC_PI_2;
15pub const K_PRECISION: f64 = 1e-12;
17
18pub const DEFAULT_SEGMENTS: i32 = 0;
19pub const DEFAULT_ANGLE: f64 = 10.0;
20pub const DEFAULT_LENGTH: f64 = 1.0;
21
22#[inline]
27pub fn radians(a: f64) -> f64 {
28 a * K_PI / 180.0
29}
30
31#[inline]
32pub fn degrees(a: f64) -> f64 {
33 a * 180.0 / K_PI
34}
35
36#[inline]
38pub fn smoothstep(edge0: f64, edge1: f64, a: f64) -> f64 {
39 let x = ((a - edge0) / (edge1 - edge0)).clamp(0.0, 1.0);
40 x * x * (3.0 - 2.0 * x)
41}
42
43pub fn sind(x: f64) -> f64 {
52 if !x.is_finite() {
53 return f64::NAN;
54 }
55 if x < 0.0 {
56 return -sind(-x);
57 }
58 let mut quo = (x / 90.0).round_ties_even() as i64;
63 let mut r = x - quo as f64 * 90.0;
64 if r > 45.0 {
65 quo += 1;
66 r -= 90.0;
67 } else if r < -45.0 {
68 quo -= 1;
69 r += 90.0;
70 } else if r == 45.0 && quo % 2 != 0 {
71 quo += 1;
73 r = -45.0;
74 } else if r == -45.0 && quo % 2 != 0 {
75 quo -= 1;
76 r = 45.0;
77 }
78 match ((quo % 4) + 4) % 4 {
79 0 => math::sin(radians(r)),
80 1 => math::cos(radians(r)),
81 2 => -math::sin(radians(r)),
82 3 => -math::cos(radians(r)),
83 _ => 0.0,
84 }
85}
86
87#[inline]
89pub fn cosd(x: f64) -> f64 {
90 sind(x + 90.0)
91}
92
93pub type SimplePolygon = Vec<Vec2>;
99
100pub type Polygons = Vec<SimplePolygon>;
102
103#[derive(Clone, Copy, Debug, PartialEq)]
105pub struct PolyVert {
106 pub pos: Vec2,
107 pub idx: i32,
108}
109
110pub type SimplePolygonIdx = Vec<PolyVert>;
112
113pub type PolygonsIdx = Vec<SimplePolygonIdx>;
115
116#[derive(Clone, Copy, Debug, PartialEq)]
121pub struct Box {
122 pub min: Vec3,
123 pub max: Vec3,
124}
125
126impl Default for Box {
127 fn default() -> Self {
128 Box {
129 min: Vec3::splat(f64::INFINITY),
130 max: Vec3::splat(f64::NEG_INFINITY),
131 }
132 }
133}
134
135impl Box {
136 pub fn new() -> Self {
138 Self::default()
139 }
140
141 pub fn from_points(p1: Vec3, p2: Vec3) -> Self {
143 Box {
144 min: Vec3::new(p1.x.min(p2.x), p1.y.min(p2.y), p1.z.min(p2.z)),
145 max: Vec3::new(p1.x.max(p2.x), p1.y.max(p2.y), p1.z.max(p2.z)),
146 }
147 }
148
149 pub fn from_point(p: Vec3) -> Self {
151 Box { min: p, max: p }
152 }
153
154 pub fn is_empty(&self) -> bool {
156 self.min.x > self.max.x || self.min.y > self.max.y || self.min.z > self.max.z
157 }
158
159 pub fn size(&self) -> Vec3 {
160 self.max - self.min
161 }
162
163 pub fn center(&self) -> Vec3 {
164 (self.max + self.min) * 0.5
165 }
166
167 pub fn scale(&self) -> f64 {
169 let abs_min = Vec3::new(self.min.x.abs(), self.min.y.abs(), self.min.z.abs());
170 let abs_max = Vec3::new(self.max.x.abs(), self.max.y.abs(), self.max.z.abs());
171 let m = Vec3::new(
172 abs_min.x.max(abs_max.x),
173 abs_min.y.max(abs_max.y),
174 abs_min.z.max(abs_max.z),
175 );
176 m.x.max(m.y).max(m.z)
177 }
178
179 pub fn contains_point(&self, p: Vec3) -> bool {
180 p.x >= self.min.x && p.x <= self.max.x
181 && p.y >= self.min.y && p.y <= self.max.y
182 && p.z >= self.min.z && p.z <= self.max.z
183 }
184
185 pub fn contains_box(&self, other: &Box) -> bool {
186 other.min.x >= self.min.x && other.max.x <= self.max.x
187 && other.min.y >= self.min.y && other.max.y <= self.max.y
188 && other.min.z >= self.min.z && other.max.z <= self.max.z
189 }
190
191 pub fn union_point(&mut self, p: Vec3) {
193 self.min.x = self.min.x.min(p.x);
194 self.min.y = self.min.y.min(p.y);
195 self.min.z = self.min.z.min(p.z);
196 self.max.x = self.max.x.max(p.x);
197 self.max.y = self.max.y.max(p.y);
198 self.max.z = self.max.z.max(p.z);
199 }
200
201 pub fn union_box(&self, other: &Box) -> Box {
203 Box {
204 min: Vec3::new(
205 self.min.x.min(other.min.x),
206 self.min.y.min(other.min.y),
207 self.min.z.min(other.min.z),
208 ),
209 max: Vec3::new(
210 self.max.x.max(other.max.x),
211 self.max.y.max(other.max.y),
212 self.max.z.max(other.max.z),
213 ),
214 }
215 }
216
217 pub fn transform(&self, t: &Mat3x4) -> Box {
219 use crate::linalg::Vec4 as V4;
220 let min_t = *t * V4::new(self.min.x, self.min.y, self.min.z, 1.0);
221 let max_t = *t * V4::new(self.max.x, self.max.y, self.max.z, 1.0);
222 Box {
223 min: Vec3::new(min_t.x.min(max_t.x), min_t.y.min(max_t.y), min_t.z.min(max_t.z)),
224 max: Vec3::new(min_t.x.max(max_t.x), min_t.y.max(max_t.y), min_t.z.max(max_t.z)),
225 }
226 }
227
228 pub fn does_overlap_box(&self, other: &Box) -> bool {
229 self.min.x <= other.max.x && self.min.y <= other.max.y && self.min.z <= other.max.z
230 && self.max.x >= other.min.x && self.max.y >= other.min.y && self.max.z >= other.min.z
231 }
232
233 pub fn does_overlap_point_xy(&self, p: Vec3) -> bool {
235 p.x >= self.min.x && p.x <= self.max.x && p.y >= self.min.y && p.y <= self.max.y
236 }
237
238 pub fn is_finite(&self) -> bool {
239 self.min.x.is_finite() && self.min.y.is_finite() && self.min.z.is_finite()
240 && self.max.x.is_finite() && self.max.y.is_finite() && self.max.z.is_finite()
241 }
242}
243
244impl std::ops::Add<Vec3> for Box {
245 type Output = Box;
246 fn add(self, shift: Vec3) -> Box {
247 Box { min: self.min + shift, max: self.max + shift }
248 }
249}
250impl std::ops::AddAssign<Vec3> for Box {
251 fn add_assign(&mut self, shift: Vec3) {
252 self.min = self.min + shift;
253 self.max = self.max + shift;
254 }
255}
256impl std::ops::Mul<Vec3> for Box {
257 type Output = Box;
258 fn mul(self, scale: Vec3) -> Box {
259 Box { min: self.min * scale, max: self.max * scale }
260 }
261}
262impl std::ops::MulAssign<Vec3> for Box {
263 fn mul_assign(&mut self, scale: Vec3) {
264 self.min = self.min * scale;
265 self.max = self.max * scale;
266 }
267}
268
269#[derive(Clone, Copy, Debug, PartialEq)]
274pub struct Rect {
275 pub min: Vec2,
276 pub max: Vec2,
277}
278
279impl Default for Rect {
280 fn default() -> Self {
281 Rect {
282 min: Vec2::splat(f64::INFINITY),
283 max: Vec2::splat(f64::NEG_INFINITY),
284 }
285 }
286}
287
288impl Rect {
289 pub fn new() -> Self {
290 Self::default()
291 }
292
293 pub fn from_points(a: Vec2, b: Vec2) -> Self {
294 Rect {
295 min: Vec2::new(a.x.min(b.x), a.y.min(b.y)),
296 max: Vec2::new(a.x.max(b.x), a.y.max(b.y)),
297 }
298 }
299
300 pub fn size(&self) -> Vec2 {
301 self.max - self.min
302 }
303
304 pub fn area(&self) -> f64 {
305 let sz = self.size();
306 sz.x * sz.y
307 }
308
309 pub fn scale(&self) -> f64 {
310 let abs_min = Vec2::new(self.min.x.abs(), self.min.y.abs());
311 let abs_max = Vec2::new(self.max.x.abs(), self.max.y.abs());
312 let m = Vec2::new(abs_min.x.max(abs_max.x), abs_min.y.max(abs_max.y));
313 m.x.max(m.y)
314 }
315
316 pub fn center(&self) -> Vec2 {
317 (self.max + self.min) * 0.5
318 }
319
320 pub fn contains_point(&self, p: Vec2) -> bool {
321 p.x >= self.min.x && p.x <= self.max.x && p.y >= self.min.y && p.y <= self.max.y
322 }
323
324 pub fn contains_rect(&self, other: &Rect) -> bool {
325 other.min.x >= self.min.x && other.max.x <= self.max.x
326 && other.min.y >= self.min.y && other.max.y <= self.max.y
327 }
328
329 pub fn does_overlap(&self, other: &Rect) -> bool {
330 self.min.x <= other.max.x && self.min.y <= other.max.y
331 && self.max.x >= other.min.x && self.max.y >= other.min.y
332 }
333
334 pub fn is_empty(&self) -> bool {
335 self.max.y <= self.min.y || self.max.x <= self.min.x
336 }
337
338 pub fn is_finite(&self) -> bool {
339 self.min.x.is_finite() && self.min.y.is_finite()
340 && self.max.x.is_finite() && self.max.y.is_finite()
341 }
342
343 pub fn union_point(&mut self, p: Vec2) {
344 self.min.x = self.min.x.min(p.x);
345 self.min.y = self.min.y.min(p.y);
346 self.max.x = self.max.x.max(p.x);
347 self.max.y = self.max.y.max(p.y);
348 }
349
350 pub fn union_rect(&self, other: &Rect) -> Rect {
351 Rect {
352 min: Vec2::new(self.min.x.min(other.min.x), self.min.y.min(other.min.y)),
353 max: Vec2::new(self.max.x.max(other.max.x), self.max.y.max(other.max.y)),
354 }
355 }
356}
357
358impl std::ops::Add<Vec2> for Rect {
359 type Output = Rect;
360 fn add(self, shift: Vec2) -> Rect {
361 Rect { min: self.min + shift, max: self.max + shift }
362 }
363}
364impl std::ops::AddAssign<Vec2> for Rect {
365 fn add_assign(&mut self, shift: Vec2) {
366 self.min = self.min + shift;
367 self.max = self.max + shift;
368 }
369}
370impl std::ops::Mul<Vec2> for Rect {
371 type Output = Rect;
372 fn mul(self, scale: Vec2) -> Rect {
373 Rect { min: self.min * scale, max: self.max * scale }
374 }
375}
376impl std::ops::MulAssign<Vec2> for Rect {
377 fn mul_assign(&mut self, scale: Vec2) {
378 self.min = self.min * scale;
379 self.max = self.max * scale;
380 }
381}
382
383#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
388pub enum OpType {
389 Add,
390 Subtract,
391 Intersect,
392}
393
394#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
399pub enum Error {
400 NoError,
401 NonFiniteVertex,
402 NotManifold,
403 VertexOutOfBounds,
404 PropertiesWrongLength,
405 MissingPositionProperties,
406 MergeVectorsDifferentLengths,
407 MergeIndexOutOfBounds,
408 TransformWrongLength,
409 RunIndexWrongLength,
410 FaceIdWrongLength,
411 InvalidConstruction,
412 ResultTooLarge,
413 InvalidTangents,
414}
415
416impl Error {
417 pub fn to_str(self) -> &'static str {
418 match self {
419 Error::NoError => "No Error",
420 Error::NonFiniteVertex => "Non-Finite Vertex",
421 Error::NotManifold => "Not Manifold",
422 Error::VertexOutOfBounds => "Vertex Out of Bounds",
423 Error::PropertiesWrongLength => "Properties Wrong Length",
424 Error::MissingPositionProperties => "Missing Position Properties",
425 Error::MergeVectorsDifferentLengths => "Merge Vectors Different Lengths",
426 Error::MergeIndexOutOfBounds => "Merge Index Out of Bounds",
427 Error::TransformWrongLength => "Transform Wrong Length",
428 Error::RunIndexWrongLength => "Run Index Wrong Length",
429 Error::FaceIdWrongLength => "Face ID Wrong Length",
430 Error::InvalidConstruction => "Invalid Construction",
431 Error::ResultTooLarge => "Result Too Large",
432 Error::InvalidTangents => "Invalid Tangents",
433 }
434 }
435}
436
437impl std::fmt::Display for Error {
438 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
439 write!(f, "{}", self.to_str())
440 }
441}
442
443use std::sync::OnceLock;
448use std::sync::Mutex;
449
450struct QualityState {
451 min_circular_angle: f64,
452 min_circular_edge_length: f64,
453 circular_segments: i32,
454}
455
456static QUALITY_STATE: OnceLock<Mutex<QualityState>> = OnceLock::new();
457
458fn quality_state() -> &'static Mutex<QualityState> {
459 QUALITY_STATE.get_or_init(|| {
460 Mutex::new(QualityState {
461 min_circular_angle: DEFAULT_ANGLE,
462 min_circular_edge_length: DEFAULT_LENGTH,
463 circular_segments: DEFAULT_SEGMENTS,
464 })
465 })
466}
467
468pub struct Quality;
469
470impl Quality {
471 pub fn set_min_circular_angle(angle: f64) {
472 quality_state().lock().unwrap().min_circular_angle = angle;
473 }
474
475 pub fn set_min_circular_edge_length(length: f64) {
476 quality_state().lock().unwrap().min_circular_edge_length = length;
477 }
478
479 pub fn set_circular_segments(n: i32) {
480 quality_state().lock().unwrap().circular_segments = n;
481 }
482
483 pub fn get_circular_segments(radius: f64) -> i32 {
484 let q = quality_state().lock().unwrap();
485 if q.circular_segments > 0 {
486 return q.circular_segments;
487 }
488 let n_seg_a = (360.0 / q.min_circular_angle) as i32;
490 let n_seg_l = (2.0 * radius.abs() * K_PI / q.min_circular_edge_length) as i32;
491 let mut n_seg = n_seg_a.min(n_seg_l) + 3;
492 n_seg -= n_seg % 4;
493 n_seg.max(4)
494 }
495
496 pub fn reset_to_defaults() {
497 let mut q = quality_state().lock().unwrap();
498 q.min_circular_angle = DEFAULT_ANGLE;
499 q.min_circular_edge_length = DEFAULT_LENGTH;
500 q.circular_segments = DEFAULT_SEGMENTS;
501 }
502}
503
504#[derive(Clone, Debug)]
509pub struct ExecutionParams {
510 pub intermediate_checks: bool,
511 pub self_intersection_checks: bool,
512 pub process_overlaps: bool,
513 pub suppress_errors: bool,
514 pub cleanup_triangles: bool,
515 pub verbose: i32,
516}
517
518impl Default for ExecutionParams {
519 fn default() -> Self {
520 ExecutionParams {
521 intermediate_checks: false,
522 self_intersection_checks: false,
523 process_overlaps: true,
524 suppress_errors: false,
525 cleanup_triangles: true,
526 verbose: 0,
527 }
528 }
529}
530
531#[derive(Clone, Copy, Debug, PartialEq)]
536pub struct Smoothness {
537 pub halfedge: usize,
539 pub smoothness: f64,
541}
542
543#[derive(Clone, Debug, Default)]
549pub struct MeshGLP<P: Copy + Default, I: Copy + Default = u32> {
550 pub num_prop: I,
552 pub vert_properties: Vec<P>,
554 pub tri_verts: Vec<I>,
556 pub merge_from_vert: Vec<I>,
558 pub merge_to_vert: Vec<I>,
560 pub run_index: Vec<I>,
562 pub run_original_id: Vec<u32>,
564 pub run_transform: Vec<P>,
566 pub face_id: Vec<I>,
568 pub halfedge_tangent: Vec<P>,
570 pub run_flags: Vec<u8>,
572 pub tolerance: P,
574}
575
576impl MeshGLP<f32, u32> {
577 pub fn num_vert(&self) -> usize {
578 if self.num_prop == 0 { 0 } else { self.vert_properties.len() / self.num_prop as usize }
579 }
580
581 pub fn num_tri(&self) -> usize {
582 self.tri_verts.len() / 3
583 }
584
585 pub fn get_vert_pos(&self, v: usize) -> [f32; 3] {
586 let offset = v * self.num_prop as usize;
587 [self.vert_properties[offset], self.vert_properties[offset + 1], self.vert_properties[offset + 2]]
588 }
589
590 pub fn get_tri_verts(&self, t: usize) -> [u32; 3] {
591 let offset = 3 * t;
592 [self.tri_verts[offset], self.tri_verts[offset + 1], self.tri_verts[offset + 2]]
593 }
594
595 pub fn get_tangent(&self, h: usize) -> [f32; 4] {
596 let offset = 4 * h;
597 [
598 self.halfedge_tangent[offset],
599 self.halfedge_tangent[offset + 1],
600 self.halfedge_tangent[offset + 2],
601 self.halfedge_tangent[offset + 3],
602 ]
603 }
604
605 pub fn merge(&mut self) -> bool {
610 use crate::collider::Collider;
611 use crate::disjoint_sets::DisjointSets;
612 use crate::sort::morton_code;
613 use std::collections::BTreeSet;
614
615 let num_vert = self.num_vert();
616 let num_tri = self.num_tri();
617
618 let mut merge_map: Vec<usize> = (0..num_vert).collect();
620 for i in 0..self.merge_from_vert.len() {
621 merge_map[self.merge_from_vert[i] as usize] = self.merge_to_vert[i] as usize;
622 }
623
624 let next = [1usize, 2, 0];
626 let mut open_edges: BTreeSet<(usize, usize)> = BTreeSet::new();
627 for tri in 0..num_tri {
628 for i in 0..3 {
629 let a = merge_map[self.tri_verts[3 * tri + next[i]] as usize];
630 let b = merge_map[self.tri_verts[3 * tri + i] as usize];
631 let edge = (a, b);
632 let rev = (b, a);
634 if open_edges.contains(&rev) {
635 open_edges.remove(&rev);
636 } else {
637 open_edges.insert(edge);
638 }
639 }
640 }
641
642 if open_edges.is_empty() {
643 return false;
644 }
645
646 let open_verts: Vec<usize> = {
650 let mut vset = std::collections::BTreeSet::new();
651 for (_a, b) in &open_edges {
652 vset.insert(*b);
653 }
654 vset.into_iter().collect()
655 };
656 let num_open = open_verts.len();
657
658 let mut bbox = Box::default();
660 for v in 0..num_vert {
661 let pos = self.get_vert_pos(v);
662 let p = Vec3::new(pos[0] as f64, pos[1] as f64, pos[2] as f64);
663 bbox.union_point(p);
664 }
665
666 let tolerance = f64::max(
667 self.tolerance as f64,
668 f32::EPSILON as f64 * bbox.scale(),
669 );
670
671 let mut vert_box: Vec<Box> = Vec::with_capacity(num_open);
673 let mut vert_morton: Vec<u32> = Vec::with_capacity(num_open);
674 for &v in &open_verts {
675 let pos = self.get_vert_pos(v);
676 let center = Vec3::new(pos[0] as f64, pos[1] as f64, pos[2] as f64);
677 let half_tol = tolerance / 2.0;
678 let bx = Box::from_points(
679 center - Vec3::new(half_tol, half_tol, half_tol),
680 center + Vec3::new(half_tol, half_tol, half_tol),
681 );
682 vert_box.push(bx);
683 vert_morton.push(morton_code(center, &bbox));
684 }
685
686 let mut order: Vec<usize> = (0..num_open).collect();
688 order.sort_by_key(|&i| vert_morton[i]);
689
690 let sorted_box: Vec<Box> = order.iter().map(|&i| vert_box[i]).collect();
691 let sorted_morton: Vec<u32> = order.iter().map(|&i| vert_morton[i]).collect();
692 let sorted_verts: Vec<usize> = order.iter().map(|&i| open_verts[i]).collect();
693
694 let collider = Collider::new(sorted_box.clone(), sorted_morton);
696 let uf = DisjointSets::new(num_vert as u32);
697
698 collider.collisions_with_boxes(&sorted_box, false, |a, b| {
699 uf.unite(sorted_verts[a] as u32, sorted_verts[b] as u32);
700 });
701
702 for i in 0..self.merge_from_vert.len() {
704 uf.unite(self.merge_from_vert[i], self.merge_to_vert[i]);
705 }
706
707 self.merge_from_vert.clear();
709 self.merge_to_vert.clear();
710 for v in 0..num_vert {
711 let merge_to = uf.find(v as u32) as usize;
712 if merge_to != v {
713 self.merge_from_vert.push(v as u32);
714 self.merge_to_vert.push(merge_to as u32);
715 }
716 }
717
718 true
719 }
720
721 pub fn backside(&self, run: usize) -> bool {
725 run < self.run_flags.len() && (self.run_flags[run] & 1) != 0
726 }
727
728 pub fn has_normals(&self, run: usize) -> bool {
733 run < self.run_flags.len() && (self.run_flags[run] & 2) != 0
734 }
735
736 pub fn update_normals(&mut self, normal_idx: usize) {
742 if normal_idx < 3 || normal_idx + 3 > self.num_prop as usize {
743 return;
744 }
745 let num_vert = self.num_vert();
746 let num_run = self.run_original_id.len();
747 let np = self.num_prop as usize;
748 let mut vert_updated = vec![false; num_vert];
749
750 for run in 0..num_run {
751 let offset = 12 * run;
753 let has_transform = offset + 12 <= self.run_transform.len();
754
755 let (m00, m01, m02,
757 m10, m11, m12,
758 m20, m21, m22) = if has_transform {
759 let t = &self.run_transform[offset..offset + 12];
760 (t[0] as f64, t[3] as f64, t[6] as f64,
762 t[1] as f64, t[4] as f64, t[7] as f64,
763 t[2] as f64, t[5] as f64, t[8] as f64)
764 } else {
765 (1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
766 };
767
768 let det = m00*(m11*m22 - m12*m21) - m01*(m10*m22 - m12*m20) + m02*(m10*m21 - m11*m20);
773 let (n00, n01, n02, n10, n11, n12, n20, n21, n22) = if det.abs() < 1e-30 {
774 (1.0f64, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
775 } else {
776 let inv = 1.0 / det;
777 let a00 = (m11*m22 - m12*m21) * inv;
779 let a01 = (m02*m21 - m01*m22) * inv;
780 let a02 = (m01*m12 - m02*m11) * inv;
781 let a10 = (m12*m20 - m10*m22) * inv;
782 let a11 = (m00*m22 - m02*m20) * inv;
783 let a12 = (m02*m10 - m00*m12) * inv;
784 let a20 = (m10*m21 - m11*m20) * inv;
785 let a21 = (m01*m20 - m00*m21) * inv;
786 let a22 = (m00*m11 - m01*m10) * inv;
787 (a00, a01, a02, a10, a11, a12, a20, a21, a22)
788 };
789
790 let sign = if self.backside(run) { -1.0f64 } else { 1.0 };
791
792 let start = if run < self.run_index.len() { self.run_index[run] as usize } else { 0 };
794 let end = if run + 1 < self.run_index.len() { self.run_index[run + 1] as usize } else { self.tri_verts.len() };
795
796 for idx in (start..end).step_by(1) {
797 let vert = self.tri_verts[idx] as usize;
798 if vert >= num_vert || vert_updated[vert] { continue; }
799 vert_updated[vert] = true;
800 let prop_start = vert * np + normal_idx;
801 let nx = self.vert_properties[prop_start] as f64;
802 let ny = self.vert_properties[prop_start + 1] as f64;
803 let nz = self.vert_properties[prop_start + 2] as f64;
804 let tx = n00*nx + n01*ny + n02*nz;
806 let ty = n10*nx + n11*ny + n12*nz;
807 let tz = n20*nx + n21*ny + n22*nz;
808 let len = (tx*tx + ty*ty + tz*tz).sqrt();
810 let (tx, ty, tz) = if len > 0.0 {
811 (sign * tx / len, sign * ty / len, sign * tz / len)
812 } else {
813 (0.0, 0.0, 0.0)
814 };
815 self.vert_properties[prop_start] = tx as f32;
816 self.vert_properties[prop_start + 1] = ty as f32;
817 self.vert_properties[prop_start + 2] = tz as f32;
818 }
819 }
820 self.run_transform.clear();
821 self.run_flags.clear();
822 }
823}
824
825impl MeshGLP<f64, u64> {
826 pub fn num_vert(&self) -> usize {
827 if self.num_prop == 0 { 0 } else { self.vert_properties.len() / self.num_prop as usize }
828 }
829
830 pub fn num_tri(&self) -> usize {
831 self.tri_verts.len() / 3
832 }
833
834 pub fn get_vert_pos(&self, v: usize) -> [f64; 3] {
835 let offset = v * self.num_prop as usize;
836 [self.vert_properties[offset], self.vert_properties[offset + 1], self.vert_properties[offset + 2]]
837 }
838
839 pub fn get_tri_verts(&self, t: usize) -> [u64; 3] {
840 let offset = 3 * t;
841 [self.tri_verts[offset], self.tri_verts[offset + 1], self.tri_verts[offset + 2]]
842 }
843
844 pub fn get_tangent(&self, h: usize) -> [f64; 4] {
845 let offset = 4 * h;
846 [
847 self.halfedge_tangent[offset],
848 self.halfedge_tangent[offset + 1],
849 self.halfedge_tangent[offset + 2],
850 self.halfedge_tangent[offset + 3],
851 ]
852 }
853}
854
855pub type MeshGL = MeshGLP<f32, u32>;
857
858pub type MeshGL64 = MeshGLP<f64, u64>;
860
861#[derive(Clone, Debug, Default)]
867pub struct RayHit {
868 pub face_id: u64,
870 pub distance: f64,
873 pub position: crate::linalg::Vec3,
875 pub normal: crate::linalg::Vec3,
877}
878
879#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
884pub struct Halfedge {
885 pub start_vert: i32,
886 pub end_vert: i32,
887 pub paired_halfedge: i32,
888 pub prop_vert: i32,
889}
890
891impl Halfedge {
892 pub fn is_forward(&self) -> bool {
893 self.start_vert < self.end_vert
894 }
895}
896
897impl PartialOrd for Halfedge {
898 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
899 Some(self.cmp(other))
900 }
901}
902
903impl Ord for Halfedge {
904 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
905 if self.start_vert == other.start_vert {
906 self.end_vert.cmp(&other.end_vert)
907 } else {
908 self.start_vert.cmp(&other.start_vert)
909 }
910 }
911}
912
913#[derive(Clone, Copy, Debug, PartialEq)]
918pub struct Barycentric {
919 pub tri: i32,
920 pub uvw: Vec4,
921}
922
923#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
928pub struct TriRef {
929 pub mesh_id: i32,
931 pub original_id: i32,
933 pub face_id: i32,
935 pub coplanar_id: i32,
937}
938
939impl TriRef {
940 pub fn same_face(&self, other: &TriRef) -> bool {
941 self.mesh_id == other.mesh_id
942 && self.coplanar_id == other.coplanar_id
943 && self.face_id == other.face_id
944 }
945}
946
947#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
952pub struct TmpEdge {
953 pub first: i32,
954 pub second: i32,
955 pub halfedge_idx: i32,
956}
957
958impl TmpEdge {
959 pub fn new(start: i32, end: i32, idx: i32) -> Self {
960 TmpEdge {
961 first: start.min(end),
962 second: start.max(end),
963 halfedge_idx: idx,
964 }
965 }
966}
967
968impl PartialOrd for TmpEdge {
969 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
970 Some(self.cmp(other))
971 }
972}
973
974impl Ord for TmpEdge {
975 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
976 if self.first == other.first {
977 self.second.cmp(&other.second)
978 } else {
979 self.first.cmp(&other.first)
980 }
981 }
982}
983
984#[derive(Clone, Debug)]
990pub struct Relation {
991 pub original_id: i32,
992 pub transform: Mat3x4,
993 pub back_side: bool,
994 pub has_normals: bool,
999}
1000
1001impl Default for Relation {
1002 fn default() -> Self {
1003 Relation {
1004 original_id: -1,
1005 transform: Mat3x4::identity(),
1006 back_side: false,
1007 has_normals: false,
1008 }
1009 }
1010}
1011
1012impl Relation {
1013 pub fn get_normal_transform(&self) -> Mat3 {
1017 let sign = if self.back_side { -1.0 } else { 1.0 };
1018 self.transform.rotation().transpose().inverse() * sign
1020 }
1021
1022 pub fn get_inverse_normal_transform(&self) -> Mat3 {
1026 let sign = if self.back_side { -1.0 } else { 1.0 };
1027 self.transform.rotation().transpose() * sign
1029 }
1030}
1031
1032#[derive(Clone, Debug, Default)]
1034pub struct MeshRelationD {
1035 pub original_id: i32,
1037 pub mesh_id_transform: BTreeMap<i32, Relation>,
1041 pub tri_ref: Vec<TriRef>,
1042}
1043
1044impl MeshRelationD {
1045 pub fn new() -> Self {
1046 MeshRelationD {
1047 original_id: -1,
1048 mesh_id_transform: BTreeMap::new(),
1049 tri_ref: Vec::new(),
1050 }
1051 }
1052}
1053
1054#[inline]
1060pub fn next_halfedge(current: i32) -> i32 {
1061 let n = current + 1;
1062 if n % 3 == 0 { n - 3 } else { n }
1063}
1064
1065pub fn prev_halfedge(current: i32) -> i32 {
1068 let base = current - (current % 3);
1069 let pos = (current % 3 + 2) % 3;
1070 base + pos
1071}
1072
1073#[inline]
1075pub fn next3(i: i32) -> i32 {
1076 let n = i + 1;
1077 if n == 3 { 0 } else { n }
1078}
1079
1080#[cfg(test)]
1082#[path = "types_tests.rs"]
1083mod tests;