1use std::ptr;
2
3use crate::error::Result;
4use crate::ffi;
5use crate::handle::ObjectHandle;
6use crate::mesh::Mesh;
7use crate::object::Object;
8use crate::types::{BoundingBox, VoxelArrayInfo, VoxelIndexExtent};
9use crate::util::{parse_json, required_handle};
10
11#[derive(Debug, Clone)]
12pub struct VoxelArray {
13 handle: ObjectHandle,
14}
15
16impl VoxelArray {
17 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
18 Self { handle }
19 }
20
21 pub fn new(
22 voxel_indices: &[[i32; 4]],
23 bounding_box: BoundingBox,
24 voxel_extent: f32,
25 ) -> Result<Self> {
26 let flattened = voxel_indices
27 .iter()
28 .flat_map(|index| index.iter().copied())
29 .collect::<Vec<_>>();
30 let mut out_voxel_array = ptr::null_mut();
31 let mut out_error = ptr::null_mut();
32 let status = unsafe {
33 ffi::mdl_voxel_array_new_with_indices(
34 flattened.as_ptr(),
35 voxel_indices.len() as u64,
36 bounding_box.min[0],
37 bounding_box.min[1],
38 bounding_box.min[2],
39 bounding_box.max[0],
40 bounding_box.max[1],
41 bounding_box.max[2],
42 voxel_extent,
43 &mut out_voxel_array,
44 &mut out_error,
45 )
46 };
47 crate::util::status_result(status, out_error)?;
48 Ok(Self::from_handle(required_handle(
49 out_voxel_array,
50 "MDLVoxelArray",
51 )?))
52 }
53
54 pub fn info(&self) -> Result<VoxelArrayInfo> {
55 parse_json(
56 unsafe { ffi::mdl_voxel_array_info_json(self.handle.as_ptr()) },
57 "MDLVoxelArray",
58 )
59 }
60
61 #[must_use]
62 pub fn count(&self) -> usize {
63 unsafe { ffi::mdl_voxel_array_count(self.handle.as_ptr()) as usize }
64 }
65
66 pub fn set_voxel(&self, index: [i32; 4]) {
67 unsafe {
68 ffi::mdl_voxel_array_set_voxel(
69 self.handle.as_ptr(),
70 index[0],
71 index[1],
72 index[2],
73 index[3],
74 );
75 };
76 }
77
78 #[must_use]
79 #[allow(clippy::fn_params_excessive_bools)]
80 pub fn voxel_exists(
81 &self,
82 index: [i32; 4],
83 allow_any_x: bool,
84 allow_any_y: bool,
85 allow_any_z: bool,
86 allow_any_shell: bool,
87 ) -> bool {
88 unsafe {
89 ffi::mdl_voxel_array_voxel_exists(
90 self.handle.as_ptr(),
91 index[0],
92 index[1],
93 index[2],
94 index[3],
95 i32::from(allow_any_x),
96 i32::from(allow_any_y),
97 i32::from(allow_any_z),
98 i32::from(allow_any_shell),
99 ) != 0
100 }
101 }
102
103 #[must_use]
104 pub fn voxel_indices(&self) -> Vec<[i32; 4]> {
105 let count = self.count();
106 if count == 0 {
107 return Vec::new();
108 }
109 let mut flattened = vec![0_i32; count * 4];
110 let written = unsafe {
111 ffi::mdl_voxel_array_copy_indices(
112 self.handle.as_ptr(),
113 flattened.as_mut_ptr(),
114 count as u64,
115 )
116 } as usize;
117 flattened.truncate(written * 4);
118 flattened
119 .chunks_exact(4)
120 .map(|chunk| [chunk[0], chunk[1], chunk[2], chunk[3]])
121 .collect()
122 }
123
124 #[must_use]
125 pub fn voxels_within_extent(&self, extent: &VoxelIndexExtent) -> Vec<[i32; 4]> {
126 let capacity = self.count();
127 if capacity == 0 {
128 return Vec::new();
129 }
130 let mut flattened = vec![0_i32; capacity * 4];
131 let written = unsafe {
132 ffi::mdl_voxel_array_copy_voxels_within_extent(
133 self.handle.as_ptr(),
134 extent.minimum_extent[0],
135 extent.minimum_extent[1],
136 extent.minimum_extent[2],
137 extent.minimum_extent[3],
138 extent.maximum_extent[0],
139 extent.maximum_extent[1],
140 extent.maximum_extent[2],
141 extent.maximum_extent[3],
142 flattened.as_mut_ptr(),
143 capacity as u64,
144 )
145 } as usize;
146 flattened.truncate(written * 4);
147 flattened
148 .chunks_exact(4)
149 .map(|chunk| [chunk[0], chunk[1], chunk[2], chunk[3]])
150 .collect()
151 }
152
153 pub fn union_with(&self, other: &Self) {
154 unsafe { ffi::mdl_voxel_array_union(self.handle.as_ptr(), other.handle.as_ptr()) };
155 }
156
157 pub fn intersect_with(&self, other: &Self) {
158 unsafe { ffi::mdl_voxel_array_intersect(self.handle.as_ptr(), other.handle.as_ptr()) };
159 }
160
161 pub fn difference_with(&self, other: &Self) {
162 unsafe { ffi::mdl_voxel_array_difference(self.handle.as_ptr(), other.handle.as_ptr()) };
163 }
164
165 #[must_use]
166 pub fn index_of_spatial_location(&self, location: [f32; 3]) -> [i32; 4] {
167 let mut values = [0_i32; 4];
168 unsafe {
169 ffi::mdl_voxel_array_index_of_spatial_location(
170 self.handle.as_ptr(),
171 location[0],
172 location[1],
173 location[2],
174 values.as_mut_ptr(),
175 );
176 };
177 values
178 }
179
180 #[must_use]
181 pub fn spatial_location_of_index(&self, index: [i32; 4]) -> [f32; 3] {
182 let mut values = [0.0_f32; 3];
183 unsafe {
184 ffi::mdl_voxel_array_spatial_location_of_index(
185 self.handle.as_ptr(),
186 index[0],
187 index[1],
188 index[2],
189 index[3],
190 &mut values[0],
191 &mut values[1],
192 &mut values[2],
193 );
194 };
195 values
196 }
197
198 #[must_use]
199 pub fn voxel_bounding_box_at_index(&self, index: [i32; 4]) -> BoundingBox {
200 let mut min = [0.0_f32; 3];
201 let mut max = [0.0_f32; 3];
202 unsafe {
203 ffi::mdl_voxel_array_voxel_bounding_box_at_index(
204 self.handle.as_ptr(),
205 index[0],
206 index[1],
207 index[2],
208 index[3],
209 &mut min[0],
210 &mut min[1],
211 &mut min[2],
212 &mut max[0],
213 &mut max[1],
214 &mut max[2],
215 );
216 };
217 BoundingBox { min, max }
218 }
219
220 pub fn convert_to_signed_shell_field(&self) {
221 unsafe { ffi::mdl_voxel_array_convert_to_signed_shell_field(self.handle.as_ptr()) };
222 }
223
224 pub fn set_shell_field_interior_thickness(&self, value: f32) {
225 unsafe {
226 ffi::mdl_voxel_array_set_shell_field_interior_thickness(self.handle.as_ptr(), value);
227 };
228 }
229
230 pub fn set_shell_field_exterior_thickness(&self, value: f32) {
231 unsafe {
232 ffi::mdl_voxel_array_set_shell_field_exterior_thickness(self.handle.as_ptr(), value);
233 };
234 }
235
236 #[must_use]
237 pub fn coarse_mesh(&self) -> Option<Mesh> {
238 let ptr = unsafe { ffi::mdl_voxel_array_coarse_mesh(self.handle.as_ptr()) };
239 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(Mesh::from_handle)
240 }
241
242 #[must_use]
243 pub fn mesh(&self) -> Option<Mesh> {
244 let ptr = unsafe { ffi::mdl_voxel_array_mesh(self.handle.as_ptr()) };
245 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(Mesh::from_handle)
246 }
247
248 #[must_use]
249 pub fn as_object(&self) -> Object {
250 Object::from_handle(self.handle.clone())
251 }
252}