#![allow(non_camel_case_types)]
use cavalier_contours::{
core::math::Vector2,
polyline::{
BooleanOp, PlineBooleanOptions, PlineContainsOptions, PlineOffsetOptions,
PlineSelfIntersectOptions, PlineSource, PlineSourceMut, PlineVertex, Polyline,
SelfIntersectsInclude,
},
shape_algorithms::{Shape, ShapeOffsetOptions},
static_aabb2d_index::StaticAABB2DIndex,
};
use core::slice;
use std::panic;
macro_rules! ffi_catch_unwind {
($body: expr) => {
match panic::catch_unwind(move || $body) {
Ok(r) => r,
Err(_) => -1,
}
};
}
#[derive(Debug, Clone)]
pub struct cavc_aabbindex(pub StaticAABB2DIndex<f64>);
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct cavc_point {
pub x: f64,
pub y: f64,
}
impl cavc_point {
#[must_use]
pub fn new(x: f64, y: f64) -> Self {
cavc_point { x, y }
}
#[must_use]
pub fn from_internal(v: Vector2<f64>) -> Self {
cavc_point::new(v.x, v.y)
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct cavc_vertex {
pub x: f64,
pub y: f64,
pub bulge: f64,
}
impl cavc_vertex {
#[must_use]
pub fn new(x: f64, y: f64, bulge: f64) -> Self {
cavc_vertex { x, y, bulge }
}
#[must_use]
pub fn from_internal(v: PlineVertex<f64>) -> Self {
cavc_vertex::new(v.x, v.y, v.bulge)
}
}
#[derive(Debug, Clone)]
pub struct cavc_pline(pub Polyline<f64>);
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct cavc_pline_parallel_offset_o {
pub aabb_index: *const cavc_aabbindex,
pub pos_equal_eps: f64,
pub slice_join_eps: f64,
pub offset_dist_eps: f64,
pub handle_self_intersects: u8,
}
impl cavc_pline_parallel_offset_o {
#[must_use]
pub unsafe fn to_internal(&self) -> PlineOffsetOptions<'_, f64> {
let aabb_index = unsafe { self.aabb_index.as_ref().map(|w| &w.0) };
PlineOffsetOptions {
aabb_index,
pos_equal_eps: self.pos_equal_eps,
slice_join_eps: self.slice_join_eps,
offset_dist_eps: self.offset_dist_eps,
handle_self_intersects: self.handle_self_intersects != 0,
}
}
}
impl Default for cavc_pline_parallel_offset_o {
fn default() -> Self {
let d = PlineOffsetOptions::default();
Self {
aabb_index: std::ptr::null(),
pos_equal_eps: d.pos_equal_eps,
slice_join_eps: d.slice_join_eps,
offset_dist_eps: d.offset_dist_eps,
handle_self_intersects: u8::from(d.handle_self_intersects),
}
}
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_parallel_offset_o_create(
options: *mut *mut cavc_pline_parallel_offset_o,
) -> i32 {
ffi_catch_unwind!({
unsafe {
let result = cavc_pline_parallel_offset_o::default();
options.write(Box::into_raw(Box::new(result)));
}
0
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn cavc_pline_parallel_offset_o_f(
options: *mut cavc_pline_parallel_offset_o,
) {
if !options.is_null() {
unsafe {
drop(Box::from_raw(options));
}
}
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_parallel_offset_o_init(
options: *mut cavc_pline_parallel_offset_o,
) -> i32 {
ffi_catch_unwind!({
if options.is_null() {
return 1;
}
unsafe {
options.write(cavc_pline_parallel_offset_o::default());
}
0
})
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct cavc_pline_boolean_o {
pub pline1_aabb_index: *const cavc_aabbindex,
pub pos_equal_eps: f64,
pub collapsed_area_eps: f64,
}
impl cavc_pline_boolean_o {
#[must_use]
pub unsafe fn to_internal(&self) -> PlineBooleanOptions<'_, f64> {
let pline1_aabb_index = unsafe { self.pline1_aabb_index.as_ref().map(|w| &w.0) };
PlineBooleanOptions {
pline1_aabb_index,
pos_equal_eps: self.pos_equal_eps,
collapsed_area_eps: if self.collapsed_area_eps.is_nan() {
None
} else {
Some(self.collapsed_area_eps)
},
}
}
}
impl Default for cavc_pline_boolean_o {
fn default() -> Self {
let d = PlineBooleanOptions::default();
Self {
pline1_aabb_index: std::ptr::null(),
pos_equal_eps: d.pos_equal_eps,
collapsed_area_eps: f64::NAN,
}
}
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_boolean_o_create(
options: *mut *mut cavc_pline_boolean_o,
) -> i32 {
ffi_catch_unwind!({
unsafe {
let result = cavc_pline_boolean_o::default();
options.write(Box::into_raw(Box::new(result)));
}
0
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn cavc_pline_boolean_o_f(options: *mut cavc_pline_boolean_o) {
if !options.is_null() {
unsafe {
drop(Box::from_raw(options));
}
}
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_boolean_o_init(options: *mut cavc_pline_boolean_o) -> i32 {
ffi_catch_unwind!({
if options.is_null() {
return 1;
}
unsafe {
options.write(cavc_pline_boolean_o::default());
}
0
})
}
fn boolean_op_from_u32(i: u32) -> Option<BooleanOp> {
if i == 0 {
Some(BooleanOp::Or)
} else if i == 1 {
Some(BooleanOp::And)
} else if i == 2 {
Some(BooleanOp::Not)
} else if i == 3 {
Some(BooleanOp::Xor)
} else {
None
}
}
pub const CAVC_SELF_INTERSECTS_INCLUDE_ALL: u32 = 0;
pub const CAVC_SELF_INTERSECTS_INCLUDE_LOCAL: u32 = 1;
pub const CAVC_SELF_INTERSECTS_INCLUDE_GLOBAL: u32 = 2;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct cavc_pline_self_intersect_o {
pub pline_aabb_index: *const cavc_aabbindex,
pub pos_equal_eps: f64,
pub include: u32,
}
impl cavc_pline_self_intersect_o {
#[must_use]
pub unsafe fn to_internal(&self) -> Option<PlineSelfIntersectOptions<'_, f64>> {
let pline_aabb_index = unsafe { self.pline_aabb_index.as_ref().map(|w| &w.0) };
let include_value = match self.include {
0 => SelfIntersectsInclude::All,
1 => SelfIntersectsInclude::Local,
2 => SelfIntersectsInclude::Global,
_ => {
return None;
}
};
Some(PlineSelfIntersectOptions {
aabb_index: pline_aabb_index,
pos_equal_eps: self.pos_equal_eps,
include: include_value,
})
}
}
impl Default for cavc_pline_self_intersect_o {
fn default() -> Self {
let d = PlineSelfIntersectOptions::default();
Self {
pline_aabb_index: std::ptr::null(),
pos_equal_eps: d.pos_equal_eps,
include: d.include as u32,
}
}
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_self_intersect_o_create(
options: *mut *mut cavc_pline_self_intersect_o,
) -> i32 {
ffi_catch_unwind!({
unsafe {
let result = cavc_pline_self_intersect_o::default();
options.write(Box::into_raw(Box::new(result)));
}
0
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn cavc_pline_self_intersect_o_f(options: *mut cavc_pline_self_intersect_o) {
if !options.is_null() {
unsafe {
drop(Box::from_raw(options));
}
}
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_self_intersect_o_init(
options: *mut cavc_pline_self_intersect_o,
) -> i32 {
ffi_catch_unwind!({
if options.is_null() {
return 1;
}
unsafe {
options.write(cavc_pline_self_intersect_o::default());
}
0
})
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct cavc_pline_contains_o {
pub pline1_aabb_index: *const cavc_aabbindex,
pub pos_equal_eps: f64,
}
impl cavc_pline_contains_o {
#[must_use]
pub unsafe fn to_internal(&self) -> PlineContainsOptions<'_, f64> {
let pline1_aabb_index = unsafe { self.pline1_aabb_index.as_ref().map(|w| &w.0) };
PlineContainsOptions {
pline1_aabb_index,
pos_equal_eps: self.pos_equal_eps,
}
}
}
impl Default for cavc_pline_contains_o {
fn default() -> Self {
let d = PlineContainsOptions::default();
Self {
pline1_aabb_index: std::ptr::null(),
pos_equal_eps: d.pos_equal_eps,
}
}
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_contains_o_create(
options: *mut *mut cavc_pline_contains_o,
) -> i32 {
ffi_catch_unwind!({
unsafe {
let result = cavc_pline_contains_o::default();
options.write(Box::into_raw(Box::new(result)));
}
0
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn cavc_pline_contains_o_f(options: *mut cavc_pline_contains_o) {
if !options.is_null() {
unsafe {
drop(Box::from_raw(options));
}
}
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_contains_o_init(options: *mut cavc_pline_contains_o) -> i32 {
ffi_catch_unwind!({
if options.is_null() {
return 1;
}
unsafe {
options.write(cavc_pline_contains_o::default());
}
0
})
}
pub struct cavc_plinelist(pub Vec<*mut cavc_pline>);
impl Drop for cavc_plinelist {
fn drop(&mut self) {
for pline_ptr in self.0.drain(..) {
unsafe {
cavc_pline_f(pline_ptr);
}
}
}
}
impl cavc_plinelist {
pub fn from_internal<I>(plines: I) -> *mut cavc_plinelist
where
I: IntoIterator<Item = Polyline>,
{
let r = plines
.into_iter()
.map(|pl| Box::into_raw(Box::new(cavc_pline(pl))))
.collect();
Box::into_raw(Box::new(cavc_plinelist(r)))
}
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_create(
vertexes: *const cavc_vertex,
n_vertexes: usize,
is_closed: u8,
pline: *mut *const cavc_pline,
) -> i32 {
ffi_catch_unwind!({
let mut result = Polyline::new();
if is_closed != 0 {
result.set_is_closed(true);
}
if !vertexes.is_null() && n_vertexes != 0 {
let data = unsafe { slice::from_raw_parts(vertexes, n_vertexes) };
result.reserve(data.len());
for v in data {
result.add(v.x, v.y, v.bulge);
}
}
unsafe {
pline.write(Box::into_raw(Box::new(cavc_pline(result))));
}
0
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn cavc_pline_f(pline: *mut cavc_pline) {
if !pline.is_null() {
unsafe {
drop(Box::from_raw(pline));
}
}
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_set_userdata_values(
pline: *mut cavc_pline,
userdata_values: *const u64,
count: usize,
) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
unsafe {
(*pline).0.userdata.clear();
if !userdata_values.is_null() && count != 0 {
let data = slice::from_raw_parts(userdata_values, count);
(*pline).0.userdata.extend_from_slice(data);
}
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_get_userdata_count(
pline: *const cavc_pline,
count: *mut usize,
) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
unsafe {
count.write((*pline).0.userdata.len());
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_get_userdata_values(
pline: *const cavc_pline,
userdata_values: *mut u64,
) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
unsafe {
std::ptr::copy(
(*pline).0.userdata.as_ptr(),
userdata_values,
(*pline).0.userdata.len(),
);
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_reserve(pline: *mut cavc_pline, additional: usize) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
unsafe {
(*pline).0.reserve(additional);
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_clone(
pline: *const cavc_pline,
cloned: *mut *const cavc_pline,
) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
unsafe {
cloned.write(Box::into_raw(Box::new(cavc_pline((*pline).0.clone()))));
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_get_is_closed(
pline: *const cavc_pline,
is_closed: *mut u8,
) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
unsafe {
is_closed.write(u8::from((*pline).0.is_closed()));
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_set_is_closed(pline: *mut cavc_pline, is_closed: u8) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
unsafe {
(*pline).0.set_is_closed(is_closed != 0);
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_get_vertex_count(
pline: *const cavc_pline,
count: *mut usize,
) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
unsafe {
count.write((*pline).0.vertex_count());
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_get_vertex_data(
pline: *const cavc_pline,
vertex_data: *mut cavc_vertex,
) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
let buffer = unsafe { slice::from_raw_parts_mut(vertex_data, (*pline).0.vertex_count()) };
for (i, v) in unsafe { (*pline).0.iter_vertexes().enumerate() } {
buffer[i] = cavc_vertex::from_internal(v);
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_set_vertex_data(
pline: *mut cavc_pline,
vertex_data: *const cavc_vertex,
n_vertexes: usize,
) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
unsafe {
(*pline).0.clear();
let buffer = slice::from_raw_parts(vertex_data, n_vertexes);
(*pline).0.reserve(buffer.len());
for v in buffer {
(*pline).0.add(v.x, v.y, v.bulge);
}
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_clear(pline: *mut cavc_pline) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
unsafe {
(*pline).0.clear();
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_add(pline: *mut cavc_pline, x: f64, y: f64, bulge: f64) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
unsafe {
(*pline).0.add(x, y, bulge);
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_get_vertex(
pline: *const cavc_pline,
position: usize,
vertex: *mut cavc_vertex,
) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
unsafe {
if position >= (*pline).0.vertex_count() {
return 2;
}
let v = (&(*pline).0)[position];
vertex.write(cavc_vertex::from_internal(v));
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_set_vertex(
pline: *mut cavc_pline,
position: usize,
vertex: cavc_vertex,
) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
unsafe {
if position >= (*pline).0.vertex_count() {
return 2;
}
(&mut (*pline).0)[position] = PlineVertex::new(vertex.x, vertex.y, vertex.bulge);
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_remove(pline: *mut cavc_pline, position: usize) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
unsafe {
if position >= (*pline).0.vertex_count() {
return 2;
}
(*pline).0.remove(position);
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_eval_path_length(
pline: *const cavc_pline,
path_length: *mut f64,
) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
unsafe {
path_length.write((*pline).0.path_length());
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_eval_area(pline: *const cavc_pline, area: *mut f64) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
unsafe {
area.write((*pline).0.area());
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_eval_wn(
pline: *const cavc_pline,
x: f64,
y: f64,
winding_number: *mut i32,
) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
unsafe {
winding_number.write((*pline).0.winding_number(Vector2::new(x, y)));
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_invert_direction(pline: *mut cavc_pline) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
unsafe {
(*pline).0.invert_direction_mut();
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_scale(pline: *mut cavc_pline, scale_factor: f64) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
unsafe {
(*pline).0.scale_mut(scale_factor);
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_translate(
pline: *mut cavc_pline,
x_offset: f64,
y_offset: f64,
) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
unsafe {
(*pline).0.translate_mut(x_offset, y_offset);
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_remove_repeat_pos(
pline: *mut cavc_pline,
pos_equal_eps: f64,
) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
let pline = unsafe { &mut (*pline).0 };
match pline.remove_repeat_pos(pos_equal_eps) {
None => {
0
}
Some(x) => {
*pline = x;
0
}
}
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_remove_redundant(
pline: *mut cavc_pline,
pos_equal_eps: f64,
) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
let pline = unsafe { &mut (*pline).0 };
match pline.remove_redundant(pos_equal_eps) {
None => {
0
}
Some(x) => {
*pline = x;
0
}
}
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_eval_extents(
pline: *const cavc_pline,
min_x: *mut f64,
min_y: *mut f64,
max_x: *mut f64,
max_y: *mut f64,
) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
let pline = unsafe { &(*pline).0 };
match pline.extents() {
Some(aabb) => {
unsafe {
min_x.write(aabb.min_x);
min_y.write(aabb.min_y);
max_x.write(aabb.max_x);
max_y.write(aabb.max_y);
}
0
}
None => 2,
}
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_parallel_offset(
pline: *const cavc_pline,
offset: f64,
options: *const cavc_pline_parallel_offset_o,
result: *mut *const cavc_plinelist,
) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
let pline = unsafe { &(*pline).0 };
let results = if options.is_null() {
pline.parallel_offset(offset)
} else {
let opts = unsafe { &(*options).to_internal() };
pline.parallel_offset_opt(offset, opts)
};
unsafe {
result.write(cavc_plinelist::from_internal(results));
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_boolean(
pline1: *const cavc_pline,
pline2: *const cavc_pline,
operation: u32,
options: *const cavc_pline_boolean_o,
pos_plines: *mut *const cavc_plinelist,
neg_plines: *mut *const cavc_plinelist,
) -> i32 {
ffi_catch_unwind!({
if pline1.is_null() || pline2.is_null() {
return 1;
}
let op = {
match boolean_op_from_u32(operation) {
Some(op) => op,
None => {
return 2;
}
}
};
let pline1 = unsafe { &(*pline1).0 };
let pline2 = unsafe { &(*pline2).0 };
let results = if options.is_null() {
pline1.boolean(pline2, op)
} else {
let options = unsafe { &(*options).to_internal() };
pline1.boolean_opt(pline2, op, options)
};
unsafe {
pos_plines.write(cavc_plinelist::from_internal(
results.pos_plines.into_iter().map(|p| p.pline),
));
neg_plines.write(cavc_plinelist::from_internal(
results.neg_plines.into_iter().map(|p| p.pline),
));
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_scan_for_self_intersect(
pline: *const cavc_pline,
options: *const cavc_pline_self_intersect_o,
is_self_intersecting: *mut u8,
) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
let pline = unsafe { &(*pline).0 };
let computed_result;
if options.is_null() {
computed_result = pline.scan_for_self_intersect();
} else {
let options = unsafe { &(*options).to_internal() };
match options {
None => return 2, Some(unpacked_options) => {
computed_result = pline.scan_for_self_intersect_opt(unpacked_options);
}
}
}
unsafe {
is_self_intersecting.write(u8::from(computed_result));
}
0
})
}
pub const CAVC_CONTAINS_RESULT_INVALID_INPUT: u32 = 0;
pub const CAVC_CONTAINS_RESULT_PLINE1_INSIDE_PLINE2: u32 = 1;
pub const CAVC_CONTAINS_RESULT_PLINE2_INSIDE_PLINE1: u32 = 2;
pub const CAVC_CONTAINS_RESULT_DISJOINT: u32 = 3;
pub const CAVC_CONTAINS_RESULT_INTERSECTED: u32 = 4;
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_contains(
pline1: *const cavc_pline,
pline2: *const cavc_pline,
options: *const cavc_pline_contains_o,
result: *mut u32,
) -> i32 {
ffi_catch_unwind!({
if pline1.is_null() || pline2.is_null() {
if !result.is_null() {
unsafe { result.write(CAVC_CONTAINS_RESULT_INVALID_INPUT) };
}
return 1;
}
let pline1 = unsafe { &(*pline1).0 };
let pline2 = unsafe { &(*pline2).0 };
let computed_result = if options.is_null() {
pline1.contains(pline2)
} else {
let options = unsafe { &(*options).to_internal() };
pline1.contains_opt(pline2, options)
};
unsafe {
result.write(computed_result as u32);
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_create_approx_aabbindex(
pline: *const cavc_pline,
aabbindex: *mut *const cavc_aabbindex,
) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
let pline = unsafe { &(*pline).0 };
let result = pline.create_approx_aabb_index();
unsafe {
aabbindex.write(Box::into_raw(Box::new(cavc_aabbindex(result))));
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_pline_create_aabbindex(
pline: *const cavc_pline,
aabbindex: *mut *const cavc_aabbindex,
) -> i32 {
ffi_catch_unwind!({
if pline.is_null() {
return 1;
}
let pline = unsafe { &(*pline).0 };
let result = pline.create_aabb_index();
unsafe {
aabbindex.write(Box::into_raw(Box::new(cavc_aabbindex(result))));
}
0
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn cavc_aabbindex_f(aabbindex: *mut cavc_aabbindex) {
if !aabbindex.is_null() {
unsafe { drop(Box::from_raw(aabbindex)) }
}
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_aabbindex_get_extents(
aabbindex: *const cavc_aabbindex,
min_x: *mut f64,
min_y: *mut f64,
max_x: *mut f64,
max_y: *mut f64,
) -> i32 {
ffi_catch_unwind!({
if aabbindex.is_null() {
return 1;
}
let aabbindex = unsafe { &(*aabbindex).0 };
if let Some(bounds) = aabbindex.bounds() {
unsafe {
min_x.write(bounds.min_x);
min_y.write(bounds.min_y);
max_x.write(bounds.max_x);
max_y.write(bounds.max_y);
}
} else {
unsafe {
min_x.write(f64::NAN);
min_y.write(f64::NAN);
max_x.write(f64::NAN);
max_y.write(f64::NAN);
}
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_plinelist_create(
capacity: usize,
plinelist: *mut *mut cavc_plinelist,
) -> i32 {
ffi_catch_unwind!({
unsafe {
plinelist.write(Box::into_raw(Box::new(cavc_plinelist(Vec::with_capacity(
capacity,
)))));
}
0
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn cavc_plinelist_f(plinelist: *mut cavc_plinelist) {
if !plinelist.is_null() {
unsafe { drop(Box::from_raw(plinelist)) }
}
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_plinelist_get_count(
plinelist: *const cavc_plinelist,
count: *mut usize,
) -> i32 {
ffi_catch_unwind!({
if plinelist.is_null() {
return 1;
}
unsafe {
count.write((*plinelist).0.len());
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_plinelist_get_pline(
plinelist: *const cavc_plinelist,
position: usize,
pline: *mut *const cavc_pline,
) -> i32 {
ffi_catch_unwind!({
if plinelist.is_null() {
return 1;
}
let plinelist = unsafe { &(*plinelist).0 };
match plinelist.get(position) {
Some(pl) => {
unsafe {
pline.write(*pl);
}
0
}
None => 2,
}
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_plinelist_push(
plinelist: *mut cavc_plinelist,
pline: *mut cavc_pline,
) -> i32 {
ffi_catch_unwind!({
if plinelist.is_null() {
return 1;
}
if pline.is_null() {
return 2;
}
unsafe {
(*plinelist).0.push(pline);
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_plinelist_pop(
plinelist: *mut cavc_plinelist,
pline: *mut *const cavc_pline,
) -> i32 {
ffi_catch_unwind!({
if plinelist.is_null() {
return 1;
}
let plinelist = unsafe { &mut (*plinelist).0 };
match plinelist.pop() {
Some(p) => {
unsafe {
if !pline.is_null() {
pline.write(p);
}
}
0
}
None => 2,
}
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_plinelist_take(
plinelist: *mut cavc_plinelist,
position: usize,
pline: *mut *const cavc_pline,
) -> i32 {
ffi_catch_unwind!({
if plinelist.is_null() {
return 1;
}
let plinelist = unsafe { &mut (*plinelist).0 };
if position >= plinelist.len() {
return 2;
}
unsafe {
let result = plinelist.remove(position);
if !pline.is_null() {
pline.write(result);
}
}
0
})
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct cavc_shape_offset_o {
pub pos_equal_eps: f64,
pub offset_dist_eps: f64,
pub slice_join_eps: f64,
}
impl cavc_shape_offset_o {
#[must_use]
pub fn to_internal(&self) -> ShapeOffsetOptions<f64> {
ShapeOffsetOptions {
pos_equal_eps: self.pos_equal_eps,
offset_dist_eps: self.offset_dist_eps,
slice_join_eps: self.slice_join_eps,
}
}
}
impl Default for cavc_shape_offset_o {
fn default() -> Self {
let d = ShapeOffsetOptions::default();
Self {
pos_equal_eps: d.pos_equal_eps,
offset_dist_eps: d.offset_dist_eps,
slice_join_eps: d.slice_join_eps,
}
}
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_shape_offset_o_init(options: *mut cavc_shape_offset_o) -> i32 {
ffi_catch_unwind!({
if options.is_null() {
return 1;
}
unsafe {
options.write(cavc_shape_offset_o::default());
}
0
})
}
#[derive(Debug, Clone)]
pub struct cavc_shape(pub Shape<f64>);
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_shape_create(
plinelist: *const cavc_plinelist,
shape: *mut *mut cavc_shape,
) -> i32 {
ffi_catch_unwind!({
if plinelist.is_null() {
return 1;
}
unsafe {
let count: usize = (*plinelist).0.len();
let mut v: Vec<Polyline<f64>> = Vec::with_capacity(count);
for pline in &(*plinelist).0 {
v.push((**pline).0.clone());
}
let s = Shape::from_plines(v);
shape.write(Box::into_raw(Box::new(cavc_shape(s))));
}
0
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn cavc_shape_f(shape: *mut cavc_shape) {
if !shape.is_null() {
unsafe { drop(Box::from_raw(shape)) }
}
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_shape_parallel_offset(
shape: *const cavc_shape,
offset: f64,
options: *const cavc_shape_offset_o,
result: *mut *mut cavc_shape,
) -> i32 {
ffi_catch_unwind!({
if shape.is_null() {
return 1;
}
unsafe {
let results = if options.is_null() {
let default_options = ShapeOffsetOptions::new();
(*shape).0.parallel_offset(offset, &default_options)
} else {
(*shape)
.0
.parallel_offset(offset, &(*options).to_internal())
};
result.write(Box::into_raw(Box::new(cavc_shape(results))));
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_shape_get_ccw_count(
shape: *const cavc_shape,
count: *mut usize,
) -> i32 {
ffi_catch_unwind!({
if shape.is_null() {
return 1;
}
unsafe {
count.write((*shape).0.ccw_plines.len());
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_shape_get_ccw_polyline_count(
shape: *const cavc_shape,
polyline_index: usize,
count: *mut usize,
) -> i32 {
ffi_catch_unwind!({
if shape.is_null() {
return 1;
}
unsafe {
if polyline_index >= ((*shape).0.ccw_plines.len()) {
return 2;
}
let ccw_plines = &(*shape).0.ccw_plines;
let polyline = &ccw_plines[polyline_index].polyline;
count.write(polyline.vertex_data.len());
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_shape_get_ccw_polyline_is_closed(
shape: *const cavc_shape,
polyline_index: usize,
is_closed: *mut u8,
) -> i32 {
ffi_catch_unwind!({
if shape.is_null() {
return 1;
}
unsafe {
if polyline_index >= ((*shape).0.ccw_plines.len()) {
return 2;
}
let ccw_plines = &(*shape).0.ccw_plines;
let polyline = &ccw_plines[polyline_index].polyline;
is_closed.write(u8::from(polyline.is_closed));
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_shape_get_ccw_polyline_vertex_data(
shape: *const cavc_shape,
polyline_index: usize,
vertex_data: *mut cavc_vertex,
) -> i32 {
ffi_catch_unwind!({
if shape.is_null() {
return 1;
}
unsafe {
if polyline_index >= ((*shape).0.ccw_plines.len()) {
return 2;
}
let ccw_plines = &(*shape).0.ccw_plines;
let pline = &ccw_plines[polyline_index].polyline;
let buffer = slice::from_raw_parts_mut(vertex_data, pline.vertex_count());
for (i, v) in pline.iter_vertexes().enumerate() {
buffer[i] = cavc_vertex::from_internal(v);
}
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_shape_set_ccw_pline_userdata_values(
shape: *mut cavc_shape,
polyline_index: usize,
userdata_values: *const u64,
count: usize,
) -> i32 {
ffi_catch_unwind!({
if shape.is_null() {
return 1;
}
unsafe {
if polyline_index >= ((*shape).0.ccw_plines.len()) {
return 2;
}
let ccw_plines = &mut (*shape).0.ccw_plines;
let pline = &mut ccw_plines[polyline_index].polyline;
pline.userdata.clear();
if !userdata_values.is_null() && count != 0 {
let data = slice::from_raw_parts(userdata_values, count);
pline.userdata.extend_from_slice(data);
}
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_shape_get_ccw_pline_userdata_count(
shape: *const cavc_shape,
polyline_index: usize,
count: *mut usize,
) -> i32 {
ffi_catch_unwind!({
if shape.is_null() {
return 1;
}
unsafe {
if polyline_index >= ((*shape).0.ccw_plines.len()) {
return 2;
}
let ccw_plines = &(*shape).0.ccw_plines;
let pline = &ccw_plines[polyline_index].polyline;
count.write(pline.userdata.len());
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_shape_get_ccw_pline_userdata_values(
shape: *const cavc_shape,
polyline_index: usize,
userdata_values: *mut u64,
) -> i32 {
ffi_catch_unwind!({
if shape.is_null() {
return 1;
}
unsafe {
let ccw_plines = &(*shape).0.ccw_plines;
let pline = &ccw_plines[polyline_index].polyline;
std::ptr::copy(
pline.userdata.as_ptr(),
userdata_values,
pline.userdata.len(),
);
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_shape_get_cw_count(
shape: *const cavc_shape,
count: *mut usize,
) -> i32 {
ffi_catch_unwind!({
if shape.is_null() {
return 1;
}
unsafe {
count.write((*shape).0.cw_plines.len());
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_shape_get_cw_polyline_count(
shape: *const cavc_shape,
polyline_index: usize,
count: *mut usize,
) -> i32 {
ffi_catch_unwind!({
if shape.is_null() {
return 1;
}
unsafe {
if polyline_index >= ((*shape).0.cw_plines.len()) {
return 2;
}
let cw_plines = &(*shape).0.cw_plines;
let polyline = &cw_plines[polyline_index].polyline;
count.write(polyline.vertex_data.len());
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_shape_get_cw_polyline_is_closed(
shape: *const cavc_shape,
polyline_index: usize,
is_closed: *mut u8,
) -> i32 {
ffi_catch_unwind!({
if shape.is_null() {
return 1;
}
unsafe {
let shape = &(*shape).0;
if polyline_index >= shape.cw_plines.len() {
return 2;
}
is_closed.write(u8::from(shape.cw_plines[polyline_index].polyline.is_closed));
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_shape_get_cw_polyline_vertex_data(
shape: *const cavc_shape,
polyline_index: usize,
vertex_data: *mut cavc_vertex,
) -> i32 {
ffi_catch_unwind!({
if shape.is_null() {
return 1;
}
unsafe {
if polyline_index >= ((*shape).0.cw_plines.len()) {
return 2;
}
let cw_plines = &(*shape).0.cw_plines;
let pline = &cw_plines[polyline_index].polyline;
let buffer = slice::from_raw_parts_mut(vertex_data, pline.vertex_count());
for (i, v) in pline.iter_vertexes().enumerate() {
buffer[i] = cavc_vertex::from_internal(v);
}
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_shape_set_cw_pline_userdata_values(
shape: *mut cavc_shape,
polyline_index: usize,
userdata_values: *const u64,
count: usize,
) -> i32 {
ffi_catch_unwind!({
if shape.is_null() {
return 1;
}
unsafe {
if polyline_index >= ((*shape).0.cw_plines.len()) {
return 2;
}
let cw_plines = &mut (*shape).0.cw_plines;
let pline = &mut cw_plines[polyline_index].polyline;
pline.userdata.clear();
if !userdata_values.is_null() && count != 0 {
let data = slice::from_raw_parts(userdata_values, count);
pline.userdata.extend_from_slice(data);
}
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_shape_get_cw_pline_userdata_count(
shape: *const cavc_shape,
polyline_index: usize,
count: *mut usize,
) -> i32 {
ffi_catch_unwind!({
if shape.is_null() {
return 1;
}
unsafe {
if polyline_index >= ((*shape).0.cw_plines.len()) {
return 2;
}
let cw_plines = &(*shape).0.cw_plines;
let pline = &cw_plines[polyline_index].polyline;
count.write(pline.userdata.len());
}
0
})
}
#[unsafe(no_mangle)]
#[must_use]
pub unsafe extern "C" fn cavc_shape_get_cw_pline_userdata_values(
shape: *const cavc_shape,
polyline_index: usize,
userdata_values: *mut u64,
) -> i32 {
ffi_catch_unwind!({
if shape.is_null() {
return 1;
}
unsafe {
let cw_plines = &(*shape).0.cw_plines;
let pline = &cw_plines[polyline_index].polyline;
std::ptr::copy(
pline.userdata.as_ptr(),
userdata_values,
pline.userdata.len(),
);
}
0
})
}