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
26pub 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 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 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 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 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 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 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 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 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 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 pub fn num_facets(&self) -> usize {
211 unsafe { sys::qh_get_num_facets(self.qh.get()) as _ }
212 }
213
214 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 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 ($($arg:tt)*) => {
277 if cfg!(feature = "print_debug") {
278 dbg!($($arg)*)
279 } else {
280 #[allow(unused_variables)]
282 let tmp = { $($arg)* };
283 tmp
284 }
285 }
286}
287
288#[macro_export]
289macro_rules! log {
290 ($($arg:tt)*) => {
292 if cfg!(feature = "print_debug") {
293 println!($($arg)*)
294 } else {
295
296 }
297 }
298}
299