use cpp::cpp;
cpp! {{
#include "voro++.hh"
using namespace voro;
}}
macro_rules! vec_ptr_pair {
($size:expr) => {{
let size: usize = ($size);
let mut rust_vec = Vec::with_capacity(size);
unsafe {
rust_vec.set_len(size);
}
let data_ptr = rust_vec.as_mut_ptr();
(rust_vec, data_ptr)
}};
}
pub trait VoronoiCellBaseFFI {
fn ptr(&self) -> *mut std::ffi::c_void;
}
pub trait VoronoiCellBase: VoronoiCellBaseFFI {
fn number_of_faces(&self) -> i32 {
let ptr = self.ptr();
cpp!(unsafe [ptr as "voronoicell_base*"] -> i32 as "int" {
return ptr->number_of_faces();
})
}
fn number_of_edges(&self) -> i32 {
let ptr = self.ptr();
cpp!(unsafe [ptr as "voronoicell_base*"] -> i32 as "int" {
return ptr->number_of_edges();
})
}
fn number_of_vertices(&self) -> i32 {
let ptr = self.ptr();
cpp!(unsafe [ptr as "voronoicell_base*"] -> i32 as "int" {
return ptr->p;
})
}
fn translate(&mut self, xyz: &[f64; 3]) {
let ptr = self.ptr();
cpp!(unsafe [ptr as "voronoicell_base*",
xyz as "double*"] -> f64 as "double" {
ptr->translate(xyz[0], xyz[1], xyz[2]);
});
}
fn surface_area(&self) -> f64 {
let ptr = self.ptr();
cpp!(unsafe [ptr as "voronoicell_base*"] -> f64 as "double" {
return ptr->surface_area();
})
}
fn volume(&self) -> f64 {
let ptr = self.ptr();
cpp!(unsafe [ptr as "voronoicell_base*"] -> f64 as "double" {
return ptr->volume();
})
}
fn total_edge_distance(&self) -> f64 {
let ptr = self.ptr();
cpp!(unsafe [ptr as "voronoicell_base*"] -> f64 as "double" {
return ptr->total_edge_distance();
})
}
fn centroid(&self) -> [f64; 3] {
let ptr = self.ptr();
let mut c = [f64::NAN; 3];
let x = &mut c;
cpp!(unsafe [ptr as "voronoicell_base*", x as "double*"] {
ptr->centroid(x[0], x[1], x[2]);
});
return c;
}
fn vertices(&self) -> Vec<[f64; 3]> {
let ptr = self.ptr();
let (coords, data_ptr) = vec_ptr_pair!(self.number_of_vertices() as usize);
cpp!(unsafe [ptr as "voronoicell_base*", data_ptr as "double*"] {
std::vector<double> temp;
ptr->vertices(temp);
std::copy(temp.begin(), temp.end(), data_ptr);
});
return coords;
}
fn face_areas(&self) -> Vec<f64> {
let ptr = self.ptr();
let (areas, data_ptr) = vec_ptr_pair!(self.number_of_faces() as usize);
cpp!(unsafe [ptr as "voronoicell_base*", data_ptr as "double*"] {
std::vector<double> temp;
ptr->face_areas(temp);
std::copy(temp.begin(), temp.end(), data_ptr);
});
return areas;
}
fn face_perimeters(&self) -> Vec<f64> {
let ptr = self.ptr();
let (perimeters, data_ptr) = vec_ptr_pair!(self.number_of_faces() as usize);
cpp!(unsafe [ptr as "voronoicell_base*", data_ptr as "double*"] {
std::vector<double> temp;
ptr->face_perimeters(temp);
std::copy(temp.begin(), temp.end(), data_ptr);
});
return perimeters;
}
fn face_vertices(&self) -> Vec<Vec<usize>> {
let ptr = self.ptr();
let retval = vec![];
let ptr_retval = &retval;
cpp!(unsafe [ptr as "voronoicell_base*", ptr_retval as "void*"] {
std::vector<int> temp;
ptr->face_vertices(temp);
int *data = temp.data();
int len = temp.size();
return rust!(_unused_name [data: *const i32 as "int*", len: i32 as "int",
ptr_retval: &mut Vec<Vec<usize>> as "void*"] {
use std::convert::TryInto;
let mut countdown = 0;
let mut face_idx = -1;
for i in 0..len as isize {
let v = *data.offset(i);
if countdown == 0 {
countdown = v;
ptr_retval.push(Default::default());
face_idx += 1;
}
else {
countdown -= 1;
ptr_retval[face_idx as usize].push(v.try_into().unwrap());
}
}
});
});
return retval;
}
fn normals(&self) -> Vec<[f64; 3]> {
let ptr = self.ptr();
let (normals, data_ptr) = vec_ptr_pair!(self.number_of_faces() as usize);
cpp!(unsafe [ptr as "voronoicell_base*", data_ptr as "double*"] {
std::vector<double> temp;
ptr->normals(temp);
std::copy(temp.begin(), temp.end(), data_ptr);
});
return normals;
}
fn max_radius_squared(&self) -> f64 {
let ptr = self.ptr();
cpp!(unsafe [ptr as "voronoicell_base*"] -> f64 as "double" {
return ptr->max_radius_squared() * 0.25;
})
}
}