openstellaris/triangle/src/lib.rs

116 lines
2.6 KiB
Rust
Raw Normal View History

2023-12-29 22:36:27 +00:00
#[macro_use]
extern crate derive_builder;
extern crate triangle_sys as sys;
#[cfg(test)]
mod tests;
2023-12-26 01:40:37 +00:00
use std::{ffi::CString, mem::MaybeUninit, ptr};
2023-12-29 22:36:27 +00:00
use anyhow::Result;
2023-12-26 01:40:37 +00:00
2023-12-29 22:36:27 +00:00
#[derive(Builder)]
2023-12-30 00:46:18 +00:00
pub struct TrianglulateOpts<P = Vec<Point>> {
2023-12-29 22:36:27 +00:00
point_list: P,
/// Generates a Voronoi diagram
#[builder(default)]
voronoi: bool,
}
impl<P: Clone> TrianglulateOpts<P> {
pub fn builder() -> TrianglulateOptsBuilder<P> {
TrianglulateOptsBuilder::default()
}
}
#[derive(Clone, Copy, Debug)]
pub struct Point {
2023-12-30 00:46:18 +00:00
pub x: f64,
pub y: f64,
2023-12-29 22:36:27 +00:00
}
#[derive(Debug)]
pub struct TriangulateResult {
pub point_list: Vec<Point>,
2023-12-30 05:40:38 +00:00
pub voronoi_point_list: Vec<Point>,
2023-12-29 22:36:27 +00:00
}
pub fn triangulate<P>(opts: TrianglulateOpts<P>) -> Result<TriangulateResult>
where
P: IntoIterator<Item = Point>,
{
let mut switches = Vec::new();
2023-12-30 05:40:38 +00:00
switches.push("p");
switches.push("c");
switches.push("z");
switches.push("A");
switches.push("e");
switches.push("n");
2023-12-29 22:36:27 +00:00
if opts.voronoi {
switches.push("v");
}
let switches = CString::new(switches.join(""))?;
let point_list = opts.point_list.into_iter().collect::<Vec<_>>();
let mut flat_point_list = point_list
.iter()
.flat_map(|point| [point.x, point.y])
.collect::<Vec<_>>();
2023-12-30 00:46:18 +00:00
let input = MaybeUninit::<sys::triangulateio>::zeroed();
let output = MaybeUninit::<sys::triangulateio>::zeroed();
let vorout = MaybeUninit::<sys::triangulateio>::zeroed();
2023-12-26 01:40:37 +00:00
2023-12-29 22:36:27 +00:00
let mut input = unsafe { input.assume_init() };
let mut output = unsafe { output.assume_init() };
2023-12-30 00:46:18 +00:00
let mut vorout = unsafe { vorout.assume_init() };
2023-12-29 22:36:27 +00:00
input.pointlist = flat_point_list.as_mut_ptr();
input.numberofpoints = point_list.len() as i32;
// TODO: Implement point attributes
input.numberofpointattributes = 0;
2023-12-30 00:46:18 +00:00
println!("Going to triangulate...");
2023-12-26 01:40:37 +00:00
unsafe {
sys::triangulate(
switches.as_ptr() as *mut _,
&mut input as *mut _,
2023-12-29 22:36:27 +00:00
&mut output as *mut _,
2023-12-30 00:46:18 +00:00
&mut vorout as *mut _,
2023-12-26 01:40:37 +00:00
)
};
2023-12-30 05:40:38 +00:00
println!("Triangulated {}.", output.numberoftriangles);
2023-12-30 00:46:18 +00:00
2023-12-30 05:40:38 +00:00
let point_list = point_list_from_flat_point_list(
output.pointlist,
output.numberofpoints as usize * 2,
);
let voronoi_point_list = point_list_from_flat_point_list(
vorout.pointlist,
vorout.numberofpoints as usize * 2,
);
Ok(TriangulateResult {
point_list,
voronoi_point_list,
})
}
fn point_list_from_flat_point_list(ptr: *mut f64, len: usize) -> Vec<Point> {
let flat_point_list = unsafe { Vec::from_raw_parts(ptr, len, len) };
flat_point_list
2023-12-29 22:36:27 +00:00
.chunks(2)
.map(|points| Point {
x: points[0],
y: points[1],
})
2023-12-30 05:40:38 +00:00
.collect::<Vec<_>>()
2023-12-26 01:40:37 +00:00
}