1use crate::constants::{
4 BODY_ISB_ANGLE_COUNT, BODY_JOINT_COUNT, BODY_LANDMARK_COUNT, HAND_JOINT_COUNT,
5 HAND_LANDMARK_COUNT,
6};
7use crate::types::{
8 HandJoint, HandLandmarkName, IsbAngleName, Joint, Landmark, LandmarkName, Quaternion,
9};
10
11macro_rules! named_frame {
14 (
15 $(#[$attr:meta])*
16 $name:ident, elem = $elem:ty, key = $key:ty, count = $count:expr,
17 { $( $field:ident => $variant:ident ),+ $(,)? }
18 ) => {
19 $(#[$attr])*
20 #[derive(Clone, Copy, Debug, Default, PartialEq)]
21 pub struct $name {
22 $( pub $field: $elem ),+
23 }
24
25 impl $name {
26 pub const fn from_array(values: [$elem; $count]) -> Self {
31 let [ $( $field ),+ ] = values;
32 Self { $( $field ),+ }
33 }
34
35 pub const fn to_array(&self) -> [$elem; $count] {
37 [ $( self.$field ),+ ]
38 }
39
40 pub const fn get(&self, key: $key) -> $elem {
42 match key {
43 $( <$key>::$variant => self.$field ),+
44 }
45 }
46
47 pub fn iter(&self) -> impl Iterator<Item = ($key, $elem)> {
49 [ $( (<$key>::$variant, self.$field) ),+ ].into_iter()
50 }
51 }
52 };
53}
54
55named_frame! {
56 BodyQuaternionFrame, elem = Quaternion, key = Joint, count = BODY_JOINT_COUNT,
58 {
59 hips => Hips,
60 spine => Spine,
61 neck => Neck,
62 right_arm => RightArm,
63 right_forearm => RightForearm,
64 left_arm => LeftArm,
65 left_forearm => LeftForearm,
66 right_upleg => RightUpLeg,
67 right_leg => RightLeg,
68 right_foot => RightFoot,
69 left_upleg => LeftUpLeg,
70 left_leg => LeftLeg,
71 left_foot => LeftFoot,
72 }
73}
74
75named_frame! {
76 BodyLandmarkFrame, elem = Landmark, key = LandmarkName, count = BODY_LANDMARK_COUNT,
78 {
79 sacroiliac_joint => SacroiliacJoint,
80 suprasternal_notch => SuprasternalNotch,
81 nose => Nose,
82 left_ear => LeftEar,
83 right_ear => RightEar,
84 left_shoulder => LeftShoulder,
85 right_shoulder => RightShoulder,
86 left_elbow => LeftElbow,
87 right_elbow => RightElbow,
88 left_wrist => LeftWrist,
89 right_wrist => RightWrist,
90 left_hip => LeftHip,
91 right_hip => RightHip,
92 left_knee => LeftKnee,
93 right_knee => RightKnee,
94 left_ankle => LeftAnkle,
95 right_ankle => RightAnkle,
96 left_foot_index => LeftFootIndex,
97 right_foot_index => RightFootIndex,
98 }
99}
100
101named_frame! {
102 HandQuaternionFrame, elem = Quaternion, key = HandJoint, count = HAND_JOINT_COUNT,
104 {
105 wrist => Wrist,
106 thumb_mcp => ThumbMcp,
107 thumb_pip => ThumbPip,
108 thumb_dip => ThumbDip,
109 index_mcp => IndexMcp,
110 index_pip => IndexPip,
111 index_dip => IndexDip,
112 middle_mcp => MiddleMcp,
113 middle_pip => MiddlePip,
114 middle_dip => MiddleDip,
115 ring_mcp => RingMcp,
116 ring_pip => RingPip,
117 ring_dip => RingDip,
118 pinky_mcp => PinkyMcp,
119 pinky_pip => PinkyPip,
120 pinky_dip => PinkyDip,
121 }
122}
123
124named_frame! {
125 HandLandmarkFrame, elem = Landmark, key = HandLandmarkName, count = HAND_LANDMARK_COUNT,
127 {
128 wrist => Wrist,
129 thumb_cmc => ThumbCmc,
130 thumb_mcp => ThumbMcp,
131 thumb_ip => ThumbIp,
132 thumb_tip => ThumbTip,
133 index_mcp => IndexMcp,
134 index_pip => IndexPip,
135 index_dip => IndexDip,
136 index_tip => IndexTip,
137 middle_mcp => MiddleMcp,
138 middle_pip => MiddlePip,
139 middle_dip => MiddleDip,
140 middle_tip => MiddleTip,
141 ring_mcp => RingMcp,
142 ring_pip => RingPip,
143 ring_dip => RingDip,
144 ring_tip => RingTip,
145 pinky_mcp => PinkyMcp,
146 pinky_pip => PinkyPip,
147 pinky_dip => PinkyDip,
148 pinky_tip => PinkyTip,
149 }
150}
151
152named_frame! {
153 BodyIsbAnglesFrame, elem = f64, key = IsbAngleName, count = BODY_ISB_ANGLE_COUNT,
158 {
159 thorax_lateral_bend => ThoraxLateralBend,
160 thorax_axial_rotation => ThoraxAxialRotation,
161 neck_flexion => NeckFlexion,
162 neck_lateral_bend => NeckLateralBend,
163 neck_axial_rotation => NeckAxialRotation,
164 right_shoulder_plane_of_elevation => RightShoulderPlaneOfElevation,
165 right_shoulder_elevation => RightShoulderElevation,
166 left_shoulder_plane_of_elevation => LeftShoulderPlaneOfElevation,
167 left_shoulder_elevation => LeftShoulderElevation,
168 right_elbow_flexion => RightElbowFlexion,
169 left_elbow_flexion => LeftElbowFlexion,
170 right_hip_flexion => RightHipFlexion,
171 right_hip_adduction => RightHipAdduction,
172 right_hip_internal_rotation => RightHipInternalRotation,
173 left_hip_flexion => LeftHipFlexion,
174 left_hip_adduction => LeftHipAdduction,
175 left_hip_internal_rotation => LeftHipInternalRotation,
176 right_knee_flexion => RightKneeFlexion,
177 left_knee_flexion => LeftKneeFlexion,
178 right_ankle_dorsiflexion => RightAnkleDorsiflexion,
179 left_ankle_dorsiflexion => LeftAnkleDorsiflexion,
180 }
181}
182
183#[cfg(test)]
184mod tests {
185 use super::*;
186
187 #[test]
188 fn from_array_then_to_array_round_trips() {
189 let mut values = [Quaternion::default(); BODY_JOINT_COUNT];
191 for (i, q) in values.iter_mut().enumerate() {
192 *q = Quaternion {
193 w: i as f64,
194 x: 0.0,
195 y: 0.0,
196 z: 0.0,
197 };
198 }
199
200 let frame = BodyQuaternionFrame::from_array(values);
202
203 assert_eq!(frame.to_array(), values);
205 assert_eq!(frame.hips.w, 0.0);
206 assert_eq!(frame.left_foot.w, 12.0);
207 }
208
209 #[test]
210 fn get_matches_field_access() {
211 let frame = HandLandmarkFrame {
213 thumb_tip: Landmark {
214 x: 1.0,
215 y: 2.0,
216 z: 3.0,
217 confidence: 0.5,
218 },
219 ..HandLandmarkFrame::default()
220 };
221
222 assert_eq!(frame.get(HandLandmarkName::ThumbTip), frame.thumb_tip);
224 }
225
226 #[test]
227 fn iter_yields_wire_order() {
228 let frame = BodyLandmarkFrame::default();
230
231 let names: Vec<LandmarkName> = frame.iter().map(|(name, _)| name).collect();
233
234 assert_eq!(names, LandmarkName::ALL.to_vec());
236 }
237}