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::bit_coder::ByteWriter;
9use draco_oxide_core::codec::connectivity::edgebreaker::EdgebreakerKind;
10use draco_oxide_core::mesh::ds::AttributeDS;
11use draco_oxide_core::types::{ConfigType, CornerIdx};
12
13/// Entry point for encoding connectivity. Encodes the mesh connectivity with
14/// the method selected in the configuration and returns the corner order of
15/// the edgebreaker traversal (empty for sequential encoding).
16pub fn encode_connectivity<'faces, W>(
17    adss: &mut [AttributeDS<'faces>],
18    writer: &mut W,
19    cfg: &super::Config,
20) -> Result<Vec<CornerIdx>, Err>
21where
22    W: ByteWriter,
23{
24    encode_connectivity_datatype_unpacked(adss, writer, cfg.connectivity.clone())
25}
26
27/// Dispatches connectivity encoding to the edgebreaker or sequential encoder
28/// according to the given connectivity configuration.
29pub fn encode_connectivity_datatype_unpacked<'faces, W>(
30    adss: &mut [AttributeDS<'faces>],
31    writer: &mut W,
32    cfg: Config,
33) -> Result<Vec<CornerIdx>, Err>
34where
35    W: ByteWriter,
36{
37    let corners_of_edgebreaker = match cfg {
38        Config::Edgebreaker(cfg) => {
39            let result = match cfg.traversal {
40                EdgebreakerKind::Standard => {
41                    let encoder =
42                        edgebreaker::Edgebreaker::new(cfg, adss, |_| DefaultTraversal::new())?;
43                    encoder.encode_connectivity(writer)?
44                }
45                EdgebreakerKind::Predictive => {
46                    unimplemented!("Predictive edgebreaker encoding is not implemented yet");
47                }
48                EdgebreakerKind::Valence => {
49                    let encoder = edgebreaker::Edgebreaker::new(cfg, adss, ValenceTraversal::new)?;
50                    encoder.encode_connectivity(writer)?
51                }
52            };
53
54            result
55        }
56        Config::Sequential(cfg) => {
57            // Sequential attributes are stored per point, so the point space is
58            // what the face indices address and what sizes them.
59            let num_points = adss[0].global_ds().num_points();
60            let faces = (0..adss[0].global_ds().num_faces())
61                .map(|i| {
62                    let c = CornerIdx::from(3 * i);
63                    [
64                        adss[0].global_ds().point_idx(c),
65                        adss[0].global_ds().point_idx(c.next()),
66                        adss[0].global_ds().point_idx(c.next().next()),
67                    ]
68                })
69                .collect::<Vec<_>>();
70            let encoder = sequential::Sequential::new(&faces, cfg, num_points);
71            // Sequential encoding does not produce an edgebreaker traversal ordering.
72            encoder.encode_connectivity(writer)?
73        }
74    };
75    Ok(corners_of_edgebreaker)
76}
77
78/// Interface implemented by the connectivity encoders. Consumes the encoder,
79/// writes the encoded connectivity to the writer, and returns the corner
80/// order of the traversal.
81pub trait ConnectivityEncoder {
82    type Err;
83    type Config;
84    fn encode_connectivity<W>(self, writer: &mut W) -> Result<Vec<CornerIdx>, Self::Err>
85    where
86        W: ByteWriter;
87}
88
89/// Errors from connectivity encoding.
90#[remain::sorted]
91#[derive(thiserror::Error, Debug)]
92pub enum Err {
93    /// Edgebreaker encoding failed.
94    #[error("Edgebreaker encoding error: {0}")]
95    EdgebreakerError(#[from] edgebreaker::Err),
96    /// The position attribute has an unsupported component type.
97    #[error("Position attribute must be of type f32 or f64")]
98    PositionAttributeTypeError,
99    /// Sequential encoding failed.
100    #[error("Sequential encoding error: {0}")]
101    SequentialError(#[from] sequential::Err),
102    /// The mesh has more connectivity attributes than the encoder supports.
103    #[error("Too many connectivity attributes")]
104    TooManyConnectivityAttributes,
105}
106
107/// Selection of the connectivity encoding method, carrying the configuration
108/// of the selected method. Exported as `ConnectivityConfig`.
109#[remain::sorted]
110#[derive(Clone, Debug)]
111pub enum Config {
112    /// Edgebreaker connectivity encoding.
113    Edgebreaker(edgebreaker::Config),
114    /// Sequential connectivity encoding, which stores face indices directly
115    /// without compressing the connectivity.
116    Sequential(sequential::Config),
117}
118
119impl ConfigType for Config {
120    fn default() -> Self {
121        Self::Edgebreaker(edgebreaker::Config::default())
122    }
123}
124
125impl Config {
126    /// The wire-level connectivity method this config selects, as written into
127    /// the Draco header and used to branch attribute sequencing.
128    pub fn encoder_method(&self) -> draco_oxide_core::codec::header::EncoderMethod {
129        use draco_oxide_core::codec::header::EncoderMethod;
130        match self {
131            Config::Edgebreaker(_) => EncoderMethod::Edgebreaker,
132            Config::Sequential(_) => EncoderMethod::Sequential,
133        }
134    }
135}