open_dis_rust/entity_information/
collision_elastic_pdu.rs

1//     open-dis-rust - Rust implementation of the IEEE-1278.1 Distributed Interactive Simulation
2//                     (DIS) application protocol v6 and v7
3//     Copyright (C) 2023 Cameron Howell
4//
5//     Licensed under the BSD 2-Clause License
6
7use bytes::{Buf, BufMut, BytesMut};
8use std::any::Any;
9
10use crate::common::{
11    dis_error::DISError,
12    entity_coordinate_vector::EntityCoordinateVector,
13    entity_id::EntityId,
14    event_id::EventId,
15    linear_velocity::LinearVelocity,
16    pdu::Pdu,
17    pdu_header::{PduHeader, PduType, ProtocolFamily},
18};
19
20#[derive(Clone, Debug)]
21/// Implemented according to IEEE 1278.1-2012 ยง7.2.4
22pub struct CollisionElasticPdu {
23    pub pdu_header: PduHeader,
24    pub issuing_entity_id: EntityId,
25    pub colliding_entity_id: EntityId,
26    pub event_id: EventId,
27    pub padding: u16,
28    pub contact_velocity: LinearVelocity,
29    pub mass: f32,
30    pub location_of_impact: EntityCoordinateVector,
31    pub collision_intermediate_result_xx: f32,
32    pub collision_intermediate_result_xy: f32,
33    pub collision_intermediate_result_xz: f32,
34    pub collision_intermediate_result_yy: f32,
35    pub collision_intermediate_result_yz: f32,
36    pub collision_intermediate_result_zz: f32,
37    pub unit_surface_normal: EntityCoordinateVector,
38    pub coefficient_of_restitution: f32,
39}
40
41impl Default for CollisionElasticPdu {
42    fn default() -> Self {
43        CollisionElasticPdu {
44            pdu_header: PduHeader::default(
45                PduType::CollisionElastic,
46                ProtocolFamily::EntityInformation,
47                100,
48            ),
49            issuing_entity_id: EntityId::default(1),
50            colliding_entity_id: EntityId::default(2),
51            event_id: EventId::default(1),
52            padding: 0,
53            contact_velocity: LinearVelocity::default(),
54            mass: 0.0,
55            location_of_impact: EntityCoordinateVector::default(),
56            collision_intermediate_result_xx: 0.0,
57            collision_intermediate_result_xy: 0.0,
58            collision_intermediate_result_xz: 0.0,
59            collision_intermediate_result_yy: 0.0,
60            collision_intermediate_result_yz: 0.0,
61            collision_intermediate_result_zz: 0.0,
62            unit_surface_normal: EntityCoordinateVector::default(),
63            coefficient_of_restitution: 0.0,
64        }
65    }
66}
67
68impl Pdu for CollisionElasticPdu {
69    fn serialize(&mut self, buf: &mut BytesMut) {
70        self.pdu_header.length = u16::try_from(std::mem::size_of_val(self))
71            .expect("The length of the PDU should fit in a u16.");
72        self.pdu_header.serialize(buf);
73        self.issuing_entity_id.serialize(buf);
74        self.colliding_entity_id.serialize(buf);
75        self.event_id.serialize(buf);
76        buf.put_u16(self.padding);
77        self.contact_velocity.serialize(buf);
78        buf.put_f32(self.mass);
79        self.location_of_impact.serialize(buf);
80        buf.put_f32(self.collision_intermediate_result_xx);
81        buf.put_f32(self.collision_intermediate_result_xy);
82        buf.put_f32(self.collision_intermediate_result_xz);
83        buf.put_f32(self.collision_intermediate_result_yy);
84        buf.put_f32(self.collision_intermediate_result_yz);
85        buf.put_f32(self.collision_intermediate_result_zz);
86        self.unit_surface_normal.serialize(buf);
87        buf.put_f32(self.coefficient_of_restitution);
88    }
89
90    #[allow(clippy::similar_names)]
91    fn deserialize(mut buffer: BytesMut) -> Result<CollisionElasticPdu, DISError> {
92        let pdu_header = PduHeader::decode(&mut buffer);
93        if pdu_header.pdu_type == PduType::CollisionElastic {
94            let issuing_entity_id = EntityId::decode(&mut buffer);
95            let colliding_entity_id = EntityId::decode(&mut buffer);
96            let event_id = EventId::decode(&mut buffer);
97            let padding = buffer.get_u16();
98            let contact_velocity = LinearVelocity::decode(&mut buffer);
99            let mass = buffer.get_f32();
100            let location_of_impact = EntityCoordinateVector::decode(&mut buffer);
101            let collision_intermediate_result_xx = buffer.get_f32();
102            let collision_intermediate_result_xy = buffer.get_f32();
103            let collision_intermediate_result_xz = buffer.get_f32();
104            let collision_intermediate_result_yy = buffer.get_f32();
105            let collision_intermediate_result_yz = buffer.get_f32();
106            let collision_intermediate_result_zz = buffer.get_f32();
107            let unit_surface_normal = EntityCoordinateVector::decode(&mut buffer);
108            let coefficient_of_restitution = buffer.get_f32();
109            Ok(CollisionElasticPdu {
110                pdu_header,
111                issuing_entity_id,
112                colliding_entity_id,
113                event_id,
114                padding,
115                contact_velocity,
116                mass,
117                location_of_impact,
118                collision_intermediate_result_xx,
119                collision_intermediate_result_xy,
120                collision_intermediate_result_xz,
121                collision_intermediate_result_yy,
122                collision_intermediate_result_yz,
123                collision_intermediate_result_zz,
124                unit_surface_normal,
125                coefficient_of_restitution,
126            })
127        } else {
128            Err(DISError::InvalidDISHeader)
129        }
130    }
131
132    fn as_any(&self) -> &dyn Any {
133        self
134    }
135
136    #[allow(clippy::similar_names)]
137    fn deserialize_without_header(
138        mut buffer: BytesMut,
139        pdu_header: PduHeader,
140    ) -> Result<Self, DISError>
141    where
142        Self: Sized,
143    {
144        let issuing_entity_id = EntityId::decode(&mut buffer);
145        let colliding_entity_id = EntityId::decode(&mut buffer);
146        let event_id = EventId::decode(&mut buffer);
147        let padding = buffer.get_u16();
148        let contact_velocity = LinearVelocity::decode(&mut buffer);
149        let mass = buffer.get_f32();
150        let location_of_impact = EntityCoordinateVector::decode(&mut buffer);
151        let collision_intermediate_result_xx = buffer.get_f32();
152        let collision_intermediate_result_xy = buffer.get_f32();
153        let collision_intermediate_result_xz = buffer.get_f32();
154        let collision_intermediate_result_yy = buffer.get_f32();
155        let collision_intermediate_result_yz = buffer.get_f32();
156        let collision_intermediate_result_zz = buffer.get_f32();
157        let unit_surface_normal = EntityCoordinateVector::decode(&mut buffer);
158        let coefficient_of_restitution = buffer.get_f32();
159        Ok(CollisionElasticPdu {
160            pdu_header,
161            issuing_entity_id,
162            colliding_entity_id,
163            event_id,
164            padding,
165            contact_velocity,
166            mass,
167            location_of_impact,
168            collision_intermediate_result_xx,
169            collision_intermediate_result_xy,
170            collision_intermediate_result_xz,
171            collision_intermediate_result_yy,
172            collision_intermediate_result_yz,
173            collision_intermediate_result_zz,
174            unit_surface_normal,
175            coefficient_of_restitution,
176        })
177    }
178}
179
180#[cfg(test)]
181mod tests {
182    use super::CollisionElasticPdu;
183    use crate::common::{
184        pdu::Pdu,
185        pdu_header::{PduHeader, PduType, ProtocolFamily},
186    };
187    use bytes::BytesMut;
188
189    #[test]
190    fn create_header() {
191        let collision_elastic_pdu = CollisionElasticPdu::default();
192        let header = PduHeader::default(
193            PduType::CollisionElastic,
194            ProtocolFamily::EntityInformation,
195            100,
196        );
197        assert_eq!(
198            header.protocol_version,
199            collision_elastic_pdu.pdu_header.protocol_version
200        );
201        assert_eq!(
202            header.exercise_id,
203            collision_elastic_pdu.pdu_header.exercise_id
204        );
205        assert_eq!(header.pdu_type, collision_elastic_pdu.pdu_header.pdu_type);
206        assert_eq!(
207            header.protocol_family,
208            collision_elastic_pdu.pdu_header.protocol_family
209        );
210        assert_eq!(header.length, collision_elastic_pdu.pdu_header.length);
211        assert_eq!(header.padding, collision_elastic_pdu.pdu_header.padding);
212    }
213
214    #[test]
215    fn deserialize_header() {
216        let mut collision_elastic_pdu = CollisionElasticPdu::default();
217        let mut buffer = BytesMut::new();
218        collision_elastic_pdu.serialize(&mut buffer);
219
220        let new_collision_elastic_pdu = CollisionElasticPdu::deserialize(buffer).unwrap();
221        assert_eq!(
222            new_collision_elastic_pdu.pdu_header,
223            collision_elastic_pdu.pdu_header
224        );
225    }
226}