use crate::context_handle::PtrWrap;
use crate::error::Error;
use crate::functions::*;
use crate::{
AsRaw, AsRawMut, ContextHandle, ContextHandling, ContextInteractions, GResult, Geom,
OutputDimension,
};
use geos_sys::*;
use std::convert::TryFrom;
use std::sync::Arc;
/// The `WKTWriter` type is used to generate `WKT` formatted output from [`Geometry`](crate::Geometry).
///
/// # Example
///
/// ```
/// use geos::{Geometry, WKTWriter};
///
/// let point_geom = Geometry::new_from_wkt("POINT (2.5 2.5)").expect("Invalid geometry");
/// let mut writer = WKTWriter::new().expect("Failed to create WKTWriter");
///
/// assert_eq!(writer.write(&point_geom).unwrap(), "POINT (2.5000000000000000 2.5000000000000000)");
/// ```
pub struct WKTWriter<'a> {
ptr: PtrWrap<*mut GEOSWKTWriter>,
context: Arc<ContextHandle<'a>>,
}
impl<'a> WKTWriter<'a> {
/// Creates a new `WKTWriter` instance.
///
/// # Example
///
/// ```
/// use geos::{Geometry, WKTWriter};
///
/// let point_geom = Geometry::new_from_wkt("POINT (2.5 2.5)").expect("Invalid geometry");
/// let mut writer = WKTWriter::new().expect("Failed to create WKTWriter");
///
/// assert_eq!(writer.write(&point_geom).unwrap(), "POINT (2.5000000000000000 2.5000000000000000)");
/// ```
pub fn new() -> GResult<WKTWriter<'a>> {
match ContextHandle::init_e(Some("WKTWriter::new")) {
Ok(context_handle) => Self::new_with_context(Arc::new(context_handle)),
Err(e) => Err(e),
}
}
/// Creates a new `WKTWriter` instance with a given context.
///
/// # Example
///
/// ```
/// use geos::{ContextHandling, Geometry, WKTWriter};
///
/// let point_geom = Geometry::new_from_wkt("POINT (2.5 2.5)").expect("Invalid geometry");
/// let mut writer = WKTWriter::new_with_context(point_geom.clone_context())
/// .expect("Failed to create WKTWriter");
///
/// assert_eq!(writer.write(&point_geom).unwrap(), "POINT (2.5000000000000000 2.5000000000000000)");
/// ```
pub fn new_with_context(context: Arc<ContextHandle<'a>>) -> GResult<WKTWriter<'a>> {
unsafe {
let ptr = GEOSWKTWriter_create_r(context.as_raw());
WKTWriter::new_from_raw(ptr, context, "new_with_context")
}
}
pub(crate) unsafe fn new_from_raw(
ptr: *mut GEOSWKTWriter,
context: Arc<ContextHandle<'a>>,
caller: &str,
) -> GResult<WKTWriter<'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!(
"WKTWriter::{}{}",
caller, extra
)));
}
Ok(WKTWriter {
ptr: PtrWrap(ptr),
context,
})
}
/// Writes out the given `geometry` as WKT format.
///
/// # Example
///
/// ```
/// use geos::{Geometry, WKTWriter};
///
/// let point_geom = Geometry::new_from_wkt("POINT (2.5 2.5)").expect("Invalid geometry");
/// let mut writer = WKTWriter::new().expect("Failed to create WKTWriter");
///
/// assert_eq!(writer.write(&point_geom).unwrap(), "POINT (2.5000000000000000 2.5000000000000000)");
/// ```
pub fn write<'b, G: Geom<'b>>(&mut self, geometry: &G) -> GResult<String> {
unsafe {
let ptr =
GEOSWKTWriter_write_r(self.get_raw_context(), self.as_raw_mut(), geometry.as_raw());
managed_string(ptr, self.get_context_handle(), "WKTWriter::write")
}
}
/// Sets the `precision` to be used when calling [`WKTWriter::write`]. Often, what users
/// actually want is the [`WKTWriter::set_trim`] method instead.
///
/// # Example
///
/// ```
/// use geos::{Geometry, WKTWriter};
///
/// let point_geom = Geometry::new_from_wkt("POINT (2.5 2.5)").expect("Invalid geometry");
/// let mut writer = WKTWriter::new().expect("Failed to create WKTWriter");
///
/// writer.set_rounding_precision(2);
/// assert_eq!(writer.write(&point_geom).unwrap(), "POINT (2.50 2.50)");
///
/// writer.set_rounding_precision(4);
/// assert_eq!(writer.write(&point_geom).unwrap(), "POINT (2.5000 2.5000)");
/// ```
pub fn set_rounding_precision(&mut self, precision: u32) {
unsafe {
GEOSWKTWriter_setRoundingPrecision_r(
self.get_raw_context(),
self.as_raw_mut(),
precision as _,
)
}
}
/// Sets the number of dimensions to be used when calling [`WKTWriter::write`]. By default, it
/// is 2.
///
/// # Example
///
/// ```
/// use geos::{Geometry, OutputDimension, WKTWriter};
///
/// let point_geom = Geometry::new_from_wkt("POINT (1.1 2.2 3.3)").expect("Invalid geometry");
/// let mut writer = WKTWriter::new().expect("Failed to create WKTWriter");
/// writer.set_trim(true);
///
/// assert_eq!(writer.write(&point_geom).unwrap(), "POINT (1.1 2.2)");
///
/// writer.set_output_dimension(OutputDimension::ThreeD);
/// assert_eq!(writer.write(&point_geom).unwrap(), "POINT Z (1.1 2.2 3.3)");
/// ```
pub fn set_output_dimension(&mut self, dimension: OutputDimension) {
unsafe {
GEOSWKTWriter_setOutputDimension_r(
self.get_raw_context(),
self.as_raw_mut(),
dimension.into(),
)
}
}
/// Returns the number of dimensions to be used when calling [`WKTWriter::write`]. By default,
/// it is 2.
///
/// # Example
///
/// ```
/// use geos::{OutputDimension, WKTWriter};
///
/// let mut writer = WKTWriter::new().expect("Failed to create WKTWriter");
///
/// assert_eq!(writer.get_out_dimension(), Ok(OutputDimension::TwoD));
/// writer.set_output_dimension(OutputDimension::ThreeD);
/// assert_eq!(writer.get_out_dimension(), Ok(OutputDimension::ThreeD));
/// ```
pub fn get_out_dimension(&self) -> GResult<OutputDimension> {
unsafe {
let out = GEOSWKTWriter_getOutputDimension_r(
self.get_raw_context(),
self.as_raw_mut_override(),
);
OutputDimension::try_from(out).map_err(|e| Error::GenericError(e.to_owned()))
}
}
/// Enables/disables trimming of unnecessary decimals.
///
/// # Example
///
/// ```
/// use geos::{Geometry, WKTWriter};
///
/// let point_geom = Geometry::new_from_wkt("POINT (2.5 2.5)").expect("Invalid geometry");
/// let mut writer = WKTWriter::new().expect("Failed to create WKTWriter");
///
/// assert_eq!(writer.write(&point_geom).unwrap(), "POINT (2.5000000000000000 2.5000000000000000)");
///
/// writer.set_trim(true);
/// assert_eq!(writer.write(&point_geom).unwrap(), "POINT (2.5 2.5)");
/// ```
pub fn set_trim(&mut self, trim: bool) {
unsafe { GEOSWKTWriter_setTrim_r(self.get_raw_context(), self.as_raw_mut(), trim as _) }
}
/// Enables/disables old 3D/4D WKT style generation.
///
/// # Example
///
/// ```
/// use geos::{Geometry, OutputDimension, WKTWriter};
///
/// let point_geom = Geometry::new_from_wkt("POINT (2.5 2.5 2.5)").expect("Invalid geometry");
/// let mut writer = WKTWriter::new().expect("Failed to create WKTWriter");
///
/// writer.set_output_dimension(OutputDimension::ThreeD);
/// writer.set_trim(true);
///
/// assert_eq!(writer.write(&point_geom).unwrap(), "POINT Z (2.5 2.5 2.5)");
///
/// writer.set_old_3D(true);
/// assert_eq!(writer.write(&point_geom).unwrap(), "POINT (2.5 2.5 2.5)");
/// ```
#[allow(non_snake_case)]
pub fn set_old_3D(&mut self, use_old_3D: bool) {
unsafe {
GEOSWKTWriter_setOld3D_r(self.get_raw_context(), self.as_raw_mut(), use_old_3D as _)
}
}
}
unsafe impl<'a> Send for WKTWriter<'a> {}
unsafe impl<'a> Sync for WKTWriter<'a> {}
impl<'a> Drop for WKTWriter<'a> {
fn drop(&mut self) {
unsafe { GEOSWKTWriter_destroy_r(self.get_raw_context(), self.as_raw_mut()) };
}
}
impl<'a> ContextInteractions<'a> for WKTWriter<'a> {
/// Set the context handle to the `WKTWriter`.
///
/// ```
/// use geos::{ContextInteractions, ContextHandle, WKTWriter};
///
/// let context_handle = ContextHandle::init().expect("invalid init");
/// let mut writer = WKTWriter::new().expect("failed to create WKT writer");
/// context_handle.set_notice_message_handler(Some(Box::new(|s| println!("new message: {}", s))));
/// writer.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 `WKTWriter`.
///
/// ```
/// use geos::{ContextInteractions, WKTWriter};
///
/// let mut writer = WKTWriter::new().expect("failed to create WKT writer");
/// let context = writer.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 WKTWriter<'a> {
type RawType = GEOSWKTWriter;
fn as_raw(&self) -> *const Self::RawType {
*self.ptr
}
}
impl<'a> AsRawMut for WKTWriter<'a> {
type RawType = GEOSWKTWriter;
unsafe fn as_raw_mut_override(&self) -> *mut Self::RawType {
*self.ptr
}
}
impl<'a> ContextHandling for WKTWriter<'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)
}
}