1#[path = "subdivision_partition.rs"]
24mod subdivision_partition;
25use subdivision_partition::{BaryIndices, Partition, lerp_vec4, next3};
26
27use crate::impl_mesh::ManifoldImpl;
28use crate::linalg::{BVec4, IVec3, IVec4, Mat3, Mat3x4, Vec3, Vec4};
29use crate::types::{next_halfedge, Barycentric, Halfedge, TmpEdge, TriRef};
30
31fn create_tmp_edges(halfedge: &[Halfedge]) -> Vec<TmpEdge> {
36 let mut edges: Vec<TmpEdge> = Vec::with_capacity(halfedge.len());
37 for (idx, half) in halfedge.iter().enumerate() {
38 if half.is_forward() {
39 edges.push(TmpEdge::new(half.start_vert, half.end_vert, idx as i32));
40 }
41 }
42 debug_assert!(
43 edges.len() == halfedge.len() / 2,
44 "Not oriented! edges={} halfedges={}",
45 edges.len(),
46 halfedge.len()
47 );
48 edges
49}
50
51impl ManifoldImpl {
56 pub fn get_neighbor(&self, tri: i32) -> i32 {
58 let mut neighbor: i32 = -1;
59 for i in 0..3 {
60 if self.is_marked_inside_quad((3 * tri + i) as usize) {
61 neighbor = if neighbor == -1 { i } else { -2 };
62 }
63 }
64 neighbor
65 }
66
67 pub fn get_halfedges_quad(&self, tri: i32) -> IVec4 {
69 let mut halfedges = IVec4::new(-1, -1, -1, -1);
70 for i in 0..3 {
71 halfedges[i] = 3 * tri + i as i32;
72 }
73 let neighbor = self.get_neighbor(tri);
74 if neighbor >= 0 {
75 let pair = self.halfedge[(3 * tri + neighbor) as usize].paired_halfedge;
77 if pair / 3 < tri {
78 return IVec4::new(-1, -1, -1, -1); }
80 halfedges[2] = next_halfedge(halfedges[neighbor as usize]);
81 halfedges[3] = next_halfedge(halfedges[2]);
82 halfedges[0] = next_halfedge(pair);
83 halfedges[1] = next_halfedge(halfedges[0]);
84 }
85 halfedges
86 }
87
88 fn get_indices(&self, halfedge: i32) -> BaryIndices {
90 let mut tri = halfedge / 3;
91 let mut idx = halfedge % 3;
92 let neighbor = self.get_neighbor(tri);
93 if idx == neighbor {
94 return BaryIndices { tri: -1, start4: -1, end4: -1 };
95 }
96
97 if neighbor < 0 {
98 BaryIndices { tri, start4: idx, end4: next3(idx) }
100 } else {
101 let pair = self.halfedge[(3 * tri + neighbor) as usize].paired_halfedge;
103 if pair / 3 < tri {
104 tri = pair / 3;
105 idx = if next3(neighbor) == idx { 0 } else { 1 };
106 } else {
107 idx = if next3(neighbor) == idx { 2 } else { 3 };
108 }
109 BaryIndices { tri, start4: idx, end4: (idx + 1) % 4 }
110 }
111 }
112
113 fn fill_retained_verts(&self, vert_bary: &mut [Barycentric]) {
115 let num_tri = self.halfedge.len() / 3;
116 for tri in 0..num_tri {
117 for i in 0..3 {
118 let indices = self.get_indices((3 * tri + i) as i32);
119 if indices.start4 < 0 {
120 continue; }
122 let mut uvw = Vec4::splat(0.0);
123 uvw[indices.start4 as usize] = 1.0;
124 vert_bary[self.halfedge[3 * tri + i].start_vert as usize] = Barycentric {
125 tri: indices.tri,
126 uvw,
127 };
128 }
129 }
130 }
131
132 pub fn subdivide(
135 &mut self,
136 edge_divisions: &dyn Fn(Vec3, Vec4, Vec4) -> i32,
137 keep_interior: bool,
138 ) -> Vec<Barycentric> {
139 let edges = create_tmp_edges(&self.halfedge);
140 let num_vert = self.num_vert();
141 let num_edge = edges.len();
142 let num_tri = self.num_tri();
143
144 let mut half2edge = vec![0i32; 2 * num_edge];
146 for (edge, tmp) in edges.iter().enumerate() {
147 let idx = tmp.halfedge_idx as usize;
148 half2edge[idx] = edge as i32;
149 half2edge[self.halfedge[idx].paired_halfedge as usize] = edge as i32;
150 }
151
152 let face_halfedges: Vec<IVec4> = (0..num_tri)
154 .map(|tri| self.get_halfedges_quad(tri as i32))
155 .collect();
156
157 let mut edge_added = vec![0i32; num_edge];
159 for i in 0..num_edge {
160 let edge = &edges[i];
161 let h_idx = edge.halfedge_idx as usize;
162 if self.is_marked_inside_quad(h_idx) {
163 edge_added[i] = 0;
164 continue;
165 }
166 let vec = self.vert_pos[edge.first as usize] - self.vert_pos[edge.second as usize];
167 let tangent0 = if self.halfedge_tangent.is_empty() {
168 Vec4::splat(0.0)
169 } else {
170 self.halfedge_tangent[h_idx]
171 };
172 let tangent1 = if self.halfedge_tangent.is_empty() {
173 Vec4::splat(0.0)
174 } else {
175 self.halfedge_tangent[self.halfedge[h_idx].paired_halfedge as usize]
176 };
177 edge_added[i] = edge_divisions(vec, tangent0, tangent1);
178 }
179
180 if keep_interior {
182 let orig_edge_added = edge_added.clone();
183 for i in 0..num_edge {
184 let edge = &edges[i];
185 let h_idx = edge.halfedge_idx as usize;
186 if self.is_marked_inside_quad(h_idx) {
187 continue;
188 }
189
190 let this_added = orig_edge_added[i];
191 let added_fn = |mut h: i32| -> i32 {
192 let mut longest = 0;
193 let mut total = 0;
194 for _ in 0..3 {
195 let added = orig_edge_added[half2edge[h as usize] as usize];
196 longest = longest.max(added);
197 total += added;
198 h = next_halfedge(h);
199 if self.is_marked_inside_quad(h as usize) {
200 longest = 0;
201 total = 1;
202 break;
203 }
204 }
205 let min_extra = (longest as f64 * 0.2) as i32 + 1;
206 let extra = 2 * longest + min_extra - total;
207 if longest == 0 {
208 return 0;
209 }
210 if extra > 0 {
211 (extra * (longest - this_added)) / longest
212 } else {
213 0
214 }
215 };
216
217 let a1 = added_fn(h_idx as i32);
218 let a2 = added_fn(self.halfedge[h_idx].paired_halfedge);
219 edge_added[i] = orig_edge_added[i] + a1.max(a2);
220 }
221 }
222
223 let mut edge_offset = vec![0i32; num_edge];
225 let mut acc = num_vert as i32;
226 for i in 0..num_edge {
227 edge_offset[i] = acc;
228 acc += edge_added[i];
229 }
230
231 let total_edge_verts = acc - num_vert as i32;
233 let mut vert_bary = vec![
234 Barycentric {
235 tri: 0,
236 uvw: Vec4::splat(0.0)
237 };
238 acc as usize
239 ];
240 self.fill_retained_verts(&mut vert_bary);
241
242 for i in 0..num_edge {
244 let n = edge_added[i];
245 let offset = edge_offset[i];
246 let indices = self.get_indices(edges[i].halfedge_idx);
247 if indices.tri < 0 {
248 continue; }
250 let frac = 1.0 / (n as f64 + 1.0);
251 for j in 0..n {
252 let mut uvw = Vec4::splat(0.0);
253 uvw[indices.end4 as usize] = (j + 1) as f64 * frac;
254 uvw[indices.start4 as usize] = 1.0 - uvw[indices.end4 as usize];
255 vert_bary[(offset + j) as usize] = Barycentric { tri: indices.tri, uvw };
256 }
257 }
258
259 let sub_tris: Vec<Partition> = (0..num_tri)
261 .map(|tri| {
262 let halfedges = face_halfedges[tri];
263 let mut divisions = IVec4::default();
264 for i in 0..4 {
265 if halfedges[i] >= 0 {
266 divisions[i] = edge_added[half2edge[halfedges[i] as usize] as usize] + 1;
267 }
268 }
269 Partition::get_partition(divisions)
270 })
271 .collect();
272
273 let mut tri_offset = vec![0i32; num_tri];
275 {
276 let mut acc = 0i32;
277 for tri in 0..num_tri {
278 tri_offset[tri] = acc;
279 acc += sub_tris[tri].tri_vert.len() as i32;
280 }
281 }
282
283 let mut interior_offset = vec![0i32; num_tri];
285 {
286 let mut acc = vert_bary.len() as i32;
287 for tri in 0..num_tri {
288 interior_offset[tri] = acc;
289 acc += sub_tris[tri].num_interior();
290 }
291 }
292
293 let total_new_tris = if num_tri > 0 {
295 tri_offset[num_tri - 1] + sub_tris[num_tri - 1].tri_vert.len() as i32
296 } else {
297 0
298 };
299 let total_new_verts = if num_tri > 0 {
300 interior_offset[num_tri - 1] + sub_tris[num_tri - 1].num_interior()
301 } else {
302 vert_bary.len() as i32
303 };
304
305 let mut tri_verts = vec![IVec3::default(); total_new_tris as usize];
306 vert_bary.resize(
307 total_new_verts as usize,
308 Barycentric { tri: 0, uvw: Vec4::splat(0.0) },
309 );
310 let mut tri_ref_out = vec![TriRef::default(); total_new_tris as usize];
311 let mut face_normal_out = vec![Vec3::splat(0.0); total_new_tris as usize];
312
313 for tri in 0..num_tri {
315 let halfedges = face_halfedges[tri];
316 if halfedges[0] < 0 {
317 continue;
318 }
319
320 let mut tri3 = IVec4::default();
321 let mut edge_offs = IVec4::default();
322 let mut edge_fwd = BVec4::splat(false);
323 for i in 0..4 {
324 if halfedges[i] < 0 {
325 tri3[i] = -1;
326 continue;
327 }
328 let he = &self.halfedge[halfedges[i] as usize];
329 tri3[i] = he.start_vert;
330 edge_offs[i] = edge_offset[half2edge[halfedges[i] as usize] as usize];
331 edge_fwd[i] = he.is_forward();
332 }
333
334 let new_tris = sub_tris[tri].reindex(
335 tri3,
336 edge_offs,
337 edge_fwd,
338 interior_offset[tri],
339 );
340
341 let start = tri_offset[tri] as usize;
342 for (j, t) in new_tris.iter().enumerate() {
343 tri_verts[start + j] = *t;
344 tri_ref_out[start + j] = self.mesh_relation.tri_ref[tri];
345 face_normal_out[start + j] = self.face_normal[tri];
346 }
347
348 let idx = sub_tris[tri].idx;
350 let v_idx = if halfedges[3] >= 0 || idx[1] == next3(idx[0]) {
351 idx
352 } else {
353 IVec4::new(idx[2], idx[0], idx[1], idx[3])
354 };
355 let mut r_idx = IVec4::default();
356 for i in 0..4 {
357 r_idx[v_idx[i] as usize] = i as i32;
358 }
359
360 let sub_bary = &sub_tris[tri].vert_bary;
361 let int_off = sub_tris[tri].interior_offset() as usize;
362 for (j, bary) in sub_bary[int_off..].iter().enumerate() {
363 vert_bary[interior_offset[tri] as usize + j] = Barycentric {
364 tri: tri as i32,
365 uvw: Vec4::new(
366 bary[r_idx[0] as usize],
367 bary[r_idx[1] as usize],
368 bary[r_idx[2] as usize],
369 bary[r_idx[3] as usize],
370 ),
371 };
372 }
373 }
374
375 self.mesh_relation.tri_ref = tri_ref_out;
376 self.face_normal = face_normal_out;
377
378 let mut new_vert_pos = vec![Vec3::splat(0.0); vert_bary.len()];
380 for (vert, bary) in vert_bary.iter().enumerate() {
381 let halfedges = face_halfedges[bary.tri as usize];
382 if halfedges[3] < 0 {
383 let tri_pos = Mat3::from_cols(
385 self.vert_pos[self.halfedge[halfedges[0] as usize].start_vert as usize],
386 self.vert_pos[self.halfedge[halfedges[1] as usize].start_vert as usize],
387 self.vert_pos[self.halfedge[halfedges[2] as usize].start_vert as usize],
388 );
389 new_vert_pos[vert] = tri_pos * bary.uvw.xyz();
390 } else {
391 let quad_pos = Mat3x4::from_cols(
393 self.vert_pos[self.halfedge[halfedges[0] as usize].start_vert as usize],
394 self.vert_pos[self.halfedge[halfedges[1] as usize].start_vert as usize],
395 self.vert_pos[self.halfedge[halfedges[2] as usize].start_vert as usize],
396 self.vert_pos[self.halfedge[halfedges[3] as usize].start_vert as usize],
397 );
398 new_vert_pos[vert] = quad_pos * bary.uvw;
399 }
400 }
401 self.vert_pos = new_vert_pos;
402
403 if self.num_prop > 0 {
405 let num_prop_vert = self.num_prop_vert();
406 let added_verts = self.num_vert() - num_vert;
407 let prop_offset = num_prop_vert as i32 - num_vert as i32;
408 let num_prop = self.num_prop as usize;
409
410 let mut prop =
412 vec![0.0f64; num_prop * (num_prop_vert + added_verts + total_edge_verts as usize)];
413
414 for (i, &v) in self.properties.iter().enumerate() {
416 prop[i] = v;
417 }
418
419 for i in 0..added_verts {
421 let vert = num_prop_vert + i;
422 let bary = &vert_bary[num_vert + i];
423 let halfedges = face_halfedges[bary.tri as usize];
424
425 for p in 0..num_prop {
426 if halfedges[3] < 0 {
427 let mut tri_prop = Vec3::splat(0.0);
429 for k in 0..3 {
430 tri_prop[k] = self.properties
431 [self.halfedge[3 * bary.tri as usize + k].prop_vert as usize
432 * num_prop
433 + p];
434 }
435 prop[vert * num_prop + p] =
436 tri_prop.x * bary.uvw.x + tri_prop.y * bary.uvw.y + tri_prop.z * bary.uvw.z;
437 } else {
438 let mut quad_prop = Vec4::splat(0.0);
440 for k in 0..4 {
441 quad_prop[k] = self.properties
442 [self.halfedge[halfedges[k] as usize].prop_vert as usize
443 * num_prop
444 + p];
445 }
446 prop[vert * num_prop + p] = quad_prop.x * bary.uvw.x
447 + quad_prop.y * bary.uvw.y
448 + quad_prop.z * bary.uvw.z
449 + quad_prop.w * bary.uvw.w;
450 }
451 }
452 }
453
454 for i in 0..num_edge {
456 let n = edge_added[i];
457 let offset = edge_offset[i] as usize + prop_offset as usize + added_verts;
458 let frac = 1.0 / (n as f64 + 1.0);
459 let halfedge_idx =
460 self.halfedge[edges[i].halfedge_idx as usize].paired_halfedge as usize;
461 let prop0 = self.halfedge[halfedge_idx].prop_vert as usize;
462 let prop1 =
463 self.halfedge[next_halfedge(halfedge_idx as i32) as usize].prop_vert as usize;
464 for j in 0..n as usize {
465 for p in 0..num_prop {
466 let t = (j + 1) as f64 * frac;
467 prop[(offset + j) * num_prop + p] = self.properties[prop0 * num_prop + p]
468 + (self.properties[prop1 * num_prop + p]
469 - self.properties[prop0 * num_prop + p])
470 * t;
471 }
472 }
473 }
474
475 let mut tri_prop_out = vec![IVec3::default(); total_new_tris as usize];
477 for tri in 0..num_tri {
478 let halfedges = face_halfedges[tri];
479 if halfedges[0] < 0 {
480 continue;
481 }
482
483 let mut tri3 = IVec4::default();
484 let mut edge_offs = IVec4::default();
485 let mut edge_fwd = BVec4::splat(true);
486 for i in 0..4 {
487 if halfedges[i] < 0 {
488 tri3[i] = -1;
489 continue;
490 }
491 let he = &self.halfedge[halfedges[i] as usize];
492 tri3[i] = he.prop_vert;
493 edge_offs[i] = edge_offset[half2edge[halfedges[i] as usize] as usize];
494 if !he.is_forward() {
495 let paired = he.paired_halfedge;
496 if self.halfedge[paired as usize].prop_vert
497 != self.halfedge[next_halfedge(halfedges[i]) as usize].prop_vert
498 || self.halfedge[next_halfedge(paired) as usize].prop_vert
499 != he.prop_vert
500 {
501 edge_offs[i] += added_verts as i32;
503 } else {
504 edge_fwd[i] = false;
505 }
506 }
507 }
508
509 let prop_edge_offs = IVec4::new(
511 edge_offs[0] + prop_offset,
512 edge_offs[1] + prop_offset,
513 edge_offs[2] + prop_offset,
514 edge_offs[3] + prop_offset,
515 );
516
517 let new_tris = sub_tris[tri].reindex(
518 tri3,
519 prop_edge_offs,
520 edge_fwd,
521 interior_offset[tri] + prop_offset,
522 );
523
524 let start = tri_offset[tri] as usize;
525 for (j, t) in new_tris.iter().enumerate() {
526 tri_prop_out[start + j] = *t;
527 }
528 }
529
530 self.properties = prop;
531 self.create_halfedges(&tri_prop_out, &tri_verts);
532 } else {
533 self.create_halfedges(&tri_verts, &[]);
534 }
535
536 vert_bary
537 }
538}
539
540pub fn subdivide_impl(mesh: &ManifoldImpl, levels: usize) -> ManifoldImpl {
543 if levels == 0 || mesh.is_empty() {
544 return mesh.clone();
545 }
546
547 let mut current = mesh.clone();
548 for _ in 0..levels {
549 current.subdivide(&|_vec, _t0, _t1| 1, false);
550 current.calculate_bbox();
551 current.set_epsilon(-1.0, false);
552 }
553
554 current
555}
556
557#[cfg(test)]
558#[path = "subdivision_tests.rs"]
559mod tests;