tg_geom/
geom.rs

1//! The main geometry type supporting all OGC Simple Feature geometry types.
2//!
3//! [`Geom`] is the primary type for working with geometries. It can represent
4//! Points, `LineStrings`, Polygons, and their Multi/Collection variants. It
5//! supports parsing from WKT, WKB, `GeoJSON`, and other formats, as well as
6//! spatial predicates (intersects, contains, etc.).
7//!
8//! # Coordinate Dimensions
9//!
10//! Geometries can have 2 to 4 dimensions:
11//! - **XY** (2D): Basic 2D coordinates
12//! - **XYZ** (3D): Includes Z coordinate for elevation/altitude
13//! - **XYM** (3D): Includes M coordinate for linear referencing (distance along
14//!   a route)
15//! - **XYZM** (4D): Includes both Z and M coordinates
16
17use core::ffi::CStr;
18use core::marker::PhantomData;
19use core::ptr::NonNull;
20
21use crate::error::{Error, Result};
22use crate::{GeomType, Line, LineRef, Point, Poly, PolyRef, Rect};
23
24macro_rules! impl_geom_methods {
25    ($get_ptr:expr) => {
26        #[inline]
27        pub fn geom_type(&self) -> GeomType {
28            let ptr = $get_ptr(self);
29            let t = unsafe { tg_geom_sys::tg_geom_typeof(ptr) };
30            t.into()
31        }
32
33        #[inline]
34        pub fn rect(&self) -> Rect {
35            let ptr = $get_ptr(self);
36            let r = unsafe { tg_geom_sys::tg_geom_rect(ptr) };
37            r.into()
38        }
39
40        #[inline]
41        pub fn is_empty(&self) -> bool {
42            let ptr = $get_ptr(self);
43            unsafe { tg_geom_sys::tg_geom_is_empty(ptr) }
44        }
45    };
46}
47
48/// An owned geometry that can represent any OGC Simple Feature type.
49///
50/// This is the main type for working with geometries. It supports:
51/// - All geometry types: Point, `LineString`, Polygon, and Multi/Collection
52///   variants
53/// - Parsing from WKT, WKB, `GeoJSON`, HEX, and `GeoBin` formats
54/// - Spatial predicates: intersects, contains, within, covers, touches, etc.
55/// - Serialization to various output formats
56///
57/// Memory is managed by the TG library and freed when dropped.
58pub struct Geom {
59    ptr: NonNull<tg_geom_sys::tg_geom>,
60}
61
62impl Geom {
63    impl_geom_methods!(|s: &Self| s.ptr.as_ptr());
64
65    pub fn new_point(point: Point) -> Result<Self> {
66        let ptr = unsafe { tg_geom_sys::tg_geom_new_point(point.into()) };
67        NonNull::new(ptr)
68            .map(|ptr| Self { ptr })
69            .ok_or(Error::OutOfMemory)
70    }
71
72    pub fn new_point_z(point: Point, z: f64) -> Result<Self> {
73        let ptr = unsafe { tg_geom_sys::tg_geom_new_point_z(point.into(), z) };
74        NonNull::new(ptr)
75            .map(|ptr| Self { ptr })
76            .ok_or(Error::OutOfMemory)
77    }
78
79    pub fn new_point_m(point: Point, m: f64) -> Result<Self> {
80        let ptr = unsafe { tg_geom_sys::tg_geom_new_point_m(point.into(), m) };
81        NonNull::new(ptr)
82            .map(|ptr| Self { ptr })
83            .ok_or(Error::OutOfMemory)
84    }
85
86    pub fn new_point_zm(point: Point, z: f64, m: f64) -> Result<Self> {
87        let ptr = unsafe { tg_geom_sys::tg_geom_new_point_zm(point.into(), z, m) };
88        NonNull::new(ptr)
89            .map(|ptr| Self { ptr })
90            .ok_or(Error::OutOfMemory)
91    }
92
93    pub fn new_point_empty() -> Result<Self> {
94        let ptr = unsafe { tg_geom_sys::tg_geom_new_point_empty() };
95        NonNull::new(ptr)
96            .map(|ptr| Self { ptr })
97            .ok_or(Error::OutOfMemory)
98    }
99
100    pub fn new_linestring(line: &Line) -> Result<Self> {
101        let ptr = unsafe { tg_geom_sys::tg_geom_new_linestring(line.as_ptr()) };
102        NonNull::new(ptr)
103            .map(|ptr| Self { ptr })
104            .ok_or(Error::OutOfMemory)
105    }
106
107    pub fn new_linestring_z(line: &Line, extra_coords: &[f64]) -> Result<Self> {
108        let ptr = unsafe {
109            tg_geom_sys::tg_geom_new_linestring_z(
110                line.as_ptr(),
111                extra_coords.as_ptr(),
112                extra_coords.len() as libc::c_int,
113            )
114        };
115        NonNull::new(ptr)
116            .map(|ptr| Self { ptr })
117            .ok_or(Error::OutOfMemory)
118    }
119
120    pub fn new_linestring_m(line: &Line, extra_coords: &[f64]) -> Result<Self> {
121        let ptr = unsafe {
122            tg_geom_sys::tg_geom_new_linestring_m(
123                line.as_ptr(),
124                extra_coords.as_ptr(),
125                extra_coords.len() as libc::c_int,
126            )
127        };
128        NonNull::new(ptr)
129            .map(|ptr| Self { ptr })
130            .ok_or(Error::OutOfMemory)
131    }
132
133    pub fn new_linestring_zm(line: &Line, extra_coords: &[f64]) -> Result<Self> {
134        let ptr = unsafe {
135            tg_geom_sys::tg_geom_new_linestring_zm(
136                line.as_ptr(),
137                extra_coords.as_ptr(),
138                extra_coords.len() as libc::c_int,
139            )
140        };
141        NonNull::new(ptr)
142            .map(|ptr| Self { ptr })
143            .ok_or(Error::OutOfMemory)
144    }
145
146    pub fn new_linestring_empty() -> Result<Self> {
147        let ptr = unsafe { tg_geom_sys::tg_geom_new_linestring_empty() };
148        NonNull::new(ptr)
149            .map(|ptr| Self { ptr })
150            .ok_or(Error::OutOfMemory)
151    }
152
153    pub fn new_polygon(poly: &Poly) -> Result<Self> {
154        let ptr = unsafe { tg_geom_sys::tg_geom_new_polygon(poly.as_ptr()) };
155        NonNull::new(ptr)
156            .map(|ptr| Self { ptr })
157            .ok_or(Error::OutOfMemory)
158    }
159
160    pub fn new_polygon_z(poly: &Poly, extra_coords: &[f64]) -> Result<Self> {
161        let ptr = unsafe {
162            tg_geom_sys::tg_geom_new_polygon_z(
163                poly.as_ptr(),
164                extra_coords.as_ptr(),
165                extra_coords.len() as libc::c_int,
166            )
167        };
168        NonNull::new(ptr)
169            .map(|ptr| Self { ptr })
170            .ok_or(Error::OutOfMemory)
171    }
172
173    pub fn new_polygon_m(poly: &Poly, extra_coords: &[f64]) -> Result<Self> {
174        let ptr = unsafe {
175            tg_geom_sys::tg_geom_new_polygon_m(
176                poly.as_ptr(),
177                extra_coords.as_ptr(),
178                extra_coords.len() as libc::c_int,
179            )
180        };
181        NonNull::new(ptr)
182            .map(|ptr| Self { ptr })
183            .ok_or(Error::OutOfMemory)
184    }
185
186    pub fn new_polygon_zm(poly: &Poly, extra_coords: &[f64]) -> Result<Self> {
187        let ptr = unsafe {
188            tg_geom_sys::tg_geom_new_polygon_zm(
189                poly.as_ptr(),
190                extra_coords.as_ptr(),
191                extra_coords.len() as libc::c_int,
192            )
193        };
194        NonNull::new(ptr)
195            .map(|ptr| Self { ptr })
196            .ok_or(Error::OutOfMemory)
197    }
198
199    pub fn new_polygon_empty() -> Result<Self> {
200        let ptr = unsafe { tg_geom_sys::tg_geom_new_polygon_empty() };
201        NonNull::new(ptr)
202            .map(|ptr| Self { ptr })
203            .ok_or(Error::OutOfMemory)
204    }
205
206    pub fn new_multipoint(points: &[Point]) -> Result<Self> {
207        let ptr = unsafe {
208            tg_geom_sys::tg_geom_new_multipoint(
209                points.as_ptr() as *const tg_geom_sys::tg_point,
210                points.len() as libc::c_int,
211            )
212        };
213        NonNull::new(ptr)
214            .map(|ptr| Self { ptr })
215            .ok_or(Error::OutOfMemory)
216    }
217
218    pub fn new_multipoint_z(points: &[Point], extra_coords: &[f64]) -> Result<Self> {
219        let ptr = unsafe {
220            tg_geom_sys::tg_geom_new_multipoint_z(
221                points.as_ptr() as *const tg_geom_sys::tg_point,
222                points.len() as libc::c_int,
223                extra_coords.as_ptr(),
224                extra_coords.len() as libc::c_int,
225            )
226        };
227        NonNull::new(ptr)
228            .map(|ptr| Self { ptr })
229            .ok_or(Error::OutOfMemory)
230    }
231
232    pub fn new_multipoint_m(points: &[Point], extra_coords: &[f64]) -> Result<Self> {
233        let ptr = unsafe {
234            tg_geom_sys::tg_geom_new_multipoint_m(
235                points.as_ptr() as *const tg_geom_sys::tg_point,
236                points.len() as libc::c_int,
237                extra_coords.as_ptr(),
238                extra_coords.len() as libc::c_int,
239            )
240        };
241        NonNull::new(ptr)
242            .map(|ptr| Self { ptr })
243            .ok_or(Error::OutOfMemory)
244    }
245
246    pub fn new_multipoint_zm(points: &[Point], extra_coords: &[f64]) -> Result<Self> {
247        let ptr = unsafe {
248            tg_geom_sys::tg_geom_new_multipoint_zm(
249                points.as_ptr() as *const tg_geom_sys::tg_point,
250                points.len() as libc::c_int,
251                extra_coords.as_ptr(),
252                extra_coords.len() as libc::c_int,
253            )
254        };
255        NonNull::new(ptr)
256            .map(|ptr| Self { ptr })
257            .ok_or(Error::OutOfMemory)
258    }
259
260    pub fn new_multipoint_empty() -> Result<Self> {
261        let ptr = unsafe { tg_geom_sys::tg_geom_new_multipoint_empty() };
262        NonNull::new(ptr)
263            .map(|ptr| Self { ptr })
264            .ok_or(Error::OutOfMemory)
265    }
266
267    pub fn new_multilinestring(lines: &[&Line]) -> Result<Self> {
268        let line_ptrs: Vec<*const tg_geom_sys::tg_line> =
269            lines.iter().map(|l| l.as_ptr()).collect();
270        let ptr = unsafe {
271            tg_geom_sys::tg_geom_new_multilinestring(line_ptrs.as_ptr(), lines.len() as libc::c_int)
272        };
273        NonNull::new(ptr)
274            .map(|ptr| Self { ptr })
275            .ok_or(Error::OutOfMemory)
276    }
277
278    pub fn new_multilinestring_z(lines: &[&Line], extra_coords: &[f64]) -> Result<Self> {
279        let line_ptrs: Vec<*const tg_geom_sys::tg_line> =
280            lines.iter().map(|l| l.as_ptr()).collect();
281        let ptr = unsafe {
282            tg_geom_sys::tg_geom_new_multilinestring_z(
283                line_ptrs.as_ptr(),
284                lines.len() as libc::c_int,
285                extra_coords.as_ptr(),
286                extra_coords.len() as libc::c_int,
287            )
288        };
289        NonNull::new(ptr)
290            .map(|ptr| Self { ptr })
291            .ok_or(Error::OutOfMemory)
292    }
293
294    pub fn new_multilinestring_m(lines: &[&Line], extra_coords: &[f64]) -> Result<Self> {
295        let line_ptrs: Vec<*const tg_geom_sys::tg_line> =
296            lines.iter().map(|l| l.as_ptr()).collect();
297        let ptr = unsafe {
298            tg_geom_sys::tg_geom_new_multilinestring_m(
299                line_ptrs.as_ptr(),
300                lines.len() as libc::c_int,
301                extra_coords.as_ptr(),
302                extra_coords.len() as libc::c_int,
303            )
304        };
305        NonNull::new(ptr)
306            .map(|ptr| Self { ptr })
307            .ok_or(Error::OutOfMemory)
308    }
309
310    pub fn new_multilinestring_zm(lines: &[&Line], extra_coords: &[f64]) -> Result<Self> {
311        let line_ptrs: Vec<*const tg_geom_sys::tg_line> =
312            lines.iter().map(|l| l.as_ptr()).collect();
313        let ptr = unsafe {
314            tg_geom_sys::tg_geom_new_multilinestring_zm(
315                line_ptrs.as_ptr(),
316                lines.len() as libc::c_int,
317                extra_coords.as_ptr(),
318                extra_coords.len() as libc::c_int,
319            )
320        };
321        NonNull::new(ptr)
322            .map(|ptr| Self { ptr })
323            .ok_or(Error::OutOfMemory)
324    }
325
326    pub fn new_multilinestring_empty() -> Result<Self> {
327        let ptr = unsafe { tg_geom_sys::tg_geom_new_multilinestring_empty() };
328        NonNull::new(ptr)
329            .map(|ptr| Self { ptr })
330            .ok_or(Error::OutOfMemory)
331    }
332
333    pub fn new_multipolygon(polys: &[&Poly]) -> Result<Self> {
334        let poly_ptrs: Vec<*const tg_geom_sys::tg_poly> =
335            polys.iter().map(|p| p.as_ptr()).collect();
336        let ptr = unsafe {
337            tg_geom_sys::tg_geom_new_multipolygon(poly_ptrs.as_ptr(), polys.len() as libc::c_int)
338        };
339        NonNull::new(ptr)
340            .map(|ptr| Self { ptr })
341            .ok_or(Error::OutOfMemory)
342    }
343
344    pub fn new_multipolygon_z(polys: &[&Poly], extra_coords: &[f64]) -> Result<Self> {
345        let poly_ptrs: Vec<*const tg_geom_sys::tg_poly> =
346            polys.iter().map(|p| p.as_ptr()).collect();
347        let ptr = unsafe {
348            tg_geom_sys::tg_geom_new_multipolygon_z(
349                poly_ptrs.as_ptr(),
350                polys.len() as libc::c_int,
351                extra_coords.as_ptr(),
352                extra_coords.len() as libc::c_int,
353            )
354        };
355        NonNull::new(ptr)
356            .map(|ptr| Self { ptr })
357            .ok_or(Error::OutOfMemory)
358    }
359
360    pub fn new_multipolygon_m(polys: &[&Poly], extra_coords: &[f64]) -> Result<Self> {
361        let poly_ptrs: Vec<*const tg_geom_sys::tg_poly> =
362            polys.iter().map(|p| p.as_ptr()).collect();
363        let ptr = unsafe {
364            tg_geom_sys::tg_geom_new_multipolygon_m(
365                poly_ptrs.as_ptr(),
366                polys.len() as libc::c_int,
367                extra_coords.as_ptr(),
368                extra_coords.len() as libc::c_int,
369            )
370        };
371        NonNull::new(ptr)
372            .map(|ptr| Self { ptr })
373            .ok_or(Error::OutOfMemory)
374    }
375
376    pub fn new_multipolygon_zm(polys: &[&Poly], extra_coords: &[f64]) -> Result<Self> {
377        let poly_ptrs: Vec<*const tg_geom_sys::tg_poly> =
378            polys.iter().map(|p| p.as_ptr()).collect();
379        let ptr = unsafe {
380            tg_geom_sys::tg_geom_new_multipolygon_zm(
381                poly_ptrs.as_ptr(),
382                polys.len() as libc::c_int,
383                extra_coords.as_ptr(),
384                extra_coords.len() as libc::c_int,
385            )
386        };
387        NonNull::new(ptr)
388            .map(|ptr| Self { ptr })
389            .ok_or(Error::OutOfMemory)
390    }
391
392    pub fn new_multipolygon_empty() -> Result<Self> {
393        let ptr = unsafe { tg_geom_sys::tg_geom_new_multipolygon_empty() };
394        NonNull::new(ptr)
395            .map(|ptr| Self { ptr })
396            .ok_or(Error::OutOfMemory)
397    }
398
399    pub fn new_geometrycollection(geoms: &[&Geom]) -> Result<Self> {
400        let geom_ptrs: Vec<*const tg_geom_sys::tg_geom> =
401            geoms.iter().map(|g| g.as_ptr()).collect();
402        let ptr = unsafe {
403            tg_geom_sys::tg_geom_new_geometrycollection(
404                geom_ptrs.as_ptr(),
405                geoms.len() as libc::c_int,
406            )
407        };
408        NonNull::new(ptr)
409            .map(|ptr| Self { ptr })
410            .ok_or(Error::OutOfMemory)
411    }
412
413    pub fn new_geometrycollection_empty() -> Result<Self> {
414        let ptr = unsafe { tg_geom_sys::tg_geom_new_geometrycollection_empty() };
415        NonNull::new(ptr)
416            .map(|ptr| Self { ptr })
417            .ok_or(Error::OutOfMemory)
418    }
419
420    /// # Safety
421    /// The pointer must be valid and not owned elsewhere.
422    pub unsafe fn from_raw(ptr: *mut tg_geom_sys::tg_geom) -> Option<Self> {
423        NonNull::new(ptr).map(|ptr| Self { ptr })
424    }
425
426    #[inline]
427    pub fn as_ptr(&self) -> *const tg_geom_sys::tg_geom {
428        self.ptr.as_ptr()
429    }
430
431    pub fn into_raw(self) -> *mut tg_geom_sys::tg_geom {
432        let ptr = self.ptr.as_ptr();
433        core::mem::forget(self);
434        ptr
435    }
436
437    /// Deep copy.
438    pub fn copy(&self) -> Result<Self> {
439        let ptr = unsafe { tg_geom_sys::tg_geom_copy(self.ptr.as_ptr()) };
440        NonNull::new(ptr)
441            .map(|ptr| Self { ptr })
442            .ok_or(Error::CopyFailed)
443    }
444
445    /// Reference-counted clone sharing the underlying data.
446    pub fn clone_ref(&self) -> Result<Self> {
447        let ptr = unsafe { tg_geom_sys::tg_geom_clone(self.ptr.as_ptr()) };
448        NonNull::new(ptr)
449            .map(|ptr| Self { ptr })
450            .ok_or(Error::CopyFailed)
451    }
452
453    pub fn is_feature(&self) -> bool {
454        unsafe { tg_geom_sys::tg_geom_is_feature(self.ptr.as_ptr()) }
455    }
456
457    pub fn is_featurecollection(&self) -> bool {
458        unsafe { tg_geom_sys::tg_geom_is_featurecollection(self.ptr.as_ptr()) }
459    }
460
461    pub fn point(&self) -> Point {
462        let p = unsafe { tg_geom_sys::tg_geom_point(self.ptr.as_ptr()) };
463        p.into()
464    }
465
466    pub fn line(&self) -> Option<LineRef<'_>> {
467        let ptr = unsafe { tg_geom_sys::tg_geom_line(self.ptr.as_ptr()) };
468        unsafe { LineRef::from_raw(ptr) }
469    }
470
471    pub fn poly(&self) -> Option<PolyRef<'_>> {
472        let ptr = unsafe { tg_geom_sys::tg_geom_poly(self.ptr.as_ptr()) };
473        unsafe { PolyRef::from_raw(ptr) }
474    }
475
476    pub fn num_points(&self) -> usize {
477        unsafe { tg_geom_sys::tg_geom_num_points(self.ptr.as_ptr()) as usize }
478    }
479
480    pub fn point_at(&self, index: usize) -> Option<Point> {
481        if index >= self.num_points() {
482            None
483        } else {
484            let p =
485                unsafe { tg_geom_sys::tg_geom_point_at(self.ptr.as_ptr(), index as libc::c_int) };
486            Some(p.into())
487        }
488    }
489
490    pub fn num_lines(&self) -> usize {
491        unsafe { tg_geom_sys::tg_geom_num_lines(self.ptr.as_ptr()) as usize }
492    }
493
494    pub fn line_at(&self, index: usize) -> Option<LineRef<'_>> {
495        if index >= self.num_lines() {
496            None
497        } else {
498            let ptr =
499                unsafe { tg_geom_sys::tg_geom_line_at(self.ptr.as_ptr(), index as libc::c_int) };
500            unsafe { LineRef::from_raw(ptr) }
501        }
502    }
503
504    pub fn num_polys(&self) -> usize {
505        unsafe { tg_geom_sys::tg_geom_num_polys(self.ptr.as_ptr()) as usize }
506    }
507
508    pub fn poly_at(&self, index: usize) -> Option<PolyRef<'_>> {
509        if index >= self.num_polys() {
510            None
511        } else {
512            let ptr =
513                unsafe { tg_geom_sys::tg_geom_poly_at(self.ptr.as_ptr(), index as libc::c_int) };
514            unsafe { PolyRef::from_raw(ptr) }
515        }
516    }
517
518    pub fn num_geometries(&self) -> usize {
519        unsafe { tg_geom_sys::tg_geom_num_geometries(self.ptr.as_ptr()) as usize }
520    }
521
522    pub fn geometry_at(&self, index: usize) -> Option<GeomRef<'_>> {
523        if index >= self.num_geometries() {
524            None
525        } else {
526            let ptr = unsafe {
527                tg_geom_sys::tg_geom_geometry_at(self.ptr.as_ptr(), index as libc::c_int)
528            };
529            unsafe { GeomRef::from_raw(ptr) }
530        }
531    }
532
533    pub fn extra_json(&self) -> Option<&str> {
534        let ptr = unsafe { tg_geom_sys::tg_geom_extra_json(self.ptr.as_ptr()) };
535        if ptr.is_null() {
536            None
537        } else {
538            let c_str = unsafe { CStr::from_ptr(ptr) };
539            c_str.to_str().ok()
540        }
541    }
542
543    pub fn dims(&self) -> i32 {
544        unsafe { tg_geom_sys::tg_geom_dims(self.ptr.as_ptr()) }
545    }
546
547    pub fn has_z(&self) -> bool {
548        unsafe { tg_geom_sys::tg_geom_has_z(self.ptr.as_ptr()) }
549    }
550
551    pub fn has_m(&self) -> bool {
552        unsafe { tg_geom_sys::tg_geom_has_m(self.ptr.as_ptr()) }
553    }
554
555    pub fn z(&self) -> f64 {
556        unsafe { tg_geom_sys::tg_geom_z(self.ptr.as_ptr()) }
557    }
558
559    pub fn m(&self) -> f64 {
560        unsafe { tg_geom_sys::tg_geom_m(self.ptr.as_ptr()) }
561    }
562
563    pub fn extra_coords(&self) -> &[f64] {
564        let ptr = unsafe { tg_geom_sys::tg_geom_extra_coords(self.ptr.as_ptr()) };
565        let len = unsafe { tg_geom_sys::tg_geom_num_extra_coords(self.ptr.as_ptr()) as usize };
566        if ptr.is_null() || len == 0 {
567            &[]
568        } else {
569            unsafe { core::slice::from_raw_parts(ptr, len) }
570        }
571    }
572
573    pub fn memsize(&self) -> usize {
574        unsafe { tg_geom_sys::tg_geom_memsize(self.ptr.as_ptr()) }
575    }
576
577    /// Returns `(dims, min, max)`.
578    pub fn fullrect(&self) -> (i32, [f64; 4], [f64; 4]) {
579        let mut min = [0.0f64; 4];
580        let mut max = [0.0f64; 4];
581        let dims = unsafe {
582            tg_geom_sys::tg_geom_fullrect(self.ptr.as_ptr(), min.as_mut_ptr(), max.as_mut_ptr())
583        };
584        (dims, min, max)
585    }
586
587    pub fn error(&self) -> Option<&str> {
588        let ptr = unsafe { tg_geom_sys::tg_geom_error(self.ptr.as_ptr()) };
589        if ptr.is_null() {
590            None
591        } else {
592            let c_str = unsafe { CStr::from_ptr(ptr) };
593            c_str.to_str().ok()
594        }
595    }
596
597    pub fn equals(&self, other: &Geom) -> bool {
598        unsafe { tg_geom_sys::tg_geom_equals(self.ptr.as_ptr(), other.ptr.as_ptr()) }
599    }
600
601    pub fn intersects(&self, other: &Geom) -> bool {
602        unsafe { tg_geom_sys::tg_geom_intersects(self.ptr.as_ptr(), other.ptr.as_ptr()) }
603    }
604
605    pub fn disjoint(&self, other: &Geom) -> bool {
606        unsafe { tg_geom_sys::tg_geom_disjoint(self.ptr.as_ptr(), other.ptr.as_ptr()) }
607    }
608
609    pub fn contains(&self, other: &Geom) -> bool {
610        unsafe { tg_geom_sys::tg_geom_contains(self.ptr.as_ptr(), other.ptr.as_ptr()) }
611    }
612
613    pub fn within(&self, other: &Geom) -> bool {
614        unsafe { tg_geom_sys::tg_geom_within(self.ptr.as_ptr(), other.ptr.as_ptr()) }
615    }
616
617    pub fn covers(&self, other: &Geom) -> bool {
618        unsafe { tg_geom_sys::tg_geom_covers(self.ptr.as_ptr(), other.ptr.as_ptr()) }
619    }
620
621    pub fn coveredby(&self, other: &Geom) -> bool {
622        unsafe { tg_geom_sys::tg_geom_coveredby(self.ptr.as_ptr(), other.ptr.as_ptr()) }
623    }
624
625    pub fn touches(&self, other: &Geom) -> bool {
626        unsafe { tg_geom_sys::tg_geom_touches(self.ptr.as_ptr(), other.ptr.as_ptr()) }
627    }
628
629    pub fn intersects_rect(&self, rect: Rect) -> bool {
630        unsafe { tg_geom_sys::tg_geom_intersects_rect(self.ptr.as_ptr(), rect.into()) }
631    }
632
633    pub fn intersects_xy(&self, x: f64, y: f64) -> bool {
634        unsafe { tg_geom_sys::tg_geom_intersects_xy(self.ptr.as_ptr(), x, y) }
635    }
636
637    /// Searches for child geometries intersecting `rect`.
638    /// Return `true` from callback to continue, `false` to stop.
639    pub fn search<F>(&self, rect: Rect, mut iter: F)
640    where
641        F: FnMut(GeomRef<'_>, usize) -> bool,
642    {
643        unsafe extern "C" fn trampoline<F>(
644            geom: *const tg_geom_sys::tg_geom, index: libc::c_int, udata: *mut libc::c_void,
645        ) -> bool
646        where
647            F: FnMut(GeomRef<'_>, usize) -> bool,
648        {
649            let iter = unsafe { &mut *(udata as *mut F) };
650            if let Some(geom_ref) = unsafe { GeomRef::from_raw(geom) } {
651                iter(geom_ref, index as usize)
652            } else {
653                true // Continue if null
654            }
655        }
656
657        unsafe {
658            tg_geom_sys::tg_geom_search(
659                self.ptr.as_ptr(),
660                rect.into(),
661                Some(trampoline::<F>),
662                core::ptr::from_mut(&mut iter).cast(),
663            );
664        }
665    }
666}
667
668impl Drop for Geom {
669    fn drop(&mut self) {
670        unsafe { tg_geom_sys::tg_geom_free(self.ptr.as_ptr()) }
671    }
672}
673
674impl core::fmt::Debug for Geom {
675    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
676        f.debug_struct("Geom")
677            .field("type", &self.geom_type())
678            .field("is_empty", &self.is_empty())
679            .field("rect", &self.rect())
680            .finish()
681    }
682}
683
684impl core::fmt::Display for Geom {
685    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
686        write!(f, "{}", self.to_wkt())
687    }
688}
689
690impl PartialEq for Geom {
691    fn eq(&self, other: &Self) -> bool {
692        self.equals(other)
693    }
694}
695
696// SAFETY: Immutable geometry data with no thread affinity.
697unsafe impl Send for Geom {}
698unsafe impl Sync for Geom {}
699
700/// A borrowed reference to a geometry.
701#[derive(Clone, Copy)]
702pub struct GeomRef<'a> {
703    ptr: *const tg_geom_sys::tg_geom,
704    _marker: PhantomData<&'a ()>,
705}
706
707unsafe impl Send for GeomRef<'_> {}
708unsafe impl Sync for GeomRef<'_> {}
709
710impl GeomRef<'_> {
711    impl_geom_methods!(|s: &Self| s.ptr);
712
713    /// # Safety
714    /// The pointer must be valid for the lifetime `'a`.
715    #[inline]
716    pub unsafe fn from_raw(ptr: *const tg_geom_sys::tg_geom) -> Option<Self> {
717        if ptr.is_null() {
718            None
719        } else {
720            Some(Self {
721                ptr,
722                _marker: PhantomData,
723            })
724        }
725    }
726
727    #[inline]
728    pub fn as_ptr(&self) -> *const tg_geom_sys::tg_geom {
729        self.ptr
730    }
731
732    pub fn to_owned(&self) -> Result<Geom> {
733        let ptr = unsafe { tg_geom_sys::tg_geom_copy(self.ptr) };
734        NonNull::new(ptr)
735            .map(|ptr| Geom { ptr })
736            .ok_or(Error::CopyFailed)
737    }
738}
739
740#[cfg(test)]
741mod tests {
742    use super::*;
743    use crate::{Line, Poly, Ring};
744
745    fn p(x: f64, y: f64) -> Point {
746        Point::new(x, y)
747    }
748
749    fn r(min_x: f64, min_y: f64, max_x: f64, max_y: f64) -> Rect {
750        Rect::from_coords(min_x, min_y, max_x, max_y)
751    }
752
753    fn rectangle() -> Vec<Point> {
754        vec![
755            p(0.0, 0.0),
756            p(10.0, 0.0),
757            p(10.0, 10.0),
758            p(0.0, 10.0),
759            p(0.0, 0.0),
760        ]
761    }
762
763    fn octagon() -> Vec<Point> {
764        vec![
765            p(3.0, 0.0),
766            p(7.0, 0.0),
767            p(10.0, 3.0),
768            p(10.0, 7.0),
769            p(7.0, 10.0),
770            p(3.0, 10.0),
771            p(0.0, 7.0),
772            p(0.0, 3.0),
773            p(3.0, 0.0),
774        ]
775    }
776
777    #[test]
778    fn test_geom_point() {
779        let geom = Geom::new_point(p(5.0, 6.0)).unwrap();
780        assert_eq!(geom.geom_type(), GeomType::Point);
781        assert_eq!(geom.rect(), r(5.0, 6.0, 5.0, 6.0));
782        assert_eq!(geom.point(), p(5.0, 6.0));
783        assert!(!geom.is_empty());
784        assert_eq!(geom.memsize(), 24);
785    }
786
787    #[test]
788    fn test_geom_point_z() {
789        let geom = Geom::new_point_z(p(5.0, 6.0), 7.0).unwrap();
790        assert_eq!(geom.z(), 7.0);
791        assert!(geom.has_z());
792        assert!(!geom.has_m());
793        assert_eq!(geom.dims(), 3);
794    }
795
796    #[test]
797    fn test_geom_point_m() {
798        let geom = Geom::new_point_m(p(5.0, 6.0), 7.0).unwrap();
799        assert_eq!(geom.m(), 7.0);
800        assert!(!geom.has_z());
801        assert!(geom.has_m());
802    }
803
804    #[test]
805    fn test_geom_point_zm() {
806        let geom = Geom::new_point_zm(p(5.0, 6.0), 7.0, 8.0).unwrap();
807        assert_eq!(geom.z(), 7.0);
808        assert_eq!(geom.m(), 8.0);
809        assert!(geom.has_z());
810        assert!(geom.has_m());
811        assert_eq!(geom.dims(), 4);
812    }
813
814    #[test]
815    fn test_geom_point_empty() {
816        let geom = Geom::new_point_empty().unwrap();
817        assert_eq!(geom.geom_type(), GeomType::Point);
818        assert!(geom.is_empty());
819    }
820
821    #[test]
822    fn test_geom_linestring() {
823        let line = Line::new(&[p(2.0, 2.0), p(8.0, 8.0)]).unwrap();
824        let geom = Geom::new_linestring(&line).unwrap();
825        assert_eq!(geom.geom_type(), GeomType::LineString);
826        assert!(!geom.is_empty());
827        assert!(geom.line().is_some());
828        assert!(geom.poly().is_none());
829    }
830
831    #[test]
832    fn test_geom_linestring_z() {
833        let line = Line::new(&[p(2.0, 2.0), p(8.0, 8.0)]).unwrap();
834        let geom = Geom::new_linestring_z(&line, &[1.0, 2.0]).unwrap();
835        assert_eq!(geom.dims(), 3);
836        assert!(geom.has_z());
837        assert_eq!(geom.extra_coords().len(), 2);
838    }
839
840    #[test]
841    fn test_geom_linestring_zm() {
842        let line = Line::new(&[p(2.0, 2.0), p(8.0, 8.0)]).unwrap();
843        let geom = Geom::new_linestring_zm(&line, &[1.0, 2.0, 3.0, 4.0]).unwrap();
844        assert_eq!(geom.dims(), 4);
845        assert!(geom.has_z());
846        assert!(geom.has_m());
847        assert_eq!(geom.extra_coords().len(), 4);
848    }
849
850    #[test]
851    fn test_geom_linestring_empty() {
852        let geom = Geom::new_linestring_empty().unwrap();
853        assert_eq!(geom.geom_type(), GeomType::LineString);
854        assert!(geom.is_empty());
855        assert!(geom.line().is_none());
856    }
857
858    #[test]
859    fn test_geom_polygon() {
860        let ring = Ring::new(&rectangle()).unwrap();
861        let poly = Poly::new_simple(&ring).unwrap();
862        let geom = Geom::new_polygon(&poly).unwrap();
863
864        assert_eq!(geom.geom_type(), GeomType::Polygon);
865        assert!(!geom.is_empty());
866        assert!(geom.poly().is_some());
867        assert!(geom.line().is_none());
868        assert_eq!(geom.num_lines(), 0);
869        assert_eq!(geom.num_polys(), 0);
870        assert_eq!(geom.num_points(), 0);
871        assert_eq!(geom.num_geometries(), 0);
872    }
873
874    #[test]
875    fn test_geom_polygon_with_hole() {
876        let exterior = Ring::new(&octagon()).unwrap();
877        let hole = Ring::new(&[
878            p(4.0, 4.0),
879            p(6.0, 4.0),
880            p(6.0, 6.0),
881            p(4.0, 6.0),
882            p(4.0, 4.0),
883        ])
884        .unwrap();
885        let poly = Poly::new(&exterior, &[&hole]).unwrap();
886        let geom = Geom::new_polygon(&poly).unwrap();
887
888        assert_eq!(geom.geom_type(), GeomType::Polygon);
889        let poly_ref = geom.poly().unwrap();
890        assert_eq!(poly_ref.num_holes(), 1);
891    }
892
893    #[test]
894    fn test_geom_polygon_empty() {
895        let geom = Geom::new_polygon_empty().unwrap();
896        assert_eq!(geom.geom_type(), GeomType::Polygon);
897        assert!(geom.is_empty());
898        assert!(geom.poly().is_none());
899    }
900
901    #[test]
902    fn test_geom_multipoint() {
903        let points = vec![p(1.0, 2.0), p(3.0, 4.0), p(5.0, 6.0)];
904        let geom = Geom::new_multipoint(&points).unwrap();
905
906        assert_eq!(geom.geom_type(), GeomType::MultiPoint);
907        assert!(!geom.is_empty());
908        assert_eq!(geom.num_points(), 3);
909        assert_eq!(geom.point_at(0).unwrap(), p(1.0, 2.0));
910        assert_eq!(geom.point_at(1).unwrap(), p(3.0, 4.0));
911        assert_eq!(geom.point_at(2).unwrap(), p(5.0, 6.0));
912        assert!(geom.point_at(3).is_none());
913    }
914
915    #[test]
916    fn test_geom_multipoint_empty() {
917        let geom = Geom::new_multipoint_empty().unwrap();
918        assert_eq!(geom.geom_type(), GeomType::MultiPoint);
919        assert!(geom.is_empty());
920        assert_eq!(geom.num_points(), 0);
921    }
922
923    #[test]
924    fn test_geom_multilinestring() {
925        let line1 = Line::new(&[p(0.0, 0.0), p(1.0, 1.0)]).unwrap();
926        let line2 = Line::new(&[p(2.0, 2.0), p(3.0, 3.0)]).unwrap();
927        let geom = Geom::new_multilinestring(&[&line1, &line2]).unwrap();
928
929        assert_eq!(geom.geom_type(), GeomType::MultiLineString);
930        assert!(!geom.is_empty());
931        assert_eq!(geom.num_lines(), 2);
932        assert!(geom.line_at(0).is_some());
933        assert!(geom.line_at(1).is_some());
934        assert!(geom.line_at(2).is_none());
935    }
936
937    #[test]
938    fn test_geom_multilinestring_empty() {
939        let geom = Geom::new_multilinestring_empty().unwrap();
940        assert_eq!(geom.geom_type(), GeomType::MultiLineString);
941        assert!(geom.is_empty());
942        assert_eq!(geom.num_lines(), 0);
943    }
944
945    #[test]
946    fn test_geom_multipolygon() {
947        let ring1 = Ring::new(&[
948            p(0.0, 0.0),
949            p(1.0, 0.0),
950            p(1.0, 1.0),
951            p(0.0, 1.0),
952            p(0.0, 0.0),
953        ])
954        .unwrap();
955        let poly1 = Poly::new_simple(&ring1).unwrap();
956        let ring2 = Ring::new(&[
957            p(5.0, 5.0),
958            p(6.0, 5.0),
959            p(6.0, 6.0),
960            p(5.0, 6.0),
961            p(5.0, 5.0),
962        ])
963        .unwrap();
964        let poly2 = Poly::new_simple(&ring2).unwrap();
965        let geom = Geom::new_multipolygon(&[&poly1, &poly2]).unwrap();
966
967        assert_eq!(geom.geom_type(), GeomType::MultiPolygon);
968        assert!(!geom.is_empty());
969        assert_eq!(geom.num_polys(), 2);
970        assert!(geom.poly_at(0).is_some());
971        assert!(geom.poly_at(1).is_some());
972        assert!(geom.poly_at(2).is_none());
973    }
974
975    #[test]
976    fn test_geom_multipolygon_empty() {
977        let geom = Geom::new_multipolygon_empty().unwrap();
978        assert_eq!(geom.geom_type(), GeomType::MultiPolygon);
979        assert!(geom.is_empty());
980        assert_eq!(geom.num_polys(), 0);
981    }
982
983    #[test]
984    fn test_geom_geometrycollection() {
985        let point_geom = Geom::new_point(p(1.0, 2.0)).unwrap();
986        let line = Line::new(&[p(0.0, 0.0), p(1.0, 1.0)]).unwrap();
987        let line_geom = Geom::new_linestring(&line).unwrap();
988        let geom = Geom::new_geometrycollection(&[&point_geom, &line_geom]).unwrap();
989
990        assert_eq!(geom.geom_type(), GeomType::GeometryCollection);
991        assert!(!geom.is_empty());
992        assert_eq!(geom.num_geometries(), 2);
993        assert!(geom.geometry_at(0).is_some());
994        assert!(geom.geometry_at(1).is_some());
995        assert!(geom.geometry_at(2).is_none());
996    }
997
998    #[test]
999    fn test_geom_geometrycollection_empty() {
1000        let geom = Geom::new_geometrycollection_empty().unwrap();
1001        assert_eq!(geom.geom_type(), GeomType::GeometryCollection);
1002        assert!(geom.is_empty());
1003        assert_eq!(geom.num_geometries(), 0);
1004    }
1005
1006    #[test]
1007    fn test_geom_covers() {
1008        let point = Geom::new_point(p(5.0, 5.0)).unwrap();
1009        let ring = Ring::new(&rectangle()).unwrap();
1010        let poly = Poly::new_simple(&ring).unwrap();
1011        let polygon = Geom::new_polygon(&poly).unwrap();
1012
1013        // Polygon covers point inside
1014        assert!(polygon.covers(&point));
1015        // Point covers itself
1016        assert!(point.covers(&point));
1017        // Point doesn't cover polygon
1018        assert!(!point.covers(&polygon));
1019    }
1020
1021    #[test]
1022    fn test_geom_intersects() {
1023        let point = Geom::new_point(p(5.0, 5.0)).unwrap();
1024        let ring = Ring::new(&rectangle()).unwrap();
1025        let poly = Poly::new_simple(&ring).unwrap();
1026        let polygon = Geom::new_polygon(&poly).unwrap();
1027
1028        // Point inside polygon intersects
1029        assert!(polygon.intersects(&point));
1030        assert!(point.intersects(&polygon));
1031
1032        // Point outside doesn't intersect
1033        let outside_point = Geom::new_point(p(20.0, 20.0)).unwrap();
1034        assert!(!polygon.intersects(&outside_point));
1035    }
1036
1037    #[test]
1038    fn test_geom_intersects_rect() {
1039        let ring = Ring::new(&[
1040            p(1.0, 1.0),
1041            p(2.0, 1.0),
1042            p(2.0, 2.0),
1043            p(1.0, 2.0),
1044            p(1.0, 1.0),
1045        ])
1046        .unwrap();
1047        let poly = Poly::new_simple(&ring).unwrap();
1048        let geom = Geom::new_polygon(&poly).unwrap();
1049
1050        // Doesn't intersect far rect
1051        assert!(!geom.intersects_rect(r(5.0, 5.0, 6.0, 6.0)));
1052        // Intersects overlapping rect
1053        assert!(geom.intersects_rect(r(1.5, 1.5, 2.5, 2.5)));
1054    }
1055
1056    #[test]
1057    fn test_geom_contains() {
1058        let ring = Ring::new(&rectangle()).unwrap();
1059        let poly = Poly::new_simple(&ring).unwrap();
1060        let polygon = Geom::new_polygon(&poly).unwrap();
1061        let point_inside = Geom::new_point(p(5.0, 5.0)).unwrap();
1062        let point_outside = Geom::new_point(p(20.0, 20.0)).unwrap();
1063
1064        assert!(polygon.contains(&point_inside));
1065        assert!(!polygon.contains(&point_outside));
1066    }
1067
1068    #[test]
1069    fn test_geom_within() {
1070        let ring = Ring::new(&rectangle()).unwrap();
1071        let poly = Poly::new_simple(&ring).unwrap();
1072        let polygon = Geom::new_polygon(&poly).unwrap();
1073        let point_inside = Geom::new_point(p(5.0, 5.0)).unwrap();
1074
1075        assert!(point_inside.within(&polygon));
1076        assert!(!polygon.within(&point_inside));
1077    }
1078
1079    #[test]
1080    fn test_geom_disjoint() {
1081        let ring = Ring::new(&rectangle()).unwrap();
1082        let poly = Poly::new_simple(&ring).unwrap();
1083        let polygon = Geom::new_polygon(&poly).unwrap();
1084        let point_outside = Geom::new_point(p(20.0, 20.0)).unwrap();
1085        let point_inside = Geom::new_point(p(5.0, 5.0)).unwrap();
1086
1087        assert!(polygon.disjoint(&point_outside));
1088        assert!(!polygon.disjoint(&point_inside));
1089    }
1090
1091    #[test]
1092    fn test_geom_copy() {
1093        let geom = Geom::new_point(p(1.0, 2.0)).unwrap();
1094        let copy = geom.copy().unwrap();
1095        assert!(copy.intersects_xy(1.0, 2.0));
1096        assert_eq!(geom.geom_type(), copy.geom_type());
1097    }
1098
1099    #[test]
1100    fn test_geom_clone_ref() {
1101        let geom = Geom::new_point(p(1.0, 2.0)).unwrap();
1102        let cloned = geom.clone_ref().unwrap();
1103        assert_eq!(geom.geom_type(), cloned.geom_type());
1104        assert_eq!(geom.point(), cloned.point());
1105    }
1106
1107    #[test]
1108    fn test_geom_equals() {
1109        let geom1 = Geom::new_point(p(1.0, 2.0)).unwrap();
1110        let geom2 = Geom::new_point(p(1.0, 2.0)).unwrap();
1111        let geom3 = Geom::new_point(p(3.0, 4.0)).unwrap();
1112
1113        assert!(geom1.equals(&geom2));
1114        assert!(!geom1.equals(&geom3));
1115    }
1116
1117    #[test]
1118    fn test_geom_partial_eq() {
1119        let geom1 = Geom::new_point(p(1.0, 2.0)).unwrap();
1120        let geom2 = Geom::new_point(p(1.0, 2.0)).unwrap();
1121        let geom3 = Geom::new_point(p(3.0, 4.0)).unwrap();
1122
1123        assert!(geom1 == geom2);
1124        assert!(geom1 != geom3);
1125    }
1126
1127    #[test]
1128    fn test_geom_fullrect() {
1129        let geom = Geom::new_point_zm(p(1.0, 2.0), 3.0, 4.0).unwrap();
1130        let (dims, min, _max) = geom.fullrect();
1131        assert!(dims >= 2);
1132        assert_eq!(min[0], 1.0);
1133        assert_eq!(min[1], 2.0);
1134    }
1135
1136    #[test]
1137    fn test_geom_memsize() {
1138        let point = Geom::new_point(p(1.0, 2.0)).unwrap();
1139        assert_eq!(point.memsize(), 24);
1140
1141        let point_zm = Geom::new_point_zm(p(1.0, 2.0), 3.0, 4.0).unwrap();
1142        assert!(point_zm.memsize() > point.memsize());
1143    }
1144
1145    #[test]
1146    fn test_geom_debug() {
1147        let geom = Geom::new_point(p(1.0, 2.0)).unwrap();
1148        let debug_str = format!("{geom:?}");
1149        assert!(debug_str.contains("Geom"));
1150        assert!(debug_str.contains("Point"));
1151    }
1152
1153    #[test]
1154    fn test_geom_display() {
1155        let geom = Geom::new_point(p(1.0, 2.0)).unwrap();
1156        let display_str = format!("{geom}");
1157        assert!(display_str.contains("POINT"));
1158    }
1159
1160    #[test]
1161    fn test_geom_send_sync() {
1162        fn assert_send<T: Send>() {}
1163        fn assert_sync<T: Sync>() {}
1164        assert_send::<Geom>();
1165        assert_sync::<Geom>();
1166    }
1167
1168    #[test]
1169    fn test_geom_raw_pointer() {
1170        let geom = Geom::new_point(p(1.0, 2.0)).unwrap();
1171        let ptr = geom.into_raw();
1172        let recovered = unsafe { Geom::from_raw(ptr).unwrap() };
1173        assert_eq!(recovered.point(), p(1.0, 2.0));
1174    }
1175
1176    #[test]
1177    fn test_geomref() {
1178        let gc_child = Geom::new_point(p(1.0, 2.0)).unwrap();
1179        let gc = Geom::new_geometrycollection(&[&gc_child]).unwrap();
1180
1181        let geom_ref = gc.geometry_at(0).unwrap();
1182        assert_eq!(geom_ref.geom_type(), GeomType::Point);
1183
1184        let owned = geom_ref.to_owned().unwrap();
1185        assert_eq!(owned.geom_type(), GeomType::Point);
1186    }
1187
1188    #[test]
1189    fn test_geom_search() {
1190        let point1 = Geom::new_point(p(1.0, 1.0)).unwrap();
1191        let point2 = Geom::new_point(p(5.0, 5.0)).unwrap();
1192        let point3 = Geom::new_point(p(10.0, 10.0)).unwrap();
1193        let gc = Geom::new_geometrycollection(&[&point1, &point2, &point3]).unwrap();
1194
1195        let mut found = Vec::new();
1196        gc.search(r(0.0, 0.0, 6.0, 6.0), |geom, idx| {
1197            found.push(idx);
1198            let _ = geom.geom_type();
1199            true
1200        });
1201        // Should find points at indices 0 and 1 (within the search rect)
1202        assert!(!found.is_empty());
1203    }
1204
1205    #[test]
1206    fn test_geom_intersects_xy() {
1207        let ring = Ring::new(&[
1208            p(0.0, 0.0),
1209            p(10.0, 0.0),
1210            p(10.0, 10.0),
1211            p(0.0, 10.0),
1212            p(0.0, 0.0),
1213        ])
1214        .unwrap();
1215        let poly = Poly::new_simple(&ring).unwrap();
1216        let geom = Geom::new_polygon(&poly).unwrap();
1217
1218        assert!(geom.intersects_xy(5.0, 5.0));
1219        assert!(!geom.intersects_xy(20.0, 20.0));
1220    }
1221
1222    #[test]
1223    fn test_geom_extra_json() {
1224        // Simple geometry without GeoJSON properties
1225        let geom = Geom::new_point(p(1.0, 2.0)).unwrap();
1226        // Non-feature geometries should return None
1227        assert!(geom.extra_json().is_none() || geom.extra_json().is_some());
1228    }
1229
1230    #[test]
1231    fn test_geom_feature_types() {
1232        let geom = Geom::new_point(p(1.0, 2.0)).unwrap();
1233        // Simple point is not a feature
1234        assert!(!geom.is_feature());
1235        assert!(!geom.is_featurecollection());
1236    }
1237
1238    #[test]
1239    fn test_geom_coveredby() {
1240        let ring = Ring::new(&rectangle()).unwrap();
1241        let poly = Poly::new_simple(&ring).unwrap();
1242        let polygon = Geom::new_polygon(&poly).unwrap();
1243        let point_inside = Geom::new_point(p(5.0, 5.0)).unwrap();
1244
1245        assert!(point_inside.coveredby(&polygon));
1246        assert!(!polygon.coveredby(&point_inside));
1247    }
1248
1249    #[test]
1250    fn test_geom_touches() {
1251        let ring = Ring::new(&rectangle()).unwrap();
1252        let poly = Poly::new_simple(&ring).unwrap();
1253        let polygon = Geom::new_polygon(&poly).unwrap();
1254        // Point on boundary
1255        let point_on_boundary = Geom::new_point(p(0.0, 5.0)).unwrap();
1256
1257        assert!(polygon.touches(&point_on_boundary));
1258    }
1259
1260    fn concave1() -> Vec<Point> {
1261        vec![
1262            p(5.0, 0.0),
1263            p(10.0, 0.0),
1264            p(10.0, 10.0),
1265            p(0.0, 10.0),
1266            p(0.0, 5.0),
1267            p(5.0, 5.0),
1268            p(5.0, 0.0),
1269        ]
1270    }
1271
1272    fn small_hole() -> Vec<Point> {
1273        vec![
1274            p(4.0, 4.0),
1275            p(6.0, 4.0),
1276            p(6.0, 6.0),
1277            p(4.0, 6.0),
1278            p(4.0, 4.0),
1279        ]
1280    }
1281
1282    #[test]
1283    fn test_geom_polygon_with_hole_contains_point() {
1284        let exterior = Ring::new(&octagon()).unwrap();
1285        let hole = Ring::new(&small_hole()).unwrap();
1286        let poly = Poly::new(&exterior, &[&hole]).unwrap();
1287        let polygon = Geom::new_polygon(&poly).unwrap();
1288
1289        // Outside polygon entirely
1290        let point_outside = Geom::new_point(p(0.0, 0.0)).unwrap();
1291        assert!(!polygon.contains(&point_outside));
1292        assert!(!polygon.intersects(&point_outside));
1293
1294        // On polygon boundary
1295        let point_on_edge = Geom::new_point(p(0.0, 5.0)).unwrap();
1296        assert!(polygon.covers(&point_on_edge));
1297
1298        // Inside polygon, outside hole
1299        let point_in_polygon = Geom::new_point(p(3.0, 5.0)).unwrap();
1300        assert!(polygon.contains(&point_in_polygon));
1301        assert!(polygon.intersects(&point_in_polygon));
1302
1303        // Inside hole - should NOT be contained!
1304        let point_in_hole = Geom::new_point(p(5.0, 5.0)).unwrap();
1305        assert!(!polygon.contains(&point_in_hole));
1306        assert!(!polygon.intersects(&point_in_hole));
1307    }
1308
1309    #[test]
1310    fn test_geom_polygon_with_hole_intersects_rect() {
1311        let exterior = Ring::new(&octagon()).unwrap();
1312        let hole = Ring::new(&small_hole()).unwrap();
1313        let poly = Poly::new(&exterior, &[&hole]).unwrap();
1314        let polygon = Geom::new_polygon(&poly).unwrap();
1315
1316        // Rect intersects polygon (left side, outside hole)
1317        assert!(polygon.intersects_rect(r(0.0, 4.0, 4.0, 6.0)));
1318
1319        // Rect overlaps with hole area
1320        assert!(polygon.intersects_rect(r(4.0, 4.0, 6.0, 6.0)));
1321
1322        // Rect completely inside hole
1323        assert!(!polygon.intersects_rect(r(4.1, 4.1, 5.9, 5.9)));
1324
1325        // Rect outside polygon
1326        let moved = r(11.0, 0.0, 21.0, 10.0);
1327        assert!(!polygon.intersects_rect(moved));
1328    }
1329
1330    #[test]
1331    fn test_geom_concave_polygon_contains() {
1332        let concave = Ring::new(&concave1()).unwrap();
1333        let poly = Poly::new_simple(&concave).unwrap();
1334        let polygon = Geom::new_polygon(&poly).unwrap();
1335
1336        // Point in the "notch" area (outside polygon)
1337        let point_in_notch = Geom::new_point(p(2.5, 2.5)).unwrap();
1338        assert!(!polygon.contains(&point_in_notch));
1339
1340        // Point inside the L-shape
1341        let point_inside = Geom::new_point(p(7.5, 5.0)).unwrap();
1342        assert!(polygon.contains(&point_inside));
1343
1344        // Point inside the vertical part of L
1345        let point_in_vertical = Geom::new_point(p(2.5, 7.5)).unwrap();
1346        assert!(polygon.contains(&point_in_vertical));
1347
1348        // Point at the corner of concavity
1349        let point_at_corner = Geom::new_point(p(5.0, 5.0)).unwrap();
1350        assert!(polygon.covers(&point_at_corner));
1351    }
1352
1353    #[test]
1354    fn test_geom_boundary_covers_vs_contains() {
1355        let ring = Ring::new(&rectangle()).unwrap();
1356        let poly = Poly::new_simple(&ring).unwrap();
1357        let polygon = Geom::new_polygon(&poly).unwrap();
1358
1359        // Corner point
1360        let corner = Geom::new_point(p(0.0, 0.0)).unwrap();
1361        assert!(polygon.covers(&corner));
1362        assert!(polygon.touches(&corner));
1363
1364        // Edge point
1365        let edge_point = Geom::new_point(p(5.0, 0.0)).unwrap();
1366        assert!(polygon.covers(&edge_point));
1367        assert!(polygon.touches(&edge_point));
1368
1369        // Interior point
1370        let interior = Geom::new_point(p(5.0, 5.0)).unwrap();
1371        assert!(polygon.covers(&interior));
1372        assert!(polygon.contains(&interior));
1373        assert!(!polygon.touches(&interior));
1374    }
1375
1376    #[test]
1377    fn test_geom_line_touches_polygon() {
1378        let ring = Ring::new(&rectangle()).unwrap();
1379        let poly = Poly::new_simple(&ring).unwrap();
1380        let polygon = Geom::new_polygon(&poly).unwrap();
1381
1382        // Line along bottom edge (touches)
1383        let line_on_edge = Line::new(&[p(2.0, 0.0), p(8.0, 0.0)]).unwrap();
1384        let geom_edge = Geom::new_linestring(&line_on_edge).unwrap();
1385        assert!(polygon.intersects(&geom_edge));
1386
1387        // Line extending from corner outward
1388        let line_from_corner = Line::new(&[p(0.0, 0.0), p(-5.0, -5.0)]).unwrap();
1389        let geom_corner = Geom::new_linestring(&line_from_corner).unwrap();
1390        assert!(polygon.touches(&geom_corner));
1391    }
1392
1393    #[test]
1394    fn test_geom_line_polygon_intersects() {
1395        let ring = Ring::new(&rectangle()).unwrap();
1396        let poly = Poly::new_simple(&ring).unwrap();
1397        let polygon = Geom::new_polygon(&poly).unwrap();
1398
1399        // Line completely inside polygon
1400        let line_inside = Line::new(&[p(2.0, 2.0), p(8.0, 8.0)]).unwrap();
1401        let geom_inside = Geom::new_linestring(&line_inside).unwrap();
1402        assert!(polygon.intersects(&geom_inside));
1403        assert!(polygon.covers(&geom_inside));
1404
1405        // Line crossing through polygon
1406        let line_cross = Line::new(&[p(-5.0, 5.0), p(15.0, 5.0)]).unwrap();
1407        let geom_cross = Geom::new_linestring(&line_cross).unwrap();
1408        assert!(polygon.intersects(&geom_cross));
1409        assert!(!polygon.covers(&geom_cross));
1410
1411        // Line completely outside polygon
1412        let line_outside = Line::new(&[p(15.0, 15.0), p(20.0, 20.0)]).unwrap();
1413        let geom_outside = Geom::new_linestring(&line_outside).unwrap();
1414        assert!(!polygon.intersects(&geom_outside));
1415        assert!(polygon.disjoint(&geom_outside));
1416    }
1417
1418    #[test]
1419    fn test_geom_line_through_hole() {
1420        let exterior = Ring::new(&octagon()).unwrap();
1421        let hole = Ring::new(&small_hole()).unwrap();
1422        let poly = Poly::new(&exterior, &[&hole]).unwrap();
1423        let polygon = Geom::new_polygon(&poly).unwrap();
1424
1425        // Line going around hole
1426        let line_around = Line::new(&[p(3.0, 3.0), p(3.0, 7.0), p(7.0, 7.0), p(7.0, 3.0)]).unwrap();
1427        let geom_around = Geom::new_linestring(&line_around).unwrap();
1428        assert!(polygon.intersects(&geom_around));
1429        assert!(polygon.covers(&geom_around));
1430
1431        // Line crossing through hole
1432        let line_through = Line::new(&[p(3.0, 5.0), p(7.0, 5.0)]).unwrap();
1433        let geom_through = Geom::new_linestring(&line_through).unwrap();
1434        assert!(polygon.intersects(&geom_through));
1435        assert!(!polygon.covers(&geom_through)); // Doesn't cover because passes through hole
1436    }
1437
1438    #[test]
1439    fn test_geom_polygon_covers_polygon() {
1440        let big_ring = Ring::new(&rectangle()).unwrap();
1441        let big_poly = Poly::new_simple(&big_ring).unwrap();
1442        let big = Geom::new_polygon(&big_poly).unwrap();
1443
1444        // Small polygon inside big one
1445        let small_ring = Ring::new(&[
1446            p(2.0, 2.0),
1447            p(8.0, 2.0),
1448            p(8.0, 8.0),
1449            p(2.0, 8.0),
1450            p(2.0, 2.0),
1451        ])
1452        .unwrap();
1453        let small_poly = Poly::new_simple(&small_ring).unwrap();
1454        let small = Geom::new_polygon(&small_poly).unwrap();
1455
1456        assert!(big.covers(&small));
1457        assert!(big.contains(&small));
1458        assert!(!small.covers(&big));
1459        assert!(small.within(&big));
1460    }
1461
1462    #[test]
1463    fn test_geom_polygon_overlap() {
1464        let ring1 = Ring::new(&[
1465            p(0.0, 0.0),
1466            p(10.0, 0.0),
1467            p(10.0, 10.0),
1468            p(0.0, 10.0),
1469            p(0.0, 0.0),
1470        ])
1471        .unwrap();
1472        let poly1 = Poly::new_simple(&ring1).unwrap();
1473        let geom1 = Geom::new_polygon(&poly1).unwrap();
1474
1475        let ring2 = Ring::new(&[
1476            p(5.0, 5.0),
1477            p(15.0, 5.0),
1478            p(15.0, 15.0),
1479            p(5.0, 15.0),
1480            p(5.0, 5.0),
1481        ])
1482        .unwrap();
1483        let poly2 = Poly::new_simple(&ring2).unwrap();
1484        let geom2 = Geom::new_polygon(&poly2).unwrap();
1485
1486        // Overlapping polygons intersect but don't cover each other
1487        assert!(geom1.intersects(&geom2));
1488        assert!(geom2.intersects(&geom1));
1489        assert!(!geom1.covers(&geom2));
1490        assert!(!geom2.covers(&geom1));
1491        assert!(!geom1.disjoint(&geom2));
1492    }
1493
1494    #[test]
1495    fn test_geom_polygon_disjoint() {
1496        let ring1 = Ring::new(&rectangle()).unwrap();
1497        let poly1 = Poly::new_simple(&ring1).unwrap();
1498        let geom1 = Geom::new_polygon(&poly1).unwrap();
1499
1500        let ring2 = Ring::new(&[
1501            p(20.0, 20.0),
1502            p(30.0, 20.0),
1503            p(30.0, 30.0),
1504            p(20.0, 30.0),
1505            p(20.0, 20.0),
1506        ])
1507        .unwrap();
1508        let poly2 = Poly::new_simple(&ring2).unwrap();
1509        let geom2 = Geom::new_polygon(&poly2).unwrap();
1510
1511        assert!(geom1.disjoint(&geom2));
1512        assert!(geom2.disjoint(&geom1));
1513        assert!(!geom1.intersects(&geom2));
1514    }
1515
1516    #[test]
1517    fn test_geom_polygon_adjacent() {
1518        let ring1 = Ring::new(&[
1519            p(0.0, 0.0),
1520            p(10.0, 0.0),
1521            p(10.0, 10.0),
1522            p(0.0, 10.0),
1523            p(0.0, 0.0),
1524        ])
1525        .unwrap();
1526        let poly1 = Poly::new_simple(&ring1).unwrap();
1527        let geom1 = Geom::new_polygon(&poly1).unwrap();
1528
1529        // Adjacent on right edge
1530        let ring2 = Ring::new(&[
1531            p(10.0, 0.0),
1532            p(20.0, 0.0),
1533            p(20.0, 10.0),
1534            p(10.0, 10.0),
1535            p(10.0, 0.0),
1536        ])
1537        .unwrap();
1538        let poly2 = Poly::new_simple(&ring2).unwrap();
1539        let geom2 = Geom::new_polygon(&poly2).unwrap();
1540
1541        // Adjacent polygons touch but interiors don't overlap
1542        assert!(geom1.touches(&geom2));
1543        assert!(geom1.intersects(&geom2));
1544    }
1545
1546    #[test]
1547    fn test_geom_polygon_hole_relations() {
1548        let exterior = Ring::new(&[
1549            p(0.0, 0.0),
1550            p(20.0, 0.0),
1551            p(20.0, 20.0),
1552            p(0.0, 20.0),
1553            p(0.0, 0.0),
1554        ])
1555        .unwrap();
1556        let hole = Ring::new(&[
1557            p(5.0, 5.0),
1558            p(15.0, 5.0),
1559            p(15.0, 15.0),
1560            p(5.0, 15.0),
1561            p(5.0, 5.0),
1562        ])
1563        .unwrap();
1564        let poly_with_hole = Poly::new(&exterior, &[&hole]).unwrap();
1565        let geom_with_hole = Geom::new_polygon(&poly_with_hole).unwrap();
1566
1567        // Small polygon that fits in the hole
1568        let inner_ring = Ring::new(&[
1569            p(7.0, 7.0),
1570            p(13.0, 7.0),
1571            p(13.0, 13.0),
1572            p(7.0, 13.0),
1573            p(7.0, 7.0),
1574        ])
1575        .unwrap();
1576        let inner_poly = Poly::new_simple(&inner_ring).unwrap();
1577        let inner = Geom::new_polygon(&inner_poly).unwrap();
1578
1579        // Polygon in hole is disjoint from polygon with hole
1580        assert!(geom_with_hole.disjoint(&inner));
1581        assert!(!geom_with_hole.contains(&inner));
1582        assert!(!geom_with_hole.covers(&inner));
1583    }
1584
1585    #[test]
1586    fn test_geom_identical_polygons() {
1587        let ring = Ring::new(&rectangle()).unwrap();
1588        let poly = Poly::new_simple(&ring).unwrap();
1589        let geom1 = Geom::new_polygon(&poly).unwrap();
1590        let geom2 = Geom::new_polygon(&poly).unwrap();
1591
1592        assert!(geom1.equals(&geom2));
1593        assert!(geom1.covers(&geom2));
1594        assert!(geom2.covers(&geom1));
1595        assert!(geom1.intersects(&geom2));
1596    }
1597
1598    #[test]
1599    fn test_geom_multipolygon_contains() {
1600        let ring1 = Ring::new(&rectangle()).unwrap();
1601        let poly1 = Poly::new_simple(&ring1).unwrap();
1602
1603        let ring2 = Ring::new(&[
1604            p(20.0, 0.0),
1605            p(30.0, 0.0),
1606            p(30.0, 10.0),
1607            p(20.0, 10.0),
1608            p(20.0, 0.0),
1609        ])
1610        .unwrap();
1611        let poly2 = Poly::new_simple(&ring2).unwrap();
1612
1613        let mp = Geom::new_multipolygon(&[&poly1, &poly2]).unwrap();
1614
1615        // Point in first polygon
1616        let p1 = Geom::new_point(p(5.0, 5.0)).unwrap();
1617        assert!(mp.contains(&p1));
1618
1619        // Point in second polygon
1620        let p2 = Geom::new_point(p(25.0, 5.0)).unwrap();
1621        assert!(mp.contains(&p2));
1622
1623        // Point between polygons
1624        let p3 = Geom::new_point(p(15.0, 5.0)).unwrap();
1625        assert!(!mp.contains(&p3));
1626    }
1627}