Skip to main content

geos/
prepared_geometry.rs

1use crate::context_handle::with_context;
2use crate::functions::*;
3use crate::traits::as_raw_impl;
4use crate::{AsRaw, GResult, Geom};
5use geos_sys::*;
6use std::marker::PhantomData;
7use std::ptr::NonNull;
8
9/// `PreparedGeometry` is an interface which prepares [`Geometry`](crate::Geometry) for greater performance
10/// on repeated calls.
11///
12/// # Example
13///
14/// ```
15/// use geos::{Geom, Geometry};
16///
17/// let geom1 = Geometry::new_from_wkt("POLYGON((0 0, 10 0, 10 6, 0 6, 0 0))")?;
18/// let mut prepared_geom = geom1.to_prepared_geom()?;
19/// let geom2 = Geometry::new_from_wkt("POINT (2.5 2.5)")?;
20///
21/// assert_eq!(prepared_geom.contains(&geom2)?, true);
22/// # Ok::<(), geos::Error>(())
23/// ```
24pub struct PreparedGeometry<'a> {
25    ptr: NonNull<GEOSPreparedGeometry>,
26    phantom: PhantomData<&'a ()>,
27}
28
29impl<'a> PreparedGeometry<'a> {
30    /// Creates a new `PreparedGeometry` from a [`Geometry`](crate::Geometry).
31    ///
32    /// # Example
33    ///
34    /// ```
35    /// use geos::{Geometry, PreparedGeometry};
36    ///
37    /// let geom1 = Geometry::new_from_wkt("POLYGON((0 0, 10 0, 10 6, 0 6, 0 0))")?;
38    /// let prepared_geom = PreparedGeometry::new(&geom1);
39    /// # Ok::<(), geos::Error>(())
40    /// ```
41    pub fn new<G: Geom>(g: &'a G) -> GResult<Self> {
42        with_context(|ctx| unsafe {
43            let ptr = nullcheck!(GEOSPrepare_r(ctx.as_raw(), g.as_raw()))?;
44            Ok(PreparedGeometry {
45                ptr,
46                phantom: PhantomData,
47            })
48        })
49    }
50
51    /// Returns `true` if no points of the other geometry is outside the exterior of `self`.
52    ///
53    /// # Example
54    ///
55    /// ```
56    /// use geos::{Geom, Geometry};
57    ///
58    /// let geom1 = Geometry::new_from_wkt("POLYGON((0 0, 10 0, 10 6, 0 6, 0 0))")?;
59    /// let mut prepared_geom = geom1.to_prepared_geom()?;
60    /// let geom2 = Geometry::new_from_wkt("POINT (2.5 2.5)")?;
61    ///
62    /// assert_eq!(prepared_geom.contains(&geom2)?, true);
63    /// # Ok::<(), geos::Error>(())
64    /// ```
65    pub fn contains<G: Geom>(&self, other: &G) -> GResult<bool> {
66        with_context(|ctx| unsafe {
67            predicate!(GEOSPreparedContains_r(
68                ctx.as_raw(),
69                self.as_raw(),
70                other.as_raw()
71            ))
72        })
73    }
74
75    /// Returns `true` if every point of the `other` geometry is inside self's interior.
76    ///
77    /// # Example
78    ///
79    /// ```
80    /// use geos::{Geom, Geometry};
81    ///
82    /// let geom1 = Geometry::new_from_wkt("POLYGON((0 0, 10 0, 10 6, 0 6, 0 0))")?;
83    /// let mut prepared_geom = geom1.to_prepared_geom()?;
84    /// let geom2 = Geometry::new_from_wkt("POINT (2.5 2.5)")?;
85    ///
86    /// assert_eq!(prepared_geom.contains_properly(&geom2)?, true);
87    /// # Ok::<(), geos::Error>(())
88    /// ```
89    pub fn contains_properly<G: Geom>(&self, other: &G) -> GResult<bool> {
90        with_context(|ctx| unsafe {
91            predicate!(GEOSPreparedContainsProperly_r(
92                ctx.as_raw(),
93                self.as_raw(),
94                other.as_raw()
95            ))
96        })
97    }
98
99    /// Returns `true` if no point of `self` is outside of `other`.
100    ///
101    /// # Example
102    ///
103    /// ```
104    /// use geos::{Geom, Geometry};
105    ///
106    /// let geom = Geometry::new_from_wkt("POINT (1 2)")?;
107    /// let little_geom = geom.buffer(10., 8)?;
108    /// let big_geom = geom.buffer(20., 8)?;
109    ///
110    /// let prepared_little_geom = little_geom.to_prepared_geom()?;
111    /// let prepared_big_geom = big_geom.to_prepared_geom()?;
112    ///
113    /// assert_eq!(prepared_little_geom.covered_by(&big_geom)?, true);
114    /// assert_eq!(prepared_big_geom.covered_by(&little_geom)?, false);
115    /// # Ok::<(), geos::Error>(())
116    /// ```
117    pub fn covered_by<G: Geom>(&self, other: &G) -> GResult<bool> {
118        with_context(|ctx| unsafe {
119            predicate!(GEOSPreparedCoveredBy_r(
120                ctx.as_raw(),
121                self.as_raw(),
122                other.as_raw()
123            ))
124        })
125    }
126
127    /// Returns `true` if no point of `other` is outside of `self`.
128    ///
129    /// # Example
130    ///
131    /// ```
132    /// use geos::{Geom, Geometry};
133    ///
134    /// let geom = Geometry::new_from_wkt("POINT (1 2)")?;
135    /// let little_geom = geom.buffer(10., 8)?;
136    /// let big_geom = geom.buffer(20., 8)?;
137    ///
138    /// let prepared_little_geom = little_geom.to_prepared_geom()?;
139    /// let prepared_big_geom = big_geom.to_prepared_geom()?;
140    ///
141    /// assert_eq!(prepared_little_geom.covers(&big_geom)?, false);
142    /// assert_eq!(prepared_big_geom.covers(&little_geom)?, true);
143    /// # Ok::<(), geos::Error>(())
144    /// ```
145    pub fn covers<G: Geom>(&self, other: &G) -> GResult<bool> {
146        with_context(|ctx| unsafe {
147            predicate!(GEOSPreparedCovers_r(
148                ctx.as_raw(),
149                self.as_raw(),
150                other.as_raw()
151            ))
152        })
153    }
154
155    /// Returns `true` if `self` and `other` have at least one interior into each other.
156    ///
157    /// # Example
158    ///
159    /// ```
160    /// use geos::{Geom, Geometry};
161    ///
162    /// let geom1 = Geometry::new_from_wkt("LINESTRING(1 1,2 2)")?;
163    /// let geom2 = Geometry::new_from_wkt("LINESTRING(2 1,1 2)")?;
164    /// let prepared_geom = geom1.to_prepared_geom()?;
165    ///
166    /// assert_eq!(prepared_geom.crosses(&geom2)?, true);
167    /// # Ok::<(), geos::Error>(())
168    /// ```
169    pub fn crosses<G: Geom>(&self, other: &G) -> GResult<bool> {
170        with_context(|ctx| unsafe {
171            predicate!(GEOSPreparedCrosses_r(
172                ctx.as_raw(),
173                self.as_raw(),
174                other.as_raw()
175            ))
176        })
177    }
178
179    /// Returns `true` if `self` doesn't:
180    ///
181    /// * Overlap `other`
182    /// * Touch `other`
183    /// * Is within `other`
184    ///
185    /// # Example
186    ///
187    /// ```
188    /// use geos::{Geom, Geometry};
189    ///
190    /// let geom1 = Geometry::new_from_wkt("POINT(0 0)")?;
191    /// let prepared_geom = geom1.to_prepared_geom()?;
192    /// let geom2 = Geometry::new_from_wkt("LINESTRING(2 0, 0 2)")?;
193    /// let geom3 = Geometry::new_from_wkt("LINESTRING(0 0, 0 2)")?;
194    ///
195    /// assert_eq!(prepared_geom.disjoint(&geom2)?, true);
196    /// assert_eq!(prepared_geom.disjoint(&geom3)?, false);
197    /// # Ok::<(), geos::Error>(())
198    /// ```
199    pub fn disjoint<G: Geom>(&self, other: &G) -> GResult<bool> {
200        with_context(|ctx| unsafe {
201            predicate!(GEOSPreparedDisjoint_r(
202                ctx.as_raw(),
203                self.as_raw(),
204                other.as_raw()
205            ))
206        })
207    }
208
209    /// Returns `true` if `self` shares any portion of space with `other`. So if any of this is
210    /// `true`:
211    ///
212    /// * `self` overlaps `other`
213    /// * `self` touches `other`
214    /// * `self` is within `other`
215    ///
216    /// Then `intersects` will return `true` as well.
217    ///
218    /// # Example
219    ///
220    /// ```
221    /// use geos::{Geom, Geometry};
222    ///
223    /// let geom1 = Geometry::new_from_wkt("POINT(0 0)")?;
224    /// let prepared_geom = geom1.to_prepared_geom()?;
225    /// let geom2 = Geometry::new_from_wkt("LINESTRING(2 0, 0 2)")?;
226    /// let geom3 = Geometry::new_from_wkt("LINESTRING(0 0, 0 2)")?;
227    ///
228    /// assert_eq!(prepared_geom.intersects(&geom2)?, false);
229    /// assert_eq!(prepared_geom.intersects(&geom3)?, true);
230    /// # Ok::<(), geos::Error>(())
231    /// ```
232    pub fn intersects<G: Geom>(&self, other: &G) -> GResult<bool> {
233        with_context(|ctx| unsafe {
234            predicate!(GEOSPreparedIntersects_r(
235                ctx.as_raw(),
236                self.as_raw(),
237                other.as_raw()
238            ))
239        })
240    }
241
242    /// Returns `true` if `self` spatially overlaps `other`.
243    ///
244    /// # Example
245    ///
246    /// ```
247    /// use geos::{Geom, Geometry};
248    ///
249    /// let geom1 = Geometry::new_from_wkt("POINT(1 0.5)")?;
250    /// let prepared_geom = geom1.to_prepared_geom()?;
251    /// let geom2 = Geometry::new_from_wkt("LINESTRING(1 0, 1 1, 3 5)")?;
252    ///
253    /// assert_eq!(prepared_geom.overlaps(&geom2)?, false);
254    ///
255    /// let geom1 = geom1.buffer(3., 8)?;
256    /// let prepared_geom = geom1.to_prepared_geom()?;
257    /// let geom2 = geom2.buffer(0.5, 8)?;
258    ///
259    /// assert_eq!(prepared_geom.overlaps(&geom2)?, true);
260    /// # Ok::<(), geos::Error>(())
261    /// ```
262    pub fn overlaps<G: Geom>(&self, other: &G) -> GResult<bool> {
263        with_context(|ctx| unsafe {
264            predicate!(GEOSPreparedOverlaps_r(
265                ctx.as_raw(),
266                self.as_raw(),
267                other.as_raw()
268            ))
269        })
270    }
271
272    /// Returns `true` if the only points in common between `self` and `other` lie in the union of
273    /// the boundaries of `self` and `other`.
274    ///
275    /// # Example
276    ///
277    /// ```
278    /// use geos::{Geom, Geometry};
279    ///
280    /// let geom1 = Geometry::new_from_wkt("LINESTRING(0 0, 1 1, 0 2)")?;
281    /// let prepared_geom = geom1.to_prepared_geom()?;
282    /// let geom2 = Geometry::new_from_wkt("POINT(1 1)")?;
283    ///
284    /// assert_eq!(prepared_geom.touches(&geom2)?, false);
285    ///
286    /// let geom2 = Geometry::new_from_wkt("POINT(0 2)")?;
287    ///
288    /// assert_eq!(prepared_geom.touches(&geom2)?, true);
289    /// # Ok::<(), geos::Error>(())
290    /// ```
291    pub fn touches<G: Geom>(&self, other: &G) -> GResult<bool> {
292        with_context(|ctx| unsafe {
293            predicate!(GEOSPreparedTouches_r(
294                ctx.as_raw(),
295                self.as_raw(),
296                other.as_raw()
297            ))
298        })
299    }
300
301    /// Returns `true` if `self` is completely inside `other`.
302    ///
303    /// # Example
304    ///
305    /// ```
306    /// use geos::{Geom, Geometry};
307    ///
308    /// let geom = Geometry::new_from_wkt("POINT(50 50)")?;
309    /// let small_geom = geom.buffer(20., 8)?;
310    /// let big_geom = geom.buffer(40., 8)?;
311    ///
312    /// let small_prepared_geom = small_geom.to_prepared_geom()?;
313    /// let big_prepared_geom = big_geom.to_prepared_geom()?;
314    ///
315    /// assert_eq!(small_prepared_geom.within(&small_geom)?, true);
316    /// assert_eq!(small_prepared_geom.within(&big_geom)?, true);
317    /// assert_eq!(big_prepared_geom.within(&small_geom)?, false);
318    /// # Ok::<(), geos::Error>(())
319    /// ```
320    pub fn within<G: Geom>(&self, other: &G) -> GResult<bool> {
321        with_context(|ctx| unsafe {
322            predicate!(GEOSPreparedWithin_r(
323                ctx.as_raw(),
324                self.as_raw(),
325                other.as_raw()
326            ))
327        })
328    }
329
330    /// Returns `true` if the distance between `self` and `other` is shorter than `distance`.
331    ///
332    /// # Example
333    ///
334    /// ```
335    /// use geos::{Geom, Geometry};
336    ///
337    /// let geom1 = Geometry::new_from_wkt("POINT (1 2)")?;
338    /// let geom2 = Geometry::new_from_wkt("POINT (2 2)")?;
339    /// let geom3 = Geometry::new_from_wkt("POINT (3 2)")?;
340    ///
341    /// let prepared_geom = geom1.to_prepared_geom()?;
342    /// assert_eq!(prepared_geom.dwithin(&geom2, 1.0)?, true);
343    /// assert_eq!(prepared_geom.dwithin(&geom3, 1.0)?, false);
344    /// # Ok::<(), geos::Error>(())
345    /// ```
346    #[cfg(feature = "v3_10_0")]
347    pub fn dwithin<G: Geom>(&self, other: &G, distance: f64) -> GResult<bool> {
348        with_context(|ctx| unsafe {
349            predicate!(GEOSPreparedDistanceWithin_r(
350                ctx.as_raw(),
351                self.as_raw(),
352                other.as_raw(),
353                distance
354            ))
355        })
356    }
357
358    #[cfg(feature = "v3_12_0")]
359    pub fn contains_xy(&self, x: f64, y: f64) -> GResult<bool> {
360        with_context(|ctx| unsafe {
361            predicate!(GEOSPreparedContainsXY_r(ctx.as_raw(), self.as_raw(), x, y))
362        })
363    }
364
365    #[cfg(feature = "v3_12_0")]
366    pub fn intersects_xy(&self, x: f64, y: f64) -> GResult<bool> {
367        with_context(|ctx| unsafe {
368            predicate!(GEOSPreparedIntersectsXY_r(
369                ctx.as_raw(),
370                self.as_raw(),
371                x,
372                y
373            ))
374        })
375    }
376
377    #[cfg(feature = "v3_9_0")]
378    pub fn distance<G: Geom>(&self, other: &G) -> GResult<f64> {
379        with_context(|ctx| unsafe {
380            let mut distance = 0.0;
381            errcheck!(GEOSPreparedDistance_r(
382                ctx.as_raw(),
383                self.as_raw(),
384                other.as_raw(),
385                &mut distance
386            ))?;
387            Ok(distance)
388        })
389    }
390}
391
392unsafe impl Send for PreparedGeometry<'_> {}
393unsafe impl Sync for PreparedGeometry<'_> {}
394
395impl Drop for PreparedGeometry<'_> {
396    fn drop(&mut self) {
397        with_context(|ctx| unsafe { GEOSPreparedGeom_destroy_r(ctx.as_raw(), self.as_raw()) });
398    }
399}
400
401as_raw_impl!(PreparedGeometry<'_>, GEOSPreparedGeometry);
402
403/// Tests to ensure that the lifetime is correctly set.
404///
405/// ```compile_fail
406/// use geos::{Geom, Geometry, PreparedGeometry};
407///
408/// pub struct Boo {
409///     #[allow(dead_code)]
410///     geom: Geometry<'static>,
411///     pub prep: PreparedGeometry<'static>,
412/// }
413/// let boo = {
414///     let geom = Geometry::new_from_wkt("POLYGON((0 0, 10 0, 10 6, 0 6, 0 0))")?;
415///     let prep = geom.to_prepared_geom()?;
416///      Boo { geom, prep }
417/// };
418/// let pt = Geometry::new_from_wkt("POINT (2.5 2.5)")?;
419/// assert!(boo.prep.contains(&pt)?);
420/// ```
421///
422/// ```compile_fail
423/// use geos::{Geom, Geometry, PreparedGeometry};
424///
425/// pub struct Boo {
426///     pub prep: PreparedGeometry<'static>,
427/// }
428///
429/// let boo = {
430///     let geom1 = Geometry::new_from_wkt("POLYGON((0 0, 10 0, 10 6, 0 6, 0 0))")?;
431///     let prep = geom1.to_prepared_geom()?
432///
433///     Boo { prep }
434/// };
435///
436/// let pt = Geometry::new_from_wkt("POINT (2.5 2.5)")?;
437///
438/// assert!(boo.prep.contains(&pt)?);
439/// ```
440#[cfg(doctest)]
441pub mod lifetime_checks {}
442
443/// This code is not supposed to compile since `PreparedGeometry` is not supposed to outlive
444/// `Geometry`!
445///
446/// ```compile_fail
447/// let prep_geom = {
448///     let geom = crate::Geometry::new_from_wkt("POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))")?;
449///     geom.to_prepared_geom()?
450/// };
451///
452/// let pt = crate::Geometry::new_from_wkt("POINT(2 2)")?;
453/// _ = prep_geom.contains(&pt);
454/// ```
455#[cfg(doctest)]
456mod lifetime_prepared_geom_sigsegv {}