extern crate libc;
use std::mem;
use libc::{c_void, c_int, size_t};
#[link(name="poly2tri")]
extern "C" {
fn p2t_polyline_new() -> *mut c_void;
fn p2t_polyline_free(polygon: *mut c_void);
fn p2t_polyline_add_point(polygon: *mut c_void, x: f64, y: f64);
fn p2t_polyline_get_point(polygon: *mut c_void, idx: size_t,
x_out: *mut f64, y_out: *mut f64) -> c_int;
fn p2t_polyline_size(polygon: *const c_void) -> size_t;
fn p2t_cdt_new(polygon: *mut c_void) -> *mut c_void;
fn p2t_cdt_free(cdt: *mut c_void);
fn p2t_cdt_triangulate(cdt: *mut c_void);
fn p2t_cdt_get_triangles(cdt: *mut c_void) -> *mut c_void;
fn p2t_cdt_add_hole(cdt: *mut c_void, polygon: *mut c_void);
fn p2t_cdt_add_point(cdt: *mut c_void, x: f64, y: f64);
fn p2t_triangles_free(triangles: *mut c_void);
fn p2t_triangles_count(triangles: *mut c_void) -> size_t;
fn p2t_triangles_get_triangle(triangles: *const c_void, idx: size_t) -> *const c_void;
fn p2t_triangle_get_point(triangle: *const c_void, idx: size_t,
x_out: *mut f64, y_out: *mut f64);
}
pub struct Polygon {
ll: *mut c_void,
}
pub struct CDT {
ll: *mut c_void,
}
pub struct TriangleVec {
ll: *mut c_void,
#[allow(dead_code)]
cdt: CDT,
}
#[derive(Copy, Clone, PartialEq)]
pub struct Triangle {
pub points: [[f64; 2]; 3],
}
impl Polygon {
pub fn new() -> Polygon {
unsafe {
Polygon {
ll: p2t_polyline_new()
}
}
}
pub fn from_iterator<'a, I>(points: I) -> Polygon
where I: Iterator<Item=&'a [f64; 2]>
{
let mut rv = Polygon::new();
for point in points {
rv.add_point(point[0], point[1]);
}
rv
}
pub fn add_point(&mut self, x: f64, y: f64) {
unsafe {
p2t_polyline_add_point(self.ll, x, y);
}
}
pub fn get_point(&self, idx: usize) -> [f64; 2] {
unsafe {
let mut x: f64 = 0.0;
let mut y: f64 = 0.0;
if p2t_polyline_get_point(self.ll, idx as size_t, &mut x, &mut y) == 0 {
[x, y]
} else {
panic!("Out of range");
}
}
}
pub fn size(&self) -> usize {
unsafe {
p2t_polyline_size(self.ll) as usize
}
}
}
impl Drop for Polygon {
fn drop(&mut self) {
unsafe {
p2t_polyline_free(self.ll);
}
}
}
impl CDT {
pub fn new(polygon: Polygon) -> CDT {
unsafe {
let rv = CDT {
ll: p2t_cdt_new(polygon.ll)
};
mem::forget(polygon);
rv
}
}
pub fn add_hole(&mut self, polygon: Polygon) {
unsafe {
p2t_cdt_add_hole(self.ll, polygon.ll);
mem::forget(polygon);
}
}
pub fn add_steiner_point(&mut self, x: f64, y: f64) {
unsafe {
p2t_cdt_add_point(self.ll, x, y);
}
}
pub fn triangulate(self) -> TriangleVec {
unsafe {
p2t_cdt_triangulate(self.ll);
let ll = p2t_cdt_get_triangles(self.ll);
TriangleVec {
cdt: self,
ll: ll,
}
}
}
}
impl Drop for CDT {
fn drop(&mut self) {
unsafe {
p2t_cdt_free(self.ll);
}
}
}
impl TriangleVec {
pub fn size(&self) -> usize {
unsafe {
p2t_triangles_count(self.ll) as usize
}
}
pub fn get_triangle(&self, idx: usize) -> Triangle {
assert!(idx < self.size(), "Out of range");
let mut p0 = [0.0; 2];
let mut p1 = [0.0; 2];
let mut p2 = [0.0; 2];
unsafe {
let tri = p2t_triangles_get_triangle(self.ll, idx as size_t);
p2t_triangle_get_point(tri, 0, &mut p0[0], &mut p0[1]);
p2t_triangle_get_point(tri, 1, &mut p1[0], &mut p1[1]);
p2t_triangle_get_point(tri, 2, &mut p2[0], &mut p2[1]);
}
Triangle {
points: [p0, p1, p2]
}
}
}
impl Drop for TriangleVec {
fn drop(&mut self) {
unsafe {
p2t_triangles_free(self.ll);
}
}
}
pub fn triangulate_points<'a, I>(points: I) -> TriangleVec
where I: Iterator<Item=&'a [f64; 2]>
{
CDT::new(Polygon::from_iterator(points)).triangulate()
}
#[test]
fn test_basics() {
let mut polygon = Polygon::new();
let min = 0.01f64;
let max = 2.50f64;
polygon.add_point(min, min);
polygon.add_point(min, max);
polygon.add_point(max, max);
polygon.add_point(max, min);
assert_eq!(polygon.size(), 4);
let cdt = CDT::new(polygon);
let triangles = cdt.triangulate();
assert_eq!(triangles.size(), 2);
let tri = triangles.get_triangle(0);
assert_eq!(tri.points[0], [min, max]);
assert_eq!(tri.points[1], [max, min]);
assert_eq!(tri.points[2], [max, max]);
let tri = triangles.get_triangle(1);
assert_eq!(tri.points[0], [min, max]);
assert_eq!(tri.points[1], [min, min]);
assert_eq!(tri.points[2], [max, min]);
}
#[test]
fn test_iter() {
let points : [[f64; 2]; 4] = [[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0]];
let triangles = triangulate_points(points.into_iter());
assert_eq!(triangles.size(), 2);
}