1use crate::EntityParseError;
2use binrw::BinRead;
3use cgmath::{Deg, Quaternion, Rotation3};
4use serde::de::{Error, Unexpected};
5use serde::{Deserialize, Deserializer};
6use std::str::FromStr;
7
8#[derive(Debug, Copy, Clone, BinRead, Default)]
9pub struct Angles {
10 pub pitch: f32,
11 pub yaw: f32,
12 pub roll: f32,
13}
14
15impl<'de> Deserialize<'de> for Angles {
16 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
17 where
18 D: Deserializer<'de>,
19 {
20 let str = <&str>::deserialize(deserializer)?;
21 str.parse()
22 .map_err(|_| D::Error::invalid_value(Unexpected::Other(str), &"a list of angles"))
23 }
24}
25
26impl FromStr for Angles {
27 type Err = EntityParseError;
28
29 fn from_str(s: &str) -> Result<Self, Self::Err> {
30 let mut floats = s.split_whitespace().map(f32::from_str);
31 let pitch = floats.next().ok_or(EntityParseError::ElementCount)??;
32 let yaw = floats.next().ok_or(EntityParseError::ElementCount)??;
33 let roll = floats.next().ok_or(EntityParseError::ElementCount)??;
34 Ok(Angles { pitch, yaw, roll })
35 }
36}
37
38impl Angles {
39 pub fn as_quaternion(&self) -> Quaternion<f32> {
40 Quaternion::from_angle_y(Deg(self.yaw))
42 * Quaternion::from_angle_x(Deg(self.pitch))
43 * Quaternion::from_angle_z(Deg(self.roll))
44 }
45}