openigtlink_rust/protocol/types/
position.rs1use crate::error::{IgtlError, Result};
8use crate::protocol::message::Message;
9use bytes::{Buf, BufMut};
10
11#[derive(Debug, Clone, PartialEq)]
19pub struct PositionMessage {
20 pub position: [f32; 3], pub quaternion: [f32; 4], }
29
30impl PositionMessage {
31 pub fn identity() -> Self {
33 PositionMessage {
34 position: [0.0, 0.0, 0.0],
35 quaternion: [0.0, 0.0, 0.0, 1.0], }
37 }
38
39 pub fn new(x: f32, y: f32, z: f32) -> Self {
41 PositionMessage {
42 position: [x, y, z],
43 quaternion: [0.0, 0.0, 0.0, 1.0],
44 }
45 }
46
47 pub fn with_quaternion(position: [f32; 3], quaternion: [f32; 4]) -> Self {
49 PositionMessage {
50 position,
51 quaternion,
52 }
53 }
54
55 pub fn get_position(&self) -> (f32, f32, f32) {
57 (self.position[0], self.position[1], self.position[2])
58 }
59
60 pub fn get_quaternion(&self) -> (f32, f32, f32, f32) {
62 (
63 self.quaternion[0],
64 self.quaternion[1],
65 self.quaternion[2],
66 self.quaternion[3],
67 )
68 }
69}
70
71impl Message for PositionMessage {
72 fn message_type() -> &'static str {
73 "POSITION"
74 }
75
76 fn encode_content(&self) -> Result<Vec<u8>> {
77 let mut buf = Vec::with_capacity(28);
78
79 for &coord in &self.position {
81 buf.put_f32(coord);
82 }
83
84 for &comp in &self.quaternion {
86 buf.put_f32(comp);
87 }
88
89 Ok(buf)
90 }
91
92 fn decode_content(mut data: &[u8]) -> Result<Self> {
93 if data.len() < 28 {
94 return Err(IgtlError::InvalidSize {
95 expected: 28,
96 actual: data.len(),
97 });
98 }
99
100 let position = [data.get_f32(), data.get_f32(), data.get_f32()];
102
103 let quaternion = [
105 data.get_f32(),
106 data.get_f32(),
107 data.get_f32(),
108 data.get_f32(),
109 ];
110
111 Ok(PositionMessage {
112 position,
113 quaternion,
114 })
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 #[test]
123 fn test_message_type() {
124 assert_eq!(PositionMessage::message_type(), "POSITION");
125 }
126
127 #[test]
128 fn test_identity() {
129 let pos = PositionMessage::identity();
130 assert_eq!(pos.position, [0.0, 0.0, 0.0]);
131 assert_eq!(pos.quaternion, [0.0, 0.0, 0.0, 1.0]);
132 }
133
134 #[test]
135 fn test_new() {
136 let pos = PositionMessage::new(10.0, 20.0, 30.0);
137 assert_eq!(pos.position, [10.0, 20.0, 30.0]);
138 assert_eq!(pos.quaternion, [0.0, 0.0, 0.0, 1.0]);
139 }
140
141 #[test]
142 fn test_with_quaternion() {
143 let pos = PositionMessage::with_quaternion([1.0, 2.0, 3.0], [0.1, 0.2, 0.3, 0.4]);
144 assert_eq!(pos.position, [1.0, 2.0, 3.0]);
145 assert_eq!(pos.quaternion, [0.1, 0.2, 0.3, 0.4]);
146 }
147
148 #[test]
149 fn test_encode_size() {
150 let pos = PositionMessage::new(1.0, 2.0, 3.0);
151 let encoded = pos.encode_content().unwrap();
152 assert_eq!(encoded.len(), 28);
153 }
154
155 #[test]
156 fn test_position_roundtrip() {
157 let original = PositionMessage::with_quaternion(
158 [100.5, 200.25, 300.125],
159 [0.1, 0.2, 0.3, 0.9274], );
161
162 let encoded = original.encode_content().unwrap();
163 let decoded = PositionMessage::decode_content(&encoded).unwrap();
164
165 assert_eq!(decoded.position, original.position);
166 assert_eq!(decoded.quaternion, original.quaternion);
167 }
168
169 #[test]
170 fn test_big_endian_encoding() {
171 let pos = PositionMessage::new(1.0, 0.0, 0.0);
172 let encoded = pos.encode_content().unwrap();
173
174 assert_eq!(encoded[0], 0x3F);
176 assert_eq!(encoded[1], 0x80);
177 assert_eq!(encoded[2], 0x00);
178 assert_eq!(encoded[3], 0x00);
179 }
180
181 #[test]
182 fn test_decode_invalid_size() {
183 let data = vec![0u8; 20]; let result = PositionMessage::decode_content(&data);
185 assert!(result.is_err());
186 }
187
188 #[test]
189 fn test_get_position() {
190 let pos = PositionMessage::new(10.0, 20.0, 30.0);
191 let (x, y, z) = pos.get_position();
192 assert_eq!((x, y, z), (10.0, 20.0, 30.0));
193 }
194
195 #[test]
196 fn test_get_quaternion() {
197 let pos = PositionMessage::with_quaternion([0.0, 0.0, 0.0], [0.1, 0.2, 0.3, 0.4]);
198 let (ox, oy, oz, w) = pos.get_quaternion();
199 assert_eq!((ox, oy, oz, w), (0.1, 0.2, 0.3, 0.4));
200 }
201}