Skip to main content

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// }