manifold_rs/
lib.rs

1// Copyright © 2024 The µCAD authors <info@ucad.xyz>
2// SPDX-License-Identifier: Apache-2.0
3
4//! Rust integration of C++ library *Manifold* for geometric operations
5
6#[cfg(feature = "output")]
7pub mod output;
8
9#[cxx::bridge(namespace = "manifold_rs")]
10mod ffi {
11    // C++ types and signatures exposed to Rust.
12    unsafe extern "C++" {
13        include!("manifold_rs.h");
14
15        type Polygons;
16
17        /// Get the number of polygons.
18        fn size(self: &Polygons) -> usize;
19
20        /// Get the number of vertices in a polygon.
21        fn get_as_slice(self: &Polygons, i: usize) -> &[f64];
22
23        /// Manifold object, wrapper for C++ manifold object.
24        type Manifold;
25
26        /// Slice the manifold into a set of polygons.
27        fn slice(self: &Manifold, height: f64) -> UniquePtr<Polygons>;
28
29        /// Project the manifold onto a plane and return the resulting polygons.
30        fn project(self: &Manifold) -> UniquePtr<Polygons>;
31
32        /// Create a sphere manifold.
33        fn sphere(radius: f64, segments: u32) -> UniquePtr<Manifold>;
34
35        /// Create a cube manifold.
36        fn cube(x_size: f64, y_size: f64, z_size: f64) -> UniquePtr<Manifold>;
37
38        /// Create a cylinder manifold.
39        fn cylinder(
40            radius_low: f64,
41            radius_high: f64,
42            height: f64,
43            segments: u32,
44        ) -> UniquePtr<Manifold>;
45
46        /// Get the union of two manifolds.
47        fn union_(a: &Manifold, b: &Manifold) -> UniquePtr<Manifold>;
48
49        /// Get the intersection of two manifolds.
50        fn intersection(a: &Manifold, b: &Manifold) -> UniquePtr<Manifold>;
51
52        /// Get the difference of two manifolds.
53        fn difference(a: &Manifold, b: &Manifold) -> UniquePtr<Manifold>;
54
55        /// Trim by a plane.
56        fn trim_by_plane(
57            self: &Manifold,
58            x: f64,
59            y: f64,
60            z: f64,
61            offset: f64,
62        ) -> UniquePtr<Manifold>;
63
64        /// Convex hull.
65        fn hull(self: &Manifold) -> UniquePtr<Manifold>;
66
67        /// Translate the manifold.
68        fn translate(self: &Manifold, x: f64, y: f64, z: f64) -> UniquePtr<Manifold>;
69
70        /// Scale the manifold.
71        fn scale(self: &Manifold, x: f64, y: f64, z: f64) -> UniquePtr<Manifold>;
72
73        /// Rotate the manifold.
74        fn rotate(self: &Manifold, x: f64, y: f64, z: f64) -> UniquePtr<Manifold>;
75
76        /// Extrude a polygon to create a manifold.
77        fn extrude(
78            multi_polygon_data: &[&[f64]],
79            height: f64,
80            n_divisions: u32,
81            twist_degrees: f64,
82            scale_top_x: f64,
83            scale_top_y: f64,
84        ) -> UniquePtr<Manifold>;
85
86        /// Revolve a polygon to create a manifold.
87        fn revolve(
88            multi_polygon_data: &[&[f64]],
89            circular_segments: u32,
90            revolve_degrees: f64,
91        ) -> UniquePtr<Manifold>;
92
93        /// Refine manifold.
94        fn refine(self: &Manifold, n: i32) -> UniquePtr<Manifold>;
95
96        /// Refine manifold to Length.
97        fn refine_to_length(self: &Manifold, t: f64) -> UniquePtr<Manifold>;
98
99        /// Refine to tolerance.
100        fn refine_to_tolerance(self: &Manifold, t: f64) -> UniquePtr<Manifold>;
101
102        /// Smooth by normals.
103        fn smooth_by_normals(self: &Manifold, normal_idx: i32) -> UniquePtr<Manifold>;
104
105        /// Smooth out.
106        fn smooth_out(
107            self: &Manifold,
108            min_sharp_angle: f64,
109            min_smoothness: f64,
110        ) -> UniquePtr<Manifold>;
111
112        /// Calculate normals for the manifold and return a new one.
113        fn calculate_normals(
114            self: &Manifold,
115            normal_idx: i32,
116            min_sharp_angle: f64,
117        ) -> UniquePtr<Manifold>;
118
119        /// Manifold object, wrapper for C++ mesh object.
120        type Mesh;
121
122        /// Get the number of vertex properties of a mesh.
123        fn num_props(self: &Mesh) -> u32;
124
125        /// Get the vertices of the mesh.
126        fn vertices(self: &Mesh) -> UniquePtr<CxxVector<f32>>;
127
128        /// Get the indices of the mesh.
129        fn indices(self: &Mesh) -> UniquePtr<CxxVector<u32>>;
130
131        /// Create a mesh from a manifold.
132        fn mesh_from_manifold(manifold: &Manifold) -> UniquePtr<Mesh>;
133
134        /// Create a manifold from a mesh.
135        fn manifold_from_mesh(mesh: &Mesh) -> UniquePtr<Manifold>;
136
137        /// Create a mesh from vertices and indices.
138        ///
139        /// The vertices are a flat array of floats containing the x, y, z coordinates of each vertex.
140        /// The indices are a flat array of unsigned integers containing the indices of the vertices.
141        fn mesh_from_vertices(vertices: &[f32], indices: &[u32]) -> UniquePtr<Mesh>;
142    }
143}
144
145/// Boolean operation on manifolds.
146pub enum BooleanOp {
147    /// Union of two manifolds.
148    Union,
149    /// Intersection of two manifolds.
150    Intersection,
151    /// Difference of two manifolds.
152    Difference,
153}
154
155/// Manifold rust wrapper for C++ polygons object.
156pub struct Polygons(cxx::UniquePtr<ffi::Polygons>);
157
158impl Polygons {
159    /// Get the number of polygons.
160    pub fn size(&self) -> usize {
161        self.0.size()
162    }
163
164    /// Get the number of vertices in a polygon.
165    pub fn get_as_slice(&self, i: usize) -> &[f64] {
166        self.0.get_as_slice(i)
167    }
168}
169
170/// Manifold rust wrapper for C++ manifold object.
171pub struct Manifold(cxx::UniquePtr<ffi::Manifold>);
172
173impl Manifold {
174    /// Slice the manifold into a set of polygons.
175    pub fn slice(&self, height: f64) -> Polygons {
176        Polygons(self.0.slice(height))
177    }
178
179    /// Project the manifold onto a plane and return the resulting polygons.
180    pub fn project(&self) -> Polygons {
181        Polygons(self.0.project())
182    }
183
184    /// Trim by a plane.
185    pub fn trim_by_plane(&self, x: f64, y: f64, z: f64, offset: f64) -> Self {
186        Self(self.0.trim_by_plane(x, y, z, offset))
187    }
188
189    /// Convex hull.
190    pub fn hull(&self) -> Self {
191        Self(self.0.hull())
192    }
193
194    /// Translate the manifold.
195    pub fn translate(&self, x: f64, y: f64, z: f64) -> Self {
196        Self(self.0.translate(x, y, z))
197    }
198
199    /// Scale the manifold.
200    pub fn scale(&self, x: f64, y: f64, z: f64) -> Self {
201        Self(self.0.scale(x, y, z))
202    }
203
204    /// Rotate the manifold.
205    pub fn rotate(&self, x: f64, y: f64, z: f64) -> Self {
206        Self(self.0.rotate(x, y, z))
207    }
208
209    /// Create a sphere manifold.
210    pub fn sphere(radius: f64, segments: u32) -> Self {
211        Self(ffi::sphere(radius, segments))
212    }
213
214    /// Create a cube manifold.
215    pub fn cube(x_size: f64, y_size: f64, z_size: f64) -> Self {
216        Self(ffi::cube(x_size, y_size, z_size))
217    }
218
219    /// Create a cylinder manifold.
220    pub fn cylinder(radius_low: f64, radius_high: f64, height: f64, segments: u32) -> Self {
221        Self(ffi::cylinder(radius_low, radius_high, height, segments))
222    }
223
224    /// Get the union of two manifolds.
225    pub fn union(&self, b: &Self) -> Self {
226        Self(ffi::union_(self.inner(), b.inner()))
227    }
228
229    /// Get the intersection of two manifolds.
230    pub fn intersection(&self, b: &Self) -> Self {
231        Self(ffi::intersection(self.inner(), b.inner()))
232    }
233
234    /// Get the difference of two manifolds.
235    pub fn difference(&self, b: &Self) -> Self {
236        Self(ffi::difference(self.inner(), b.inner()))
237    }
238
239    /// Boolean operation on manifolds.
240    pub fn boolean_op(&self, b: &Self, op: crate::BooleanOp) -> Self {
241        match op {
242            crate::BooleanOp::Union => self.union(b),
243            crate::BooleanOp::Intersection => self.intersection(b),
244            crate::BooleanOp::Difference => self.difference(b),
245        }
246    }
247
248    /// Extrude a polygon to create a manifold.
249    pub fn extrude(
250        multi_polygon_data: &[&[f64]],
251        height: f64,
252        n_divisions: u32,
253        twist_degrees: f64,
254        scale_top_x: f64,
255        scale_top_y: f64,
256    ) -> Self {
257        Self(ffi::extrude(
258            multi_polygon_data,
259            height,
260            n_divisions,
261            twist_degrees,
262            scale_top_x,
263            scale_top_y,
264        ))
265    }
266
267    /// Revolve a polygon to create a manifold.
268    pub fn revolve(
269        multi_polygon_data: &[&[f64]],
270        circular_segments: u32,
271        revolve_degrees: f64,
272    ) -> Self {
273        Self(ffi::revolve(
274            multi_polygon_data,
275            circular_segments,
276            revolve_degrees,
277        ))
278    }
279
280    /// Refine manifold.
281    pub fn refine(self: &Manifold, n: i32) -> Self {
282        Self(self.0.refine(n))
283    }
284
285    /// Refine manifold to Length.
286    pub fn refine_to_length(self: &Manifold, t: f64) -> Self {
287        Self(self.0.refine_to_length(t))
288    }
289
290    /// Refine to tolerance.
291    pub fn refine_to_tolerance(self: &Manifold, t: f64) -> Self {
292        Self(self.0.refine_to_tolerance(t))
293    }
294
295    /// Smooth by normals.
296    pub fn smooth_by_normals(self: &Manifold, normal_idx: i32) -> Self {
297        Self(self.0.smooth_by_normals(normal_idx))
298    }
299
300    /// Smooth out.
301    pub fn smooth_out(self: &Manifold, min_sharp_angle: f64, min_smoothness: f64) -> Self {
302        Self(self.0.smooth_out(min_sharp_angle, min_smoothness))
303    }
304
305    /// Calculate normals for the manifold and return a new one.
306    pub fn calculate_normals(self: &Manifold, normal_idx: i32, min_sharp_angle: f64) -> Self {
307        Self(self.0.calculate_normals(normal_idx, min_sharp_angle))
308    }
309
310    /// Get the mesh representation of the manifold.
311    pub fn to_mesh(&self) -> Mesh {
312        Mesh(ffi::mesh_from_manifold(&self.0))
313    }
314
315    /// Create a manifold from a mesh.
316    pub fn from_mesh(mesh: Mesh) -> Self {
317        mesh.into()
318    }
319
320    /// Get the inner C++ manifold object.
321    fn inner(&self) -> &ffi::Manifold {
322        self.0.as_ref().unwrap()
323    }
324}
325
326/// Wrapper around a C++ mesh object.
327pub struct Mesh(cxx::UniquePtr<ffi::Mesh>);
328
329/// Implementations for the Mesh struct.
330impl Mesh {
331    /// Create a new mesh from vertices and indices.
332    pub fn new(vertices: &[f32], indices: &[u32]) -> Self {
333        let mesh = ffi::mesh_from_vertices(vertices, indices);
334        Self(mesh)
335    }
336
337    /// Number of properties per vertex
338    pub fn num_props(&self) -> u32 {
339        self.0.num_props()
340    }
341
342    /// Get the vertices of the mesh.
343    pub fn vertices(&self) -> Vec<f32> {
344        let vertices_binding = self.0.vertices();
345        let vertices = vertices_binding.as_ref().unwrap().as_slice();
346        vertices.to_vec()
347    }
348
349    /// Get the indices of the mesh.
350    pub fn indices(&self) -> Vec<u32> {
351        let indices_binding = self.0.indices();
352        let indices = indices_binding.as_ref().unwrap().as_slice();
353        indices.to_vec()
354    }
355
356    /// Get the manifold representation of the mesh.
357    pub fn to_manifold(&self) -> Manifold {
358        let manifold = ffi::manifold_from_mesh(&self.0);
359        Manifold(manifold)
360    }
361}
362
363/// Convert Mesh to Manifold struct
364impl From<Mesh> for Manifold {
365    fn from(mesh: Mesh) -> Self {
366        mesh.to_manifold()
367    }
368}
369
370/// Convert Manifold to Mesh struct
371impl From<Manifold> for Mesh {
372    fn from(manifold: Manifold) -> Self {
373        manifold.to_mesh()
374    }
375}
376
377#[test]
378fn test_manifold_ffi() {
379    let sphere = ffi::sphere(1.0, 32);
380
381    let mesh = ffi::mesh_from_manifold(&sphere);
382
383    let vertices_binding = mesh.vertices();
384    let vertices = vertices_binding.as_ref().unwrap().as_slice();
385    assert!(!vertices.is_empty());
386
387    let indices_binding = mesh.indices();
388    let indices = indices_binding.as_ref().unwrap().as_slice();
389    assert!(!indices.is_empty());
390}