From 1374ff5e4a94621b535c740007118268314c956c Mon Sep 17 00:00:00 2001 From: Jason Travis Smith Date: Thu, 7 Jan 2016 05:51:53 -0500 Subject: [PATCH] Quaternions are now Transmutable. This implements Transmutable for Quaternions and creates a test and example for this conversion. --- examples/convert_quaternion.rs | 89 ++++++++++++++++++++++++++++++++++ src/transmutable.rs | 49 ++++++++++++++++++- tests/transmutable.rs | 60 +++++++++++++++++++---- 3 files changed, 188 insertions(+), 10 deletions(-) create mode 100644 examples/convert_quaternion.rs diff --git a/examples/convert_quaternion.rs b/examples/convert_quaternion.rs new file mode 100644 index 0000000..4f353bb --- /dev/null +++ b/examples/convert_quaternion.rs @@ -0,0 +1,89 @@ +#![feature(convert)] + +extern crate alchemy; +extern crate sigils; + + + +use alchemy::F64_BYTES; +use alchemy::{Endianess, Transmutable}; +use sigils::quaternion::Quaternion; + + + +/// The size of 4 f64 Real numbers. +/// This would be different if the contained type +/// was something different, like an f32. +const SIZE_OF_QUATERNION: usize = F64_BYTES * 4; + + + +/// This just help pretty up the printing of an array of bytes. +fn stringify_array(buffer: &[u8]) -> String +{ + let mut result: String; + let mut count: usize; + + // Create a new string that starts with just + // the array opening bracket. + result = String::new(); + result.push_str("["); + + // Loop through the buffer keeping track + // of our place in it. + count = 0usize; + for byte in buffer + { + // Handle priting the last value differently. + if count >= buffer.len() - 1 + { + result.push_str(byte.to_string().as_str()); + } + else + { + result.push_str(byte.to_string().as_str()); + result.push_str(", "); + } + + // Mark that we are going to look at + // the next byte in the array. + count += 1; + } + + // Add the array closing bracket and + // return the new String. + result.push_str("]"); + result +} + + +pub fn main() +{ + let quat: Quaternion; + let final_quat: Quaternion; + let endianess: Endianess; + let mut buffer: [u8; SIZE_OF_QUATERNION]; + + // Initialize the variables. + quat = Quaternion::::from_values(6.29f64, 1.9f64, 8.5f64, 7.11f64); + buffer = [0u8; SIZE_OF_QUATERNION]; + endianess = Endianess::PLATFORM; + + println!("Transmuting a Quaternion:"); + + println!("Converting the value [{1}, <{2}, {3}, {4}>] {0}", + "into and out of an array of bytes.", + quat.scalar, quat.vector.x, quat.vector.y, quat.vector.z); + println!("Buffer starts as: {}", stringify_array(&buffer)); + + // Convert the Vector2 into an array of bytes. + quat.to_bytes(&mut buffer, endianess); + + println!("Buffer contains: {}", stringify_array(&buffer)); + + // Convert the array of bytes into a Vector2. + final_quat = Quaternion::from_bytes(&buffer, endianess); + println!("The buffer converts back to: [{}, <{}, {}, {}>]", + final_quat.scalar, final_quat.vector.x, + final_quat.vector.y, final_quat.vector.z); +} diff --git a/src/transmutable.rs b/src/transmutable.rs index dbba8d7..006adcd 100644 --- a/src/transmutable.rs +++ b/src/transmutable.rs @@ -1,5 +1,6 @@ -use sigils::{Zero, Number}; +use sigils::{Zero, Number, Real}; use sigils::vector::{Vector, Vector2, Vector3, Vector4}; +use sigils::quaternion::Quaternion; use ::byte_sized::ByteSized; use ::converter::Converter; @@ -502,3 +503,49 @@ impl Transmutable for Vector4 where T: Number + ByteSized + Transmutable vec } } + +impl Transmutable for Quaternion + where T: Real + ByteSized + Transmutable +{ + fn to_bytes(&self, buffer: &mut [u8], endianess: Endianess) + { + let byte_size: usize; + let num_bytes: usize; + + // Determine the number of bytes requires to + // represent a Quaternion. + byte_size = T::get_byte_size(); + num_bytes = byte_size * 4usize; + + // Make sure that there is enough space to store + // the bytes from this type. + assert!(buffer.len() >= num_bytes); + + // Convert this to bytes and add it to the buffer. + self.scalar.to_bytes(&mut buffer[0..byte_size], endianess); + self.vector.to_bytes(&mut buffer[byte_size..num_bytes], endianess); + } + + fn from_bytes(buffer: &[u8], endianess: Endianess) -> Quaternion + { + let byte_size: usize; + let num_bytes: usize; + let mut quat: Quaternion; + + // Determine the number of bytes requires to + // represent a Quaternion. + quat = Quaternion::::zero(); + byte_size = T::get_byte_size(); + num_bytes = byte_size * 4usize; + + // Make sure that there is enough data to read + // the bytes for this type. + assert!(buffer.len() >= num_bytes); + + // Convert the given bytes to this type and return it. + quat.scalar = T::from_bytes(&buffer[0..byte_size], endianess); + quat.vector = + Vector3::::from_bytes(&buffer[byte_size..num_bytes], endianess); + quat + } +} diff --git a/tests/transmutable.rs b/tests/transmutable.rs index a6a8c1a..37a1988 100644 --- a/tests/transmutable.rs +++ b/tests/transmutable.rs @@ -5,9 +5,10 @@ extern crate sigils; -macro_rules! transmutation_test +macro_rules! transmutation_vector_test { - ($modName: ident, $varType: ident, $numBytes: expr, [$($var: ident)*]) => + ($modName: ident, $varType: ident, $dataType:ty, + $numBytes: expr, [$($var: ident)*]) => { mod $modName { @@ -22,16 +23,16 @@ macro_rules! transmutation_test #[test] pub fn transmutation() { - let mut vec: $varType; - let final_vec: $varType; + let mut vec: $varType<$dataType>; + let final_vec: $varType<$dataType>; let endianess: Endianess; let mut rng: ThreadRng; let mut buffer: [u8; $numBytes]; // Initialize the variables. rng = thread_rng(); - vec = $varType::::zero(); - $(vec.$var = rng.next_u64();)* + vec = $varType::<$dataType>::zero(); + $(vec.$var = rng.gen();)* buffer = [0u8; $numBytes]; endianess = Endianess::PLATFORM; @@ -45,6 +46,47 @@ macro_rules! transmutation_test } -transmutation_test!(vec2, Vector2, 16, [x y]); -transmutation_test!(vec3, Vector3, 24, [x y z]); -transmutation_test!(vec4, Vector4, 32, [x y z w]); +transmutation_vector_test!(vec2, Vector2, u64, 16, [x y]); +transmutation_vector_test!(vec3, Vector3, u32, 12, [x y z]); +transmutation_vector_test!(vec4, Vector4, u16, 8, [x y z w]); + + + +mod quat +{ + use rand::{thread_rng, Rng, ThreadRng}; + + use alchemy::{Endianess, Transmutable}; + use sigils::Zero; + use sigils::quaternion::Quaternion; + + + + #[test] + pub fn transmutation() + { + let mut quat: Quaternion; + let final_quat: Quaternion; + let endianess: Endianess; + let mut rng: ThreadRng; + let mut buffer: [u8; 32]; + + // Initialize the variables. + rng = thread_rng(); + quat = Quaternion::::zero(); + quat.scalar = rng.gen(); + quat.vector.x = rng.gen(); + quat.vector.y = rng.gen(); + quat.vector.z = rng.gen(); + buffer = [0u8; 32]; + endianess = Endianess::PLATFORM; + + quat.to_bytes(&mut buffer, endianess); + final_quat = Quaternion::from_bytes(&buffer, endianess); + + assert_eq!(quat.scalar, final_quat.scalar); + assert_eq!(quat.vector.x, final_quat.vector.x); + assert_eq!(quat.vector.y, final_quat.vector.y); + assert_eq!(quat.vector.z, final_quat.vector.z); + } +}