1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
use std::slice;
extern crate libc;
use self::libc::{c_double, c_void, size_t};
use super::geo_types::{LineString, Point, Polygon};
use super::polylabel;
use super::num_traits::{Float, Signed};
#[repr(C)]
pub struct WrapperArray {
pub data: *const Array,
pub len: size_t,
}
#[repr(C)]
pub struct Array {
pub data: *const c_void,
pub len: size_t,
}
#[repr(C)]
pub struct Position {
pub x_pos: c_double,
pub y_pos: c_double,
}
impl<T> From<Point<T>> for Position
where
T: Float + Signed,
{
fn from(point: Point<T>) -> Position {
Position {
x_pos: point.x().to_f64().unwrap() as c_double,
y_pos: point.y().to_f64().unwrap() as c_double,
}
}
}
fn reconstitute(arr: &Array) -> Vec<[f64; 2]> {
unsafe { slice::from_raw_parts(arr.data as *mut [f64; 2], arr.len).to_vec() }
}
fn reconstitute2(arr: WrapperArray) -> Vec<Vec<[f64; 2]>> {
let arrays = unsafe { slice::from_raw_parts(arr.data as *mut Array, arr.len) };
arrays.into_iter().map(|x| reconstitute(x)).collect()
}
#[no_mangle]
pub extern "C" fn polylabel_ffi(
outer: Array,
inners: WrapperArray,
tolerance: c_double,
) -> Position {
let exterior: Vec<[f64; 2]> = unsafe {
slice::from_raw_parts(outer.data as *mut [c_double; 2], outer.len).to_vec()
};
let interior: Vec<Vec<[f64; 2]>> = reconstitute2(inners);
let ls_ext = LineString(exterior.iter().map(|e| Point::new(e[0], e[1])).collect());
let ls_int: Vec<LineString<c_double>> = interior
.iter()
.map(|vec| LineString(vec.iter().map(|e| Point::new(e[0], e[1])).collect()))
.collect();
let poly = Polygon::new(ls_ext, ls_int);
polylabel(&poly, &tolerance).into()
}
#[cfg(test)]
mod tests {
use super::{polylabel_ffi, Array, WrapperArray, reconstitute2};
use super::libc::{c_void, size_t};
use geo::Point;
use std::mem;
fn gen_array(v: Vec<[f64; 2]>) -> Array {
let array = Array {
data: v.as_ptr() as *const c_void,
len: v.len() as size_t,
};
mem::forget(v);
array
}
fn gen_wrapperarray(v: Vec<Vec<[f64; 2]>>) -> WrapperArray {
let converted: Vec<Array> = v.into_iter().map(|x| gen_array(x)).collect();
let array2 = WrapperArray {
data: converted.as_ptr() as *const Array,
len: converted.len() as size_t,
};
mem::forget(converted);
array2
}
#[test]
fn test_array() {
let i_a = vec![[0.5, 0.5], [1.0, 1.0], [1.5, 0.5]];
let i_b = vec![[0.55, 0.55], [0.8, 0.8], [1.2, 0.55]];
let inners = vec![i_a, i_b];
let array = gen_wrapperarray(inners);
let rec_inners = reconstitute2(array);
assert_eq!(rec_inners[0][2], [1.5, 0.5])
}
#[test]
fn test_ffi() {
let ext_vec = vec![
[4.0, 1.0],
[5.0, 2.0],
[5.0, 3.0],
[4.0, 4.0],
[3.0, 4.0],
[2.0, 3.0],
[2.0, 2.0],
[3.0, 1.0],
[4.0, 1.0],
];
let int_vec = vec![
vec![[3.5, 3.5], [4.4, 2.0], [2.6, 2.0], [3.5, 3.5]],
vec![[4.0, 3.0], [4.0, 3.2], [4.5, 3.2], [4.0, 3.0]],
];
let outer = gen_array(ext_vec);
let inners = gen_wrapperarray(int_vec);
let res = polylabel_ffi(outer, inners, 0.1);
let res_point = Point::new(res.x_pos, res.y_pos);
assert_eq!(res_point, Point::new(3.125, 2.875));
}
}