use crate::context_handle::PtrWrap;
use crate::error::{Error, PredicateType};
use crate::functions::*;
use crate::{AsRaw, ContextHandle, ContextHandling, ContextInteractions, GResult, Geom};
use geos_sys::*;
use std::mem::transmute;
use std::sync::Arc;
/// `PreparedGeometry` is an interface which prepares [`Geometry`](crate::Geometry) for greater performance
/// on repeated calls.
///
/// # Example
///
/// ```
/// use geos::{Geom, Geometry};
///
/// let geom1 = Geometry::new_from_wkt("POLYGON((0 0, 10 0, 10 6, 0 6, 0 0))")
/// .expect("Invalid geometry");
/// let mut prepared_geom = geom1.to_prepared_geom()
/// .expect("failed to create prepared geom");
/// let geom2 = Geometry::new_from_wkt("POINT (2.5 2.5)")
/// .expect("Invalid geometry");
///
/// assert_eq!(prepared_geom.contains(&geom2), Ok(true));
/// ```
pub struct PreparedGeometry<'a> {
ptr: PtrWrap<*const GEOSPreparedGeometry>,
context: Arc<ContextHandle<'a>>,
}
impl<'a> PreparedGeometry<'a> {
/// Creates a new `PreparedGeometry` from a [`Geometry`](crate::Geometry).
///
/// # Example
///
/// ```
/// use geos::{Geometry, PreparedGeometry};
///
/// let geom1 = Geometry::new_from_wkt("POLYGON((0 0, 10 0, 10 6, 0 6, 0 0))")
/// .expect("Invalid geometry");
/// let prepared_geom = PreparedGeometry::new(&geom1);
/// ```
pub fn new<'b: 'a, G: Geom<'b>>(g: &'a G) -> GResult<PreparedGeometry<'a>> {
unsafe {
let ptr = GEOSPrepare_r(g.get_raw_context(), g.as_raw());
PreparedGeometry::new_from_raw(ptr, transmute(g.clone_context()), "new")
}
}
pub(crate) unsafe fn new_from_raw(
ptr: *const GEOSPreparedGeometry,
context: Arc<ContextHandle<'a>>,
caller: &str,
) -> GResult<PreparedGeometry<'a>> {
if ptr.is_null() {
let extra = if let Some(x) = context.get_last_error() {
format!("\nLast error: {}", x)
} else {
String::new()
};
return Err(Error::NoConstructionFromNullPtr(format!(
"PreparedGeometry::{}{}",
caller, extra
)));
}
Ok(PreparedGeometry {
ptr: PtrWrap(ptr),
context,
})
}
/// Returns `true` if no points of the other geometry is outside the exterior of `self`.
///
/// # Example
///
/// ```
/// use geos::{Geom, Geometry};
///
/// let geom1 = Geometry::new_from_wkt("POLYGON((0 0, 10 0, 10 6, 0 6, 0 0))")
/// .expect("Invalid geometry");
/// let mut prepared_geom = geom1
/// .to_prepared_geom()
/// .expect("failed to create prepared geom");
/// let geom2 = Geometry::new_from_wkt("POINT (2.5 2.5)")
/// .expect("Invalid geometry");
///
/// assert_eq!(prepared_geom.contains(&geom2), Ok(true));
/// ```
pub fn contains<'b, G: Geom<'b>>(&self, other: &G) -> GResult<bool> {
let ret_val = unsafe {
GEOSPreparedContains_r(self.get_raw_context(), self.as_raw(), other.as_raw())
};
check_geos_predicate(ret_val as _, PredicateType::PreparedContains)
}
/// Returns `true` if every point of the `other` geometry is inside self's interior.
///
/// # Example
///
/// ```
/// use geos::{Geom, Geometry};
///
/// let geom1 = Geometry::new_from_wkt("POLYGON((0 0, 10 0, 10 6, 0 6, 0 0))")
/// .expect("Invalid geometry");
/// let mut prepared_geom = geom1
/// .to_prepared_geom()
/// .expect("failed to create prepared geom");
/// let geom2 = Geometry::new_from_wkt("POINT (2.5 2.5)")
/// .expect("Invalid geometry");
///
/// assert_eq!(prepared_geom.contains_properly(&geom2), Ok(true));
/// ```
pub fn contains_properly<'b, G: Geom<'b>>(&self, other: &G) -> GResult<bool> {
let ret_val = unsafe {
GEOSPreparedContainsProperly_r(self.get_raw_context(), self.as_raw(), other.as_raw())
};
check_geos_predicate(ret_val as _, PredicateType::PreparedContainsProperly)
}
/// Returns `true` if no point of `self` is outside of `other`.
///
/// # Example
///
/// ```
/// use geos::{Geom, Geometry};
///
/// let geom = Geometry::new_from_wkt("POINT (1 2)")
/// .expect("Invalid geometry");
/// let little_geom = geom.buffer(10., 8).expect("buffer failed");
/// let big_geom = geom.buffer(20., 8).expect("buffer failed");
///
/// let prepared_little_geom = little_geom
/// .to_prepared_geom()
/// .expect("to_prepared_geom failed");
/// let prepared_big_geom = big_geom
/// .to_prepared_geom()
/// .expect("to_prepared_geom failed");
///
/// assert_eq!(prepared_little_geom.covered_by(&big_geom), Ok(true));
/// assert_eq!(prepared_big_geom.covered_by(&little_geom), Ok(false));
/// ```
pub fn covered_by<'b, G: Geom<'b>>(&self, other: &G) -> GResult<bool> {
let ret_val = unsafe {
GEOSPreparedCoveredBy_r(self.get_raw_context(), self.as_raw(), other.as_raw())
};
check_geos_predicate(ret_val as _, PredicateType::PreparedCoveredBy)
}
/// Returns `true` if no point of `other` is outside of `self`.
///
/// # Example
///
/// ```
/// use geos::{Geom, Geometry};
///
/// let geom = Geometry::new_from_wkt("POINT (1 2)")
/// .expect("Invalid geometry");
/// let little_geom = geom.buffer(10., 8).expect("buffer failed");
/// let big_geom = geom.buffer(20., 8).expect("buffer failed");
///
/// let prepared_little_geom = little_geom
/// .to_prepared_geom()
/// .expect("to_prepared_geom failed");
/// let prepared_big_geom = big_geom
/// .to_prepared_geom()
/// .expect("to_prepared_geom failed");
///
/// assert_eq!(prepared_little_geom.covers(&big_geom), Ok(false));
/// assert_eq!(prepared_big_geom.covers(&little_geom), Ok(true));
/// ```
pub fn covers<'b, G: Geom<'b>>(&self, other: &G) -> GResult<bool> {
let ret_val =
unsafe { GEOSPreparedCovers_r(self.get_raw_context(), self.as_raw(), other.as_raw()) };
check_geos_predicate(ret_val as _, PredicateType::PreparedCovers)
}
/// Returns `true` if `self` and `other` have at least one interior into each other.
///
/// # Example
///
/// ```
/// use geos::{Geom, Geometry};
///
/// let geom1 = Geometry::new_from_wkt("LINESTRING(1 1,2 2)")
/// .expect("invalid geometry");
/// let geom2 = Geometry::new_from_wkt("LINESTRING(2 1,1 2)")
/// .expect("invalid geometry");
/// let prepared_geom = geom1.to_prepared_geom().expect("to_prepared_geom failed");
///
/// assert_eq!(prepared_geom.crosses(&geom2), Ok(true));
/// ```
pub fn crosses<'b, G: Geom<'b>>(&self, other: &G) -> GResult<bool> {
let ret_val =
unsafe { GEOSPreparedCrosses_r(self.get_raw_context(), self.as_raw(), other.as_raw()) };
check_geos_predicate(ret_val as _, PredicateType::PreparedCrosses)
}
/// Returns `true` if `self` doesn't:
///
/// * Overlap `other`
/// * Touch `other`
/// * Is within `other`
///
/// # Example
///
/// ```
/// use geos::{Geom, Geometry};
///
/// let geom1 = Geometry::new_from_wkt("POINT(0 0)")
/// .expect("invalid geometry");
/// let prepared_geom = geom1
/// .to_prepared_geom()
/// .expect("to_prepared_geom failed");
/// let geom2 = Geometry::new_from_wkt("LINESTRING(2 0, 0 2)")
/// .expect("invalid geometry");
/// let geom3 = Geometry::new_from_wkt("LINESTRING(0 0, 0 2)")
/// .expect("invalid geometry");
///
/// assert_eq!(prepared_geom.disjoint(&geom2), Ok(true));
/// assert_eq!(prepared_geom.disjoint(&geom3), Ok(false));
/// ```
pub fn disjoint<'b, G: Geom<'b>>(&self, other: &G) -> GResult<bool> {
let ret_val = unsafe {
GEOSPreparedDisjoint_r(self.get_raw_context(), self.as_raw(), other.as_raw())
};
check_geos_predicate(ret_val as _, PredicateType::PreparedDisjoint)
}
/// Returns `true` if `self` shares any portion of space with `other`. So if any of this is
/// `true`:
///
/// * `self` overlaps `other`
/// * `self` touches `other`
/// * `self` is within `other`
///
/// Then `intersects` will return `true` as well.
///
/// # Example
///
/// ```
/// use geos::{Geom, Geometry};
///
/// let geom1 = Geometry::new_from_wkt("POINT(0 0)")
/// .expect("invalid geometry");
/// let prepared_geom = geom1
/// .to_prepared_geom()
/// .expect("to_prepared_geom failed");
/// let geom2 = Geometry::new_from_wkt("LINESTRING(2 0, 0 2)")
/// .expect("invalid geometry");
/// let geom3 = Geometry::new_from_wkt("LINESTRING(0 0, 0 2)")
/// .expect("invalid geometry");
///
/// assert_eq!(prepared_geom.intersects(&geom2), Ok(false));
/// assert_eq!(prepared_geom.intersects(&geom3), Ok(true));
/// ```
pub fn intersects<'b, G: Geom<'b>>(&self, other: &G) -> GResult<bool> {
let ret_val = unsafe {
GEOSPreparedIntersects_r(self.get_raw_context(), self.as_raw(), other.as_raw())
};
check_geos_predicate(ret_val as _, PredicateType::PreparedIntersects)
}
/// Returns `true` if `self` spatially overlaps `other`.
///
/// # Example
///
/// ```
/// use geos::{Geom, Geometry};
///
/// let geom1 = Geometry::new_from_wkt("POINT(1 0.5)")
/// .expect("invalid geometry");
/// let prepared_geom = geom1
/// .to_prepared_geom()
/// .expect("to_prepared_geom failed");
/// let geom2 = Geometry::new_from_wkt("LINESTRING(1 0, 1 1, 3 5)")
/// .expect("invalid geometry");
///
/// assert_eq!(prepared_geom.overlaps(&geom2), Ok(false));
///
/// let geom1 = geom1.buffer(3., 8).expect("buffer failed");
/// let prepared_geom = geom1
/// .to_prepared_geom()
/// .expect("to_prepared_geom failed");
/// let geom2 = geom2.buffer(0.5, 8).expect("buffer failed");
///
/// assert_eq!(prepared_geom.overlaps(&geom2), Ok(true));
/// ```
pub fn overlaps<'b, G: Geom<'b>>(&self, other: &G) -> GResult<bool> {
let ret_val = unsafe {
GEOSPreparedOverlaps_r(self.get_raw_context(), self.as_raw(), other.as_raw())
};
check_geos_predicate(ret_val as _, PredicateType::PreparedOverlaps)
}
/// Returns `true` if the only points in common between `self` and `other` lie in the union of
/// the boundaries of `self` and `other`.
///
/// # Example
///
/// ```
/// use geos::{Geom, Geometry};
///
/// let geom1 = Geometry::new_from_wkt("LINESTRING(0 0, 1 1, 0 2)")
/// .expect("invalid geometry");
/// let prepared_geom = geom1
/// .to_prepared_geom()
/// .expect("to_prepared_geom failed");
/// let geom2 = Geometry::new_from_wkt("POINT(1 1)").expect("invalid geometry");
///
/// assert_eq!(prepared_geom.touches(&geom2), Ok(false));
///
/// let geom2 = Geometry::new_from_wkt("POINT(0 2)").expect("invalid geometry");
///
/// assert_eq!(prepared_geom.touches(&geom2), Ok(true));
/// ```
pub fn touches<'b, G: Geom<'b>>(&self, other: &G) -> GResult<bool> {
let ret_val =
unsafe { GEOSPreparedTouches_r(self.get_raw_context(), self.as_raw(), other.as_raw()) };
check_geos_predicate(ret_val as _, PredicateType::PreparedTouches)
}
/// Returns `true` if `self` is completely inside `other`.
///
/// # Example
///
/// ```
/// use geos::{Geom, Geometry};
///
/// let geom = Geometry::new_from_wkt("POINT(50 50)")
/// .expect("invalid geometry");
/// let small_geom = geom.buffer(20., 8).expect("buffer failed");
/// let big_geom = geom.buffer(40., 8).expect("buffer failed");
///
/// let small_prepared_geom = small_geom
/// .to_prepared_geom()
/// .expect("to_prepared_geom failed");
/// let big_prepared_geom = big_geom
/// .to_prepared_geom()
/// .expect("to_prepared_geom failed");
///
/// assert_eq!(small_prepared_geom.within(&small_geom), Ok(true));
/// assert_eq!(small_prepared_geom.within(&big_geom), Ok(true));
/// assert_eq!(big_prepared_geom.within(&small_geom), Ok(false));
/// ```
pub fn within<'b, G: Geom<'b>>(&self, other: &G) -> GResult<bool> {
let ret_val =
unsafe { GEOSPreparedWithin_r(self.get_raw_context(), self.as_raw(), other.as_raw()) };
check_geos_predicate(ret_val as _, PredicateType::PreparedWithin)
}
}
unsafe impl<'a> Send for PreparedGeometry<'a> {}
unsafe impl<'a> Sync for PreparedGeometry<'a> {}
impl<'a> Drop for PreparedGeometry<'a> {
fn drop(&mut self) {
unsafe { GEOSPreparedGeom_destroy_r(self.get_raw_context(), self.as_raw()) };
}
}
impl<'a> ContextInteractions<'a> for PreparedGeometry<'a> {
/// Set the context handle to the `PreparedGeometry`.
///
/// ```
/// use geos::{
/// ContextInteractions, ContextHandle, Geom, Geometry, PreparedGeometry,
/// };
///
/// let point_geom = Geometry::new_from_wkt("POINT (2.5 2.5)")
/// .expect("Invalid geometry");
/// let context_handle = ContextHandle::init().expect("invalid init");
/// let mut prepared_geom = point_geom
/// .to_prepared_geom()
/// .expect("failed to create prepared geom");
/// context_handle.set_notice_message_handler(
/// Some(Box::new(|s| println!("new message: {}", s)))
/// );
/// prepared_geom.set_context_handle(context_handle);
/// ```
fn set_context_handle(&mut self, context: ContextHandle<'a>) {
self.context = Arc::new(context);
}
/// Get the context handle of the `PreparedGeometry`.
///
/// ```
/// use geos::{
/// ContextInteractions, CoordDimensions, Geom, Geometry,
/// PreparedGeometry,
/// };
///
/// let point_geom = Geometry::new_from_wkt("POINT (2.5 2.5)")
/// .expect("Invalid geometry");
/// let prepared_geom = point_geom.to_prepared_geom()
/// .expect("failed to create prepared geom");
/// let context = prepared_geom.get_context_handle();
/// context.set_notice_message_handler(Some(Box::new(|s| println!("new message: {}", s))));
/// ```
fn get_context_handle(&self) -> &ContextHandle<'a> {
&self.context
}
}
impl<'a> AsRaw for PreparedGeometry<'a> {
type RawType = GEOSPreparedGeometry;
fn as_raw(&self) -> *const Self::RawType {
*self.ptr
}
}
impl<'a> ContextHandling for PreparedGeometry<'a> {
type Context = Arc<ContextHandle<'a>>;
fn get_raw_context(&self) -> GEOSContextHandle_t {
self.context.as_raw()
}
fn clone_context(&self) -> Arc<ContextHandle<'a>> {
Arc::clone(&self.context)
}
}
/// Tests to ensure that the lifetime is correctly set.
///
/// ```compile_fail
/// use geos::{Geom, Geometry, PreparedGeometry};
///
/// pub struct Boo {
/// #[allow(dead_code)]
/// geom: Geometry<'static>,
/// pub prep: PreparedGeometry<'static>,
/// }
/// let boo = {
/// let geom = Geometry::new_from_wkt("POLYGON((0 0, 10 0, 10 6, 0 6, 0 0))")
/// .expect("Invalid geometry");
/// let prep = geom
/// .to_prepared_geom()
/// .expect("failed to create prepared geom");
/// Boo { geom, prep }
/// };
/// let pt = Geometry::new_from_wkt("POINT (2.5 2.5)").expect("Invalid geometry");
/// assert!(boo.prep.contains(&pt).unwrap());
/// ```
///
/// ```compile_fail
/// use geos::{Geom, Geometry, PreparedGeometry};
///
/// pub struct Boo {
/// pub prep: PreparedGeometry<'static>,
/// }
///
/// let boo = {
/// let geom1 = Geometry::new_from_wkt("POLYGON((0 0, 10 0, 10 6, 0 6, 0 0))")
/// .expect("Invalid geometry");
/// let prep = geom1
/// .to_prepared_geom()
/// .expect("failed to create prepared geom");
///
/// Boo { prep }
/// };
///
/// let pt = Geometry::new_from_wkt("POINT (2.5 2.5)").expect("Invalid geometry");
///
/// assert!(boo.prep.contains(&pt).unwrap());
/// ```
#[cfg(doctest)]
pub mod lifetime_checks {}