qhull_enhanced/
lib.rs

1#![doc = include_str!("../README.md")]
2#![allow(warnings)]
3#![allow(clippy::let_and_return)]
4#![allow(clippy::missing_safety_doc)]
5#![allow(clippy::needless_borrows_for_generic_args)]
6#![allow(clippy::needless_return)]
7#![allow(clippy::unnecessary_lazy_evaluations)]
8
9use std::{cell::{RefCell, UnsafeCell}, ffi::CString, marker::PhantomData};
10
11use helpers::{prepare_delaunay_points, CollectedCoords, QhTypeRef};
12use io_buffers::IOBuffers;
13pub use qhull_sys_enhanced as sys;
14
15mod error;
16pub mod helpers;
17pub mod io_buffers;
18pub mod tmp_file;
19pub use error::*;
20mod builder;
21pub use builder::*;
22mod types;
23pub use types::*;
24pub mod examples;
25
26/// A Qhull instance
27///
28/// This struct is the main interface to the qhull library.
29/// It provides a way to compute the convex hull of a set of points and to access the results.
30///
31/// See the main [`crate` documentation](crate) and the [`examples`] module/folder for some examples.
32pub struct Qh<'a> {
33    qh: UnsafeCell<sys::qhT>,
34    coords_holder: Option<Vec<f64>>,
35    dim: usize,
36    buffers: RefCell<IOBuffers>,
37    owned_values: OwnedValues,
38    phantom: PhantomData<&'a ()>,
39}
40
41impl<'a> Qh<'a> {
42    /// Create a new builder
43    pub fn builder() -> QhBuilder {
44        QhBuilder::default()
45    }
46
47    pub fn totvol(&self) -> f64 {
48        unsafe { sys::qh_get_totvol(self.qh.get()) as _ }
49    }
50
51    pub fn totarea(&self) -> f64 {
52        unsafe { sys::qh_get_totarea(self.qh.get()) as _ }
53    }
54    /// Compute the convex hull
55    ///
56    /// Wraps [`qhull_sys_enhanced::qh_qhull`],
57    pub fn compute(&mut self) -> Result<(), QhError> {
58        let qh = unsafe { Qh::raw_ptr(self) };
59        unsafe { QhError::try_1(
60            qh,
61            &mut self.buffers().borrow_mut().err_file,
62            sys::qh_qhull,
63            (qh,),
64        ) }
65    }
66
67    /// Prepare the output of the qhull instance
68    ///
69    /// Wraps [`qhull_sys_enhanced::qh_prepare_output`],
70    pub fn prepare_output(&mut self) -> Result<(), QhError> {
71        let qh = unsafe { Qh::raw_ptr(self) };
72        unsafe { QhError::try_1(
73            qh,
74            &mut self.buffers().borrow_mut().err_file,
75            sys::qh_prepare_output,
76            (qh,),
77        ) }
78    }
79
80    /// Check the output of the qhull instance
81    ///
82    /// Wraps [`qhull_sys_enhanced::qh_check_output`],
83    pub fn check_output(&mut self) -> Result<(), QhError> {
84        let qh = unsafe { Qh::raw_ptr(self) };
85        unsafe { QhError::try_1(
86            qh,
87            &mut self.buffers().borrow_mut().err_file,
88            sys::qh_check_output,
89            (qh,),
90        ) }
91    }
92
93    pub fn check_points(&mut self) -> Result<(), QhError> {
94        let qh = unsafe { Qh::raw_ptr(self) };
95        unsafe { QhError::try_1(
96            qh,
97            &mut self.buffers().borrow_mut().err_file,
98            sys::qh_check_points,
99            (qh,),
100        ) }
101    }
102
103    /// Creates a new Delaunay triangulation
104    ///
105    /// See the `examples` directory for an example.
106    pub fn new_delaunay<I>(points: impl IntoIterator<Item = I>) -> Result<Self, QhError<'static>>
107    where
108        I: IntoIterator<Item = f64>,
109    {
110        let CollectedCoords {
111            coords,
112            count: _,
113            dim,
114        } = prepare_delaunay_points(points);
115
116        // TODO check correctness, use qdelaunay as reference
117        QhBuilder::default()
118            .delaunay(true)
119            .upper_delaunay(true)
120            .scale_last(true)
121            .triangulate(true)
122            .keep_coplanar(true)
123            .build_managed(dim, coords)
124    }
125
126    /// Get all the facets in the hull
127    ///
128    /// # Remarks
129    /// * this function will also return the sentinel face, which is the last face in the list of facets.
130    ///   To avoid it, use the [`Qh::facets`] function or just [`filter`](std::iter::Iterator::filter) the iterator
131    ///   checking for [`Facet::is_sentinel`].
132    pub fn all_facets(&self) -> impl Iterator<Item = Facet> {
133        let mut current = Facet::from_ptr(
134            unsafe { sys::qh_get_facet_list(self.qh.get() as *mut _) },
135            self.dim,
136        );
137
138        std::iter::from_fn(move || current.take().map(|v| {
139            current = v.next();
140            v
141        }))
142    }
143
144    /// Get all the facets in the hull in reverse order
145    ///
146    /// See [`Qh::all_facets`] for more information.
147    pub fn all_facets_rev(&self) -> impl Iterator<Item = Facet> {
148        let mut current = Facet::from_ptr(
149            unsafe { sys::qh_get_facet_tail(self.qh.get() as *mut _) },
150            self.dim,
151        );
152
153        std::iter::from_fn(move || current.take().map(|v| {
154            current = v.previous();
155            v
156        }))
157    }
158
159    /// Get the facets in the hull
160    ///
161    /// # Remarks
162    /// * this function will not return the sentinel face, which is the last face in the list of facets.
163    ///   To get it, use the [`Qh::all_facets`] function.
164    pub fn facets(&self) -> impl Iterator<Item = Facet> {
165        self.all_facets().filter(|f| !f.is_sentinel())
166    }
167
168    pub fn all_vertices(&self) -> impl Iterator<Item = Vertex> {
169        let mut current = Vertex::from_ptr(
170            unsafe { sys::qh_get_vertex_list(self.qh.get() as *mut _) },
171            self.dim,
172        );
173
174        std::iter::from_fn(move || current.take().map(|v| {
175            current = v.next();
176            v
177        }))
178    }
179
180    pub fn all_vertices_rev(&self) -> impl Iterator<Item = Vertex> {
181        let mut current = Vertex::from_ptr(
182            unsafe { sys::qh_get_vertex_tail(self.qh.get() as *mut _) },
183            self.dim,
184        );
185
186        std::iter::from_fn(move || current.take().map(|v| {
187            current = v.previous();
188            v
189        }))
190    }
191
192    pub fn vertices(&self) -> impl Iterator<Item = Vertex> {
193        self.all_vertices().filter(|v| !v.is_sentinel())
194    }
195
196    /// Number of facets in the hull (sentinel excluded)
197    ///
198    /// # Example
199    /// ```
200    /// # use qhull_enhanced::*;
201    /// # let mut qh = Qh::builder()
202    /// #     .build_from_iter([
203    /// #         [0.0, 0.0],
204    /// #         [1.0, 0.0],
205    /// #         [0.0, 1.0],
206    /// #         [0.25, 0.25]
207    /// #    ]).unwrap();
208    /// assert_eq!(qh.num_facets(), qh.facets().count());
209    /// ```
210    pub fn num_facets(&self) -> usize {
211        unsafe { sys::qh_get_num_facets(self.qh.get()) as _ }
212    }
213
214    /// Number of vertices in the hull (sentinel excluded)
215    ///
216    /// # Example
217    /// ```
218    /// # use qhull_enhanced::*;
219    /// # let mut qh = Qh::builder()
220    /// #     .build_from_iter([
221    /// #         [0.0, 0.0],
222    /// #         [1.0, 0.0],
223    /// #         [0.0, 1.0],
224    /// #         [0.25, 0.25]
225    /// #    ]).unwrap();
226    /// assert_eq!(qh.num_vertices(), qh.vertices().count());
227    /// ```
228    pub fn num_vertices(&self) -> usize {
229        unsafe { sys::qh_get_num_vertices(self.qh.get()) as _ }
230    }
231
232    pub fn simplices(&self) -> impl Iterator<Item = Facet> {
233        self.facets().filter(|f| f.simplicial())
234    }
235
236    /// Get the pointer to the raw qhT instance
237    ///
238    /// # Warning
239    /// Always use a try function (e.g. [`QhError::try_1`]) when calling a fallible qhull function,
240    /// but not on non-fallible functions such as [`qhull_sys_enhanced::qh_init_A`] since it would be invalid.
241    pub unsafe fn raw_ptr(qh: &Qh) -> *mut sys::qhT {
242        qh.qh.get()
243    }
244
245    pub fn buffers(&self) -> &RefCell<IOBuffers> {
246        &self.buffers
247    }
248}
249
250impl<'a> Drop for Qh<'a> {
251    fn drop(&mut self) {
252        unsafe {
253            sys::qh_freeqhull(self.qh.get_mut(), !sys::qh_ALL);
254        }
255    }
256}
257
258#[derive(Default)]
259#[allow(unused)]
260struct OwnedValues {
261    good_point_coords: Option<Vec<f64>>,
262    good_vertex_coords: Option<Vec<f64>>,
263    first_point: Option<Vec<f64>>,
264    upper_threshold: Option<Vec<f64>>,
265    lower_threshold: Option<Vec<f64>>,
266    upper_bound: Option<Vec<f64>>,
267    lower_bound: Option<Vec<f64>>,
268    feasible_point: Option<Vec<f64>>,
269    feasible_string: Option<CString>,
270    near_zero: Option<Vec<f64>>,
271}
272
273#[macro_export]
274macro_rules! cond_dbg {
275    // 开启调试的情况
276    ($($arg:tt)*) => {
277        if cfg!(feature = "print_debug") {
278            dbg!($($arg)*)
279        } else {
280            // 保持与非调试分支相同的表达式求值顺序
281            #[allow(unused_variables)]
282            let tmp = { $($arg)* };
283            tmp
284        }
285    }
286}
287
288#[macro_export]
289macro_rules! log {
290    // 开启调试的情况
291    ($($arg:tt)*) => {
292        if cfg!(feature = "print_debug") {
293            println!($($arg)*)
294        } else {
295
296        }
297    }
298}
299