1use core::marker::PhantomData;
4use core::ptr::NonNull;
5
6use crate::error::{Error, Result};
7use crate::{Rect, Ring, RingRef};
8
9macro_rules! impl_poly_methods {
10 ($get_ptr:expr, $life:lifetime) => {
11 #[inline]
12 pub fn rect(&self) -> Rect {
13 let ptr = $get_ptr(self);
14 let r = unsafe { tg_geom_sys::tg_poly_rect(ptr) };
15 r.into()
16 }
17
18 #[inline]
19 pub fn num_holes(&self) -> usize {
20 let ptr = $get_ptr(self);
21 unsafe { tg_geom_sys::tg_poly_num_holes(ptr) as usize }
22 }
23
24 #[inline]
25 pub fn clockwise(&self) -> bool {
26 let ptr = $get_ptr(self);
27 unsafe { tg_geom_sys::tg_poly_clockwise(ptr) }
28 }
29
30 #[inline]
31 pub fn exterior(&self) -> RingRef<$life> {
32 let ptr = $get_ptr(self);
33 let ptr = unsafe { tg_geom_sys::tg_poly_exterior(ptr) };
34 unsafe { RingRef::from_raw(ptr).unwrap() }
35 }
36
37 #[inline]
38 pub fn hole_at(&self, index: usize) -> Option<RingRef<$life>> {
39 if index >= self.num_holes() {
40 None
41 } else {
42 let ptr = $get_ptr(self);
43 let ptr = unsafe { tg_geom_sys::tg_poly_hole_at(ptr, index as libc::c_int) };
44 unsafe { RingRef::from_raw(ptr) }
45 }
46 }
47 };
48}
49
50pub struct Poly {
52 ptr: NonNull<tg_geom_sys::tg_poly>,
53}
54
55impl Poly {
56 impl_poly_methods!(|s: &Self| s.ptr.as_ptr(), '_);
57
58 pub fn new(exterior: &Ring, holes: &[&Ring]) -> Result<Self> {
59 let hole_ptrs: Vec<*const tg_geom_sys::tg_ring> =
60 holes.iter().map(|r| r.as_ptr()).collect();
61
62 let ptr = unsafe {
63 tg_geom_sys::tg_poly_new(
64 exterior.as_ptr(),
65 hole_ptrs.as_ptr(),
66 holes.len() as libc::c_int,
67 )
68 };
69 NonNull::new(ptr)
70 .map(|ptr| Self { ptr })
71 .ok_or(Error::OutOfMemory)
72 }
73
74 pub fn new_simple(exterior: &Ring) -> Result<Self> {
75 let ptr = unsafe { tg_geom_sys::tg_poly_new(exterior.as_ptr(), core::ptr::null(), 0) };
76 NonNull::new(ptr)
77 .map(|ptr| Self { ptr })
78 .ok_or(Error::OutOfMemory)
79 }
80
81 pub unsafe fn from_raw(ptr: *mut tg_geom_sys::tg_poly) -> Option<Self> {
84 NonNull::new(ptr).map(|ptr| Self { ptr })
85 }
86
87 #[inline]
88 pub fn as_ptr(&self) -> *const tg_geom_sys::tg_poly {
89 self.ptr.as_ptr()
90 }
91
92 pub fn into_raw(self) -> *mut tg_geom_sys::tg_poly {
93 let ptr = self.ptr.as_ptr();
94 core::mem::forget(self);
95 ptr
96 }
97
98 pub fn copy(&self) -> Result<Self> {
99 let ptr = unsafe { tg_geom_sys::tg_poly_copy(self.ptr.as_ptr()) };
100 NonNull::new(ptr)
101 .map(|ptr| Self { ptr })
102 .ok_or(Error::CopyFailed)
103 }
104
105 pub fn clone_ref(&self) -> Result<Self> {
106 let ptr = unsafe { tg_geom_sys::tg_poly_clone(self.ptr.as_ptr()) };
107 NonNull::new(ptr)
108 .map(|ptr| Self { ptr })
109 .ok_or(Error::CopyFailed)
110 }
111
112 pub fn memsize(&self) -> usize {
113 unsafe { tg_geom_sys::tg_poly_memsize(self.ptr.as_ptr()) }
114 }
115
116 pub fn iter_holes(&self) -> impl Iterator<Item = RingRef<'_>> {
117 (0..self.num_holes()).map(move |i| self.hole_at(i).unwrap())
118 }
119}
120
121impl Drop for Poly {
122 fn drop(&mut self) {
123 unsafe { tg_geom_sys::tg_poly_free(self.ptr.as_ptr()) }
124 }
125}
126
127impl core::fmt::Debug for Poly {
128 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
129 f.debug_struct("Poly")
130 .field("num_holes", &self.num_holes())
131 .field("rect", &self.rect())
132 .field("clockwise", &self.clockwise())
133 .finish()
134 }
135}
136
137unsafe impl Send for Poly {}
138unsafe impl Sync for Poly {}
139
140#[derive(Clone, Copy)]
142pub struct PolyRef<'a> {
143 ptr: *const tg_geom_sys::tg_poly,
144 _marker: PhantomData<&'a ()>,
145}
146
147unsafe impl Send for PolyRef<'_> {}
148unsafe impl Sync for PolyRef<'_> {}
149
150impl<'a> PolyRef<'a> {
151 impl_poly_methods!(|s: &Self| s.ptr, 'a);
152
153 #[inline]
156 pub unsafe fn from_raw(ptr: *const tg_geom_sys::tg_poly) -> Option<Self> {
157 if ptr.is_null() {
158 None
159 } else {
160 Some(Self {
161 ptr,
162 _marker: PhantomData,
163 })
164 }
165 }
166
167 #[inline]
168 pub fn as_ptr(&self) -> *const tg_geom_sys::tg_poly {
169 self.ptr
170 }
171
172 pub fn to_owned(&self) -> Result<Poly> {
173 let ptr = unsafe { tg_geom_sys::tg_poly_copy(self.ptr) };
174 NonNull::new(ptr)
175 .map(|ptr| Poly { ptr })
176 .ok_or(Error::CopyFailed)
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183 use crate::Point;
184
185 fn p(x: f64, y: f64) -> Point {
186 Point::new(x, y)
187 }
188
189 fn r(min_x: f64, min_y: f64, max_x: f64, max_y: f64) -> Rect {
190 Rect::from_coords(min_x, min_y, max_x, max_y)
191 }
192
193 fn octagon() -> Vec<Point> {
194 vec![
195 p(3.0, 0.0),
196 p(7.0, 0.0),
197 p(10.0, 3.0),
198 p(10.0, 7.0),
199 p(7.0, 10.0),
200 p(3.0, 10.0),
201 p(0.0, 7.0),
202 p(0.0, 3.0),
203 p(3.0, 0.0),
204 ]
205 }
206
207 fn small_hole() -> Vec<Point> {
208 vec![
209 p(4.0, 4.0),
210 p(6.0, 4.0),
211 p(6.0, 6.0),
212 p(4.0, 6.0),
213 p(4.0, 4.0),
214 ]
215 }
216
217 fn rect_ring() -> Vec<Point> {
218 vec![
219 p(0.0, 0.0),
220 p(10.0, 0.0),
221 p(10.0, 10.0),
222 p(0.0, 10.0),
223 p(0.0, 0.0),
224 ]
225 }
226
227 #[test]
228 fn test_poly_rect() {
229 let exterior = Ring::new(&octagon()).unwrap();
230 let poly = Poly::new_simple(&exterior).unwrap();
231 assert_eq!(poly.rect(), r(0.0, 0.0, 10.0, 10.0));
232 }
233
234 #[test]
235 fn test_poly_rect_with_hole() {
236 let exterior = Ring::new(&octagon()).unwrap();
237 let hole = Ring::new(&small_hole()).unwrap();
238 let poly = Poly::new(&exterior, &[&hole]).unwrap();
239 assert_eq!(poly.rect(), r(0.0, 0.0, 10.0, 10.0));
240 }
241
242 #[test]
243 fn test_poly_exterior_holes() {
244 let exterior = Ring::new(&octagon()).unwrap();
245 let poly = Poly::new_simple(&exterior).unwrap();
246 assert_eq!(poly.num_holes(), 0);
247 assert_eq!(poly.exterior().num_points(), 9);
248 }
249
250 #[test]
251 fn test_poly_with_hole() {
252 let exterior = Ring::new(&octagon()).unwrap();
253 let hole = Ring::new(&small_hole()).unwrap();
254 let poly = Poly::new(&exterior, &[&hole]).unwrap();
255
256 assert_eq!(poly.num_holes(), 1);
257 let hole_ref = poly.hole_at(0).unwrap();
258 assert_eq!(hole_ref.num_points(), 5);
259 }
260
261 #[test]
262 fn test_poly_hole_at_bounds() {
263 let exterior = Ring::new(&octagon()).unwrap();
264 let hole = Ring::new(&small_hole()).unwrap();
265 let poly = Poly::new(&exterior, &[&hole]).unwrap();
266
267 assert!(poly.hole_at(0).is_some());
268 assert!(poly.hole_at(1).is_none());
269 assert!(poly.hole_at(100).is_none());
270 }
271
272 #[test]
273 fn test_poly_no_holes() {
274 let exterior = Ring::new(&rect_ring()).unwrap();
275 let poly = Poly::new_simple(&exterior).unwrap();
276 assert_eq!(poly.num_holes(), 0);
277 assert!(poly.hole_at(0).is_none());
278 }
279
280 #[test]
281 fn test_poly_clockwise() {
282 let ccw_exterior = Ring::new(&[
283 p(0.0, 0.0),
284 p(10.0, 0.0),
285 p(10.0, 10.0),
286 p(0.0, 10.0),
287 p(0.0, 0.0),
288 ])
289 .unwrap();
290 let poly_ccw = Poly::new_simple(&ccw_exterior).unwrap();
291 assert!(!poly_ccw.clockwise());
292
293 let cw_exterior = Ring::new(&[
294 p(0.0, 0.0),
295 p(0.0, 10.0),
296 p(10.0, 10.0),
297 p(10.0, 0.0),
298 p(0.0, 0.0),
299 ])
300 .unwrap();
301 let poly_cw = Poly::new_simple(&cw_exterior).unwrap();
302 assert!(poly_cw.clockwise());
303 }
304
305 #[test]
306 fn test_poly_copy() {
307 let exterior = Ring::new(&octagon()).unwrap();
308 let hole = Ring::new(&small_hole()).unwrap();
309 let poly = Poly::new(&exterior, &[&hole]).unwrap();
310
311 let copy = poly.copy().unwrap();
312 assert_eq!(poly.num_holes(), copy.num_holes());
313 assert_eq!(poly.rect(), copy.rect());
314 }
315
316 #[test]
317 fn test_poly_clone_ref() {
318 let exterior = Ring::new(&octagon()).unwrap();
319 let poly = Poly::new_simple(&exterior).unwrap();
320 let cloned = poly.clone_ref().unwrap();
321 assert_eq!(poly.num_holes(), cloned.num_holes());
322 }
323
324 #[test]
325 fn test_poly_memsize() {
326 let exterior = Ring::new(&octagon()).unwrap();
327 let poly = Poly::new_simple(&exterior).unwrap();
328 assert!(poly.memsize() > 0);
329 }
330
331 #[test]
332 fn test_poly_iter_holes() {
333 let exterior = Ring::new(&rect_ring()).unwrap();
334 let hole1 = Ring::new(&[
335 p(2.0, 2.0),
336 p(3.0, 2.0),
337 p(3.0, 3.0),
338 p(2.0, 3.0),
339 p(2.0, 2.0),
340 ])
341 .unwrap();
342 let hole2 = Ring::new(&[
343 p(6.0, 6.0),
344 p(7.0, 6.0),
345 p(7.0, 7.0),
346 p(6.0, 7.0),
347 p(6.0, 6.0),
348 ])
349 .unwrap();
350 let poly = Poly::new(&exterior, &[&hole1, &hole2]).unwrap();
351
352 let holes: Vec<RingRef<'_>> = poly.iter_holes().collect();
353 assert_eq!(holes.len(), 2);
354 }
355
356 #[test]
357 fn test_poly_debug() {
358 let exterior = Ring::new(&octagon()).unwrap();
359 let poly = Poly::new_simple(&exterior).unwrap();
360 let debug_str = format!("{poly:?}");
361 assert!(debug_str.contains("Poly"));
362 assert!(debug_str.contains("num_holes"));
363 }
364
365 #[test]
366 fn test_poly_send_sync() {
367 fn assert_send<T: Send>() {}
368 fn assert_sync<T: Sync>() {}
369 assert_send::<Poly>();
370 assert_sync::<Poly>();
371 }
372
373 #[test]
374 fn test_poly_raw_pointer() {
375 let exterior = Ring::new(&octagon()).unwrap();
376 let poly = Poly::new_simple(&exterior).unwrap();
377 let num_holes = poly.num_holes();
378 let ptr = poly.into_raw();
379 let recovered = unsafe { Poly::from_raw(ptr).unwrap() };
380 assert_eq!(recovered.num_holes(), num_holes);
381 }
382
383 #[test]
384 fn test_polyref_to_owned() {
385 let exterior = Ring::new(&octagon()).unwrap();
386 let poly = Poly::new_simple(&exterior).unwrap();
387
388 let poly_ref = unsafe { PolyRef::from_raw(poly.as_ptr()).unwrap() };
389 let owned = poly_ref.to_owned().unwrap();
390 assert_eq!(owned.num_holes(), 0);
391 }
392}