#[macro_use] extern crate derive_builder; extern crate triangle_sys as sys; #[cfg(test)] mod tests; use std::{ffi::CString, mem::MaybeUninit, ptr}; use anyhow::Result; #[derive(Builder)] pub struct TrianglulateOpts

> { point_list: P, /// Imposes a maximum triangle area constraint. A fixed area constraint (that /// applies to every triangle) may be specified after the `a', or varying area /// constraints may be read from a .poly file or .area file. #[builder(default, setter(strip_option))] maximum_triangle_area: Option, /// Generates a Voronoi diagram #[builder(default)] voronoi: bool, } impl TrianglulateOpts

{ pub fn builder() -> TrianglulateOptsBuilder

{ TrianglulateOptsBuilder::default() } } #[derive(Clone, Copy, Debug)] pub struct Point { pub x: f64, pub y: f64, } #[derive(Debug)] pub struct TriangulateResult { pub point_list: Vec, /// A list of triangles pub triangle_list: Vec>, pub voronoi_point_list: Vec, } pub fn triangulate

(opts: TrianglulateOpts

) -> Result where P: IntoIterator, { let mut switches = Vec::new(); switches.push("p".to_owned()); switches.push("c".to_owned()); switches.push("z".to_owned()); switches.push("A".to_owned()); if let Some(maximum_triangle_area) = opts.maximum_triangle_area { switches.push(format!("a{maximum_triangle_area}")); } switches.push("q".to_owned()); switches.push("e".to_owned()); switches.push("n".to_owned()); if opts.voronoi { switches.push("v".to_owned()); } let switches = CString::new(switches.join(""))?; let point_list = opts.point_list.into_iter().collect::>(); let mut flat_point_list = point_list .iter() .flat_map(|point| [point.x, point.y]) .collect::>(); let input = MaybeUninit::::zeroed(); let output = MaybeUninit::::zeroed(); let vorout = MaybeUninit::::zeroed(); let mut input = unsafe { input.assume_init() }; let mut output = unsafe { output.assume_init() }; let mut vorout = unsafe { vorout.assume_init() }; input.pointlist = flat_point_list.as_mut_ptr(); input.numberofpoints = point_list.len() as i32; // TODO: Implement point attributes input.numberofpointattributes = 0; println!("Going to triangulate..."); unsafe { sys::triangulate( switches.as_ptr() as *mut _, &mut input as *mut _, &mut output as *mut _, &mut vorout as *mut _, ) }; println!("Triangulated {}.", output.numberoftriangles); let point_list = point_list_from_flat_point_list( output.pointlist, output.numberofpoints as usize * 2, ); let triangle_list = triangle_list_from_flat_point_list( output.trianglelist, output.numberofcorners as usize, output.numberoftriangles as usize * output.numberofcorners as usize, ); println!("aa {}", triangle_list.len()); let voronoi_point_list = point_list_from_flat_point_list( vorout.pointlist, vorout.numberofpoints as usize * 2, ); Ok(TriangulateResult { point_list, triangle_list, voronoi_point_list, }) } fn point_list_from_flat_point_list(ptr: *mut f64, len: usize) -> Vec { let flat_point_list = unsafe { Vec::from_raw_parts(ptr, len, len) }; flat_point_list .chunks_exact(2) .map(|points| Point { x: points[0], y: points[1], }) .collect::>() } fn triangle_list_from_flat_point_list( ptr: *mut i32, num_corners: usize, len: usize, ) -> Vec> { let flat_point_list = unsafe { Vec::from_raw_parts(ptr, len, len) }; flat_point_list .chunks_exact(num_corners) .map(|points| points.iter().map(|point| *point as usize).collect()) .collect::>() }