|
| 1 | +use ffi_helpers::null_pointer_check; |
| 2 | +use libc::c_double; |
| 3 | + |
| 4 | +use crate::spatialmath::{quaternion::Quaternion, vector3::Vector3}; |
| 5 | + |
| 6 | +/// The FFI interface for Quaternion functions and initialization. All public |
| 7 | +/// functions are meant to be called externally from other languages. Quaternions |
| 8 | +/// use the Real-I-J-K standard, so quaternions in other standards should be |
| 9 | +/// converted in the native language before being used to initialize quaternions |
| 10 | +/// from this library |
| 11 | +
|
| 12 | +/// Allocates a copy of the quaternion to the heap with a stable memory address and |
| 13 | +/// returns the raw pointer (for use by the FFI interface) |
| 14 | +fn to_raw_pointer(quat: &Quaternion) -> *mut Quaternion { |
| 15 | + Box::into_raw(Box::new(*quat)) |
| 16 | +} |
| 17 | + |
| 18 | +/// Initialize a quaternion from raw components and retrieve the C pointer |
| 19 | +/// to its address. |
| 20 | +/// |
| 21 | +/// # Safety |
| 22 | +/// |
| 23 | +/// When finished with the underlying quaternion initialized by this function |
| 24 | +/// the caller must remember to free the quaternion memory using the |
| 25 | +/// free_quaternion_memory FFI function |
| 26 | +#[no_mangle] |
| 27 | +pub extern "C" fn new_quaternion(real: f64, i: f64, j: f64, k: f64) -> *mut Quaternion { |
| 28 | + to_raw_pointer(&Quaternion::new(real, i, j, k)) |
| 29 | +} |
| 30 | + |
| 31 | +/// Initialize a quaternion from a real part and a C pointer to a Vector3 |
| 32 | +/// and retrieve the C pointer to its address. |
| 33 | +/// |
| 34 | +/// # Safety |
| 35 | +/// |
| 36 | +/// When finished with the underlying quaternion initialized by this function |
| 37 | +/// the caller must remember to free the quaternion memory using the |
| 38 | +/// free_quaternion_memory FFI function |
| 39 | +#[no_mangle] |
| 40 | +pub unsafe extern "C" fn new_quaternion_from_vector( |
| 41 | + real: f64, imag_ptr: *const Vector3 |
| 42 | +) -> *mut Quaternion { |
| 43 | + null_pointer_check!(imag_ptr); |
| 44 | + to_raw_pointer(&Quaternion::new_from_vector(real, *imag_ptr)) |
| 45 | +} |
| 46 | + |
| 47 | +/// Free memory at the address of the quaternion pointer. Outer processes |
| 48 | +/// that work with Quaternions via the FFI interface MUST remember |
| 49 | +/// to call this function when finished with a quaternion |
| 50 | +/// |
| 51 | +/// # Safety |
| 52 | +#[no_mangle] |
| 53 | +pub unsafe extern "C" fn free_quaternion_memory(ptr: *mut Quaternion) { |
| 54 | + if ptr.is_null() { |
| 55 | + return; |
| 56 | + } |
| 57 | + let _ = Box::from_raw(ptr); |
| 58 | +} |
| 59 | + |
| 60 | +/// Free memory at the address of the euler angles pointer. Outer processes |
| 61 | +/// that work with euler angles returned by this interface MUST remember |
| 62 | +/// to call this function when finished with the list of doubles |
| 63 | +/// |
| 64 | +/// # Safety |
| 65 | +#[no_mangle] |
| 66 | +pub unsafe extern "C" fn free_euler_angles_memory(ptr: *mut c_double) { |
| 67 | + if ptr.is_null() { |
| 68 | + return; |
| 69 | + } |
| 70 | + let _ = Box::from_raw(ptr); |
| 71 | +} |
| 72 | + |
| 73 | +/// Get the components of a quaternion as a list of C doubles, the order of the |
| 74 | +/// components will be (real, i, j, k). |
| 75 | +/// |
| 76 | +/// # Safety |
| 77 | +/// |
| 78 | +/// When finished with the underlying quaternion passed to this function |
| 79 | +/// the caller must remember to free the quaternion memory using the |
| 80 | +/// free_quaternion_memory FFI function |
| 81 | +#[no_mangle] |
| 82 | +pub unsafe extern "C" fn quaternion_get_components(quat_ptr: *const Quaternion) -> *const c_double { |
| 83 | + null_pointer_check!(quat_ptr); |
| 84 | + let components: [c_double;4] = [(*quat_ptr).real, (*quat_ptr).i, (*quat_ptr).j, (*quat_ptr).k]; |
| 85 | + Box::into_raw(Box::new(components)) as *const _ |
| 86 | +} |
| 87 | + |
| 88 | +/// Set the real component of an existing quaternion stored at the address |
| 89 | +/// of a pointer. |
| 90 | +/// |
| 91 | +/// # Safety |
| 92 | +/// |
| 93 | +/// When finished with the underlying quaternion passed to this function |
| 94 | +/// the caller must remember to free the quaternion memory using the |
| 95 | +/// free_quaternion_memory FFI function |
| 96 | +#[no_mangle] |
| 97 | +pub unsafe extern "C" fn quaternion_set_real(quat_ptr: *mut Quaternion, real: f64) { |
| 98 | + null_pointer_check!(quat_ptr); |
| 99 | + (*quat_ptr).real = real; |
| 100 | +} |
| 101 | + |
| 102 | +/// Set the i component of an existing quaternion stored at the address |
| 103 | +/// of a pointer. |
| 104 | +/// |
| 105 | +/// # Safety |
| 106 | +/// |
| 107 | +/// When finished with the underlying quaternion passed to this function |
| 108 | +/// the caller must remember to free the quaternion memory using the |
| 109 | +/// free_quaternion_memory FFI function |
| 110 | +#[no_mangle] |
| 111 | +pub unsafe extern "C" fn quaternion_set_i(quat_ptr: *mut Quaternion, i: f64) { |
| 112 | + null_pointer_check!(quat_ptr); |
| 113 | + (*quat_ptr).i = i; |
| 114 | +} |
| 115 | + |
| 116 | +/// Set the j component of an existing quaternion stored at the address |
| 117 | +/// of a pointer. |
| 118 | +/// |
| 119 | +/// # Safety |
| 120 | +/// |
| 121 | +/// When finished with the underlying quaternion passed to this function |
| 122 | +/// the caller must remember to free the quaternion memory using the |
| 123 | +/// free_quaternion_memory FFI function |
| 124 | +#[no_mangle] |
| 125 | +pub unsafe extern "C" fn quaternion_set_j(quat_ptr: *mut Quaternion, j: f64) { |
| 126 | + null_pointer_check!(quat_ptr); |
| 127 | + (*quat_ptr).j = j; |
| 128 | +} |
| 129 | + |
| 130 | +/// Set the k component of an existing quaternion stored at the address |
| 131 | +/// of a pointer. |
| 132 | +/// |
| 133 | +/// # Safety |
| 134 | +/// |
| 135 | +/// When finished with the underlying quaternion passed to this function |
| 136 | +/// the caller must remember to free the quaternion memory using the |
| 137 | +/// free_quaternion_memory FFI function |
| 138 | +#[no_mangle] |
| 139 | +pub unsafe extern "C" fn quaternion_set_k(quat_ptr: *mut Quaternion, k: f64) { |
| 140 | + null_pointer_check!(quat_ptr); |
| 141 | + (*quat_ptr).k = k; |
| 142 | +} |
| 143 | + |
| 144 | +/// Set all of the components of an existing quaternion stored at the address |
| 145 | +/// of a pointer |
| 146 | +/// |
| 147 | +/// # Safety |
| 148 | +/// |
| 149 | +/// When finished with the underlying quaternion passed to this function |
| 150 | +/// the caller must remember to free the quaternion memory using the |
| 151 | +/// free_quaternion_memory FFI function |
| 152 | +#[no_mangle] |
| 153 | +pub unsafe extern "C" fn quaternion_set_components( |
| 154 | + quat_ptr: *mut Quaternion, real: f64, i: f64, j: f64, k: f64 |
| 155 | +) { |
| 156 | + null_pointer_check!(quat_ptr); |
| 157 | + (*quat_ptr).real = real; |
| 158 | + (*quat_ptr).i = i; |
| 159 | + (*quat_ptr).j = j; |
| 160 | + (*quat_ptr).k = k; |
| 161 | +} |
| 162 | + |
| 163 | +/// Set the imaginary components of an existing quaternion stored at |
| 164 | +/// the address of a pointer (quat_ptr) from the components of a 3-vector |
| 165 | +/// (stored at vec_ptr). The convention is x -> i, y -> j, z -> k |
| 166 | +/// |
| 167 | +/// # Safety |
| 168 | +/// |
| 169 | +/// When finished with the underlying quaternion passed to this function |
| 170 | +/// the caller must remember to free the quaternion memory using the |
| 171 | +/// free_quaternion_memory FFI function (the same applies for the vector |
| 172 | +/// stored at vec_ptr) |
| 173 | +#[no_mangle] |
| 174 | +pub unsafe extern "C" fn quaternion_set_imag_from_vector(quat_ptr: *mut Quaternion, vec_ptr: *const Vector3) { |
| 175 | + null_pointer_check!(quat_ptr); |
| 176 | + null_pointer_check!(vec_ptr); |
| 177 | + (*quat_ptr).set_imag_from_vector(*vec_ptr); |
| 178 | +} |
| 179 | + |
| 180 | +/// Copies the imaginary components to a 3-vector (using x -> i, y -> j |
| 181 | +/// z -> k) and returns a pointer to the memory address of the resulting |
| 182 | +/// vector |
| 183 | +/// |
| 184 | +/// # Safety |
| 185 | +/// |
| 186 | +/// When finished with the underlying quaternion initialized by this function |
| 187 | +/// the caller must remember to free the quaternion memory using the |
| 188 | +/// free_quaternion_memory FFI function |
| 189 | +#[no_mangle] |
| 190 | +pub unsafe extern "C" fn quaternion_get_imaginary_vector(quat_ptr: *const Quaternion) -> *mut Vector3 { |
| 191 | + null_pointer_check!(quat_ptr); |
| 192 | + let imag = (*quat_ptr).imag(); |
| 193 | + imag.to_raw_pointer() |
| 194 | +} |
| 195 | + |
| 196 | +/// Normalizes an existing quaternion stored at the address of |
| 197 | +/// a pointer (quat_ptr) |
| 198 | +/// |
| 199 | +/// # Safety |
| 200 | +/// |
| 201 | +/// When finished with the underlying quaternion passed to this function |
| 202 | +/// the caller must remember to free the quaternion memory using the |
| 203 | +/// free_quaternion_memory FFI function |
| 204 | +#[no_mangle] |
| 205 | +pub unsafe extern "C" fn normalize_quaternion(quat_ptr: *mut Quaternion) { |
| 206 | + null_pointer_check!(quat_ptr); |
| 207 | + (*quat_ptr).normalize() |
| 208 | +} |
| 209 | + |
| 210 | +/// Initializes a normalized copy of a quaternion stored at the |
| 211 | +/// address of a pointer (quat_ptr) and returns a pointer to the |
| 212 | +/// memory of the result |
| 213 | +/// |
| 214 | +/// # Safety |
| 215 | +/// |
| 216 | +/// The caller must remember to free the quaternion memory of |
| 217 | +/// *both* the input and output quaternions when finished with them |
| 218 | +/// using the free_quaternion_memory FFI function |
| 219 | +#[no_mangle] |
| 220 | +pub unsafe extern "C" fn quaternion_get_normalized(quat_ptr: *const Quaternion) -> *mut Quaternion { |
| 221 | + null_pointer_check!(quat_ptr); |
| 222 | + to_raw_pointer(&(*quat_ptr).get_normalized()) |
| 223 | +} |
| 224 | + |
| 225 | +/// Converts from euler angles (in radians) to a quaternion. The euler angles are expected to |
| 226 | +/// be represented according to the Tait-Bryan formalism and applied in the Z-Y'-X" |
| 227 | +/// order (where Z -> yaw, Y -> pitch, X -> roll) |
| 228 | +/// |
| 229 | +/// # Safety |
| 230 | +/// |
| 231 | +/// When finished with the underlying quaternion initialized by this function |
| 232 | +/// the caller must remember to free the quaternion memory using the |
| 233 | +/// free_quaternion_memory FFI function |
| 234 | +#[no_mangle] |
| 235 | +pub unsafe extern "C" fn quaternion_from_euler_angles(roll: f64, pitch: f64, yaw: f64) -> *mut Quaternion { |
| 236 | + let quat = Quaternion::from_euler_angles(roll, pitch, yaw); |
| 237 | + to_raw_pointer(&quat) |
| 238 | +} |
| 239 | + |
| 240 | +/// Converts a quaternion into euler angles (in radians). The euler angles are |
| 241 | +/// represented according to the Tait-Bryan formalism and applied |
| 242 | +/// in the Z-Y'-X" order (where Z -> yaw, Y -> pitch, X -> roll). |
| 243 | +/// The return value is a pointer to a list of [roll, pitch, yaw] |
| 244 | +/// as C doubles |
| 245 | +/// |
| 246 | +/// # Safety |
| 247 | +/// |
| 248 | +/// When finished with the underlying quaternion passed to this function |
| 249 | +/// the caller must remember to free the quaternion memory using the |
| 250 | +/// free_quaternion_memory FFI function and the euler angles memory using |
| 251 | +/// the free_euler_angles memory function |
| 252 | +#[no_mangle] |
| 253 | +pub unsafe extern "C" fn quaternion_to_euler_angles(quat_ptr: *const Quaternion) -> *mut c_double { |
| 254 | + null_pointer_check!(quat_ptr); |
| 255 | + let euler_angles = (*quat_ptr).to_euler_angles(); |
| 256 | + Box::into_raw(Box::new(euler_angles)) as *mut _ |
| 257 | +} |
| 258 | + |
| 259 | +/// Scales an existing quaternion stored at the address of |
| 260 | +/// a pointer (quat_ptr) by a factor (float) |
| 261 | +/// |
| 262 | +/// # Safety |
| 263 | +/// |
| 264 | +/// When finished with the underlying quaternion passed to this function |
| 265 | +/// the caller must remember to free the quaternion memory using the |
| 266 | +/// free_quaternion_memory FFI function |
| 267 | +#[no_mangle] |
| 268 | +pub unsafe extern "C" fn scale_quaternion(quat_ptr: *mut Quaternion, factor: f64) { |
| 269 | + null_pointer_check!(quat_ptr); |
| 270 | + (*quat_ptr).scale(factor); |
| 271 | +} |
| 272 | + |
| 273 | +/// Initializes a copy of the quaternion stored at the address of a pointer (quat_ptr) |
| 274 | +/// scaled by a factor (float) and returns a pointer to the memory of the result |
| 275 | +/// |
| 276 | +/// # Safety |
| 277 | +/// |
| 278 | +/// The caller must remember to free the quaternion memory of |
| 279 | +/// *both* the input and output quaternions when finished with them |
| 280 | +/// using the free_quaternion_memory FFI function |
| 281 | +#[no_mangle] |
| 282 | +pub unsafe extern "C" fn quaternion_get_scaled(quat_ptr: *const Quaternion, factor: f64) -> *mut Quaternion { |
| 283 | + null_pointer_check!(quat_ptr); |
| 284 | + to_raw_pointer(&(*quat_ptr).get_scaled(factor)) |
| 285 | +} |
| 286 | + |
| 287 | +/// Initializes a quaternion that is the conjugate of one stored |
| 288 | +/// at the address of a pointer (quat_ptr)and returns a pointer |
| 289 | +/// to the memory of the result |
| 290 | +/// |
| 291 | +/// # Safety |
| 292 | +/// |
| 293 | +/// The caller must remember to free the quaternion memory of |
| 294 | +/// *both* the input and output quaternions when finished with them |
| 295 | +/// using the free_quaternion_memory FFI function |
| 296 | +#[no_mangle] |
| 297 | +pub unsafe extern "C" fn quaternion_get_conjugate(quat_ptr: *const Quaternion) -> *mut Quaternion { |
| 298 | + null_pointer_check!(quat_ptr); |
| 299 | + to_raw_pointer(&(*quat_ptr).conjugate()) |
| 300 | +} |
| 301 | + |
| 302 | +/// Adds two quaternions and returns a pointer to the |
| 303 | +/// memory of the result |
| 304 | +/// |
| 305 | +/// # Safety |
| 306 | +/// |
| 307 | +/// The caller must remember to free the quaternion memory of *both* the input and |
| 308 | +/// output quaternions when finished with them using the free_quaternion_memory FFI function |
| 309 | +#[no_mangle] |
| 310 | +pub unsafe extern "C" fn quaternion_add( |
| 311 | + quat_ptr_1: *const Quaternion, |
| 312 | + quat_ptr_2: *const Quaternion, |
| 313 | +) -> *mut Quaternion { |
| 314 | + null_pointer_check!(quat_ptr_1); |
| 315 | + null_pointer_check!(quat_ptr_2); |
| 316 | + to_raw_pointer(&((*quat_ptr_1) + (*quat_ptr_2))) |
| 317 | +} |
| 318 | + |
| 319 | +/// Subtracts two quaternions and returns a pointer to the |
| 320 | +/// memory of the result |
| 321 | +/// |
| 322 | +/// # Safety |
| 323 | +/// |
| 324 | +/// The caller must remember to free the quaternion memory of *both* the input and |
| 325 | +/// output quaternions when finished with them using the free_quaternion_memory FFI function |
| 326 | +#[no_mangle] |
| 327 | +pub unsafe extern "C" fn quaternion_subtract( |
| 328 | + quat_ptr_1: *const Quaternion, |
| 329 | + quat_ptr_2: *const Quaternion, |
| 330 | +) -> *mut Quaternion { |
| 331 | + null_pointer_check!(quat_ptr_1); |
| 332 | + null_pointer_check!(quat_ptr_2); |
| 333 | + to_raw_pointer(&((*quat_ptr_1) - (*quat_ptr_2))) |
| 334 | +} |
| 335 | + |
| 336 | +/// Computes the Hamiltonian product of two quaternions and |
| 337 | +/// returns a pointer to the memory of the result |
| 338 | +/// |
| 339 | +/// # Safety |
| 340 | +/// |
| 341 | +/// The caller must remember to free the quaternion memory of *both* the input and |
| 342 | +/// output quaternions when finished with them using the free_quaternion_memory FFI function |
| 343 | +#[no_mangle] |
| 344 | +pub unsafe extern "C" fn quaternion_hamiltonian_product( |
| 345 | + quat_ptr_1: *const Quaternion, |
| 346 | + quat_ptr_2: *const Quaternion, |
| 347 | +) -> *mut Quaternion { |
| 348 | + null_pointer_check!(quat_ptr_1); |
| 349 | + null_pointer_check!(quat_ptr_2); |
| 350 | + to_raw_pointer(&((*quat_ptr_1) * (*quat_ptr_2))) |
| 351 | +} |
0 commit comments