geos/
wkt_writer.rs

1use crate::context_handle::{with_context, PtrWrap};
2use crate::error::Error;
3use crate::functions::*;
4use crate::{AsRaw, AsRawMut, ContextHandle, GResult, Geom, OutputDimension};
5use geos_sys::*;
6use std::convert::TryFrom;
7
8/// The `WKTWriter` type is used to generate `WKT` formatted output from [`Geometry`](crate::Geometry).
9///
10/// # Example
11///
12/// ```
13/// use geos::{Geometry, WKTWriter};
14///
15/// let point_geom = Geometry::new_from_wkt("POINT (2.5 2.5)").expect("Invalid geometry");
16/// let mut writer = WKTWriter::new().expect("Failed to create WKTWriter");
17///
18/// assert_eq!(writer.write(&point_geom).unwrap(), "POINT (2.5000000000000000 2.5000000000000000)");
19/// ```
20pub struct WKTWriter {
21    ptr: PtrWrap<*mut GEOSWKTWriter>,
22}
23
24impl WKTWriter {
25    /// Creates a new `WKTWriter` instance.
26    ///
27    /// # Example
28    ///
29    /// ```
30    /// use geos::{Geometry, WKTWriter};
31    ///
32    /// let point_geom = Geometry::new_from_wkt("POINT (2.5 2.5)").expect("Invalid geometry");
33    /// let mut writer = WKTWriter::new().expect("Failed to create WKTWriter");
34    ///
35    /// assert_eq!(writer.write(&point_geom).unwrap(), "POINT (2.5000000000000000 2.5000000000000000)");
36    /// ```
37    pub fn new() -> GResult<WKTWriter> {
38        with_context(|ctx| unsafe {
39            let ptr = GEOSWKTWriter_create_r(ctx.as_raw());
40            WKTWriter::new_from_raw(ptr, ctx, "new_with_context")
41        })
42    }
43
44    pub(crate) unsafe fn new_from_raw(
45        ptr: *mut GEOSWKTWriter,
46        ctx: &ContextHandle,
47        caller: &str,
48    ) -> GResult<WKTWriter> {
49        if ptr.is_null() {
50            let extra = if let Some(x) = ctx.get_last_error() {
51                format!("\nLast error: {x}")
52            } else {
53                String::new()
54            };
55            return Err(Error::NoConstructionFromNullPtr(format!(
56                "WKTWriter::{caller}{extra}",
57            )));
58        }
59        Ok(WKTWriter { ptr: PtrWrap(ptr) })
60    }
61
62    /// Writes out the given `geometry` as WKT format.
63    ///
64    /// # Example
65    ///
66    /// ```
67    /// use geos::{Geometry, WKTWriter};
68    ///
69    /// let point_geom = Geometry::new_from_wkt("POINT (2.5 2.5)").expect("Invalid geometry");
70    /// let mut writer = WKTWriter::new().expect("Failed to create WKTWriter");
71    ///
72    /// assert_eq!(writer.write(&point_geom).unwrap(), "POINT (2.5000000000000000 2.5000000000000000)");
73    /// ```
74    pub fn write<G: Geom>(&mut self, geometry: &G) -> GResult<String> {
75        with_context(|ctx| unsafe {
76            let ptr = GEOSWKTWriter_write_r(ctx.as_raw(), self.as_raw_mut(), geometry.as_raw());
77            managed_string(ptr, ctx, "WKTWriter::write")
78        })
79    }
80
81    /// Sets the `precision` to be used when calling [`WKTWriter::write`]. Often, what users
82    /// actually want is the [`WKTWriter::set_trim`] method instead.
83    ///
84    /// # Example
85    ///
86    /// ```
87    /// use geos::{Geometry, WKTWriter};
88    ///
89    /// let point_geom = Geometry::new_from_wkt("POINT (2.5 2.5)").expect("Invalid geometry");
90    /// let mut writer = WKTWriter::new().expect("Failed to create WKTWriter");
91    ///
92    /// writer.set_rounding_precision(2);
93    /// assert_eq!(writer.write(&point_geom).unwrap(), "POINT (2.50 2.50)");
94    ///
95    /// writer.set_rounding_precision(4);
96    /// assert_eq!(writer.write(&point_geom).unwrap(), "POINT (2.5000 2.5000)");
97    /// ```
98    pub fn set_rounding_precision(&mut self, precision: u32) {
99        with_context(|ctx| unsafe {
100            GEOSWKTWriter_setRoundingPrecision_r(ctx.as_raw(), self.as_raw_mut(), precision as _)
101        })
102    }
103
104    /// Sets the number of dimensions to be used when calling [`WKTWriter::write`]. By default, it
105    /// is 2.
106    ///
107    /// # Example
108    ///
109    /// ```
110    /// use geos::{Geometry, OutputDimension, WKTWriter};
111    ///
112    /// let point_geom = Geometry::new_from_wkt("POINT (1.1 2.2 3.3)").expect("Invalid geometry");
113    /// let mut writer = WKTWriter::new().expect("Failed to create WKTWriter");
114    /// writer.set_trim(true);
115    ///
116    /// assert_eq!(writer.write(&point_geom).unwrap(), "POINT (1.1 2.2)");
117    ///
118    /// writer.set_output_dimension(OutputDimension::ThreeD);
119    /// assert_eq!(writer.write(&point_geom).unwrap(), "POINT Z (1.1 2.2 3.3)");
120    /// ```
121    pub fn set_output_dimension(&mut self, dimension: OutputDimension) {
122        with_context(|ctx| unsafe {
123            GEOSWKTWriter_setOutputDimension_r(ctx.as_raw(), self.as_raw_mut(), dimension.into())
124        })
125    }
126
127    /// Returns the number of dimensions to be used when calling [`WKTWriter::write`]. By default,
128    /// it is 2.
129    ///
130    /// # Example
131    ///
132    /// ```
133    /// use geos::{OutputDimension, WKTWriter};
134    ///
135    /// let mut writer = WKTWriter::new().expect("Failed to create WKTWriter");
136    ///
137    /// assert_eq!(writer.get_out_dimension(), Ok(OutputDimension::TwoD));
138    /// writer.set_output_dimension(OutputDimension::ThreeD);
139    /// assert_eq!(writer.get_out_dimension(), Ok(OutputDimension::ThreeD));
140    /// ```
141    pub fn get_out_dimension(&self) -> GResult<OutputDimension> {
142        with_context(|ctx| unsafe {
143            let out = GEOSWKTWriter_getOutputDimension_r(ctx.as_raw(), self.as_raw_mut_override());
144            OutputDimension::try_from(out).map_err(|e| Error::GenericError(e.to_owned()))
145        })
146    }
147
148    /// Enables/disables trimming of unnecessary decimals.
149    ///
150    /// # Example
151    ///
152    /// ```
153    /// use geos::{Geometry, WKTWriter};
154    ///
155    /// let point_geom = Geometry::new_from_wkt("POINT (2.5 2.5)").expect("Invalid geometry");
156    /// let mut writer = WKTWriter::new().expect("Failed to create WKTWriter");
157    ///
158    /// assert_eq!(writer.write(&point_geom).unwrap(), "POINT (2.5000000000000000 2.5000000000000000)");
159    ///
160    /// writer.set_trim(true);
161    /// assert_eq!(writer.write(&point_geom).unwrap(), "POINT (2.5 2.5)");
162    /// ```
163    pub fn set_trim(&mut self, trim: bool) {
164        with_context(|ctx| unsafe {
165            GEOSWKTWriter_setTrim_r(ctx.as_raw(), self.as_raw_mut(), trim as _)
166        })
167    }
168
169    /// Enables/disables old 3D/4D WKT style generation.
170    ///
171    /// # Example
172    ///
173    /// ```
174    /// use geos::{Geometry, OutputDimension, WKTWriter};
175    ///
176    /// let point_geom = Geometry::new_from_wkt("POINT (2.5 2.5 2.5)").expect("Invalid geometry");
177    /// let mut writer = WKTWriter::new().expect("Failed to create WKTWriter");
178    ///
179    /// writer.set_output_dimension(OutputDimension::ThreeD);
180    /// writer.set_trim(true);
181    ///
182    /// assert_eq!(writer.write(&point_geom).unwrap(), "POINT Z (2.5 2.5 2.5)");
183    ///
184    /// writer.set_old_3D(true);
185    /// assert_eq!(writer.write(&point_geom).unwrap(), "POINT (2.5 2.5 2.5)");
186    /// ```
187    #[allow(non_snake_case)]
188    pub fn set_old_3D(&mut self, use_old_3D: bool) {
189        with_context(|ctx| unsafe {
190            GEOSWKTWriter_setOld3D_r(ctx.as_raw(), self.as_raw_mut(), use_old_3D as _)
191        })
192    }
193}
194
195unsafe impl Send for WKTWriter {}
196unsafe impl Sync for WKTWriter {}
197
198impl Drop for WKTWriter {
199    fn drop(&mut self) {
200        with_context(|ctx| unsafe { GEOSWKTWriter_destroy_r(ctx.as_raw(), self.as_raw_mut()) });
201    }
202}
203
204impl AsRaw for WKTWriter {
205    type RawType = GEOSWKTWriter;
206
207    fn as_raw(&self) -> *const Self::RawType {
208        *self.ptr
209    }
210}
211
212impl AsRawMut for WKTWriter {
213    type RawType = GEOSWKTWriter;
214
215    unsafe fn as_raw_mut_override(&self) -> *mut Self::RawType {
216        *self.ptr
217    }
218}