Skip to main content

draco_rs/
pointcloud.rs

1use crate::{
2    decode::{Decoder, DecoderBuffer},
3    encode::{Encoder, EncoderBuffer},
4    prelude::*,
5};
6use autocxx::prelude::*;
7
8pub type PointCloudBuilder = WrappedDracoObject<ffi::draco::PointCloudBuilder>;
9
10impl PointCloudBuilder {
11    pub fn new(num: u32) -> Self {
12        let mut builder = ffi::draco::PointCloudBuilder::new().within_unique_ptr();
13        builder.pin_mut().Start(num);
14        Self(builder)
15    }
16
17    pub fn add_attribute(
18        &mut self,
19        attribute_type: ffi::draco::GeometryAttribute_Type,
20        num_components: i8,
21        data_type: ffi::draco::DataType,
22    ) -> AttrId {
23        self.0
24            .pin_mut()
25            .AddAttribute(attribute_type, num_components, data_type)
26            .into()
27    }
28
29    /// Adds the data from the provided slice as the attribute value for a specific point.
30    ///
31    /// # Safety
32    ///
33    /// The `point` slice must point to valid memory with a lifetime at least as long as the `PointCloudBuilder` instance.
34    /// The size and type of the data in the slice must be compatible with the attribute `attr_id`.
35    pub fn add_point<T>(
36        &mut self,
37        attr_id: AttrId,
38        point_index: impl Into<ffi::draco::PointIndex>,
39        point: &[T],
40    ) {
41        unsafe { self.add_point_with_ptr(attr_id, point_index, point.as_ptr() as *const c_void) }
42    }
43
44    /// Adds the data pointed to by the raw pointer as the attribute value for a specific point.
45    ///
46    /// # Safety
47    ///
48    /// This function is unsafe because it takes a raw pointer `ptr` to the point data.
49    /// It is the caller's responsibility to ensure that:
50    /// - `ptr` is valid and points to memory that is properly aligned for the attribute type.
51    /// - The memory pointed to by `ptr` has a lifetime at least as long as the `PointCloudBuilder` instance.
52    /// - The size of the data pointed to by `ptr` is sufficient for the attribute type associated with `attr_id`.
53    pub unsafe fn add_point_with_ptr(
54        &mut self,
55        attr_id: AttrId,
56        point_index: impl Into<ffi::draco::PointIndex>,
57        ptr: *const c_void,
58    ) {
59        self.0
60            .pin_mut()
61            .SetAttributeValueForPoint(attr_id.into(), point_index.into(), ptr);
62    }
63
64    pub fn build(mut self, deduplicate_points: bool) -> PointCloud {
65        PointCloud {
66            0: self.0.pin_mut().Finalize(deduplicate_points),
67        }
68    }
69}
70
71pub type PointCloud = WrappedDracoObject<ffi::draco::PointCloud>;
72
73impl Default for PointCloud {
74    fn default() -> Self {
75        Self::new()
76    }
77}
78
79impl PointCloud {
80    pub fn new() -> Self {
81        let pc = ffi::draco::PointCloud::new().within_unique_ptr();
82        Self(pc)
83    }
84
85    // This function returns the attribute id of the attribute with the given name
86    // It stores the value in-place
87    pub fn get_point<T>(
88        &mut self,
89        attr_id: AttrId,
90        point_index: impl Into<ffi::draco::PointIndex>,
91        point_container: &mut [T],
92    ) where
93        T: Default + Copy,
94    {
95        let pa_ptr = self.0.pin_mut().GetAttributeByUniqueId(attr_id.as_u32());
96        unsafe {
97            (*pa_ptr).GetMappedValue(
98                point_index.into(),
99                point_container.as_mut_ptr() as *mut c_void,
100            );
101        };
102    }
103
104    // This function allocates a new array of type T and fills it with the point data
105    pub fn get_point_alloc<T, const N: usize>(
106        &mut self,
107        attr_id: AttrId,
108        point_index: impl Into<ffi::draco::PointIndex>,
109    ) -> [T; N]
110    where
111        T: Default + Copy,
112    {
113        let mut point = [T::default(); N];
114        self.get_point(attr_id, point_index, &mut point);
115        point
116    }
117
118    // Returns the number of named attributes of a given type.
119    pub fn num_named_attributes(&self, attr_type: ffi::draco::GeometryAttribute_Type) -> i32 {
120        self.0.NumNamedAttributes(attr_type)
121    }
122
123    // Returns the id of the i-th named attribute of a given type.
124    pub fn get_named_attribute_id(
125        &self,
126        attr_type: ffi::draco::GeometryAttribute_Type,
127        i: i32,
128    ) -> Option<AttrId> {
129        let id = self.0.GetNamedAttributeId1(attr_type, i.into());
130        if id < 0 {
131            None
132        } else {
133            Some(AttrId(id))
134        }
135    }
136
137    // // Returns the i-th named attribute of a given type.
138    // pub fn get_named_attribute(
139    //     &self,
140    //     attr_type: ffi::draco::GeometryAttribute_Type,
141    //     i: i32,
142    // ) -> Option<NonOwningPointAttribute> {
143    //     let attr = self.0.GetNamedAttribute1(attr_type, i.into());
144    //     if attr.is_null() {
145    //         None
146    //     } else {
147    //         Some(NonOwningPointAttribute { ptr: attr })
148    //     }
149    // }
150
151    //   // Returns the named attribute of a given unique id.
152    //     pub fn get_named_attribute_by_unique_id(
153    //         &self,
154    //         attr_type: ffi::draco::GeometryAttribute_Type,
155    //         id: u32,
156    //     ) -> Option<NonOwningPointAttribute> {
157    //         let attr = self.0.GetNamedAttributeByUniqueId(attr_type, id);
158    //         if attr.is_null() {
159    //             None
160    //         } else {
161    //             Some(NonOwningPointAttribute { ptr: attr })
162    //         }
163    //     }
164
165    pub fn num_points(&self) -> u32 {
166        self.0.num_points()
167    }
168
169    pub fn len(&self) -> u32 {
170        self.0.num_points()
171    }
172
173    pub fn is_empty(&self) -> bool {
174        self.0.num_points() == 0
175    }
176
177    /// Encode the point cloud to an encoder buffer
178    pub fn to_buffer(&self, encoder: &mut Encoder) -> DracoStatusType<EncoderBuffer> {
179        let mut buffer = EncoderBuffer::new();
180
181        let status = unsafe {
182            encoder
183                .0
184                .pin_mut()
185                .EncodePointCloudToBuffer(self.0.as_ref().unwrap(), buffer.as_mut_ptr())
186                .within_unique_ptr()
187        };
188
189        if status.ok() {
190            Ok(buffer)
191        } else {
192            Err(status.into())
193        }
194    }
195
196    /// Decode a point cloud from a decoder buffer
197    ///
198    /// # Safety
199    ///
200    /// The decoder buffer must contains valid memory
201    pub fn from_buffer(decoder: &mut Decoder, buffer: &mut DecoderBuffer) -> DracoStatusType<Self> {
202        let mut status_or = unsafe {
203            decoder
204                .decoder
205                .pin_mut()
206                .DecodePointCloudFromBuffer(buffer.0.as_mut_ptr())
207        };
208        if status_or.ok() {
209            Ok(Self(status_or.pin_mut().value()))
210        } else {
211            Err(status_or.status().within_unique_ptr().into())
212        }
213    }
214}