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::deserialize(&mut buffer);
93        if pdu_header.pdu_type == PduType::CollisionElastic {
94            let issuing_entity_id = EntityId::deserialize(&mut buffer);
95            let colliding_entity_id = EntityId::deserialize(&mut buffer);
96            let event_id = EventId::deserialize(&mut buffer);
97            let padding = buffer.get_u16();
98            let contact_velocity = LinearVelocity::deserialize(&mut buffer);
99            let mass = buffer.get_f32();
100            let location_of_impact = EntityCoordinateVector::deserialize(&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::deserialize(&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::invalid_header(
129                format!(
130                    "Expected PDU type CollisionElastic, got {:?}",
131                    pdu_header.pdu_type
132                ),
133                None,
134            ))
135        }
136    }
137
138    fn as_any(&self) -> &dyn Any {
139        self
140    }
141
142    #[allow(clippy::similar_names)]
143    fn deserialize_without_header(
144        mut buffer: BytesMut,
145        pdu_header: PduHeader,
146    ) -> Result<Self, DISError>
147    where
148        Self: Sized,
149    {
150        let issuing_entity_id = EntityId::deserialize(&mut buffer);
151        let colliding_entity_id = EntityId::deserialize(&mut buffer);
152        let event_id = EventId::deserialize(&mut buffer);
153        let padding = buffer.get_u16();
154        let contact_velocity = LinearVelocity::deserialize(&mut buffer);
155        let mass = buffer.get_f32();
156        let location_of_impact = EntityCoordinateVector::deserialize(&mut buffer);
157        let collision_intermediate_result_xx = buffer.get_f32();
158        let collision_intermediate_result_xy = buffer.get_f32();
159        let collision_intermediate_result_xz = buffer.get_f32();
160        let collision_intermediate_result_yy = buffer.get_f32();
161        let collision_intermediate_result_yz = buffer.get_f32();
162        let collision_intermediate_result_zz = buffer.get_f32();
163        let unit_surface_normal = EntityCoordinateVector::deserialize(&mut buffer);
164        let coefficient_of_restitution = buffer.get_f32();
165        Ok(CollisionElasticPdu {
166            pdu_header,
167            issuing_entity_id,
168            colliding_entity_id,
169            event_id,
170            padding,
171            contact_velocity,
172            mass,
173            location_of_impact,
174            collision_intermediate_result_xx,
175            collision_intermediate_result_xy,
176            collision_intermediate_result_xz,
177            collision_intermediate_result_yy,
178            collision_intermediate_result_yz,
179            collision_intermediate_result_zz,
180            unit_surface_normal,
181            coefficient_of_restitution,
182        })
183    }
184}
185
186#[cfg(test)]
187mod tests {
188    use super::CollisionElasticPdu;
189    use crate::common::{
190        pdu::Pdu,
191        pdu_header::{PduHeader, PduType, ProtocolFamily},
192    };
193    use bytes::BytesMut;
194
195    #[test]
196    fn create_header() {
197        let collision_elastic_pdu = CollisionElasticPdu::default();
198        let header = PduHeader::default(
199            PduType::CollisionElastic,
200            ProtocolFamily::EntityInformation,
201            100,
202        );
203        assert_eq!(
204            header.protocol_version,
205            collision_elastic_pdu.pdu_header.protocol_version
206        );
207        assert_eq!(
208            header.exercise_id,
209            collision_elastic_pdu.pdu_header.exercise_id
210        );
211        assert_eq!(header.pdu_type, collision_elastic_pdu.pdu_header.pdu_type);
212        assert_eq!(
213            header.protocol_family,
214            collision_elastic_pdu.pdu_header.protocol_family
215        );
216        assert_eq!(header.length, collision_elastic_pdu.pdu_header.length);
217        assert_eq!(
218            header.status_record,
219            collision_elastic_pdu.pdu_header.status_record
220        );
221    }
222
223    #[test]
224    fn deserialize_header() {
225        let mut collision_elastic_pdu = CollisionElasticPdu::default();
226        let mut buffer = BytesMut::new();
227        collision_elastic_pdu.serialize(&mut buffer);
228
229        let new_collision_elastic_pdu = CollisionElasticPdu::deserialize(buffer).unwrap();
230        assert_eq!(
231            new_collision_elastic_pdu.pdu_header,
232            collision_elastic_pdu.pdu_header
233        );
234    }
235}