Skip to main content

draco_oxide/encode/connectivity/
mod.rs

1pub mod config;
2pub(crate) mod edgebreaker;
3pub(crate) mod sequential;
4
5use std::fmt::Debug;
6
7use crate::encode::connectivity::edgebreaker::{DefaultTraversal, ValenceTraversal};
8use draco_oxide_core::attribute::AttributeType;
9use draco_oxide_core::bit_coder::ByteWriter;
10use draco_oxide_core::codec::connectivity::edgebreaker::EdgebreakerKind;
11use draco_oxide_core::mesh::ds::AttributeDS;
12use draco_oxide_core::types::{ConfigType, CornerIdx};
13
14#[cfg(feature = "evaluation")]
15use crate::eval;
16
17/// entry point for encoding connectivity.
18pub fn encode_connectivity<'faces, W>(
19    adss: &mut [AttributeDS<'faces>],
20    writer: &mut W,
21    cfg: &super::Config,
22) -> Result<Vec<CornerIdx>, Err>
23where
24    W: ByteWriter,
25{
26    #[cfg(feature = "evaluation")]
27    eval::scope_begin("connectivity info", writer);
28
29    let result = encode_connectivity_datatype_unpacked(adss, writer, cfg.connectivity.clone());
30
31    #[cfg(feature = "evaluation")]
32    eval::scope_end(writer);
33    result
34}
35
36pub fn encode_connectivity_datatype_unpacked<'faces, W>(
37    adss: &mut [AttributeDS<'faces>],
38    writer: &mut W,
39    cfg: Config,
40) -> Result<Vec<CornerIdx>, Err>
41where
42    W: ByteWriter,
43{
44    let corners_of_edgebreaker = match cfg {
45        Config::Edgebreaker(cfg) => {
46            #[cfg(feature = "evaluation")]
47            eval::scope_begin("edgebreaker", writer);
48
49            let result = match cfg.traversal {
50                EdgebreakerKind::Standard => {
51                    let encoder =
52                        edgebreaker::Edgebreaker::new(cfg, adss, |_| DefaultTraversal::new())?;
53                    encoder.encode_connectivity(writer)?
54                }
55                EdgebreakerKind::Predictive => {
56                    unimplemented!("Predictive edgebreaker encoding is not implemented yet");
57                }
58                EdgebreakerKind::Valence => {
59                    let encoder = edgebreaker::Edgebreaker::new(cfg, adss, ValenceTraversal::new)?;
60                    encoder.encode_connectivity(writer)?
61                }
62            };
63
64            #[cfg(feature = "evaluation")]
65            eval::scope_end(writer);
66
67            result
68        }
69        Config::Sequential(cfg) => {
70            #[cfg(feature = "evaluation")]
71            eval::scope_begin("sequential", writer);
72
73            let num_points = adss
74                .iter()
75                .find(|ads| ads.att_data().get_attribute_type() == AttributeType::Position)
76                .unwrap()
77                .att_data()
78                .len();
79            let faces = (0..adss[0].global_ds().num_faces())
80                .map(|i| {
81                    let c = CornerIdx::from(3 * i);
82                    [
83                        adss[0].global_ds().point_idx(c),
84                        adss[0].global_ds().point_idx(c.next()),
85                        adss[0].global_ds().point_idx(c.next().next()),
86                    ]
87                })
88                .collect::<Vec<_>>();
89            let encoder = sequential::Sequential::new(&faces, cfg, num_points);
90            // Sequential encoding does not produce an edgebreaker traversal ordering.
91            encoder.encode_connectivity(writer)?
92        }
93    };
94    Ok(corners_of_edgebreaker)
95}
96
97pub trait ConnectivityEncoder {
98    type Err;
99    type Config;
100    fn encode_connectivity<W>(self, writer: &mut W) -> Result<Vec<CornerIdx>, Self::Err>
101    where
102        W: ByteWriter;
103}
104
105#[remain::sorted]
106#[derive(thiserror::Error, Debug)]
107pub enum Err {
108    #[error("Edgebreaker encoding error: {0}")]
109    EdgebreakerError(#[from] edgebreaker::Err),
110    #[error("Position attribute must be of type f32 or f64")]
111    PositionAttributeTypeError,
112    #[error("Sequential encoding error: {0}")]
113    SequentialError(#[from] sequential::Err),
114    #[error("Too many connectivity attributes")]
115    TooManyConnectivityAttributes,
116}
117
118#[remain::sorted]
119#[derive(Clone, Debug)]
120pub enum Config {
121    Edgebreaker(edgebreaker::Config),
122    #[allow(unused)] // we currently support only edgebreaker
123    Sequential(sequential::Config),
124}
125
126impl ConfigType for Config {
127    fn default() -> Self {
128        Self::Edgebreaker(edgebreaker::Config::default())
129    }
130}
131
132impl Config {
133    /// The wire-level connectivity method this config selects, as written into
134    /// the Draco header and used to branch attribute sequencing.
135    pub fn encoder_method(&self) -> draco_oxide_core::codec::header::EncoderMethod {
136        use draco_oxide_core::codec::header::EncoderMethod;
137        match self {
138            Config::Edgebreaker(_) => EncoderMethod::Edgebreaker,
139            Config::Sequential(_) => EncoderMethod::Sequential,
140        }
141    }
142}