draco_oxide/encode/connectivity/edgebreaker.rs
1use std::{cmp, fmt};
2
3use crate::encode::entropy::symbol_coding::encode_symbols;
4use draco_oxide_core::attribute::AttributeType;
5use draco_oxide_core::bit_coder::{BitWriter, ByteWriter};
6use draco_oxide_core::buffer::LsbFirst;
7use draco_oxide_core::codec::connectivity::edgebreaker::symbol_encoder::{
8 CrLight, Symbol, SymbolEncoder,
9};
10use draco_oxide_core::codec::entropy::rans::{self, RabsCoder};
11use draco_oxide_core::debug_write;
12use draco_oxide_core::mesh::ds::CornerTable;
13use draco_oxide_core::mesh::ds::GenericCornerTable;
14use draco_oxide_core::mesh::ds::{AttributeDS, DS};
15
16use draco_oxide_core::types::{
17 ConfigType, CornerIdx, FaceIdx, VecFaceIdx, VecVertexIdx, VertexIdx,
18};
19
20use draco_oxide_core::codec::connectivity::edgebreaker::{
21 self, EdgebreakerKind, Orientation, TopologySplit, MAX_VALENCE, MIN_VALENCE,
22};
23use draco_oxide_core::codec::entropy::SymbolEncodingMethod;
24use draco_oxide_core::utils::bit_coder::leb128_write;
25use std::collections::BTreeMap;
26use std::vec;
27
28use crate::encode::connectivity::ConnectivityEncoder;
29
30#[cfg(feature = "evaluation")]
31use crate::eval;
32
33pub(crate) struct Edgebreaker<'ads, 'faces, T>
34where
35 T: Traversal,
36{
37 /// The 'i'th entry of 'visited_vertices' is true if the Edgebreaker has
38 /// already visited the 'i' th vertex.
39 visited_vertices: VecVertexIdx<bool>,
40
41 /// The 'i'th entry of 'visited_edges' is true if the Edgebreaker has
42 /// already visited the 'i' th face.
43 visited_faces: VecFaceIdx<bool>,
44
45 /// The visited holes. i th entry of this array records whether the i th hole is visited or not.
46 visited_holes: Vec<bool>,
47
48 // A map from vertices to the hole id if the vertex is on a hole or void if the vertex is not on a hole.
49 vertex_hole_id: VecVertexIdx<Option<usize>>,
50
51 corner_traversal_stack: Vec<CornerIdx>,
52
53 last_encoded_symbol_idx: usize,
54
55 processed_connectivity_corners: Vec<CornerIdx>,
56
57 face_to_split_symbol_map: BTreeMap<usize, usize>,
58
59 num_split_symbols: usize,
60
61 vertex_traversal_length: Vec<usize>,
62
63 init_face_connectivity_corners: Vec<CornerIdx>,
64
65 traversal: T,
66
67 /// Records the topology splits detected during the edgebreaker encoding.
68 topology_splits: Vec<TopologySplit>,
69
70 adss: &'ads [AttributeDS<'faces>],
71
72 pos_corner_table: &'ads CornerTable,
73
74 posds: &'ads AttributeDS<'faces>,
75
76 gds: &'ads DS,
77
78 /// configurations for the encoder
79 #[allow(unused)]
80 // TODO: This field is not used yet, as we only support the default configuration.
81 config: Config,
82}
83
84#[derive(Clone, fmt::Debug, cmp::PartialEq)]
85pub struct Config {
86 pub traversal: EdgebreakerKind,
87 pub use_single_connectivity: bool,
88}
89
90impl ConfigType for Config {
91 fn default() -> Self {
92 Self {
93 traversal: EdgebreakerKind::Standard,
94 use_single_connectivity: false,
95 }
96 }
97}
98
99#[derive(Debug, PartialEq)]
100#[remain::sorted]
101#[derive(thiserror::Error)]
102pub enum Err {
103 #[error("Edgebreaker error: {0}")]
104 EdgebreakerError(#[from] edgebreaker::Err),
105 #[error("The input mesh has an empty AttributeDS array.")]
106 EmptyAttributeDSArray,
107 #[error("Entropy encoding error: {0}")]
108 EntropyEncodingError(#[from] crate::encode::entropy::symbol_coding::Err),
109 #[error("Too many handles.")]
110 HandleSizeTooLarge,
111 #[error("Too many holes.")]
112 HoleSizeTooLarge,
113 #[error("The input mesh is non-orientable.")]
114 NonOrientable,
115 #[error("Rabs coder error: {0}")]
116 RabsCoderError(#[from] rans::Err),
117 #[error("The input mesh has too many connected components: {0}")]
118 TooManyConnectedComponents(usize),
119}
120
121impl<'ads, 'faces, T> Edgebreaker<'ads, 'faces, T>
122where
123 T: Traversal,
124{
125 // Build the object with empty arrays.
126 pub fn new(
127 config: Config,
128 adss: &'ads [AttributeDS<'faces>],
129 make_traversal: impl FnOnce(&'ads AttributeDS<'faces>) -> T,
130 ) -> Result<Self, Err> {
131 let pos_ads = adss
132 .iter()
133 .find(|ads| ads.att_data().get_attribute_type() == AttributeType::Position)
134 .ok_or(Err::EmptyAttributeDSArray)?;
135 let gds = pos_ads.global_ds();
136 let traversal = make_traversal(pos_ads);
137
138 let out = Self {
139 visited_vertices: VecVertexIdx::from(vec![false; pos_ads.num_vertices()]),
140 visited_faces: VecFaceIdx::from(vec![false; gds.num_faces()]),
141 visited_holes: Vec::new(),
142 pos_corner_table: pos_ads.corner_table().pos_corner_table(),
143 posds: pos_ads,
144 vertex_hole_id: VecVertexIdx::new(),
145 corner_traversal_stack: Vec::new(),
146 last_encoded_symbol_idx: usize::MAX,
147 processed_connectivity_corners: Vec::new(),
148 face_to_split_symbol_map: BTreeMap::new(),
149 num_split_symbols: 0,
150 vertex_traversal_length: Vec::new(),
151 init_face_connectivity_corners: Vec::new(),
152 traversal,
153 topology_splits: Vec::new(),
154 gds,
155 adss,
156 config,
157 };
158 Ok(out)
159 }
160
161 fn compute_boundaries(&mut self) -> Result<(), Err> {
162 self.vertex_hole_id = VecVertexIdx::from(vec![None; self.posds.num_vertices()]);
163 for c in 0..self.gds.num_corners() {
164 let c = CornerIdx::from(c);
165 if self.pos_corner_table.opposite(c).is_none() {
166 // 'c' is on a boundary.
167 let mut v = self.posds.vertex_idx(c.next());
168 if self.vertex_hole_id[v].is_some() {
169 // The hole is already processed.
170 continue;
171 }
172 // Now we have found a new boundary containing the vertex 'v'.
173 let boundary_idx = self.visited_holes.len();
174 self.visited_holes.push(false);
175
176 let mut c = c;
177 while self.vertex_hole_id[v].is_none() {
178 self.vertex_hole_id[v] = Some(boundary_idx);
179 c = c.next();
180
181 while self.pos_corner_table.opposite(c).is_some() {
182 c = c.next();
183 }
184 // Id of the next vertex in the vertex on the hole.
185 v = self.posds.vertex_idx(c.next());
186 }
187 }
188 }
189 Ok(())
190 }
191
192 fn process_boundary(&mut self, start_corner: CornerIdx, encode_first_vertex: bool) -> usize {
193 let mut corner = start_corner.previous();
194 let mut opp = self.pos_corner_table.opposite(corner);
195 while opp.is_some() {
196 corner = opp.next();
197 opp = self.pos_corner_table.opposite(corner);
198 } // 'corner' now faces the hole
199
200 let start_v = self.posds.vertex_idx(start_corner);
201
202 let mut num_encoded_hole_verts = 0;
203 if encode_first_vertex {
204 self.visited_vertices[start_v] = true;
205 num_encoded_hole_verts += 1;
206 }
207
208 self.visited_holes[self.vertex_hole_id[start_v].unwrap()] = true; // it is safe to unwrap here as start_v is on a hole.
209 let mut curr_v = self.posds.vertex_idx(corner.previous());
210 while curr_v != start_v {
211 self.visited_vertices[curr_v] = true;
212 num_encoded_hole_verts += 1;
213 corner = corner.next();
214 let mut opp = self.pos_corner_table.opposite(corner);
215 while opp.is_some() {
216 corner = opp.next();
217 opp = self.pos_corner_table.opposite(corner);
218 }
219 curr_v = self.posds.vertex_idx(corner.previous());
220 }
221 num_encoded_hole_verts
222 }
223
224 /// A function implementing the Edgebreaker algorithm for a connected component that contains `c`.
225 fn edgebreaker_from(&mut self, mut c: CornerIdx) -> Result<(), Err> {
226 self.corner_traversal_stack.clear();
227 self.corner_traversal_stack.push(c);
228 let num_faces = self.gds.num_faces();
229 while let Some(&start) = self.corner_traversal_stack.last() {
230 c = start;
231 // Make sure the face hasn't been visited yet.
232 if self.visited_faces[c.face_idx()] {
233 self.corner_traversal_stack.pop();
234 continue;
235 }
236
237 let mut num_visited_faces = 0;
238 while num_visited_faces < num_faces {
239 num_visited_faces += 1;
240 self.last_encoded_symbol_idx = self.last_encoded_symbol_idx.wrapping_add(1); // since the initial value of 'last_encoded_symbol_idx' is usize::MAX, we do wrapping-add.
241
242 let face_idx = c.face_idx();
243 self.visited_faces[face_idx] = true;
244 self.processed_connectivity_corners.push(c);
245 self.traversal.new_corner_reached(c);
246 let v = self.posds.vertex_idx(c);
247 if !self.visited_vertices[v] {
248 self.visited_vertices[v] = true;
249 if self.vertex_hole_id[v].is_none() {
250 self.traversal.record_symbol(
251 Symbol::C,
252 &self.visited_faces,
253 self.pos_corner_table,
254 );
255 c = self.posds.corner_table().get_right_corner(c).unwrap(); // unwrap is safe here; we checked that the right edge is not on a boundary, and this implies that the right face exists.
256 continue;
257 }
258 }
259 let maybe_right_c = self.posds.corner_table().get_right_corner(c);
260 let maybe_left_c = self.posds.corner_table().get_left_corner(c);
261 let maybe_right_face = maybe_right_c.map(|c| c.face_idx());
262 let maybe_left_face = maybe_left_c.map(|c| c.face_idx());
263 if self.is_right_face_visited(c) {
264 if let Some(right_face) = maybe_right_face {
265 self.check_and_store_topology_split_event(
266 self.last_encoded_symbol_idx,
267 Orientation::Right,
268 right_face,
269 );
270 }
271 if self.is_left_face_visited(c) {
272 // 'E' symbol
273 if let Some(left_face) = maybe_left_face {
274 self.check_and_store_topology_split_event(
275 self.last_encoded_symbol_idx,
276 Orientation::Left,
277 left_face,
278 );
279 }
280 self.traversal.record_symbol(
281 Symbol::E,
282 &self.visited_faces,
283 self.pos_corner_table,
284 );
285 self.corner_traversal_stack.pop();
286 // End of a branch of the traversal.
287 break;
288 } else {
289 // 'R' symbol
290 self.traversal.record_symbol(
291 Symbol::R,
292 &self.visited_faces,
293 self.pos_corner_table,
294 );
295 c = maybe_left_c.unwrap(); // unwrap is safe here; we checked that the left face is not visited, which implies that the left face exist.
296 }
297 } else if self.is_left_face_visited(c) {
298 // 'L' symbol
299 if let Some(left_face) = maybe_left_face {
300 self.check_and_store_topology_split_event(
301 self.last_encoded_symbol_idx,
302 Orientation::Left,
303 left_face,
304 );
305 }
306 self.traversal.record_symbol(
307 Symbol::L,
308 &self.visited_faces,
309 self.pos_corner_table,
310 );
311 c = maybe_right_c.unwrap(); // unwrap is safe here; we checked that the right face is not visited, which implies that the right face exist.
312 } else {
313 self.traversal.record_symbol(
314 Symbol::S,
315 &self.visited_faces,
316 self.pos_corner_table,
317 );
318 self.num_split_symbols += 1;
319 if let Some(hole_idx) = self.vertex_hole_id[v] {
320 if !self.visited_holes[hole_idx] {
321 self.process_boundary(c, false);
322 }
323 }
324 self.face_to_split_symbol_map
325 .insert(usize::from(face_idx), self.last_encoded_symbol_idx);
326 *self.corner_traversal_stack.last_mut().unwrap() = maybe_left_c.unwrap();
327 self.corner_traversal_stack.push(maybe_right_c.unwrap());
328 break;
329 }
330 }
331 }
332 Ok(())
333 }
334
335 /// Checks whether the right face of the corner 'c' is visited.
336 /// If the corner is on a boundary and if the right face does not exist,
337 /// then it returns true by convention.
338 fn is_right_face_visited(&self, c: CornerIdx) -> bool {
339 if let Some(c_r) = self.posds.corner_table().get_right_corner(c) {
340 self.visited_faces[c_r.face_idx()]
341 } else {
342 true
343 }
344 }
345
346 /// Checks whether the left face of the corner 'c' is visited.
347 /// If the corner is on a boundary and if the left face does not exist,
348 /// then it returns true by convention.
349 fn is_left_face_visited(&self, c: CornerIdx) -> bool {
350 if let Some(c_l) = self.pos_corner_table.get_left_corner(c) {
351 self.visited_faces[c_l.face_idx()]
352 } else {
353 true
354 }
355 }
356
357 fn encode_topology_splits<W>(&mut self, writer: &mut W) -> Result<(), Err>
358 where
359 W: ByteWriter,
360 {
361 #[cfg(feature = "evaluation")]
362 {
363 let mut string = String::new();
364 for split in self.topology_splits.iter() {
365 string.push_str(&format!(
366 "{}:{}({:?}) ",
367 split.merging_symbol_idx,
368 split.split_symbol_idx,
369 split.merging_edge_orientation
370 ));
371 }
372 eval::write_json_pair("topology_splits", serde_json::Value::from(string), writer);
373 }
374 let mut last_idx = 0;
375 // write the number of topology splits.
376 leb128_write(self.topology_splits.len() as u64, writer);
377 for split in self.topology_splits.iter() {
378 leb128_write((split.merging_symbol_idx - last_idx) as u64, writer);
379 leb128_write(
380 (split.merging_symbol_idx - split.split_symbol_idx) as u64,
381 writer,
382 );
383 last_idx = split.merging_symbol_idx;
384 }
385 let mut bit_coder: BitWriter<'_, W, LsbFirst> = BitWriter::spown_from(writer);
386 for split in self.topology_splits.iter() {
387 let orientation = match split.merging_edge_orientation {
388 Orientation::Left => (1, 0),
389 Orientation::Right => (1, 1),
390 };
391 bit_coder.write_bits(orientation);
392 }
393 Ok(())
394 }
395
396 /// Begins the Edgebreaker iteration from the given face.
397 /// The first boolean indicates whether the face is interior (i.e. the face does not touch a boundary) or not.
398 /// The second 'usize' element is a corner chosen as follows:
399 /// It chooses the first corner of the face as the starting point is such a way that corner faces the the boundary
400 /// if the face is on the boundary.
401 /// If the face is not on the boundary, then it returns the input corner.
402 fn begin_from(&mut self, face_idx: FaceIdx) -> (bool, CornerIdx) {
403 let mut corner_index = CornerIdx::from(3 * usize::from(face_idx));
404 for _ in 0..3 {
405 if self.pos_corner_table.opposite(corner_index).is_none() {
406 // corner faces a boundary
407 return (false, corner_index);
408 }
409 if self.vertex_hole_id[self.posds.vertex_idx(corner_index)].is_some() {
410 // The corner is on a boundary.
411 let mut maybe_right_corner = corner_index;
412 while maybe_right_corner.is_some() {
413 corner_index = maybe_right_corner;
414 maybe_right_corner = self.posds.corner_table().swing_right(maybe_right_corner);
415 }
416 let start_corner = corner_index.previous();
417 return (false, start_corner);
418 }
419 corner_index = corner_index.next();
420 }
421 (true, corner_index)
422 }
423
424 fn check_and_store_topology_split_event(
425 &mut self,
426 merging_symbol_idx: usize,
427 merging_edge_orientation: Orientation,
428 split_face_idx: FaceIdx,
429 ) {
430 let split_symbol_idx = if let Some(&idx) = self
431 .face_to_split_symbol_map
432 .get(&usize::from(split_face_idx))
433 {
434 idx
435 } else {
436 // The face is not split, so we do not need to store the split event.
437 return;
438 };
439 let split = TopologySplit {
440 merging_symbol_idx,
441 split_symbol_idx,
442 merging_edge_orientation,
443 };
444
445 self.topology_splits.push(split);
446 }
447}
448
449impl<'ads, 'faces, T> ConnectivityEncoder for Edgebreaker<'ads, 'faces, T>
450where
451 T: Traversal,
452{
453 type Config = Config;
454 type Err = Err;
455 /// The main encoding paradigm for Edgebreaker.
456 ///
457 /// Returns the corners of the edgebreaker traversal (`corners_of_edgebreaker`), i.e. the
458 /// last-encoded corner of each connected component in encoded order. This ordering seeds the
459 /// per-attribute sequencing (`Traverser`) during attribute encoding, so it must be surfaced
460 /// back to the caller.
461 fn encode_connectivity<W>(mut self, writer: &mut W) -> Result<Vec<CornerIdx>, Self::Err>
462 where
463 W: ByteWriter,
464 {
465 debug_write!("Init Decoder", writer);
466 // encode the traversal decoder type
467 EdgebreakerKind::Standard.write_to(writer);
468 debug_write!("Init Decoder Done", writer);
469
470 self.compute_boundaries()?;
471
472 leb128_write(self.posds.num_vertices() as u64, writer);
473 leb128_write(self.gds.num_faces() as u64, writer);
474
475 writer.write_u8((self.adss.len() - 1) as u8);
476
477 // Run Edgebreaker once for each connected component.
478 for c in 0..self.gds.num_corners() {
479 let c = CornerIdx::from(c);
480 let face_idx = c.face_idx();
481 if self.visited_faces[face_idx] {
482 // if the face is already visited, then skip it.
483 continue;
484 }
485
486 let (is_start_face_interior, start_corner) = self.begin_from(face_idx);
487
488 self.traversal
489 .record_start_face_config(is_start_face_interior);
490
491 if is_start_face_interior {
492 let corner_index = start_corner;
493 let v = self.posds.vertex_idx(corner_index);
494 let n = self.posds.vertex_idx(corner_index.next());
495 let p = self.posds.vertex_idx(corner_index.previous());
496 self.visited_vertices[v] = true;
497 self.visited_vertices[n] = true;
498 self.visited_vertices[p] = true;
499
500 self.vertex_traversal_length.push(1);
501
502 self.visited_faces[face_idx] = true;
503
504 self.init_face_connectivity_corners
505 .push(corner_index.next());
506 let corner_opp = self.pos_corner_table.opposite(corner_index.next());
507 self.edgebreaker_from(corner_opp)?;
508 } else {
509 // if the face is on the boundary, then we start from the boundary.
510 self.process_boundary(start_corner.next(), true);
511 self.edgebreaker_from(start_corner)?;
512 }
513 }
514
515 // write the number of symbols.
516 leb128_write(self.traversal.num_symbols() as u64, writer);
517
518 // write the number of encoded split symbols.
519 leb128_write(self.num_split_symbols as u64, writer);
520
521 self.encode_topology_splits(writer)?;
522 // encode the edgebreaker symbols.
523 self.traversal
524 .encode(writer, self.adss, self.pos_corner_table, self.gds)?;
525
526 self.init_face_connectivity_corners.reverse();
527 self.init_face_connectivity_corners
528 .append(&mut self.processed_connectivity_corners);
529
530 Ok(self.init_face_connectivity_corners)
531 }
532}
533
534pub(crate) trait Traversal {
535 fn record_symbol(
536 &mut self,
537 symbol: Symbol,
538 visited_faces: &VecFaceIdx<bool>,
539 corner_table: &CornerTable,
540 );
541 fn record_start_face_config(&mut self, interior_cfg: bool);
542 fn new_corner_reached(&mut self, corner: CornerIdx);
543 fn num_symbols(&self) -> usize;
544 fn encode<W>(
545 self,
546 writer: &mut W,
547 att_data: &[AttributeDS<'_>],
548 corner_table: &CornerTable,
549 gds: &DS,
550 ) -> Result<(), Err>
551 where
552 W: ByteWriter;
553}
554
555pub(crate) struct DefaultTraversal {
556 symbols: Vec<Symbol>,
557 interior_cfg: Vec<bool>,
558 processed_connectivity_corners: Vec<CornerIdx>,
559}
560
561impl DefaultTraversal {
562 pub(crate) fn new() -> Self {
563 Self {
564 symbols: Vec::new(),
565 interior_cfg: Vec::new(),
566 processed_connectivity_corners: Vec::new(),
567 }
568 }
569}
570
571impl Traversal for DefaultTraversal {
572 fn record_symbol(
573 &mut self,
574 symbol: Symbol,
575 _visited_faces: &VecFaceIdx<bool>,
576 _corner_table: &CornerTable,
577 ) {
578 self.symbols.push(symbol);
579 }
580
581 fn new_corner_reached(&mut self, corner: CornerIdx) {
582 self.processed_connectivity_corners.push(corner);
583 }
584
585 fn record_start_face_config(&mut self, interior_cfg: bool) {
586 self.interior_cfg.push(interior_cfg);
587 }
588
589 fn num_symbols(&self) -> usize {
590 self.symbols.len()
591 }
592
593 fn encode<W>(
594 self,
595 final_writer: &mut W,
596 att_data: &[AttributeDS<'_>],
597 pos_corner_table: &CornerTable,
598 gds: &DS,
599 ) -> Result<(), Err>
600 where
601 W: ByteWriter,
602 {
603 let mut writer = Vec::new();
604 {
605 let mut writer: BitWriter<'_, Vec<u8>, LsbFirst> = BitWriter::spown_from(&mut writer);
606 for s in self.symbols.into_iter().rev() {
607 writer.write_bits(CrLight::encode_symbol(s));
608 }
609 }
610
611 // encode the size
612 leb128_write(writer.len() as u64, final_writer);
613 // write the encoded symbols.
614 for byte in writer {
615 final_writer.write_u8(byte);
616 }
617
618 // encode the start face configurations.
619 let freq_count_0 = self.interior_cfg.iter().filter(|&&cfg| !cfg).count();
620 // the probability of zero in [0,1] is scaled to [0,256], and clamped to [1,255] as the rans does not accept the zero probability.
621 let zero_prob = (((freq_count_0 as f32 / self.interior_cfg.len() as f32) * 256.0 + 0.5)
622 as u16)
623 .clamp(1, 255) as u8;
624 final_writer.write_u8(zero_prob);
625 {
626 let mut writer: RabsCoder = RabsCoder::new(zero_prob as usize, None);
627 for &cfg in self.interior_cfg.iter().rev() {
628 writer.write(if cfg { 1 } else { 0 })?;
629 }
630 let buffer = writer.flush()?;
631 leb128_write(buffer.len() as u64, final_writer);
632 for byte in buffer {
633 final_writer.write_u8(byte);
634 }
635 }
636
637 // compute the attribute seams
638 //
639 // Seams are encoded per non-position attribute only: the position
640 // attribute defines the base connectivity and carries no seams. This
641 // must match the `adss.len() - 1` attribute count written in
642 // `encode_connectivity`; including the position attribute here would
643 // emit one extra seam stream and desync the decoder.
644 let seam_atts = att_data
645 .iter()
646 .filter(|ads| ads.att_data().get_attribute_type() != AttributeType::Position)
647 .collect::<Vec<_>>();
648 let mut visited_faces = vec![false; gds.num_faces()];
649 let mut seams_data = (0..seam_atts.len())
650 .map(|_| Vec::with_capacity(gds.num_corners() >> 1))
651 .collect::<Vec<_>>();
652 for c in self.processed_connectivity_corners.into_iter().rev() {
653 let corners = [c, c.next(), c.previous()];
654 let f_idx = c.face_idx();
655 visited_faces[usize::from(f_idx)] = true;
656 for corner in &corners {
657 let opp_corner = pos_corner_table.opposite(*corner);
658 if opp_corner.is_some() {
659 let opp_face = opp_corner.face_idx();
660 if visited_faces[usize::from(opp_face)] {
661 // if the opposite face is already visited, then we do not need to record the attribute seam.
662 continue;
663 }
664 } else {
665 // if the edge opposite to the corner is on a boundary, then we do not need to record the attribute seam.
666 continue;
667 }
668
669 for (j, ads) in seam_atts.iter().enumerate() {
670 // store true if the corner is on an attribute seam, false otherwise.
671 seams_data[j].push(ads.corner_table().opposite(*corner).is_none());
672 }
673 }
674 }
675 // encode the attribute seams.
676 for seams_data in seams_data {
677 let freq_count_0 = seams_data.iter().filter(|&&s| !s).count();
678 let prob_zero = (((freq_count_0 as f32 / seams_data.len() as f32) * 256.0 + 0.5) as u16)
679 .clamp(1, 255) as u8;
680 final_writer.write_u8(prob_zero);
681 {
682 let mut writer: RabsCoder = RabsCoder::new(prob_zero as usize, None);
683 for &s in seams_data.iter().rev() {
684 writer.write(if s { 1 } else { 0 })?;
685 }
686 let buffer = writer.flush()?;
687 leb128_write(buffer.len() as u64, final_writer);
688 for byte in buffer {
689 final_writer.write_u8(byte);
690 }
691 }
692 }
693
694 Ok(())
695 }
696}
697
698pub(crate) struct ValenceTraversal<'pos_ds> {
699 vertex_valences: VecVertexIdx<usize>,
700 pos_ds: &'pos_ds AttributeDS<'pos_ds>,
701 diff_corner_to_vertex_map: BTreeMap<CornerIdx, VertexIdx>,
702 context_symbols: Vec<Vec<Symbol>>,
703 last_corner: CornerIdx,
704 prev_symbol: Option<Symbol>,
705 interior_cfg: Vec<bool>,
706 num_symbols: usize,
707}
708impl<'pos_ds> ValenceTraversal<'pos_ds> {
709 fn vertex_idx(&self, corner: CornerIdx) -> VertexIdx {
710 if let Some(&vertex) = self.diff_corner_to_vertex_map.get(&corner) {
711 vertex
712 } else {
713 self.pos_ds.vertex_idx(corner)
714 }
715 }
716
717 pub(crate) fn new(pos_ds: &'pos_ds AttributeDS) -> Self {
718 let mut vertex_valences: VecVertexIdx<usize> =
719 Vec::with_capacity(pos_ds.num_vertices()).into();
720 for i in 0..pos_ds.num_vertices() {
721 let v = VertexIdx::from(i);
722 vertex_valences.push(pos_ds.vertex_valence(v));
723 }
724
725 let num_unique_valences = MAX_VALENCE - MIN_VALENCE + 1;
726
727 let context_symbols = vec![Vec::new(); num_unique_valences];
728 Self {
729 vertex_valences,
730 pos_ds,
731 diff_corner_to_vertex_map: BTreeMap::new(),
732 context_symbols,
733 last_corner: CornerIdx::from(usize::MAX), // This will be set to a valid corner index in `new_corner_reached` before the first call to record symbol.
734 prev_symbol: None,
735 interior_cfg: Vec::new(),
736 num_symbols: 0,
737 }
738 }
739}
740
741impl<'pos_ds> Traversal for ValenceTraversal<'pos_ds> {
742 fn record_symbol(
743 &mut self,
744 symbol: Symbol,
745 visited_faces: &VecFaceIdx<bool>,
746 corner_table: &CornerTable,
747 ) {
748 self.num_symbols += 1;
749
750 let next = self.last_corner.next();
751 let prev = self.last_corner.previous();
752
753 let v_last = self.vertex_idx(self.last_corner);
754 let v_next = self.vertex_idx(next);
755 let v_prev = self.vertex_idx(prev);
756
757 let active_valence = self.vertex_valences[v_next];
758 match symbol {
759 Symbol::C => {}
760 Symbol::S => {
761 self.vertex_valences[v_next] -= 1;
762 self.vertex_valences[v_prev] -= 1;
763
764 let mut num_left_faces = 0;
765 let mut maybe_act_c = corner_table.opposite(prev);
766 while maybe_act_c.is_some() {
767 let act_c = maybe_act_c;
768 if visited_faces[act_c.face_idx()] {
769 break;
770 }
771 num_left_faces += 1;
772 maybe_act_c = corner_table.opposite(act_c.next());
773 }
774 self.vertex_valences[v_last] = num_left_faces + 1;
775
776 let new_vertex = self.vertex_valences.len();
777 let mut num_right_faces = 0;
778
779 maybe_act_c = corner_table.opposite(next);
780 while maybe_act_c.is_some() {
781 let act_c = maybe_act_c;
782 if visited_faces[act_c.face_idx()] {
783 break;
784 }
785 num_right_faces += 1;
786 self.diff_corner_to_vertex_map
787 .insert(act_c.next(), new_vertex.into());
788 maybe_act_c = corner_table.opposite(act_c.previous());
789 }
790 self.vertex_valences.push(num_right_faces + 1);
791 }
792 Symbol::R => {
793 // Update valences.
794 self.vertex_valences[v_last] -= 1;
795 self.vertex_valences[v_next] -= 1;
796 self.vertex_valences[v_prev] -= 2;
797 }
798 Symbol::L => {
799 self.vertex_valences[v_last] -= 1;
800 self.vertex_valences[v_next] -= 2;
801 self.vertex_valences[v_prev] -= 1;
802 }
803 Symbol::E => {
804 self.vertex_valences[v_last] -= 2;
805 self.vertex_valences[v_next] -= 2;
806 self.vertex_valences[v_prev] -= 2;
807 }
808 }
809
810 if let Some(prev_symbol) = self.prev_symbol {
811 let clamped_valence = active_valence.clamp(MIN_VALENCE, MAX_VALENCE);
812
813 let context = clamped_valence - MIN_VALENCE;
814 self.context_symbols[context].push(prev_symbol);
815 }
816
817 self.prev_symbol = Some(symbol);
818 }
819
820 fn record_start_face_config(&mut self, interior_cfg: bool) {
821 self.interior_cfg.push(interior_cfg);
822 }
823
824 fn new_corner_reached(&mut self, c: CornerIdx) {
825 self.last_corner = c;
826 }
827
828 fn num_symbols(&self) -> usize {
829 self.num_symbols
830 }
831
832 fn encode<W>(
833 self,
834 writer: &mut W,
835 _: &[AttributeDS<'_>],
836 _: &CornerTable,
837 _: &DS,
838 ) -> Result<(), Err>
839 where
840 W: ByteWriter,
841 {
842 // self.encode_start_faces();
843 // self.encode_attribute_seams();
844
845 // Store the contexts.
846 for context in self.context_symbols {
847 leb128_write(context.len() as u64, writer);
848 let context = context
849 .iter()
850 .map(|&s| s.get_id() as u64)
851 .collect::<Vec<_>>();
852
853 encode_symbols(context, 1, SymbolEncodingMethod::DirectCoded, writer)?;
854 }
855
856 Ok(())
857 }
858}
859
860// // #[cfg(not(feature = "evaluation"))]
861// #[cfg(test)]
862// mod tests {
863// use std::vec;
864
865// use draco_oxide_core::attribute::AttributeId;
866// use draco_oxide_core::types::Vector;
867// use draco_oxide_core::types::NdVector;
868// use crate::debug_expect;
869// use crate::prelude::{BitReader, ByteReader};
870// use draco_oxide_core::codec::connectivity::eq;
871// use draco_oxide_core::utils::bit_coder::leb128_read;
872
873// use super::*;
874
875// // #[test]
876// #[allow(unused)]
877// fn test_decompose_into_manifolds_simple() {
878// let mut faces = vec![
879// [0, 1, 6], // 0
880// [1, 6, 7], // 1
881// [2, 3, 6], // 2
882// [3, 6, 7], // 3
883// [4, 5, 6], // 4
884// [5, 6, 7], // 5
885// ];
886// let mut edgebreaker = Edgebreaker::new(Config::default());
887
888// let points = vec![NdVector::<3,f32>::zero(); 8];
889// let mut point_att = Attribute::from(
890// AttributeId::new(0),
891// points,
892// AttributeType::Position,
893// Vec::new()
894// );
895
896// assert!(edgebreaker.init(&mut [&mut point_att], &mut faces).is_ok());
897
898// let coboundary_map = edgebreaker.coboundary_map_one;
899
900// let idx_of = |edge: &[usize; 2]| edgebreaker.edges.binary_search(edge).unwrap();
901// assert_eq!(coboundary_map[idx_of(&[0,1])], vec![0]);
902// assert_eq!(coboundary_map[idx_of(&[0,6])], vec![0]);
903// assert_eq!(coboundary_map[idx_of(&[1,6])], vec![0, 1]);
904// assert_eq!(coboundary_map[idx_of(&[1,7])], vec![1]);
905// assert_eq!(coboundary_map[idx_of(&[6,7])], vec![1,3,5]);
906// assert_eq!(coboundary_map[idx_of(&[2,3])], vec![2]);
907// assert_eq!(coboundary_map[idx_of(&[2,6])], vec![2]);
908// assert_eq!(coboundary_map[idx_of(&[3,6])], vec![2,3]);
909// assert_eq!(coboundary_map[idx_of(&[3,7])], vec![3]);
910// assert_eq!(coboundary_map[idx_of(&[4,5])], vec![4]);
911// assert_eq!(coboundary_map[idx_of(&[4,6])], vec![4]);
912// assert_eq!(coboundary_map[idx_of(&[5,6])], vec![4,5]);
913// assert_eq!(coboundary_map[idx_of(&[5,7])], vec![5]);
914
915// }
916
917// // #[test]
918// #[allow(unused)]
919// fn test_compute_edges() {
920// let faces = vec![
921// [0, 1, 6], // 0
922// [1, 6, 7], // 1
923// [2, 3, 6], // 2
924// [3, 6, 7], // 3
925// [4, 5, 6], // 4
926// [5, 6, 7], // 5
927// ];
928// let mut edgebreaker = Edgebreaker::new(Config::default());
929// edgebreaker.lies_on_boundary_or_cutting_path = vec![false; 8];
930
931// edgebreaker.compute_edges(&faces);
932
933// assert_eq!( edgebreaker.edges,
934// vec![
935// [0, 1],
936// [0, 6],
937// [1, 6],
938// [1, 7],
939// [2, 3],
940// [2, 6],
941// [3, 6],
942// [3, 7],
943// [4, 5],
944// [4, 6],
945// [5, 6],
946// [5, 7],
947// [6, 7],
948// ]
949// );
950
951// assert_eq!( edgebreaker.coboundary_map_one,
952// vec![
953// vec![0],
954// vec![0],
955// vec![0,1],
956// vec![1],
957// vec![2],
958// vec![2],
959// vec![2,3],
960// vec![3],
961// vec![4],
962// vec![4],
963// vec![4,5],
964// vec![5],
965// vec![1,3,5],
966// ]
967// )
968// }
969
970// #[test]
971// fn test_check_orientability() {
972// // test1: orientable mesh
973// let faces = vec![
974// [0,1,4],
975// [0,3,4],
976// [1,2,5],
977// [1,4,5],
978// [2,5,6],
979// [3,4,7],
980// [3,7,10],
981// [4,5,7],
982// [5,6,8],
983// [5,7,8],
984// [7,8,9],
985// [7,9,10],
986// [8,9,11],
987// [9,10,11]
988// ];
989// let mut edgebreaker = Edgebreaker::new(Config::default());
990// edgebreaker.lies_on_boundary_or_cutting_path = vec![false; 12];
991// edgebreaker.face_orientation = vec!(false; faces.len());
992// edgebreaker.visited_faces = vec!(false; faces.len());
993// edgebreaker.compute_edges(&faces);
994// assert!(edgebreaker.check_orientability(&faces).is_ok());
995// assert_eq!(edgebreaker.face_orientation, vec![true, false, true, false, false, true, true, true, true, false, true, true, false, false]);
996
997// // test 2: non-orientable mesh
998// let faces = vec![
999// [0, 1, 3],
1000// [0, 1, 4],
1001// [0, 2, 3],
1002// [0, 4, 5],
1003// [2, 3, 5],
1004// [2, 4, 5],
1005// ];
1006// let mut edgebreaker = Edgebreaker::new(Config::default());
1007// edgebreaker.lies_on_boundary_or_cutting_path = vec![false; 6];
1008
1009// edgebreaker.face_orientation = vec!(false; faces.len());
1010// edgebreaker.visited_faces = vec!(false; faces.len());
1011// edgebreaker.compute_edges(&faces);
1012// assert!(edgebreaker.check_orientability(&faces).is_err());
1013
1014// let faces = [
1015// [9,12,13], [8,9,13], [8,9,10], [1,8,10], [1,10,11], [1,2,11], [2,11,12], [2,12,13],
1016// [8,13,14], [7,8,14], [1,7,8], [0,1,7], [0,1,2], [0,2,3], [2,3,13], [3,13,14],
1017// [7,14,15], [6,7,15], [0,6,7], [0,5,6], [0,3,5], [3,4,5], [3,4,14], [4,14,15],
1018// [6,12,15], [6,9,12], [5,6,9], [5,9,10], [4,5,10], [4,10,11], [4,11,15], [11,12,15]
1019// ];
1020// let orientation = vec![
1021// false, false, true, true, true, false, true, true,
1022// false, false, true, false, true, true, false, true,
1023// false, false, true, true, true, true, false, true,
1024// true, true, false, false, false, false, false, false
1025// ];
1026// // sort faces while taping orientation
1027// let (faces, orientation) = {
1028// let mut zipped = faces.iter().zip(orientation.iter()).collect::<Vec<_>>();
1029// zipped.sort_by_key(|f| f.0);
1030// let faces = zipped.iter().map(|&(&f, _)| f).collect::<Vec<_>>();
1031// let orientation = zipped.iter().map(|&(_, &o)| o).collect::<Vec<_>>();
1032// (faces, orientation)
1033// };
1034// let mut edgebreaker = Edgebreaker::new(Config::default());
1035// edgebreaker.lies_on_boundary_or_cutting_path = vec![false; 12];
1036// edgebreaker.face_orientation = vec!(false; faces.len());
1037// edgebreaker.visited_faces = vec!(false; faces.len());
1038// edgebreaker.compute_edges(&faces);
1039// assert!(edgebreaker.check_orientability(&faces).is_ok());
1040// assert_eq!(edgebreaker.face_orientation, orientation,
1041// "orientation is wrong at: {:?}",
1042// edgebreaker.face_orientation.iter()
1043// .zip(orientation.iter())
1044// .enumerate()
1045// .filter(|(_, (a,b))| a!=b)
1046// .map(|(i,_)| faces[i])
1047// .collect::<Vec<_>>()
1048// );
1049// }
1050
1051// use Symbol::*;
1052// fn read_symbols<R>(reader: &mut R, size: usize) -> Vec<Symbol>
1053// where R: ByteReader
1054// {
1055// let mut out = Vec::new();
1056// let mut reader = BitReader::spown_from(reader).unwrap();
1057// for _ in 0..size {
1058// out.push(
1059// CrLight::decode_symbol(&mut reader)
1060// );
1061// }
1062// out
1063// }
1064
1065// fn read_topology_splits<R: ByteReader>(reader: &mut R) -> Vec<TopologySplit> {
1066// let mut topology_splits = Vec::new();
1067// let num_topology_splits = leb128_read(reader).unwrap() as u32;
1068// let mut last_idx = 0;
1069// for _ in 0..num_topology_splits {
1070// let source_symbol_idx = leb128_read(reader).unwrap() as usize + last_idx;
1071// let split_symbol_idx = source_symbol_idx - leb128_read(reader).unwrap() as usize;
1072// let topology_split = TopologySplit {
1073// source_symbol_idx,
1074// split_symbol_idx,
1075// source_edge_orientation: Orientation::Right, // this value is temporary
1076// };
1077// topology_splits.push(topology_split);
1078// last_idx = source_symbol_idx;
1079// }
1080
1081// let mut reader: BitReader<_> = BitReader::spown_from(reader).unwrap();
1082// for split_mut in topology_splits.iter_mut() {
1083// // update the orientation of the topology split.
1084// split_mut.source_edge_orientation = match reader.read_bits(1).unwrap() {
1085// 0 => Orientation::Left,
1086// 1 => Orientation::Right,
1087// _ => unreachable!(),
1088// };
1089// }
1090
1091// topology_splits
1092// }
1093
1094// fn manual_test<const TEST_ORIENTABILITY: bool>(
1095// mut original_faces: Vec<[VertexIdx; 3]>,
1096// points: Vec<NdVector<3,f32>>,
1097// expected_symbols: Vec<Symbol>,
1098// expected_topology_splits: Vec<TopologySplit>,
1099// expected_faces: Option<Vec<[VertexIdx; 3]>>
1100// ) {
1101// // positions do not matter
1102// let mut point_att = Attribute::from(
1103// AttributeId::new(0),
1104// points,
1105// AttributeType::Position,
1106// Vec::new()
1107// );
1108
1109// let mut buff_writer = Vec::new();
1110// Edgebreaker::new(Config::default()).encode_connectivity(&mut original_faces, &mut [&mut point_att], &mut buff_writer).unwrap();
1111
1112// let mut reader = buff_writer.into_iter();
1113
1114// assert_eq!(reader.read_u8().unwrap(), 0);
1115// assert_eq!(reader.read_u64().unwrap(), original_faces.len() as u64);
1116// assert_eq!(expected_topology_splits, read_topology_splits(&mut reader));
1117// debug_expect!("Start of Symbols", reader);
1118// assert_eq!(expected_symbols, read_symbols(&mut reader, original_faces.len()));
1119
1120// if !TEST_ORIENTABILITY {
1121// original_faces.iter_mut().for_each(|f| f.sort());
1122// }
1123// if let Some(expected_faces) = expected_faces {
1124// assert_eq!(original_faces, expected_faces);
1125// }
1126// }
1127
1128// #[test]
1129// fn edgebreaker_disc() {
1130// let faces = vec![
1131// [0,1,4],
1132// [0,3,4],
1133// [1,2,5],
1134// [1,4,5],
1135// [2,5,6],
1136// [3,4,7],
1137// [3,7,10],
1138// [4,5,7],
1139// [5,6,8],
1140// [5,7,8],
1141// [7,8,9],
1142// [7,9,10],
1143// [8,9,11],
1144// [9,10,11]
1145// ];
1146// // positions do not matter
1147// let points = vec![NdVector::<3,f32>::zero(); faces.iter().flatten().max().unwrap()+1];
1148
1149// let expected_symbols = vec![E,E,S,R,L,R,R,C,C,R,R,R,C,C];
1150
1151// let expected_faces = vec![
1152// [0,1,2],
1153// [1,3,4],
1154// [0,3,1],
1155// [0,5,3],
1156// [0,6,5],
1157// [5,6,7],
1158// [6,8,7],
1159// [0,8,6],
1160// [0,2,8],
1161// [2,9,8],
1162// [2,10,9],
1163// [2,11,10],
1164// [1,11,2],
1165// [1,4,11] // orientation base
1166// ];
1167
1168// manual_test::<true>(faces, points, expected_symbols, Vec::new(), Some(expected_faces));
1169// }
1170
1171// #[test]
1172// fn edgebreaker_split() {
1173// let faces = vec![
1174// [0,1,2],
1175// [0,2,4],
1176// [0,4,5],
1177// [2,3,4]
1178// ];
1179// // positions do not matter
1180// let points = vec![NdVector::<3,f32>::zero(); faces.iter().flatten().max().unwrap()+1];
1181
1182// let expected_symbols = vec![E,E,S,R];
1183
1184// let expected_faces = vec![
1185// [0,2,1],
1186// [1,4,3],
1187// [0,1,3],
1188// [0,3,5] // orientation base
1189// ];
1190
1191// manual_test::<true>(faces, points, expected_symbols, Vec::new(), Some(expected_faces));
1192// }
1193
1194// #[test]
1195// fn edgebreaker_triangle() {
1196// let faces = vec![
1197// [0,1,3],
1198// [1,2,3],
1199// [2,3,4],
1200// [3,4,5]
1201// ];
1202
1203// let points = vec![NdVector::<3,f32>::zero(); faces.iter().flatten().max().unwrap()+1];
1204// let expected_symbols = vec![E,R,R,L];
1205// let expected_faces = vec![
1206// [0,2,1],
1207// [0,1,3],
1208// [0,3,4],
1209// [0,4,5] // base
1210// ];
1211// manual_test::<true>(faces, points, expected_symbols, Vec::new(), Some(expected_faces));
1212// }
1213
1214// #[test]
1215// fn edgebreaker_begin_from_center() {
1216// // mesh forming a square whose initial edge is not on the boundary.
1217// let mut original_faces = vec![
1218// [9,23,24], [8,9,23], [8,9,10], [1,8,10], [1,10,11], [1,2,11], [2,11,12], [2,12,13],
1219// [8,22,23], [7,8,22], [1,7,8], [0,1,7], [0,1,2], [0,2,3], [2,3,13], [3,13,14],
1220// [7,21,22], [6,7,21], [0,6,7], [0,5,6], [0,3,5], [3,4,5], [3,4,14], [4,14,15],
1221// [6,20,21], [6,19,20], [5,6,19], [5,18,19], [4,5,18], [4,17,18], [4,15,17], [15,16,17]
1222// ];
1223// original_faces.sort();
1224// // positions do not matter
1225// let points = vec![NdVector::<3,f32>::zero(); original_faces.iter().flatten().max().unwrap()+1];
1226
1227// let expected_symbols = vec![E, E, E, S, R, L, R, L, R, R, L, R, S, R, E, S, R, C, R, E, L, S, R, C, C, C, R, C, C, L, S /* hole */, C];
1228// let expected_topology_splits = vec![
1229// TopologySplit {
1230// source_symbol_idx: 16,
1231// split_symbol_idx: 16,
1232// source_edge_orientation: Orientation::Left,
1233// },
1234// ];
1235// manual_test::<false>(original_faces, points, expected_symbols, expected_topology_splits, None);
1236// }
1237
1238// #[test]
1239// fn edgebreaker_handle() {
1240// // create torus in order to test the handle symbol.
1241// let mut original_faces = vec![
1242// [9,12,13], [8,9,13], [8,9,10], [1,8,10], [1,10,11], [1,2,11], [2,11,12], [2,12,13],
1243// [8,13,14], [7,8,14], [1,7,8], [0,1,7], [0,1,2], [0,2,3], [2,3,13], [3,13,14],
1244// [7,14,15], [6,7,15], [0,6,7], [0,5,6], [0,3,5], [3,4,5], [3,4,14], [4,14,15],
1245// [6,12,15], [6,9,12], [5,6,9], [5,9,10], [4,5,10], [4,10,11], [4,11,15], [11,12,15]
1246// ];
1247// original_faces.sort();
1248// // positions do not matter
1249// let points = vec![NdVector::<3,f32>::zero(); original_faces.iter().flatten().max().unwrap()+1];
1250
1251// let expected_symbols = vec![E, E, S, R, E, E, S, L, R, S, R, C, S /* handle */, R, C, S /* handle */, R, C, C, R, C, C, R, C, C, C, R, C, C, C, C, C];
1252// let expected_topology_splits = vec![
1253// TopologySplit {
1254// source_symbol_idx: 31,
1255// split_symbol_idx: 17,
1256// source_edge_orientation: Orientation::Left,
1257// },
1258// TopologySplit {
1259// source_symbol_idx: 28,
1260// split_symbol_idx: 20,
1261// source_edge_orientation: Orientation::Right,
1262// }
1263// ];
1264
1265// manual_test::<false>(original_faces, points, expected_symbols, expected_topology_splits, None);
1266// }
1267
1268// // #[test]
1269// #[allow(unused)] // uncomment the test to run it. it is commented out as it takes a long time to run.
1270// fn connectivity_check_after_vertex_permutation() {
1271// let (bunny,_) = tobj::load_obj(
1272// format!("../tests/data/punctured_sphere.obj"),
1273// &tobj::GPU_LOAD_OPTIONS
1274// ).unwrap();
1275// let bunny = &bunny[0];
1276// let mesh = &bunny.mesh;
1277
1278// let faces_original = mesh.indices.chunks(3)
1279// .map(|x| [x[0] as usize, x[1] as usize, x[2] as usize])
1280// .collect::<Vec<_>>();
1281
1282// let mut faces = faces_original.clone();
1283
1284// let points = mesh.positions.chunks(3)
1285// .map(|x| NdVector::<3,f32>::from([x[0], x[1], x[2]]))
1286// .collect::<Vec<_>>();
1287
1288// let mut point_att = Attribute::from(AttributeId::new(0), points, AttributeType::Position, Vec::new());
1289// let mut edgebreaker = Edgebreaker::new(Config::default());
1290// assert!(edgebreaker.init(&mut [&mut point_att], &mut faces).is_ok());
1291// let mut writer = Vec::new();
1292// assert!(edgebreaker.encode_connectivity(&mut faces, &mut [&mut point_att], &mut writer).is_ok());
1293
1294// assert!(eq::weak_eq_by_laplacian(&faces, &faces_original).unwrap());
1295// }
1296// }