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 {}