use crate::context_handle::PtrWrap;
use crate::enums::*;
use crate::error::{Error, GResult, PredicateType};
use crate::geometry::Geometry;
use crate::{AsRawMut, ContextHandle, ContextHandling, Geom};
use geos_sys::*;
use std::convert::TryFrom;
use std::ffi::CStr;
use std::os::raw::c_char;
use std::str;
use std::sync::Arc;
pub(crate) unsafe fn unmanaged_string(raw_ptr: *const c_char, caller: &str) -> GResult<String> {
if raw_ptr.is_null() {
return Err(Error::NoConstructionFromNullPtr(format!(
"{caller}::unmanaged_string",
)));
}
let c_str = CStr::from_ptr(raw_ptr);
match str::from_utf8(c_str.to_bytes()) {
Ok(s) => Ok(s.to_string()),
Err(e) => Err(Error::GenericError(format!(
"{caller}::unmanaged_string failed: {e}",
))),
}
}
pub(crate) unsafe fn managed_string(
raw_ptr: *mut c_char,
context: &ContextHandle,
caller: &str,
) -> GResult<String> {
if raw_ptr.is_null() {
return Err(Error::NoConstructionFromNullPtr(format!(
"{caller}::managed_string",
)));
}
let s = unmanaged_string(raw_ptr, caller);
GEOSFree_r(context.as_raw(), raw_ptr as *mut _);
s
}
#[allow(dead_code)]
pub fn clip_by_rect<'a, G: Geom<'a>>(
g: &G,
xmin: f64,
ymin: f64,
xmax: f64,
ymax: f64,
) -> GResult<Geometry<'a>> {
unsafe {
let context = g.clone_context();
let ptr = GEOSClipByRect_r(context.as_raw(), g.as_raw(), xmin, ymin, xmax, ymax);
Geometry::new_from_raw(ptr, context, "clip_by_rect")
}
}
pub fn version() -> GResult<String> {
unsafe { unmanaged_string(GEOSversion(), "version") }
}
pub(crate) fn check_geos_predicate(val: i8, p: PredicateType) -> GResult<bool> {
match val {
1 => Ok(true),
0 => Ok(false),
_ => Err(Error::GeosFunctionError(p, val as _)),
}
}
pub(crate) fn check_ret(val: i32, p: PredicateType) -> GResult<()> {
match val {
1 => Ok(()),
_ => Err(Error::GeosFunctionError(p, val)),
}
}
pub(crate) fn check_same_geometry_type(geoms: &[Geometry], geom_type: GeometryTypes) -> bool {
geoms.iter().all(|g| g.geometry_type() == geom_type)
}
pub(crate) fn create_multi_geom(
mut geoms: Vec<Geometry<'_>>,
output_type: GeometryTypes,
) -> GResult<Geometry<'_>> {
let nb_geoms = geoms.len();
let context = if geoms.is_empty() {
match ContextHandle::init() {
Ok(ch) => Arc::new(ch),
_ => return Err(Error::GenericError("GEOS_init_r failed".to_owned())),
}
} else {
geoms[0].clone_context()
};
let res = {
let mut geoms: Vec<*mut GEOSGeometry> = geoms.iter_mut().map(|g| g.as_raw_mut()).collect();
unsafe {
let ptr = GEOSGeom_createCollection_r(
context.as_raw(),
output_type.into(),
geoms.as_mut_ptr() as *mut _,
nb_geoms as _,
);
Geometry::new_from_raw(ptr, context, "create_multi_geom")
}
};
for g in geoms.iter_mut() {
g.ptr = PtrWrap(::std::ptr::null_mut());
}
res
}
pub fn orientation_index(
ax: f64,
ay: f64,
bx: f64,
by: f64,
px: f64,
py: f64,
) -> GResult<Orientation> {
match ContextHandle::init() {
Ok(context) => unsafe {
match Orientation::try_from(GEOSOrientationIndex_r(
context.as_raw(),
ax,
ay,
bx,
by,
px,
py,
)) {
Ok(o) => Ok(o),
Err(e) => Err(Error::GenericError(e.to_owned())),
}
},
Err(e) => Err(e),
}
}
#[cfg(any(feature = "v3_7_0", feature = "dox"))]
#[allow(clippy::too_many_arguments)]
pub fn segment_intersection(
ax0: f64,
ay0: f64,
ax1: f64,
ay1: f64,
bx0: f64,
by0: f64,
bx1: f64,
by1: f64,
) -> GResult<Option<(f64, f64)>> {
match ContextHandle::init() {
Ok(context) => unsafe {
let mut cx = 0.;
let mut cy = 0.;
let ret = GEOSSegmentIntersection_r(
context.as_raw(),
ax0,
ay0,
ax1,
ay1,
bx0,
by0,
bx1,
by1,
&mut cx,
&mut cy,
);
if ret == -1 {
Ok(None)
} else if ret == 0 {
Ok(Some((cx, cy)))
} else {
Err(Error::GenericError(
"GEOSSegmentIntersection_r failed".to_owned(),
))
}
},
Err(e) => Err(e),
}
}
#[cfg(test)]
mod test {
use super::check_geos_predicate;
use crate::error::PredicateType;
#[test]
fn check_geos_predicate_ok_test() {
assert!(!check_geos_predicate(0, PredicateType::Intersects).unwrap());
}
#[test]
fn check_geos_predicate_ko_test() {
assert!(check_geos_predicate(1, PredicateType::Intersects).unwrap());
}
#[test]
fn check_geos_predicate_err_test() {
let r = check_geos_predicate(42, PredicateType::Intersects);
let e = r.err().unwrap();
assert_eq!(
format!("{}", e),
"error while calling libgeos method Intersects (error number = 42)".to_string()
);
}
}