1use std::collections::BTreeMap;
32
33use crate::impl_mesh::ManifoldImpl;
34use crate::linalg::{Vec3, dot};
35use crate::types::{Halfedge, TriRef};
36
37#[derive(Clone)]
42pub(super) struct EdgePos {
43 edge_pos: f64,
44 vert: i32,
45 collision_id: i32,
46 is_start: bool,
47}
48
49impl EdgePos {
50 fn sort_key(&self) -> (OrderedF64, i32) {
51 (OrderedF64(self.edge_pos), self.collision_id)
52 }
53}
54
55#[derive(Clone, Copy, PartialEq)]
57struct OrderedF64(f64);
58
59impl Eq for OrderedF64 {}
60
61impl PartialOrd for OrderedF64 {
62 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
63 Some(self.cmp(other))
64 }
65}
66
67impl Ord for OrderedF64 {
68 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
69 self.0.partial_cmp(&other.0).unwrap_or(std::cmp::Ordering::Equal)
70 }
71}
72
73#[inline]
78pub(super) fn abs_sum(a: i32, b: i32) -> i32 {
79 a.abs() + b.abs()
80}
81
82pub(super) fn exclusive_scan_abs(input: &[i32], init: i32) -> Vec<i32> {
84 let mut result = Vec::with_capacity(input.len());
85 let mut acc = init;
86 for &v in input {
87 result.push(acc);
88 acc = abs_sum(acc, v);
89 }
90 result
91}
92
93pub(super) fn size_output(
100 out_r: &mut ManifoldImpl,
101 in_p: &ManifoldImpl,
102 in_q: &ManifoldImpl,
103 i03: &[i32],
104 i30: &[i32],
105 i12: &[i32],
106 i21: &[i32],
107 p1q2: &[[i32; 2]],
108 p2q1: &[[i32; 2]],
109 invert_q: bool,
110) -> (Vec<i32>, Vec<i32>) {
111 let num_tri_p = in_p.num_tri();
112 let num_tri_q = in_q.num_tri();
113 let mut sides_per_face = vec![0i32; num_tri_p + num_tri_q];
114
115 for face in 0..num_tri_p {
117 for j in 0..3 {
118 let v = in_p.halfedge[3 * face + j].start_vert as usize;
119 sides_per_face[face] += i03[v].abs();
120 }
121 }
122 for face in 0..num_tri_q {
123 for j in 0..3 {
124 let v = in_q.halfedge[3 * face + j].start_vert as usize;
125 sides_per_face[num_tri_p + face] += i30[v].abs();
126 }
127 }
128
129 for (idx, pair) in p1q2.iter().enumerate() {
131 let edge_p = pair[0] as usize;
132 let face_q = pair[1] as usize;
133 let inclusion = i12[idx].abs();
134 sides_per_face[num_tri_p + face_q] += inclusion;
135 let half = in_p.halfedge[edge_p];
136 sides_per_face[edge_p / 3] += inclusion;
137 sides_per_face[half.paired_halfedge as usize / 3] += inclusion;
138 }
139 for (idx, pair) in p2q1.iter().enumerate() {
140 let face_p = pair[0] as usize;
141 let edge_q = pair[1] as usize;
142 let inclusion = i21[idx].abs();
143 sides_per_face[face_p] += inclusion;
144 let half = in_q.halfedge[edge_q];
145 sides_per_face[num_tri_p + edge_q / 3] += inclusion;
146 sides_per_face[num_tri_p + half.paired_halfedge as usize / 3] += inclusion;
147 }
148
149 let mut face_pq2r = vec![0i32; num_tri_p + num_tri_q];
151 let mut count = 0i32;
152 for i in 0..sides_per_face.len() {
153 face_pq2r[i] = count;
154 if sides_per_face[i] > 0 {
155 count += 1;
156 }
157 }
158 let num_face_r = count as usize;
159
160 out_r.face_normal.resize(num_face_r, Vec3::splat(0.0));
162 let mut out_idx = 0;
163 for i in 0..num_tri_p {
164 if sides_per_face[i] > 0 {
165 out_r.face_normal[out_idx] = in_p.face_normal[i];
166 out_idx += 1;
167 }
168 }
169 for i in 0..num_tri_q {
170 if sides_per_face[num_tri_p + i] > 0 {
171 let normal = in_q.face_normal[i];
172 out_r.face_normal[out_idx] = if invert_q {
173 Vec3::new(-normal.x, -normal.y, -normal.z)
174 } else {
175 normal
176 };
177 out_idx += 1;
178 }
179 }
180
181 let active_sides: Vec<i32> = sides_per_face.iter().filter(|&&s| s > 0).copied().collect();
183 let mut face_edge = vec![0i32; active_sides.len() + 1];
184 for (i, &s) in active_sides.iter().enumerate() {
185 face_edge[i + 1] = face_edge[i] + s;
186 }
187 let num_halfedge = *face_edge.last().unwrap() as usize;
188 out_r.halfedge.resize(
189 num_halfedge,
190 Halfedge {
191 start_vert: -1,
192 end_vert: -1,
193 paired_halfedge: -1,
194 prop_vert: -1,
195 },
196 );
197
198 (face_edge, face_pq2r)
199}
200
201pub(super) fn add_new_edge_verts(
206 edges_p: &mut BTreeMap<i32, Vec<EdgePos>>,
207 edges_new: &mut BTreeMap<(i32, i32), Vec<EdgePos>>,
208 p1q2: &[[i32; 2]],
209 i12: &[i32],
210 v12r: &[i32],
211 halfedge_p: &[Halfedge],
212 forward: bool,
213 offset: usize,
214) {
215 for i in 0..p1q2.len() {
216 let edge_p = p1q2[i][if forward { 0 } else { 1 }];
217 let face_q = p1q2[i][if forward { 1 } else { 0 }];
218 let vert = v12r[i];
219 let inclusion = i12[i];
220
221 let halfedge = halfedge_p[edge_p as usize];
222 let mut key_right = (halfedge.paired_halfedge / 3, face_q);
223 if !forward {
224 key_right = (key_right.1, key_right.0);
225 }
226 let mut key_left = (edge_p / 3, face_q);
227 if !forward {
228 key_left = (key_left.1, key_left.0);
229 }
230
231 let direction = inclusion < 0;
232 let collision_id = (i + offset) as i32;
233
234 let dir_p = direction;
239 let dir_right = direction ^ !forward;
240 let dir_left = direction ^ forward;
241
242 let ep = edges_p.entry(edge_p).or_default();
244 for j in 0..inclusion.abs() {
245 ep.push(EdgePos {
246 edge_pos: 0.0,
247 vert: vert + j,
248 collision_id,
249 is_start: dir_p,
250 });
251 }
252
253 let er = edges_new.entry(key_right).or_default();
255 for j in 0..inclusion.abs() {
256 er.push(EdgePos {
257 edge_pos: 0.0,
258 vert: vert + j,
259 collision_id,
260 is_start: dir_right,
261 });
262 }
263
264 let el = edges_new.entry(key_left).or_default();
266 for j in 0..inclusion.abs() {
267 el.push(EdgePos {
268 edge_pos: 0.0,
269 vert: vert + j,
270 collision_id,
271 is_start: dir_left,
272 });
273 }
274 }
275}
276
277fn cpp_partition<T, P: Fn(&T) -> bool>(v: &mut [T], pred: P) -> usize {
288 let mut first = 0usize;
289 let mut last = v.len();
290 loop {
291 loop {
292 if first == last {
293 return first;
294 }
295 if !pred(&v[first]) {
296 break;
297 }
298 first += 1;
299 }
300 loop {
301 last -= 1;
302 if first == last {
303 return first;
304 }
305 if pred(&v[last]) {
306 break;
307 }
308 }
309 v.swap(first, last);
310 first += 1;
311 }
312}
313
314fn pair_up<F: FnMut(Halfedge)>(edge_pos: &mut Vec<EdgePos>, mut f: F) {
315 assert!(
316 edge_pos.len() % 2 == 0,
317 "Non-manifold edge! Not an even number of points. Got {} points: starts={}, ends={}",
318 edge_pos.len(),
319 edge_pos.iter().filter(|e| e.is_start).count(),
320 edge_pos.iter().filter(|e| !e.is_start).count(),
321 );
322 let n_edges = edge_pos.len() / 2;
323
324 let middle = cpp_partition(edge_pos, |e| e.is_start);
327 debug_assert_eq!(middle, n_edges, "Non-manifold edge!");
328 edge_pos[..n_edges].sort_by_key(|e| e.sort_key());
329 edge_pos[n_edges..].sort_by_key(|e| e.sort_key());
330
331 for i in 0..n_edges {
332 f(Halfedge {
333 start_vert: edge_pos[i].vert,
334 end_vert: edge_pos[i + n_edges].vert,
335 paired_halfedge: -1,
336 prop_vert: -1,
337 });
338 }
339}
340
341pub(super) fn append_partial_edges(
346 out_r: &mut ManifoldImpl,
347 whole_halfedge_p: &mut Vec<bool>,
348 face_ptr_r: &mut Vec<i32>,
349 edges_p: &mut BTreeMap<i32, Vec<EdgePos>>,
350 halfedge_ref: &mut Vec<TriRef>,
351 in_p: &ManifoldImpl,
352 i03: &[i32],
353 vp2r: &[i32],
354 face_p2r: &[i32],
355 forward: bool,
356) {
357 for (&edge_p, edge_pos_p) in edges_p.iter_mut() {
358 edge_pos_p.sort_by_key(|e| e.sort_key());
359
360 let halfedge = in_p.halfedge[edge_p as usize];
361 whole_halfedge_p[edge_p as usize] = false;
362 whole_halfedge_p[halfedge.paired_halfedge as usize] = false;
363
364 let v_start = halfedge.start_vert as usize;
365 let v_end = halfedge.end_vert as usize;
366
367 let edge_vec = in_p.vert_pos[v_end] - in_p.vert_pos[v_start];
372
373 for edge in edge_pos_p.iter_mut() {
375 edge.edge_pos = dot(out_r.vert_pos[edge.vert as usize], edge_vec);
376 }
377
378 let inclusion = i03[v_start];
381 if inclusion != 0 {
382 let start_pos = dot(out_r.vert_pos[vp2r[v_start] as usize], edge_vec);
383 for j in 0..inclusion.abs() {
384 edge_pos_p.push(EdgePos {
385 edge_pos: start_pos,
386 vert: vp2r[v_start] + j,
387 collision_id: i32::MAX,
388 is_start: inclusion > 0,
389 });
390 }
391 }
392
393 let inclusion = i03[v_end];
395 if inclusion != 0 {
396 let end_pos = dot(out_r.vert_pos[vp2r[v_end] as usize], edge_vec);
397 for j in 0..inclusion.abs() {
398 edge_pos_p.push(EdgePos {
399 edge_pos: end_pos,
400 vert: vp2r[v_end] + j,
401 collision_id: i32::MAX,
402 is_start: inclusion < 0,
403 });
404 }
405 }
406
407 let face_left_p = edge_p as usize / 3;
409 let face_left = face_p2r[face_left_p];
410 let face_right_p = halfedge.paired_halfedge as usize / 3;
411 let face_right = face_p2r[face_right_p];
412
413 let forward_ref = TriRef {
414 mesh_id: if forward { 0 } else { 1 },
415 original_id: -1,
416 face_id: face_left_p as i32,
417 coplanar_id: -1,
418 };
419 let backward_ref = TriRef {
420 mesh_id: if forward { 0 } else { 1 },
421 original_id: -1,
422 face_id: face_right_p as i32,
423 coplanar_id: -1,
424 };
425
426 pair_up(edge_pos_p, |mut e| {
427 let forward_edge = face_ptr_r[face_left as usize];
428 face_ptr_r[face_left as usize] += 1;
429 let backward_edge = face_ptr_r[face_right as usize];
430 face_ptr_r[face_right as usize] += 1;
431
432 e.paired_halfedge = backward_edge;
433 out_r.halfedge[forward_edge as usize] = e;
434 halfedge_ref[forward_edge as usize] = forward_ref;
435
436 let rev = Halfedge {
437 start_vert: e.end_vert,
438 end_vert: e.start_vert,
439 paired_halfedge: forward_edge,
440 prop_vert: -1,
441 };
442 out_r.halfedge[backward_edge as usize] = rev;
443 halfedge_ref[backward_edge as usize] = backward_ref;
444 });
445 }
446}
447
448pub(super) fn append_new_edges(
453 out_r: &mut ManifoldImpl,
454 face_ptr_r: &mut Vec<i32>,
455 edges_new: &mut BTreeMap<(i32, i32), Vec<EdgePos>>,
456 halfedge_ref: &mut Vec<TriRef>,
457 face_pq2r: &[i32],
458 num_face_p: usize,
459) {
460 for (&(face_p, face_q), edge_pos) in edges_new.iter_mut() {
461 edge_pos.sort_by_key(|e| e.sort_key());
462
463 let mut min = Vec3::splat(f64::INFINITY);
465 let mut max = Vec3::splat(f64::NEG_INFINITY);
466 for edge in edge_pos.iter() {
467 let p = out_r.vert_pos[edge.vert as usize];
468 min.x = min.x.min(p.x);
469 min.y = min.y.min(p.y);
470 min.z = min.z.min(p.z);
471 max.x = max.x.max(p.x);
472 max.y = max.y.max(p.y);
473 max.z = max.z.max(p.z);
474 }
475 let size = max - min;
476 let dim = if size.x > size.y && size.x > size.z {
478 0
479 } else if size.y > size.z {
480 1
481 } else {
482 2
483 };
484
485 for edge in edge_pos.iter_mut() {
486 let p = out_r.vert_pos[edge.vert as usize];
487 edge.edge_pos = match dim {
488 0 => p.x,
489 1 => p.y,
490 _ => p.z,
491 };
492 }
493
494 let face_left = face_pq2r[face_p as usize];
495 let face_right = face_pq2r[num_face_p + face_q as usize];
496 let forward_ref = TriRef {
497 mesh_id: 0,
498 original_id: -1,
499 face_id: face_p,
500 coplanar_id: -1,
501 };
502 let backward_ref = TriRef {
503 mesh_id: 1,
504 original_id: -1,
505 face_id: face_q,
506 coplanar_id: -1,
507 };
508
509 pair_up(edge_pos, |mut e| {
510 let forward_edge = face_ptr_r[face_left as usize];
511 face_ptr_r[face_left as usize] += 1;
512 let backward_edge = face_ptr_r[face_right as usize];
513 face_ptr_r[face_right as usize] += 1;
514
515 e.paired_halfedge = backward_edge;
516 out_r.halfedge[forward_edge as usize] = e;
517 halfedge_ref[forward_edge as usize] = forward_ref;
518
519 let rev = Halfedge {
520 start_vert: e.end_vert,
521 end_vert: e.start_vert,
522 paired_halfedge: forward_edge,
523 prop_vert: -1,
524 };
525 out_r.halfedge[backward_edge as usize] = rev;
526 halfedge_ref[backward_edge as usize] = backward_ref;
527 });
528 }
529}
530
531pub(super) fn append_whole_edges(
536 out_r: &mut ManifoldImpl,
537 face_ptr_r: &mut Vec<i32>,
538 halfedge_ref: &mut Vec<TriRef>,
539 in_p: &ManifoldImpl,
540 whole_halfedge_p: &[bool],
541 i03: &[i32],
542 vp2r: &[i32],
543 face_p2r: &[i32],
544 forward: bool,
545) {
546 for idx in 0..in_p.halfedge.len() {
547 if !whole_halfedge_p[idx] {
548 continue;
549 }
550 let mut halfedge = in_p.halfedge[idx];
551 if !halfedge.is_forward() {
552 continue;
553 }
554
555 let inclusion = i03[halfedge.start_vert as usize];
556 if inclusion == 0 {
557 continue;
558 }
559 if inclusion < 0 {
560 std::mem::swap(&mut halfedge.start_vert, &mut halfedge.end_vert);
562 }
563 halfedge.start_vert = vp2r[halfedge.start_vert as usize];
564 halfedge.end_vert = vp2r[halfedge.end_vert as usize];
565
566 let face_left_p = idx / 3;
567 let new_face = face_p2r[face_left_p];
568 let face_right_p = halfedge.paired_halfedge as usize / 3;
569 let face_right = face_p2r[face_right_p];
570
571 let forward_ref = TriRef {
572 mesh_id: if forward { 0 } else { 1 },
573 original_id: -1,
574 face_id: face_left_p as i32,
575 coplanar_id: -1,
576 };
577 let backward_ref = TriRef {
578 mesh_id: if forward { 0 } else { 1 },
579 original_id: -1,
580 face_id: face_right_p as i32,
581 coplanar_id: -1,
582 };
583
584 for i in 0..inclusion.abs() {
585 let forward_edge = face_ptr_r[new_face as usize];
586 face_ptr_r[new_face as usize] += 1;
587 let backward_edge = face_ptr_r[face_right as usize];
588 face_ptr_r[face_right as usize] += 1;
589
590 let he = Halfedge {
591 start_vert: halfedge.start_vert + i,
592 end_vert: halfedge.end_vert + i,
593 paired_halfedge: backward_edge,
594 prop_vert: -1,
595 };
596 out_r.halfedge[forward_edge as usize] = he;
597 halfedge_ref[forward_edge as usize] = forward_ref;
598
599 let rev = Halfedge {
600 start_vert: halfedge.end_vert + i,
601 end_vert: halfedge.start_vert + i,
602 paired_halfedge: forward_edge,
603 prop_vert: -1,
604 };
605 out_r.halfedge[backward_edge as usize] = rev;
606 halfedge_ref[backward_edge as usize] = backward_ref;
607 }
608 }
609}
610
611#[path = "boolean_result_assemble.rs"]
613mod boolean_result_assemble;
614pub use boolean_result_assemble::boolean_result;
615