manifold_rust/robust/
assemble.rs1use num_rational::BigRational;
24use num_traits::One;
25
26use crate::linalg::Vec3;
27use crate::manifold::Manifold;
28use crate::types::MeshGL64;
29
30use super::exact::rational::{rat_to_f64, R3};
31use super::intersection_graph::Piece;
32use super::tri_tri::dominant_axis;
33
34pub struct PropCtx<'a> {
38 pub num_prop: [usize; 2],
39 pub tris: [&'a [[Vec3; 3]]; 2],
40 pub props: [&'a [f64]; 2],
41}
42
43impl<'a> PropCtx<'a> {
44 pub fn out_num_prop(&self) -> usize {
45 self.num_prop[0].max(self.num_prop[1])
46 }
47}
48
49fn barycentric_r(p: &R3, tri: &[R3; 3]) -> [BigRational; 3] {
53 use super::exact::predicates::tri_normal_r;
54 let n = tri_normal_r(&tri[0], &tri[1], &tri[2]);
55 let axis = dominant_axis(&n);
56 let p2 = p.project_drop(axis);
57 let a = tri[0].project_drop(axis);
58 let b = tri[1].project_drop(axis);
59 let c = tri[2].project_drop(axis);
60 let total = b.sub(&a).cross(&c.sub(&a));
61 let w0 = b.sub(&p2).cross(&c.sub(&p2)) / &total;
62 let w1 = c.sub(&p2).cross(&a.sub(&p2)) / &total;
63 let w2 = BigRational::one() - &w0 - &w1;
64 [w0, w1, w2]
65}
66
67fn interpolate_props(ctx: &PropCtx, piece: &Piece, v: &R3, out: usize) -> Vec<f64> {
69 let m = piece.mesh as usize;
70 let np = ctx.num_prop[m];
71 let mut result = vec![0.0f64; out];
72 if np == 0 {
73 return result;
74 }
75 let base = 3 * piece.tri * np;
76 let corner = |i: usize| &ctx.props[m][base + i * np..base + (i + 1) * np];
77 let (c0, c1, c2) = (corner(0), corner(1), corner(2));
78
79 let all_const = (0..np).all(|k| c0[k] == c1[k] && c0[k] == c2[k]);
81 if all_const {
82 result[..np].copy_from_slice(c0);
83 return result;
84 }
85
86 let t = ctx.tris[m][piece.tri];
87 let corners = [
88 R3::from_vec3(t[0]),
89 R3::from_vec3(t[1]),
90 R3::from_vec3(t[2]),
91 ];
92 let w = barycentric_r(v, &corners);
93 let wf = [rat_to_f64(&w[0]), rat_to_f64(&w[1]), rat_to_f64(&w[2])];
94 for k in 0..np {
95 result[k] = if c0[k] == c1[k] && c0[k] == c2[k] {
96 c0[k]
97 } else {
98 wf[0] * c0[k] + wf[1] * c1[k] + wf[2] * c2[k]
99 };
100 }
101 result
102}
103
104pub fn assemble<F: Fn(usize) -> bool>(
112 pieces: &[Piece],
113 verts: &[R3],
114 verts_f64: &[Vec3],
115 select: F,
116 props: Option<&PropCtx>,
117) -> Manifold {
118 let out_prop = props.map_or(0, |p| p.out_num_prop());
119
120 type Key = (u32, Vec<u64>);
123 let mut vert_index: std::collections::HashMap<Key, u64> = std::collections::HashMap::new();
124 let mut vert_order: Vec<(u32, Vec<f64>)> = Vec::new();
125 let mut tri_verts: Vec<u64> = Vec::new();
126
127 for (pi, piece) in pieces.iter().enumerate() {
128 if !select(pi) {
129 continue;
130 }
131 for &vid in &piece.vi {
132 let pvals = match props {
133 Some(ctx) if out_prop > 0 => {
134 interpolate_props(ctx, piece, &verts[vid as usize], out_prop)
135 }
136 _ => Vec::new(),
137 };
138 let key = (vid, pvals.iter().map(|x| x.to_bits()).collect());
139 let next = vert_order.len() as u64;
140 let id = *vert_index.entry(key).or_insert_with(|| {
141 vert_order.push((vid, pvals));
142 next
143 });
144 tri_verts.push(id);
145 }
146 }
147 if tri_verts.is_empty() {
148 return Manifold::empty();
149 }
150
151 let stride = 3 + out_prop;
152 let mut mesh = MeshGL64::default();
153 mesh.num_prop = stride as u64;
154 mesh.vert_properties = Vec::with_capacity(stride * vert_order.len());
155 for (vid, pvals) in &vert_order {
156 let p = verts_f64[*vid as usize];
157 mesh.vert_properties.extend([p.x, p.y, p.z]);
158 mesh.vert_properties.extend(pvals.iter());
159 }
160 mesh.tri_verts = tri_verts;
161
162 if out_prop > 0 {
165 let mut by_pos: std::collections::HashMap<u32, u64> = std::collections::HashMap::new();
166 for (i, (vid, _)) in vert_order.iter().enumerate() {
167 match by_pos.get(vid) {
168 Some(&first) => {
169 mesh.merge_from_vert.push(i as u64);
170 mesh.merge_to_vert.push(first);
171 }
172 None => {
173 by_pos.insert(*vid, i as u64);
174 }
175 }
176 }
177 }
178
179 let out = Manifold::from_mesh_gl64_robust(&mesh);
183
184 if out.status() == crate::types::Error::NoError && !out.as_impl().is_soup && !out.is_empty() {
189 let mut imp = out.into_impl();
190 crate::edge_op::simplify_topology(&mut imp, 0);
191 imp.remove_unreferenced_verts();
192 imp.calculate_bbox();
193 imp.sort_geometry();
194 return Manifold::from_impl(imp);
195 }
196 out
197}