qualia_core_db/domains/geospatial/
reference_frame.rs1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
6pub struct ReferenceFrame {
7 pub id: u64,
9 pub parent_id: Option<u64>,
11 pub translation: [f64; 3],
13 pub rotation: [f64; 4],
15 pub scale: f64,
17}
18
19impl Default for ReferenceFrame {
20 fn default() -> Self {
21 Self {
22 id: 0,
23 parent_id: None,
24 translation: [0.0, 0.0, 0.0],
25 rotation: [1.0, 0.0, 0.0, 0.0], scale: 1.0,
27 }
28 }
29}
30
31impl ReferenceFrame {
32 pub fn new(id: u64, parent_id: Option<u64>) -> Self {
33 Self {
34 id,
35 parent_id,
36 ..Default::default()
37 }
38 }
39
40 pub fn transform_to_parent(&self, local_point: [f64; 3]) -> [f64; 3] {
42 let [x, y, z] = local_point;
43
44 let sx = x * self.scale;
46 let sy = y * self.scale;
47 let sz = z * self.scale;
48
49 let [qw, qx, qy, qz] = self.rotation;
51
52 let ix = qw * sx + qy * sz - qz * sy;
53 let iy = qw * sy + qz * sx - qx * sz;
54 let iz = qw * sz + qx * sy - qy * sx;
55 let iw = -qx * sx - qy * sy - qz * sz;
56
57 let rx = ix * qw + iw * -qx + iy * -qz - iz * -qy;
58 let ry = iy * qw + iw * -qy + iz * -qx - ix * -qz;
59 let rz = iz * qw + iw * -qz + ix * -qy - iy * -qx;
60
61 [
63 rx + self.translation[0],
64 ry + self.translation[1],
65 rz + self.translation[2],
66 ]
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn test_transform_to_parent() {
76 let mut frame = ReferenceFrame::new(1, None);
77 frame.translation = [10.0, 20.0, 30.0];
78 frame.scale = 0.5;
79 let half_angle = std::f64::consts::PI / 4.0;
81 frame.rotation = [half_angle.cos(), 0.0, 0.0, half_angle.sin()];
82
83 let local_pt = [2.0, 0.0, 0.0];
84 let transformed = frame.transform_to_parent(local_pt);
85
86 assert!((transformed[0] - 10.0).abs() < 1e-8);
91 assert!((transformed[1] - 21.0).abs() < 1e-8);
92 assert!((transformed[2] - 30.0).abs() < 1e-8);
93 }
94}