1use std::collections::BTreeMap;
5
6use crate::boolean3::Boolean3;
7use crate::edge_op::simplify_topology;
8use crate::face_op::{face2tri, get_barycentric, reorder_halfedges};
9use crate::impl_mesh::{reserve_ids, ManifoldImpl};
10use crate::linalg::Vec3;
11use crate::types::{OpType, TriRef};
12
13use super::{EdgePos, abs_sum, exclusive_scan_abs,
14 size_output, add_new_edge_verts, append_partial_edges,
15 append_new_edges, append_whole_edges};
16
17pub(super) fn update_reference(out_r: &mut ManifoldImpl, in_p: &ManifoldImpl, in_q: &ManifoldImpl, invert_q: bool) {
22 let offset_q = reserve_ids(in_q.mesh_relation.mesh_id_transform.len() as u32) as i32;
23
24 for tri_ref in out_r.mesh_relation.tri_ref.iter_mut() {
25 let tri = tri_ref.face_id;
26 let pq = tri_ref.mesh_id == 0;
27 if pq {
28 if (tri as usize) < in_p.mesh_relation.tri_ref.len() {
29 *tri_ref = in_p.mesh_relation.tri_ref[tri as usize];
30 }
31 } else {
32 if (tri as usize) < in_q.mesh_relation.tri_ref.len() {
33 *tri_ref = in_q.mesh_relation.tri_ref[tri as usize];
34 tri_ref.mesh_id += offset_q;
35 }
36 }
37 }
38
39 for (&k, v) in &in_p.mesh_relation.mesh_id_transform {
40 out_r.mesh_relation.mesh_id_transform.insert(k, v.clone());
41 }
42 for (&k, v) in &in_q.mesh_relation.mesh_id_transform {
43 let mut rel = v.clone();
44 rel.back_side ^= invert_q;
45 out_r.mesh_relation.mesh_id_transform.insert(k + offset_q, rel);
46 }
47}
48
49pub(super) fn create_properties(out_r: &mut ManifoldImpl, in_p: &ManifoldImpl, in_q: &ManifoldImpl, invert_q: bool) {
54 let num_prop_p = in_p.num_prop;
55 let num_prop_q = in_q.num_prop;
56 let num_prop = num_prop_p.max(num_prop_q);
57 out_r.num_prop = num_prop;
58 if num_prop == 0 {
59 return;
60 }
61
62 let num_tri = out_r.num_tri();
63
64 let mut bary = vec![Vec3::splat(0.0); out_r.halfedge.len()];
66 for tri in 0..num_tri {
67 let ref_pq = out_r.mesh_relation.tri_ref[tri];
68 if out_r.halfedge[3 * tri].start_vert < 0 {
69 continue;
70 }
71
72 let tri_pq = ref_pq.face_id as usize;
73 let pq = ref_pq.mesh_id == 0;
74 let vert_pos = if pq { &in_p.vert_pos } else { &in_q.vert_pos };
75 let halfedge = if pq { &in_p.halfedge } else { &in_q.halfedge };
76
77 if 3 * tri_pq + 2 >= halfedge.len() {
78 continue;
79 }
80
81 let tri_pos = [
82 vert_pos[halfedge[3 * tri_pq].start_vert as usize],
83 vert_pos[halfedge[3 * tri_pq + 1].start_vert as usize],
84 vert_pos[halfedge[3 * tri_pq + 2].start_vert as usize],
85 ];
86
87 for i in 0..3 {
88 let vert = out_r.halfedge[3 * tri + i].start_vert;
89 if vert >= 0 && (vert as usize) < out_r.vert_pos.len() {
90 bary[3 * tri + i] = get_barycentric(out_r.vert_pos[vert as usize], tri_pos, out_r.epsilon);
91 }
92 }
93 }
94
95 out_r.properties.clear();
97 out_r.properties.reserve(out_r.num_vert() * num_prop);
98 let mut idx = 0i32;
99
100 let id_miss_prop = out_r.num_vert() as i32;
102 let mut prop_idx: Vec<Vec<([i32; 3], i32)>> = vec![Vec::new(); out_r.num_vert() + 1];
104 let mut prop_miss_idx: [Vec<i32>; 2] = [
106 vec![-1i32; in_q.num_prop_vert()],
107 vec![-1i32; in_p.num_prop_vert()],
108 ];
109
110 #[inline]
111 fn next3(i: usize) -> usize { (i + 1) % 3 }
112 #[inline]
113 fn prev3(i: usize) -> usize { (i + 2) % 3 }
114
115 for tri in 0..num_tri {
116 if out_r.halfedge[3 * tri].start_vert < 0 {
117 continue;
118 }
119 let ref_pq = out_r.mesh_relation.tri_ref[tri];
120 let pq = ref_pq.mesh_id == 0;
121 let pq_flag: i32 = if pq { 0 } else { 1 };
122 let old_num_prop = if pq { num_prop_p } else { num_prop_q };
123 let properties = if pq { &in_p.properties } else { &in_q.properties };
124 let halfedge = if pq { &in_p.halfedge } else { &in_q.halfedge };
125
126 let negate_normals = !pq
132 && invert_q
133 && old_num_prop >= 3
134 && in_q.tri_has_normals(ref_pq.face_id as usize);
135
136 for i in 0..3 {
137 let vert = out_r.halfedge[3 * tri + i].start_vert;
138 let uvw = bary[3 * tri + i];
139
140 let mut key = [pq_flag, id_miss_prop, -1i32, -1i32];
142 if old_num_prop > 0 && 3 * ref_pq.face_id as usize + 2 < halfedge.len() {
143 let mut edge: i32 = -2;
144 for j in 0..3usize {
145 if uvw[j] == 1.0 {
146 key[2] = halfedge[3 * ref_pq.face_id as usize + j].prop_vert;
148 edge = -1;
149 break;
150 }
151 if uvw[j] == 0.0 {
152 edge = j as i32;
153 }
154 }
155 if edge >= 0 {
156 let p0 = halfedge[3 * ref_pq.face_id as usize + next3(edge as usize)].prop_vert;
158 let p1 = halfedge[3 * ref_pq.face_id as usize + prev3(edge as usize)].prop_vert;
159 key[1] = vert;
160 key[2] = p0.min(p1);
161 key[3] = p0.max(p1);
162 } else if edge == -2 {
163 key[1] = vert;
165 }
166 }
167
168 let mut found = false;
170 if key[1] == id_miss_prop && key[2] >= 0 {
171 let pq_idx = key[0] as usize;
173 let prop_key = key[2] as usize;
174 if pq_idx < 2 && prop_key < prop_miss_idx[pq_idx].len() {
175 let entry = prop_miss_idx[pq_idx][prop_key];
176 if entry >= 0 {
177 out_r.halfedge[3 * tri + i].prop_vert = entry;
178 found = true;
179 } else {
180 prop_miss_idx[pq_idx][prop_key] = idx;
181 }
182 }
183 } else {
184 let bin_idx = key[1] as usize;
186 if bin_idx < prop_idx.len() {
187 let search_key = [key[0], key[2], key[3]];
188 if let Some(entry) = prop_idx[bin_idx].iter().find(|(k, _)| *k == search_key) {
189 out_r.halfedge[3 * tri + i].prop_vert = entry.1;
190 found = true;
191 } else {
192 prop_idx[bin_idx].push((search_key, idx));
193 }
194 }
195 }
196
197 if found {
198 continue;
199 }
200
201 out_r.halfedge[3 * tri + i].prop_vert = idx;
203 idx += 1;
204
205 for p in 0..num_prop {
206 if p < old_num_prop && 3 * ref_pq.face_id as usize + 2 < halfedge.len() {
207 let mut old_props = [0.0f64; 3];
208 for j in 0..3 {
209 let prop_vert = halfedge[3 * ref_pq.face_id as usize + j].prop_vert;
210 if prop_vert >= 0 {
211 let prop_idx_val = old_num_prop * prop_vert as usize + p;
212 if prop_idx_val < properties.len() {
213 old_props[j] = properties[prop_idx_val];
214 }
215 }
216 }
217 let mut val = uvw.x * old_props[0] + uvw.y * old_props[1] + uvw.z * old_props[2];
218 if negate_normals && p < 3 {
219 val = -val;
220 }
221 out_r.properties.push(val);
222 } else {
223 out_r.properties.push(0.0);
224 }
225 }
226 }
227 }
228}
229
230pub fn boolean_result(
238 in_p: &ManifoldImpl,
239 in_q: &ManifoldImpl,
240 op: OpType,
241 bool3: &Boolean3,
242) -> ManifoldImpl {
243 debug_assert!(
244 bool3.expand_p == (op == OpType::Add),
245 "Result op type not compatible with constructor op type."
246 );
247
248 let c1 = if op == OpType::Intersect { 0 } else { 1 };
249 let c2 = if op == OpType::Add { 1 } else { 0 };
250 let c3 = if op == OpType::Intersect { 1 } else { -1 };
251
252 if in_p.is_empty() {
254 if !in_q.is_empty() && op == OpType::Add {
255 return in_q.clone();
256 }
257 return ManifoldImpl::new();
258 } else if in_q.is_empty() {
259 if op == OpType::Intersect {
260 return ManifoldImpl::new();
261 }
262 return in_p.clone();
263 }
264
265 if !bool3.valid {
267 return ManifoldImpl::new();
268 }
269
270 let invert_q = op == OpType::Subtract;
271
272 let i12: Vec<i32> = bool3.xv12.x12.iter().map(|&v| c3 * v).collect();
274 let i21: Vec<i32> = bool3.xv21.x12.iter().map(|&v| c3 * v).collect();
275 let i03: Vec<i32> = bool3.w03.iter().map(|&v| c1 + c3 * v).collect();
276 let i30: Vec<i32> = bool3.w30.iter().map(|&v| c2 + c3 * v).collect();
277
278 let vp2r = exclusive_scan_abs(&i03, 0);
280 let num_vert_r = if let Some(&last) = i03.last() {
281 abs_sum(*vp2r.last().unwrap_or(&0), last)
282 } else {
283 0
284 };
285 let n_pv = num_vert_r;
286
287 let vq2r = exclusive_scan_abs(&i30, num_vert_r);
288 let num_vert_r = if let Some(&last) = i30.last() {
289 abs_sum(*vq2r.last().unwrap_or(&num_vert_r), last)
290 } else {
291 num_vert_r
292 };
293 let n_qv = num_vert_r - n_pv;
294
295 let v12r = if !bool3.xv12.v12.is_empty() {
296 exclusive_scan_abs(&i12, num_vert_r)
297 } else {
298 Vec::new()
299 };
300 let num_vert_r = if !i12.is_empty() {
301 abs_sum(*v12r.last().unwrap_or(&num_vert_r), *i12.last().unwrap())
302 } else {
303 num_vert_r
304 };
305 let n12 = num_vert_r - n_pv - n_qv;
306
307 let v21r = if !bool3.xv21.v12.is_empty() {
308 exclusive_scan_abs(&i21, num_vert_r)
309 } else {
310 Vec::new()
311 };
312 let num_vert_r = if !i21.is_empty() {
313 abs_sum(*v21r.last().unwrap_or(&num_vert_r), *i21.last().unwrap())
314 } else {
315 num_vert_r
316 };
317 let _n21 = num_vert_r - n_pv - n_qv - n12;
318
319 let mut out_r = ManifoldImpl::new();
321 if num_vert_r == 0 {
322 return out_r;
323 }
324
325 out_r.epsilon = in_p.epsilon.max(in_q.epsilon);
326 out_r.tolerance = in_p.tolerance.max(in_q.tolerance);
327
328 out_r.vert_pos.resize(num_vert_r as usize, Vec3::splat(0.0));
330
331 for vert in 0..in_p.num_vert() {
333 let n = i03[vert].abs();
334 for i in 0..n {
335 out_r.vert_pos[(vp2r[vert] + i) as usize] = in_p.vert_pos[vert];
336 }
337 }
338 for vert in 0..in_q.num_vert() {
340 let n = i30[vert].abs();
341 for i in 0..n {
342 out_r.vert_pos[(vq2r[vert] + i) as usize] = in_q.vert_pos[vert];
343 }
344 }
345 for vert in 0..i12.len() {
347 let n = i12[vert].abs();
348 for i in 0..n {
349 out_r.vert_pos[(v12r[vert] + i) as usize] = bool3.xv12.v12[vert];
350 }
351 }
352 for vert in 0..i21.len() {
354 let n = i21[vert].abs();
355 for i in 0..n {
356 out_r.vert_pos[(v21r[vert] + i) as usize] = bool3.xv21.v12[vert];
357 }
358 }
359
360 let mut edges_p: BTreeMap<i32, Vec<EdgePos>> = BTreeMap::new();
362 let mut edges_q: BTreeMap<i32, Vec<EdgePos>> = BTreeMap::new();
363 let mut edges_new: BTreeMap<(i32, i32), Vec<EdgePos>> = BTreeMap::new();
364
365 add_new_edge_verts(
366 &mut edges_p,
367 &mut edges_new,
368 &bool3.xv12.p1q2,
369 &i12,
370 &v12r,
371 &in_p.halfedge,
372 true,
373 0,
374 );
375 add_new_edge_verts(
376 &mut edges_q,
377 &mut edges_new,
378 &bool3.xv21.p1q2,
379 &i21,
380 &v21r,
381 &in_q.halfedge,
382 false,
383 bool3.xv12.p1q2.len(),
384 );
385
386 let (face_edge, face_pq2r) = size_output(
388 &mut out_r,
389 in_p,
390 in_q,
391 &i03,
392 &i30,
393 &i12,
394 &i21,
395 &bool3.xv12.p1q2,
396 &bool3.xv21.p1q2,
397 invert_q,
398 );
399
400 let mut face_ptr_r = face_edge.clone();
402 let mut whole_halfedge_p = vec![true; in_p.halfedge.len()];
403 let mut whole_halfedge_q = vec![true; in_q.halfedge.len()];
404 let mut halfedge_ref = vec![
405 TriRef {
406 mesh_id: 0,
407 original_id: -1,
408 face_id: -1,
409 coplanar_id: -1,
410 };
411 2 * out_r.num_edge()
412 ];
413
414 append_partial_edges(
415 &mut out_r,
416 &mut whole_halfedge_p,
417 &mut face_ptr_r,
418 &mut edges_p,
419 &mut halfedge_ref,
420 in_p,
421 &i03,
422 &vp2r,
423 &face_pq2r[..in_p.num_tri()],
424 true,
425 );
426 append_partial_edges(
427 &mut out_r,
428 &mut whole_halfedge_q,
429 &mut face_ptr_r,
430 &mut edges_q,
431 &mut halfedge_ref,
432 in_q,
433 &i30,
434 &vq2r,
435 &face_pq2r[in_p.num_tri()..],
436 false,
437 );
438 append_new_edges(
439 &mut out_r,
440 &mut face_ptr_r,
441 &mut edges_new,
442 &mut halfedge_ref,
443 &face_pq2r,
444 in_p.num_tri(),
445 );
446 append_whole_edges(
447 &mut out_r,
448 &mut face_ptr_r,
449 &mut halfedge_ref,
450 in_p,
451 &whole_halfedge_p,
452 &i03,
453 &vp2r,
454 &face_pq2r[..in_p.num_tri()],
455 true,
456 );
457 append_whole_edges(
458 &mut out_r,
459 &mut face_ptr_r,
460 &mut halfedge_ref,
461 in_q,
462 &whole_halfedge_q,
463 &i30,
464 &vq2r,
465 &face_pq2r[in_p.num_tri()..],
466 false,
467 );
468
469 face2tri(&mut out_r, &face_edge, &halfedge_ref, false);
471 reorder_halfedges(&mut out_r);
472
473 create_properties(&mut out_r, in_p, in_q, invert_q);
475
476 update_reference(&mut out_r, in_p, in_q, invert_q);
478
479 simplify_topology(&mut out_r, (n_pv + n_qv) as i32);
481 out_r.remove_unreferenced_verts();
482
483 out_r.calculate_bbox();
485 out_r.sort_geometry();
486 out_r.increment_mesh_ids();
487
488 out_r
489}