use ffi_helpers::null_pointer_check;
use libc::c_double;
use nalgebra::{Matrix3, Quaternion, Rotation3, UnitQuaternion};
fn to_raw_pointer(rot: &Rotation3<f64>) -> *mut Rotation3<f64> {
Box::into_raw(Box::new(*rot))
}
#[no_mangle]
pub unsafe extern "C" fn viam_free_rotation_matrix_memory(ptr: *mut Rotation3<f64>) {
if ptr.is_null() {
return;
}
let _ = Box::from_raw(ptr);
}
#[no_mangle]
#[deprecated]
pub unsafe extern "C" fn free_rotation_matrix_memory(ptr: *mut Rotation3<f64>) {
viam_free_rotation_matrix_memory(ptr)
}
#[no_mangle]
pub unsafe extern "C" fn viam_new_rotation_matrix(
elements: *const [f64; 9],
) -> *mut Rotation3<f64> {
null_pointer_check!(elements);
let e = *elements;
let matrix = Matrix3::new(
e[0], e[1], e[2],
e[3], e[4], e[5],
e[6], e[7], e[8],
);
let rot = Rotation3::from_matrix_unchecked(matrix);
to_raw_pointer(&rot)
}
#[no_mangle]
#[deprecated]
pub unsafe extern "C" fn new_rotation_matrix(elements: *const [f64; 9]) -> *mut Rotation3<f64> {
viam_new_rotation_matrix(elements)
}
#[no_mangle]
pub unsafe extern "C" fn viam_rotation_matrix_from_quaternion(
quat: *const Quaternion<f64>,
) -> *mut Rotation3<f64> {
null_pointer_check!(quat);
let unit_quat = UnitQuaternion::new_normalize(*quat);
let rot = unit_quat.to_rotation_matrix();
to_raw_pointer(&rot)
}
#[no_mangle]
#[deprecated]
pub unsafe extern "C" fn rotation_matrix_from_quaternion(
quat: *const Quaternion<f64>,
) -> *mut Rotation3<f64> {
viam_rotation_matrix_from_quaternion(quat)
}
#[no_mangle]
pub unsafe extern "C" fn viam_rotation_matrix_get_elements(
rot_ptr: *const Rotation3<f64>,
) -> *const c_double {
null_pointer_check!(rot_ptr);
let m = (*rot_ptr).matrix();
let elements: [c_double; 9] = [
m[(0, 0)], m[(0, 1)], m[(0, 2)],
m[(1, 0)], m[(1, 1)], m[(1, 2)],
m[(2, 0)], m[(2, 1)], m[(2, 2)],
];
Box::into_raw(Box::new(elements)) as *const _
}
#[no_mangle]
#[deprecated]
pub unsafe extern "C" fn rotation_matrix_get_elements(
rot_ptr: *const Rotation3<f64>,
) -> *const c_double {
viam_rotation_matrix_get_elements(rot_ptr)
}
#[no_mangle]
pub unsafe extern "C" fn viam_free_rotation_matrix_elements(ptr: *mut c_double) {
if ptr.is_null() {
return;
}
let ptr = ptr as *mut [c_double; 9];
let _: Box<[c_double; 9]> = Box::from_raw(ptr);
}
#[no_mangle]
#[deprecated]
pub unsafe extern "C" fn free_rotation_matrix_elements(ptr: *mut c_double) {
viam_free_rotation_matrix_elements(ptr)
}
#[cfg(test)]
mod tests {
use super::*;
unsafe fn read_elements(rot: *const Rotation3<f64>) -> [f64; 9] {
let ptr = viam_rotation_matrix_get_elements(rot) as *mut c_double;
let out = *(ptr as *const [f64; 9]);
viam_free_rotation_matrix_elements(ptr);
out
}
#[test]
fn new_and_get_elements_round_trip_row_major() {
let elements: [f64; 9] = [0.0, -1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0];
unsafe {
let rot = viam_new_rotation_matrix(&elements);
let got = read_elements(rot);
for i in 0..9 {
assert!((got[i] - elements[i]).abs() < 1e-12, "index {i}: got {}, want {}", got[i], elements[i]);
}
viam_free_rotation_matrix_memory(rot);
}
}
#[test]
fn quaternion_to_rotation_matrix_returns_row_major() {
let half = std::f64::consts::FRAC_PI_4;
let q = Quaternion::new(half.cos(), 0.0, 0.0, half.sin());
unsafe {
let rot = viam_rotation_matrix_from_quaternion(&q);
let got = read_elements(rot);
let want: [f64; 9] = [0.0, -1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0];
for i in 0..9 {
assert!((got[i] - want[i]).abs() < 1e-12, "index {i}: got {}, want {}", got[i], want[i]);
}
viam_free_rotation_matrix_memory(rot);
}
}
#[test]
fn asymmetric_matrix_survives_round_trip() {
let elements: [f64; 9] = [
0.70710678, -0.61237244, 0.35355339,
0.70710678, 0.61237244, -0.35355339,
0.0, 0.5, 0.8660254,
];
unsafe {
let rot = viam_new_rotation_matrix(&elements);
let got = read_elements(rot);
for i in 0..9 {
assert!((got[i] - elements[i]).abs() < 1e-8, "index {i}: got {}, want {}", got[i], elements[i]);
}
viam_free_rotation_matrix_memory(rot);
}
}
}