From 01c73e11f698fcde9df31f4bad00df8181cc91e7 Mon Sep 17 00:00:00 2001 From: Nick Ufer Date: Mon, 18 Nov 2024 12:56:05 +0100 Subject: [PATCH] feat: upgrades to manifold v3.0.0 feat: adds ManifoldError feat: adds Manifold#revolve refactor: moves constructors to impl blocks refactor: improves Angle struct --- Cargo.toml | 10 +- src/bounding_box.rs | 40 ++-- src/error.rs | 86 +++++++++ src/lib.rs | 24 ++- src/manifold.rs | 432 ++++++++++++++++++++++-------------------- src/mesh_gl.rs | 29 ++- src/polygons.rs | 72 +++++-- src/quality.rs | 10 +- src/simple_polygon.rs | 48 ++--- src/types.rs | 66 +++++-- 10 files changed, 501 insertions(+), 316 deletions(-) create mode 100644 src/error.rs diff --git a/Cargo.toml b/Cargo.toml index 6508f6d..58b9179 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,14 +3,16 @@ name = "manifold3d" description = "Bindings for Manifold - a Geometry library for topological robustness" homepage = "https://github.com/NickUfer/manifold3d-rs" license = "Apache-2.0" -version = "0.0.1" +version = "0.0.2" edition = "2021" [dependencies] -thiserror = "1.0.64" +thiserror = "2.0" num-traits = "0.2.19" -manifold-sys = { version = "0.0.2" } +manifold3d-sys = { version = "0.0.3" } nalgebra = { version = "0.33.0", optional = true } [features] -nalgebra_interop = ["nalgebra"] \ No newline at end of file +nalgebra_interop = ["nalgebra"] +export = ["manifold3d-sys/export"] +parallel = ["manifold3d-sys/parallel"] \ No newline at end of file diff --git a/src/bounding_box.rs b/src/bounding_box.rs index 9a9b9b1..df54842 100644 --- a/src/bounding_box.rs +++ b/src/bounding_box.rs @@ -1,5 +1,5 @@ use crate::types::{Matrix4x3, Point3, Vec3}; -use manifold_sys::{ +use manifold3d_sys::{ manifold_alloc_box, manifold_box, manifold_box_center, manifold_box_contains_box, manifold_box_contains_pt, manifold_box_dimensions, manifold_box_does_overlap_box, manifold_box_does_overlap_pt, manifold_box_include_pt, manifold_box_is_finite, @@ -11,27 +11,27 @@ use std::os::raw::c_void; pub struct BoundingBox(*mut ManifoldBox); -pub fn new(min_point: Point3, max_point: Point3) -> BoundingBox { - let manifold_box_ptr = unsafe { manifold_alloc_box() }; - unsafe { - manifold_box( - manifold_box_ptr as *mut c_void, - min_point.x, - min_point.y, - min_point.z, - max_point.x, - max_point.y, - max_point.z, - ) - }; - BoundingBox(manifold_box_ptr) -} +impl BoundingBox { + pub fn new(min_point: Point3, max_point: Point3) -> BoundingBox { + let manifold_box_ptr = unsafe { manifold_alloc_box() }; + unsafe { + manifold_box( + manifold_box_ptr as *mut c_void, + min_point.x, + min_point.y, + min_point.z, + max_point.x, + max_point.y, + max_point.z, + ) + }; + BoundingBox(manifold_box_ptr) + } -pub(crate) fn from_ptr(ptr: *mut ManifoldBox) -> BoundingBox { - BoundingBox(ptr) -} + pub(crate) fn from_ptr(ptr: *mut ManifoldBox) -> BoundingBox { + BoundingBox(ptr) + } -impl BoundingBox { pub fn min_point(&self) -> Point3 { unsafe { Point3::from(manifold_box_min(self.0)) } } diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..2364a75 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,86 @@ +use crate::manifold::Manifold; +use manifold3d_sys::{ + manifold_status, ManifoldError, ManifoldError_MANIFOLD_FACE_ID_WRONG_LENGTH, + ManifoldError_MANIFOLD_INVALID_CONSTRUCTION, ManifoldError_MANIFOLD_MERGE_INDEX_OUT_OF_BOUNDS, + ManifoldError_MANIFOLD_MERGE_VECTORS_DIFFERENT_LENGTHS, + ManifoldError_MANIFOLD_MISSING_POSITION_PROPERTIES, ManifoldError_MANIFOLD_NON_FINITE_VERTEX, + ManifoldError_MANIFOLD_NOT_MANIFOLD, ManifoldError_MANIFOLD_NO_ERROR, + ManifoldError_MANIFOLD_PROPERTIES_WRONG_LENGTH, ManifoldError_MANIFOLD_RUN_INDEX_WRONG_LENGTH, + ManifoldError_MANIFOLD_TRANSFORM_WRONG_LENGTH, + ManifoldError_MANIFOLD_VERTEX_INDEX_OUT_OF_BOUNDS, +}; + +#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq)] +#[non_exhaustive] +pub enum Error { + NoError, + NonFiniteVertex, + NotManifold, + VertexIndexOutOfBounds, + PropertiesWrongLength, + MissingPositionProperties, + MergeVectorsDifferentLengths, + MergeIndexOutOfBounds, + TransformWrongLength, + RunIndexWrongLength, + FaceIdWrongLength, + InvalidConstruction, + Unknown(u32), +} + +impl From for Error { + fn from(value: u32) -> Self { + #[allow(non_upper_case_globals)] + match value { + ManifoldError_MANIFOLD_NO_ERROR => Error::NoError, + ManifoldError_MANIFOLD_NON_FINITE_VERTEX => Error::NonFiniteVertex, + ManifoldError_MANIFOLD_NOT_MANIFOLD => Error::NotManifold, + ManifoldError_MANIFOLD_VERTEX_INDEX_OUT_OF_BOUNDS => Error::VertexIndexOutOfBounds, + ManifoldError_MANIFOLD_PROPERTIES_WRONG_LENGTH => Error::PropertiesWrongLength, + ManifoldError_MANIFOLD_MISSING_POSITION_PROPERTIES => Error::MissingPositionProperties, + ManifoldError_MANIFOLD_MERGE_VECTORS_DIFFERENT_LENGTHS => { + Error::MergeVectorsDifferentLengths + } + ManifoldError_MANIFOLD_MERGE_INDEX_OUT_OF_BOUNDS => Error::MergeIndexOutOfBounds, + ManifoldError_MANIFOLD_TRANSFORM_WRONG_LENGTH => Error::TransformWrongLength, + ManifoldError_MANIFOLD_RUN_INDEX_WRONG_LENGTH => Error::RunIndexWrongLength, + ManifoldError_MANIFOLD_FACE_ID_WRONG_LENGTH => Error::FaceIdWrongLength, + ManifoldError_MANIFOLD_INVALID_CONSTRUCTION => Error::InvalidConstruction, + value => Error::Unknown(value), + } + } +} + +pub trait ManifoldErrorExt { + fn is_error(&self) -> bool; +} + +pub fn check_error(manifold: Manifold) -> Result { + match Error::from(unsafe { manifold_status(manifold.ptr()) }) { + Error::NoError => Ok(manifold), + e => Err(e), + } +} + +impl ManifoldErrorExt for ManifoldError { + fn is_error(&self) -> bool { + *self != 0 + } +} + +mod tests { + use crate::error::Error; + use manifold3d_sys::{ + ManifoldError_MANIFOLD_NON_FINITE_VERTEX, ManifoldError_MANIFOLD_NO_ERROR, + }; + + #[test] + fn test_error_from_u32() { + // Checks whether the error discrimination works at all + assert_eq!(Error::from(ManifoldError_MANIFOLD_NO_ERROR), Error::NoError); + assert_eq!( + Error::from(ManifoldError_MANIFOLD_NON_FINITE_VERTEX), + Error::NonFiniteVertex + ); + } +} diff --git a/src/lib.rs b/src/lib.rs index 929ae7f..9dccb8d 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,19 @@ #![allow(dead_code)] -pub mod bounding_box; -pub mod manifold; -pub mod mesh_gl; -pub mod polygons; -pub mod quality; -pub mod simple_polygon; -pub mod types; +mod bounding_box; +mod error; +mod manifold; +mod mesh_gl; +mod polygons; +mod quality; +mod simple_polygon; +mod types; + +pub use bounding_box::*; +pub use error::*; +pub use manifold::*; +pub use mesh_gl::*; +pub use polygons::*; +pub use quality::*; +pub use simple_polygon::*; +pub use types::*; diff --git a/src/manifold.rs b/src/manifold.rs index 25d725e..2f75af1 100644 --- a/src/manifold.rs +++ b/src/manifold.rs @@ -1,8 +1,8 @@ use crate::bounding_box::BoundingBox; +use crate::error::{check_error, Error}; use crate::mesh_gl::MeshGL; use crate::types::{PositiveF64, PositiveI32, Vec3}; -use crate::{bounding_box, mesh_gl}; -use manifold_sys::{ +use manifold3d_sys::{ manifold_alloc_box, manifold_alloc_manifold, manifold_alloc_meshgl, manifold_bounding_box, manifold_copy, manifold_cube, manifold_cylinder, manifold_delete_manifold, manifold_empty, manifold_get_meshgl, manifold_is_empty, manifold_num_edge, manifold_num_tri, manifold_num_vert, @@ -12,209 +12,225 @@ use std::os::raw::{c_int, c_void}; pub struct Manifold(*mut ManifoldManifold); -pub fn new_tetrahedron() -> Manifold { - let manifold_ptr = unsafe { manifold_alloc_manifold() }; - unsafe { manifold_tetrahedron(manifold_ptr as *mut c_void) }; - Manifold(manifold_ptr) -} +impl Manifold { + pub fn new_tetrahedron() -> Manifold { + let manifold_ptr = unsafe { manifold_alloc_manifold() }; + unsafe { manifold_tetrahedron(manifold_ptr as *mut c_void) }; + Manifold(manifold_ptr) + } -/// Constructs a 3D cuboid with the specified dimensions in the first octant of 3D space. -/// -/// By default, the cuboid's origin will be at the corner touching the coordinate system's origin -/// (i.e., the point (0, 0, 0)). If [origin_at_center] is set to `true`, the cuboid will be centered -/// at the origin, with its edges extending equally in all directions. -/// -/// # Returns -/// - A guaranteed non-empty `Manifold` representing a cuboid with the specified dimensions. -/// -/// # Examples -/// ``` -/// use manifold3d::manifold::new_cuboid; -/// use manifold3d::types::PositiveF64; -/// -/// // A cuboid of size 1x2x3, touching the origin in the first octant. -/// let cuboid = new_cuboid(1u8, 2u16, 3u32, false); -/// -/// // A cube of size 1.5x1.5x1.5 with its center at (0, 0, 0). -/// let cube_edge_length: PositiveF64 = 1.5.try_into().unwrap(); -/// let cube = new_cuboid(cube_edge_length, cube_edge_length, cube_edge_length, true); -/// ``` -pub fn new_cuboid( - x_size: impl Into, - y_size: impl Into, - z_size: impl Into, - origin_at_center: bool, -) -> Manifold { - new_cuboid_unchecked( - x_size.into(), - y_size.into(), - z_size.into(), - origin_at_center, - ) -} + /// Constructs a 3D cuboid with the specified dimensions in the first octant of 3D space. + /// + /// By default, the cuboid's origin will be at the corner touching the coordinate system's origin + /// (i.e., the point (0, 0, 0)). If [origin_at_center] is set to `true`, the cuboid will be centered + /// at the origin, with its edges extending equally in all directions. + /// + /// # Returns + /// - A guaranteed non-empty `Manifold` representing a cuboid with the specified dimensions. + /// + /// # Examples + /// ``` + /// use manifold3d::Manifold; + /// use manifold3d::PositiveF64; + /// + /// // A cuboid of size 1x2x3, touching the origin in the first octant. + /// let cuboid = Manifold::new_cuboid(1u8, 2u16, 3u32, false); + /// + /// // A cube of size 1.5x1.5x1.5 with its center at (0, 0, 0). + /// let cube_edge_length: PositiveF64 = 1.5.try_into().unwrap(); + /// let cube = Manifold::new_cuboid(cube_edge_length, cube_edge_length, cube_edge_length, true); + /// ``` + pub fn new_cuboid( + x_size: impl Into, + y_size: impl Into, + z_size: impl Into, + origin_at_center: bool, + ) -> Manifold { + unsafe { + Self::new_cuboid_unchecked( + x_size.into(), + y_size.into(), + z_size.into(), + origin_at_center, + ) + } + } -/// Constructs a 3D cuboid with the specified dimensions in the first octant of 3D space. -/// -/// By default, the cuboid's origin will be at the corner touching the coordinate system's origin -/// (i.e., the point (0, 0, 0)). If [origin_at_center] is set to `true`, the cuboid will be centered -/// at the origin, with its edges extending equally in all directions. -/// -/// # Returns -/// - If any dimension (`x_size`, `y_size`, or `z_size`) is negative, or if all dimensions are zero, -/// an empty `Manifold` will be returned. -/// - Otherwise, a `Manifold` representing a cuboid with the specified dimensions will be created. -/// -/// # Examples -/// ``` -/// use manifold3d::manifold::new_cuboid_unchecked; -/// -/// // A cuboid of size 1x2x3, touching the origin in the first octant. -/// let cuboid = new_cuboid_unchecked(1u8, 2u16, 3u32, false); -/// -/// // A cube of size 1.5x1.5x1.5 with its center at the coordinate system's origin. -/// let cube_edge_length = 1.5; -/// let cube = new_cuboid_unchecked(cube_edge_length, cube_edge_length, cube_edge_length, true); -/// ``` -pub fn new_cuboid_unchecked( - x_size: impl Into, - y_size: impl Into, - z_size: impl Into, - origin_at_center: bool, -) -> Manifold { - let manifold_ptr = unsafe { manifold_alloc_manifold() }; - unsafe { - manifold_cube( - manifold_ptr as *mut c_void, - x_size.into(), - y_size.into(), - z_size.into(), - origin_at_center as c_int, - ) - }; + /// Constructs a 3D cuboid with the specified dimensions in the first octant of 3D space. + /// + /// By default, the cuboid's origin will be at the corner touching the coordinate system's origin + /// (i.e., the point (0, 0, 0)). If [origin_at_center] is set to `true`, the cuboid will be centered + /// at the origin, with its edges extending equally in all directions. + /// + /// # Returns + /// - If any dimension (`x_size`, `y_size`, or `z_size`) is negative, or if all dimensions are zero, + /// an empty `Manifold` will be returned. + /// - Otherwise, a `Manifold` representing a cuboid with the specified dimensions will be created. + /// + /// # Examples + /// ``` + /// use manifold3d::Manifold; + /// + /// // A cuboid of size 1x2x3, touching the origin in the first octant. + /// let cuboid = unsafe { Manifold::new_cuboid_unchecked(1u8, 2u16, 3u32, false) }; + /// + /// // A cube of size 1.5x1.5x1.5 with its center at the coordinate system's origin. + /// let cube_edge_length = 1.5; + /// let cube = unsafe { + /// Manifold::new_cuboid_unchecked(cube_edge_length, cube_edge_length, cube_edge_length, true) + /// }; + /// ``` + pub unsafe fn new_cuboid_unchecked( + x_size: impl Into, + y_size: impl Into, + z_size: impl Into, + origin_at_center: bool, + ) -> Manifold { + let manifold_ptr = unsafe { manifold_alloc_manifold() }; + unsafe { + manifold_cube( + manifold_ptr as *mut c_void, + x_size.into(), + y_size.into(), + z_size.into(), + origin_at_center as c_int, + ) + }; - Manifold(manifold_ptr) -} + Manifold(manifold_ptr) + } -/// Constructs a 3D cuboid with the specified dimensions in the first octant of 3D space. -/// -/// By default, the cuboid's origin will be at the corner touching the coordinate system's origin -/// (i.e., the point (0, 0, 0)). If [origin_at_center] is set to `true`, the cuboid will be centered -/// at the origin, with its edges extending equally in all directions. -/// -/// # Returns -/// - If any dimension (`x_size`, `y_size`, or `z_size`) is negative, or if all dimensions are zero, -/// an empty `Manifold` will be returned. -/// - Otherwise, a `Manifold` representing a cuboid with the specified dimensions will be created. -/// -/// # Examples -/// ``` -/// use manifold3d::manifold::{new_cuboid_from_vec_unchecked, new_cuboid_unchecked}; -/// use manifold3d::types::Vec3; -/// -/// // A cuboid of size 1x2x3, touching the origin in the first octant. -/// let cuboid = new_cuboid_from_vec_unchecked( -/// Vec3 { -/// x: 1.0, -/// y: 2.0, -/// z: 3.0, -/// }, -/// false, -/// ); -/// -/// // A cube of size 1.5x1.5x1.5 with its center at (0, 0, 0). -/// let cube_edge_length = 1.5; -/// let cube = new_cuboid_from_vec_unchecked( -/// Vec3 { -/// x: cube_edge_length, -/// y: cube_edge_length, -/// z: cube_edge_length, -/// }, -/// true, -/// ); -/// ``` -pub fn new_cuboid_from_vec_unchecked(size: impl Into, origin_at_center: bool) -> Manifold { - let size = size.into(); - new_cuboid_unchecked(size.x, size.y, size.z, origin_at_center) -} + /// Constructs a 3D cuboid with the specified dimensions in the first octant of 3D space. + /// + /// By default, the cuboid's origin will be at the corner touching the coordinate system's origin + /// (i.e., the point (0, 0, 0)). If [origin_at_center] is set to `true`, the cuboid will be centered + /// at the origin, with its edges extending equally in all directions. + /// + /// # Returns + /// - If any dimension (`x_size`, `y_size`, or `z_size`) is negative, or if all dimensions are zero, + /// an empty `Manifold` will be returned. + /// - Otherwise, a `Manifold` representing a cuboid with the specified dimensions will be created. + /// + /// # Examples + /// ``` + /// use manifold3d::Manifold; + /// use manifold3d::Vec3; + /// + /// // A cuboid of size 1x2x3, touching the origin in the first octant. + /// let cuboid = unsafe { + /// Manifold::new_cuboid_from_vec_unchecked( + /// Vec3 { + /// x: 1.0, + /// y: 2.0, + /// z: 3.0, + /// }, + /// false, + /// ) + /// }; + /// + /// // A cube of size 1.5x1.5x1.5 with its center at (0, 0, 0). + /// let cube_edge_length = 1.5; + /// let cube = unsafe { + /// Manifold::new_cuboid_from_vec_unchecked( + /// Vec3 { + /// x: cube_edge_length, + /// y: cube_edge_length, + /// z: cube_edge_length, + /// }, + /// true, + /// ) + /// }; + /// ``` + pub unsafe fn new_cuboid_from_vec_unchecked( + size: impl Into, + origin_at_center: bool, + ) -> Manifold { + let size = size.into(); + Self::new_cuboid_unchecked(size.x, size.y, size.z, origin_at_center) + } -pub fn new_cylinder( - height: impl Into, - bottom_radius: impl Into, - top_radius: Option>, - circular_segments: Option>, - origin_at_center: bool, -) -> Manifold { - let bottom_radius = bottom_radius.into(); - // Set top radius = bottom radius if none is set - let top_radius = top_radius.map_or(bottom_radius, |t| t.into()); - // 0 segments = usage of static quality defaults - let circular_segments = circular_segments.map_or(0, |c| c.into().get()); - new_cylinder_unchecked( - height.into(), - bottom_radius, - top_radius, - circular_segments, - origin_at_center, - ) -} + pub fn new_cylinder( + height: impl Into, + bottom_radius: impl Into, + top_radius: Option>, + circular_segments: Option>, + origin_at_center: bool, + ) -> Manifold { + let bottom_radius = bottom_radius.into(); + // Set top radius = bottom radius if none is set + let top_radius = top_radius.map_or(bottom_radius, |t| t.into()); + // 0 segments triggers use of static quality defaults + let circular_segments = circular_segments.map_or(0, |c| c.into().get()); + unsafe { + Self::new_cylinder_unchecked( + height.into(), + bottom_radius, + top_radius, + circular_segments, + origin_at_center, + ) + } + } -pub fn new_cylinder_unchecked( - height: impl Into, - bottom_radius: impl Into, - top_radius: impl Into, - circular_segments: impl Into, - origin_at_center: bool, -) -> Manifold { - let manifold_ptr = unsafe { manifold_alloc_manifold() }; - unsafe { - manifold_cylinder( - manifold_ptr as *mut c_void, - height.into(), - bottom_radius.into(), - top_radius.into(), - circular_segments.into(), - origin_at_center as c_int, - ) - }; - Manifold(manifold_ptr) -} + pub unsafe fn new_cylinder_unchecked( + height: impl Into, + bottom_radius: impl Into, + top_radius: impl Into, + circular_segments: impl Into, + origin_at_center: bool, + ) -> Manifold { + let manifold_ptr = unsafe { + manifold_cylinder( + manifold_alloc_manifold() as *mut c_void, + height.into(), + bottom_radius.into().into(), + top_radius.into(), + circular_segments.into(), + origin_at_center as c_int, + ) + }; + check_error(Manifold::from_ptr(manifold_ptr)).unwrap() + } -pub fn new_sphere( - radius: impl Into, - circular_segments: Option>, -) -> Manifold { - // 0 segments = usage of static quality defaults - let circular_segments = circular_segments.map_or(0, |c| c.into().get()); - new_sphere_unchecked(radius.into(), circular_segments) -} + pub fn new_sphere( + radius: impl Into, + circular_segments: Option>, + ) -> Manifold { + // 0 segments triggers use of static quality defaults + let circular_segments = circular_segments.map_or(0, |c| c.into().get()); + unsafe { Self::new_sphere_unchecked(radius.into(), circular_segments) }.unwrap() + } -pub fn new_sphere_unchecked(radius: impl Into, circular_segments: impl Into) -> Manifold { - let manifold_ptr = unsafe { manifold_alloc_manifold() }; - unsafe { - manifold_sphere( - manifold_ptr as *mut c_void, - radius.into(), - circular_segments.into() as c_int, - ) - }; - Manifold(manifold_ptr) -} + pub unsafe fn new_sphere_unchecked( + radius: impl Into, + circular_segments: impl Into, + ) -> Result { + let manifold_ptr = unsafe { + manifold_sphere( + manifold_alloc_manifold() as *mut c_void, + radius.into(), + circular_segments.into() as c_int, + ) + }; + check_error(Manifold::from_ptr(manifold_ptr)) + } -pub fn new_empty() -> Manifold { - let manifold_ptr = unsafe { manifold_alloc_manifold() }; - unsafe { manifold_empty(manifold_ptr as *mut c_void) }; - Manifold(manifold_ptr) -} + pub fn new_empty() -> Manifold { + Manifold::from_ptr(unsafe { manifold_empty(manifold_alloc_manifold() as *mut c_void) }) + } -pub fn new_from_mesh_gl(mesh_gl: &MeshGL) -> Manifold { - Manifold::from(mesh_gl) -} + pub fn from_mesh_gl(mesh_gl: &MeshGL) -> Result { + Manifold::try_from(mesh_gl) + } -pub(crate) fn from_ptr(ptr: *mut ManifoldManifold) -> Manifold { - Manifold(ptr) -} + pub(crate) fn from_ptr(ptr: *mut ManifoldManifold) -> Manifold { + Manifold(ptr) + } + + pub(crate) fn ptr(&self) -> *mut ManifoldManifold { + self.0 + } -impl Manifold { pub fn is_empty(&self) -> bool { unsafe { manifold_is_empty(self.0) == 1 } } @@ -232,31 +248,33 @@ impl Manifold { } pub fn get_mesh(&self) -> MeshGL { - let mesh_gl_ptr = unsafe { manifold_alloc_meshgl() }; - unsafe { manifold_get_meshgl(mesh_gl_ptr as *mut c_void, self.0) }; - mesh_gl::from_ptr(mesh_gl_ptr) + let mesh_gl_ptr = + unsafe { manifold_get_meshgl(manifold_alloc_meshgl() as *mut c_void, self.0) }; + MeshGL::from_ptr(mesh_gl_ptr) } pub fn bounding_box(&self) -> BoundingBox { - let bounding_box_ptr = unsafe { manifold_alloc_box() }; - unsafe { manifold_bounding_box(bounding_box_ptr as *mut c_void, self.0) }; - bounding_box::from_ptr(bounding_box_ptr) + let bounding_box_ptr = + unsafe { manifold_bounding_box(manifold_alloc_box() as *mut c_void, self.0) }; + BoundingBox::from_ptr(bounding_box_ptr) } } -impl From<&'_ MeshGL> for Manifold { - fn from(value: &MeshGL) -> Self { - let manifold_ptr = unsafe { manifold_alloc_manifold() }; - unsafe { manifold_of_meshgl(manifold_ptr as *mut c_void, value.ptr()) }; - Manifold(manifold_ptr) +impl TryFrom<&'_ MeshGL> for Manifold { + type Error = Error; + + fn try_from(value: &'_ MeshGL) -> Result { + let manifold_ptr = + unsafe { manifold_of_meshgl(manifold_alloc_manifold() as *mut c_void, value.ptr()) }; + check_error(Manifold::from_ptr(manifold_ptr)) } } impl Clone for Manifold { fn clone(&self) -> Self { - let manifold_ptr = unsafe { manifold_alloc_manifold() }; - unsafe { manifold_copy(manifold_ptr as *mut c_void, self.0) }; - Manifold(manifold_ptr) + let manifold_ptr = + unsafe { manifold_copy(manifold_alloc_manifold() as *mut c_void, self.0) }; + Manifold::from_ptr(manifold_ptr) } } diff --git a/src/mesh_gl.rs b/src/mesh_gl.rs index ffce81c..a88b799 100644 --- a/src/mesh_gl.rs +++ b/src/mesh_gl.rs @@ -1,5 +1,5 @@ use crate::manifold::Manifold; -use manifold_sys::{ +use manifold3d_sys::{ manifold_alloc_manifold, manifold_alloc_meshgl, manifold_delete_meshgl, manifold_meshgl_copy, manifold_meshgl_face_id_length, manifold_meshgl_merge, manifold_meshgl_merge_length, manifold_meshgl_num_prop, manifold_meshgl_num_tri, manifold_meshgl_num_vert, @@ -11,18 +11,17 @@ use manifold_sys::{ use std::alloc::{alloc, Layout}; use std::collections::HashMap; use std::os::raw::c_void; -use crate::manifold; pub type HalfedgeIndex = usize; pub type Smoothness = f64; pub struct MeshGL(*mut ManifoldMeshGL); -pub(crate) fn from_ptr(ptr: *mut ManifoldMeshGL) -> MeshGL { - MeshGL(ptr) -} - impl MeshGL { + pub(crate) fn from_ptr(ptr: *mut ManifoldMeshGL) -> MeshGL { + MeshGL(ptr) + } + pub(crate) fn ptr(&self) -> *mut ManifoldMeshGL { self.0 } @@ -56,7 +55,7 @@ impl MeshGL { length, ) }; - manifold::from_ptr(manifold_ptr) + Manifold::from_ptr(manifold_ptr) } pub fn properties_per_vertex_count(&self) -> i32 { @@ -115,16 +114,16 @@ impl MeshGL { } } -impl Drop for MeshGL { - fn drop(&mut self) { - unsafe { manifold_delete_meshgl(self.0) } - } -} - impl Clone for MeshGL { fn clone(&self) -> Self { - let mesh_gl_ptr = unsafe { manifold_alloc_meshgl() }; - unsafe { manifold_meshgl_copy(mesh_gl_ptr as *mut c_void, self.0) }; + let mesh_gl_ptr = + unsafe { manifold_meshgl_copy(manifold_alloc_meshgl() as *mut c_void, self.0) }; MeshGL(mesh_gl_ptr) } } + +impl Drop for MeshGL { + fn drop(&mut self) { + unsafe { manifold_delete_meshgl(self.0) } + } +} diff --git a/src/polygons.rs b/src/polygons.rs index ff9c558..1ee23d5 100644 --- a/src/polygons.rs +++ b/src/polygons.rs @@ -1,11 +1,11 @@ +use crate::error::{check_error, Error}; use crate::manifold::Manifold; use crate::simple_polygon::SimplePolygon; -use crate::types::{PositiveF64, PositiveI32, Vec2}; -use crate::{manifold, simple_polygon}; -use manifold_sys::{ +use crate::types::{NormalizedAngle, PositiveF64, PositiveI32, Vec2}; +use manifold3d_sys::{ manifold_alloc_manifold, manifold_alloc_polygons, manifold_alloc_simple_polygon, - manifold_extrude, manifold_polygons, manifold_polygons_get_simple, manifold_polygons_length, - ManifoldPolygons, + manifold_delete_polygons, manifold_extrude, manifold_polygons, manifold_polygons_get_simple, + manifold_polygons_length, manifold_revolve, ManifoldPolygons, }; use std::os::raw::c_void; @@ -18,10 +18,9 @@ pub fn new_from_simple_polygons(simple_polygons: Vec) -> Polygons .map(|p| p.ptr()) .collect::>(); - let polygons_ptr = unsafe { manifold_alloc_polygons() }; - unsafe { + let polygons_ptr = unsafe { manifold_polygons( - polygons_ptr as *mut c_void, + manifold_alloc_polygons() as *mut c_void, simple_polygons.as_mut_ptr(), simple_polygons_length, ) @@ -30,37 +29,41 @@ pub fn new_from_simple_polygons(simple_polygons: Vec) -> Polygons } impl Polygons { - pub fn simple_polygons_count(&self) -> usize { + pub fn count(&self) -> usize { unsafe { manifold_polygons_length(self.0) } } - pub fn get_simple_polygon(&self, index: impl Into) -> Option { + pub fn get(&self, index: impl Into) -> Option { let index: i32 = index.into().get(); - if index as i64 >= self.simple_polygons_count() as i64 { + if index as i64 >= self.count() as i64 { return None; } - let simple_polygon_ptr = unsafe { manifold_alloc_simple_polygon() }; - unsafe { manifold_polygons_get_simple(simple_polygon_ptr as *mut c_void, self.0, index) }; - Some(simple_polygon::from_ptr(simple_polygon_ptr)) + let simple_polygon_ptr = unsafe { + manifold_polygons_get_simple( + manifold_alloc_simple_polygon() as *mut c_void, + self.0, + index, + ) + }; + Some(SimplePolygon::from_ptr(simple_polygon_ptr)) } pub fn extrude( &self, height: impl Into, - division_count: Option>, - twist_degrees: Option, + division_count: impl Into, + twist_degrees: f64, top_scaling: Option>, - ) -> Manifold { + ) -> Result { let height = height.into().get(); - let division_count = division_count.map(|d| d.into().get()).unwrap_or(0); - let twist_degrees = twist_degrees.unwrap_or(0.0); + let division_count: i32 = division_count.into().into(); let top_scaling = top_scaling .map(|v| v.into()) .unwrap_or(Vec2 { x: 1.0, y: 1.0 }); let manifold_ptr = unsafe { manifold_alloc_manifold() }; - unsafe { + let manifold_ptr = unsafe { manifold_extrude( manifold_ptr as *mut c_void, self.0, @@ -71,6 +74,33 @@ impl Polygons { top_scaling.y, ) }; - manifold::from_ptr(manifold_ptr) + check_error(Manifold::from_ptr(manifold_ptr)) + } + + pub fn revolve( + &self, + circular_segments: Option>, + revolve_degrees: Option>, + ) -> Result { + // 0 segments triggers use of static quality defaults + let circular_segments = circular_segments.map(|c| c.into().get()).unwrap_or(0); + let revolve_degrees = revolve_degrees + .map(|a| a.into().as_degrees()) + .unwrap_or(360.0); + let manifold_ptr = unsafe { + manifold_revolve( + manifold_alloc_manifold() as *mut c_void, + self.0, + circular_segments, + revolve_degrees, + ) + }; + check_error(Manifold::from_ptr(manifold_ptr)) + } +} + +impl Drop for Polygons { + fn drop(&mut self) { + unsafe { manifold_delete_polygons(self.0) } } } diff --git a/src/quality.rs b/src/quality.rs index 6a0729d..f438348 100644 --- a/src/quality.rs +++ b/src/quality.rs @@ -1,12 +1,12 @@ -use crate::types::{Angle, PositiveF64, PositiveI32}; -use manifold_sys::{ +use crate::types::{NormalizedAngle, PositiveF64, PositiveI32}; +use manifold3d_sys::{ manifold_get_circular_segments, manifold_reset_to_circular_defaults, manifold_set_circular_segments, manifold_set_min_circular_angle, manifold_set_min_circular_edge_length, }; use std::num::NonZeroI32; -pub fn set_min_circular_angle(angle: Angle) { +pub fn set_min_circular_angle(angle: NormalizedAngle) { unsafe { manifold_set_min_circular_angle(angle.as_degrees()) } } @@ -45,7 +45,7 @@ pub fn reset_to_circular_defaults() { #[cfg(test)] mod tests { use crate::quality::*; - use crate::types::{Angle, PositiveF64, PositiveI32}; + use crate::types::{NormalizedAngle, PositiveF64, PositiveI32}; #[test] fn test_set_and_get_circular_segments() { @@ -59,7 +59,7 @@ mod tests { #[test] fn test_set_min_circular_angle_and_edge_length_and_get_circular_segments() { reset_to_circular_defaults(); - set_min_circular_angle(Angle::from_positive_num(PositiveI32::new(365).unwrap())); + set_min_circular_angle(NormalizedAngle::from_degrees(365.0)); set_min_circular_edge_length(PositiveF64::new(1.0).unwrap()); let result = get_circular_segments(PositiveF64::new(10.0).unwrap()); assert_eq!(result.get(), 64); diff --git a/src/simple_polygon.rs b/src/simple_polygon.rs index 43c76c6..1bc3fc7 100644 --- a/src/simple_polygon.rs +++ b/src/simple_polygon.rs @@ -1,35 +1,33 @@ use crate::types::{Point2, PositiveI32}; -use manifold_sys::{ - manifold_alloc_simple_polygon, manifold_simple_polygon, manifold_simple_polygon_get_point, - manifold_simple_polygon_length, ManifoldSimplePolygon, ManifoldVec2, -}; +use manifold3d_sys::{manifold_alloc_simple_polygon, manifold_delete_simple_polygon, manifold_simple_polygon, manifold_simple_polygon_get_point, manifold_simple_polygon_length, ManifoldSimplePolygon, ManifoldVec2}; use std::os::raw::{c_int, c_void}; pub struct SimplePolygon(*mut ManifoldSimplePolygon); -pub fn new_from_points(points: Vec>) -> SimplePolygon { - let mut points = points.into_iter().map(|x| x.into()).collect::>(); - let points_length = points.len(); - - let polygon_ptr = unsafe { manifold_alloc_simple_polygon() }; - unsafe { - manifold_simple_polygon( - polygon_ptr as *mut c_void, - points.as_mut_ptr(), - points_length, - ) - }; - SimplePolygon(polygon_ptr) -} +impl SimplePolygon { + pub fn new_from_points(points: Vec>) -> SimplePolygon { + let mut points = points.into_iter().map(|x| x.into()).collect::>(); + let points_length = points.len(); -pub(crate) fn from_ptr(ptr: *mut ManifoldSimplePolygon) -> SimplePolygon { - SimplePolygon(ptr) -} + let polygon_ptr = unsafe { manifold_alloc_simple_polygon() }; + unsafe { + manifold_simple_polygon( + polygon_ptr as *mut c_void, + points.as_mut_ptr(), + points_length, + ) + }; + SimplePolygon(polygon_ptr) + } + + pub(crate) fn from_ptr(ptr: *mut ManifoldSimplePolygon) -> SimplePolygon { + SimplePolygon(ptr) + } -impl SimplePolygon { pub fn point_count(&self) -> usize { unsafe { manifold_simple_polygon_length(self.0) } } + pub fn get_point(&self, index: impl Into) -> Option { let index: i32 = index.into().get(); if index as i64 >= self.point_count() as i64 { @@ -43,3 +41,9 @@ impl SimplePolygon { self.0 } } + +impl Drop for SimplePolygon { + fn drop(&mut self) { + unsafe { manifold_delete_simple_polygon(self.0) } + } +} \ No newline at end of file diff --git a/src/types.rs b/src/types.rs index 000388f..5faf1f6 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,4 +1,5 @@ -use manifold_sys::{ManifoldVec2, ManifoldVec3}; +use manifold3d_sys::{ManifoldVec2, ManifoldVec3}; +use std::ops::{Add, AddAssign, Sub, SubAssign}; use thiserror::Error; #[derive(Error, Debug)] @@ -158,6 +159,7 @@ impl PositiveNum { Ok(PositiveNum(value)) } + #[inline(always)] fn is_valid(value: T) -> bool { value > T::zero() } @@ -216,31 +218,65 @@ impl_into_primitive!(PositiveF64, f64); impl_positive_num_from!(PositiveF64, f64, (u8, u16, u32)); impl_positive_num_try_from!(PositiveF64, f64, (i8, i16, i32, f32, f64)); +/// Represents an angle, measured in degrees, constrained to the range [-360.0, 360.0]. #[derive(Debug, Clone, Copy, PartialEq)] -pub struct Angle(f64); +pub struct NormalizedAngle(f64); -impl Angle { - pub fn from_positive_num(value: PositiveNum) -> Self +impl NormalizedAngle { + pub fn from_degrees(value: T) -> Self where - T: num_traits::Num + PartialOrd + Copy, - f64: From, + T: Into, { - Angle(f64::from(value.get()) % 360.0) + NormalizedAngle(Self::normalize(value)) } - pub fn from_unchecked(value: T) -> Self - where - f64: From, - { - let mut value = f64::from(value) % 360.0; + pub fn as_degrees(&self) -> f64 { + self.0 + } + + fn normalize(value: impl Into) -> f64 { + let mut value = value.into() % 360.0; if value < 0.0 { value = 360.0 - value; } + value + } +} - Angle(value) +impl From> for NormalizedAngle +where + T: num_traits::Num + PartialOrd + Copy, + f64: From, +{ + fn from(value: PositiveNum) -> Self { + NormalizedAngle(f64::from(value.get()) % 360.0) } +} - pub fn as_degrees(&self) -> f64 { - self.0 +impl Add for NormalizedAngle { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self::from_degrees(self.0 + rhs.0) + } +} + +impl AddAssign for NormalizedAngle { + fn add_assign(&mut self, rhs: Self) { + self.0 = Self::normalize(self.0 + rhs.0); + } +} + +impl Sub for NormalizedAngle { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + Self::from_degrees(self.0 - rhs.0) + } +} + +impl SubAssign for NormalizedAngle { + fn sub_assign(&mut self, rhs: Self) { + self.0 = Self::normalize(self.0 - rhs.0); } }