Skip to main content

manifold_csg/
rect.rs

1//! 2D axis-aligned bounding rectangle wrapping `ManifoldRect`.
2
3use manifold_csg_sys::*;
4
5/// A 2D axis-aligned bounding rectangle.
6///
7/// Wraps the manifold3d `Rect` type, providing spatial queries (containment,
8/// overlap), combining operations (union, expand), and transforms.
9///
10/// Obtain a `Rect` from [`CrossSection::bounds`](crate::CrossSection::bounds),
11/// or construct one directly from min/max coordinates.
12pub struct Rect {
13    pub(crate) ptr: *mut ManifoldRect,
14}
15
16// SAFETY: Rect owns its C-allocated ManifoldRect exclusively. The C++ Rect
17// type is a simple value type (two vec2s) with no shared/thread-local state,
18// so transferring ownership across threads is safe.
19unsafe impl Send for Rect {}
20
21// SAFETY: Rect is a simple value type (two vec2s) with no lazy evaluation
22// or mutable internal state. Concurrent read access is safe.
23unsafe impl Sync for Rect {}
24
25impl Clone for Rect {
26    fn clone(&self) -> Self {
27        Self::new(self.min(), self.max())
28    }
29}
30
31impl Drop for Rect {
32    fn drop(&mut self) {
33        if !self.ptr.is_null() {
34            // SAFETY: self.ptr was allocated by manifold_alloc_rect.
35            unsafe { manifold_delete_rect(self.ptr) };
36        }
37    }
38}
39
40impl std::fmt::Debug for Rect {
41    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42        f.debug_struct("Rect")
43            .field("min", &self.min())
44            .field("max", &self.max())
45            .finish()
46    }
47}
48
49impl Rect {
50    /// Create a rectangle from min and max corners.
51    #[must_use]
52    pub fn new(min: [f64; 2], max: [f64; 2]) -> Self {
53        // SAFETY: manifold_alloc_rect returns a valid handle.
54        let ptr = unsafe { manifold_alloc_rect() };
55        // SAFETY: ptr is valid from alloc.
56        unsafe {
57            manifold_rect(ptr, min[0], min[1], max[0], max[1]);
58        }
59        Self { ptr }
60    }
61
62    /// Construct from a raw `ManifoldRect` pointer (takes ownership).
63    pub(crate) fn from_ptr(ptr: *mut ManifoldRect) -> Self {
64        Self { ptr }
65    }
66
67    /// Minimum corner `[x, y]`.
68    #[must_use]
69    pub fn min(&self) -> [f64; 2] {
70        // SAFETY: self.ptr is valid (invariant).
71        let v = unsafe { manifold_rect_min(self.ptr) };
72        [v.x, v.y]
73    }
74
75    /// Maximum corner `[x, y]`.
76    #[must_use]
77    pub fn max(&self) -> [f64; 2] {
78        // SAFETY: self.ptr is valid (invariant).
79        let v = unsafe { manifold_rect_max(self.ptr) };
80        [v.x, v.y]
81    }
82
83    /// Dimensions `[width, height]`.
84    #[must_use]
85    pub fn dimensions(&self) -> [f64; 2] {
86        // SAFETY: self.ptr is valid (invariant).
87        let v = unsafe { manifold_rect_dimensions(self.ptr) };
88        [v.x, v.y]
89    }
90
91    /// Center point `[x, y]`.
92    #[must_use]
93    pub fn center(&self) -> [f64; 2] {
94        // SAFETY: self.ptr is valid (invariant).
95        let v = unsafe { manifold_rect_center(self.ptr) };
96        [v.x, v.y]
97    }
98
99    /// The maximum distance from the center to any corner (half-diagonal).
100    #[must_use]
101    pub fn scale(&self) -> f64 {
102        // SAFETY: self.ptr is valid (invariant).
103        unsafe { manifold_rect_scale(self.ptr) }
104    }
105
106    /// Whether the rectangle is empty (zero area).
107    #[must_use]
108    pub fn is_empty(&self) -> bool {
109        // SAFETY: self.ptr is valid (invariant).
110        unsafe { manifold_rect_is_empty(self.ptr) != 0 }
111    }
112
113    /// Whether the rectangle has finite (non-infinite, non-NaN) bounds.
114    #[must_use]
115    pub fn is_finite(&self) -> bool {
116        // SAFETY: self.ptr is valid (invariant).
117        unsafe { manifold_rect_is_finite(self.ptr) != 0 }
118    }
119
120    /// Whether the rectangle fully contains the given point.
121    #[must_use]
122    pub fn contains_point(&self, point: [f64; 2]) -> bool {
123        // SAFETY: self.ptr is valid (invariant).
124        unsafe { manifold_rect_contains_pt(self.ptr, point[0], point[1]) != 0 }
125    }
126
127    /// Whether the rectangle fully contains another rectangle.
128    #[must_use]
129    pub fn contains_rect(&self, other: &Rect) -> bool {
130        // SAFETY: both pointers are valid (invariant).
131        unsafe { manifold_rect_contains_rect(self.ptr, other.ptr) != 0 }
132    }
133
134    /// Whether this rectangle overlaps with another rectangle.
135    #[must_use]
136    pub fn overlaps_rect(&self, other: &Rect) -> bool {
137        // SAFETY: both pointers are valid (invariant).
138        unsafe { manifold_rect_does_overlap_rect(self.ptr, other.ptr) != 0 }
139    }
140
141    /// Expand this rectangle to include the given point.
142    pub fn include_point(&mut self, point: [f64; 2]) {
143        // SAFETY: self.ptr is valid (invariant).
144        unsafe { manifold_rect_include_pt(self.ptr, point[0], point[1]) };
145    }
146
147    /// Return the union (smallest rectangle containing both) of two rectangles.
148    #[must_use]
149    pub fn union(&self, other: &Rect) -> Rect {
150        // SAFETY: manifold_alloc_rect returns a valid handle.
151        let ptr = unsafe { manifold_alloc_rect() };
152        // SAFETY: all three pointers are valid.
153        unsafe { manifold_rect_union(ptr, self.ptr, other.ptr) };
154        Rect { ptr }
155    }
156
157    /// Apply a 3x2 affine transformation matrix (column-major).
158    ///
159    /// Layout: `[x1, y1, x2, y2, x3, y3]` where columns are:
160    /// - col1 `(x1,y1)` — X basis vector
161    /// - col2 `(x2,y2)` — Y basis vector
162    /// - col3 `(x3,y3)` — translation
163    #[must_use]
164    pub fn transform(&self, m: &[f64; 6]) -> Rect {
165        // SAFETY: manifold_alloc_rect returns a valid handle.
166        let ptr = unsafe { manifold_alloc_rect() };
167        // SAFETY: all pointers are valid.
168        unsafe {
169            manifold_rect_transform(ptr, self.ptr, m[0], m[1], m[2], m[3], m[4], m[5]);
170        }
171        Rect { ptr }
172    }
173
174    /// Translate the rectangle by `[x, y]`.
175    #[must_use]
176    pub fn translate(&self, v: [f64; 2]) -> Rect {
177        // SAFETY: manifold_alloc_rect returns a valid handle.
178        let ptr = unsafe { manifold_alloc_rect() };
179        // SAFETY: all pointers are valid.
180        unsafe { manifold_rect_translate(ptr, self.ptr, v[0], v[1]) };
181        Rect { ptr }
182    }
183
184    /// Scale the rectangle by `[x, y]` factors.
185    #[must_use]
186    pub fn mul(&self, v: [f64; 2]) -> Rect {
187        // SAFETY: manifold_alloc_rect returns a valid handle.
188        let ptr = unsafe { manifold_alloc_rect() };
189        // SAFETY: all pointers are valid.
190        unsafe { manifold_rect_mul(ptr, self.ptr, v[0], v[1]) };
191        Rect { ptr }
192    }
193}