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}