robot_description_builder/link/
collision.rs1#[cfg(feature = "urdf")]
2use crate::to_rdf::to_urdf::ToURDF;
3#[cfg(feature = "xml")]
4use quick_xml::{events::attributes::Attribute, name::QName};
5
6use super::{builder::CollisionBuilder, geometry::GeometryInterface};
7use crate::{identifiers::GroupID, transform::Transform};
8
9#[derive(Debug)]
23pub struct Collision {
24 pub(crate) name: Option<String>,
29 pub(crate) transform: Option<Transform>,
35 pub(crate) geometry: Box<dyn GeometryInterface + Sync + Send>,
37}
38
39impl Collision {
40 pub fn builder(
42 geometry: impl Into<Box<dyn GeometryInterface + Sync + Send>>,
43 ) -> CollisionBuilder {
44 CollisionBuilder::new(geometry)
45 }
46
47 pub fn name(&self) -> Option<&String> {
49 self.name.as_ref()
50 }
51
52 pub fn transform(&self) -> Option<&Transform> {
54 self.transform.as_ref()
55 }
56
57 pub fn geometry(&self) -> &Box<dyn GeometryInterface + Sync + Send> {
59 &self.geometry
60 }
61
62 pub fn rebuild(&self) -> CollisionBuilder {
64 CollisionBuilder {
65 name: self.name.clone(),
66 transform: self.transform,
67 geometry: self.geometry.boxed_clone(),
68 }
69 }
70}
71
72#[cfg(feature = "urdf")]
73impl ToURDF for Collision {
74 fn to_urdf(
75 &self,
76 writer: &mut quick_xml::Writer<std::io::Cursor<Vec<u8>>>,
77 urdf_config: &crate::to_rdf::to_urdf::URDFConfig,
78 ) -> Result<(), quick_xml::Error> {
79 let mut element = writer.create_element("collision");
80 if let Some(name) = self.name() {
81 element = element.with_attribute(Attribute {
82 key: QName(b"name"),
83 value: name.display().as_bytes().into(),
84 });
85 }
86
87 element.write_inner_content(|writer| -> quick_xml::Result<()> {
88 if let Some(transform) = self.transform() {
89 transform.to_urdf(writer, urdf_config)?
90 }
91
92 self.geometry()
93 .shape_container()
94 .to_urdf(writer, urdf_config)?;
95 Ok(())
96 })?;
97
98 Ok(())
99 }
100}
101
102impl PartialEq for Collision {
103 fn eq(&self, other: &Self) -> bool {
104 self.name == other.name
105 && self.transform == other.transform
106 && *self.geometry == *other.geometry
107 }
108}
109
110impl Clone for Collision {
111 fn clone(&self) -> Self {
112 Self {
113 name: self.name.clone(),
114 transform: self.transform,
115 geometry: self.geometry.boxed_clone(),
116 }
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use std::f32::consts::PI;
123 use test_log::test;
124
125 use crate::{
126 link::{
127 builder::CollisionBuilder,
128 collision::Collision,
129 geometry::{BoxGeometry, CylinderGeometry, SphereGeometry},
130 },
131 transform::Transform,
132 };
133
134 #[cfg(feature = "urdf")]
135 mod to_urdf {
136 use super::{test, *};
137 use crate::to_rdf::to_urdf::{ToURDF, URDFConfig};
138 use std::io::Seek;
139
140 fn test_to_urdf_collision(
141 collision: CollisionBuilder,
142 result: String,
143 urdf_config: &URDFConfig,
144 ) {
145 let mut writer = quick_xml::Writer::new(std::io::Cursor::new(Vec::new()));
146 assert!(collision.build().to_urdf(&mut writer, urdf_config).is_ok());
147
148 writer.get_mut().rewind().unwrap();
149
150 assert_eq!(
151 std::io::read_to_string(writer.into_inner()).unwrap(),
152 result
153 )
154 }
155
156 #[test]
157 fn no_name_no_origin() {
158 test_to_urdf_collision(
159 Collision::builder(BoxGeometry::new(1.0, 2.0, 3.0)),
160 String::from(r#"<collision><geometry><box size="1 2 3"/></geometry></collision>"#),
161 &URDFConfig::default(),
162 );
163 }
164
165 #[test]
166 fn name_no_origin() {
167 test_to_urdf_collision(
168 Collision::builder(CylinderGeometry::new(9., 6.258)).named("myLink_col"),
169 String::from(
170 r#"<collision name="myLink_col"><geometry><cylinder radius="9" length="6.258"/></geometry></collision>"#,
171 ),
172 &URDFConfig::default(),
173 );
174 }
175
176 #[test]
177 fn no_name_origin() {
178 test_to_urdf_collision(
179 Collision::builder(SphereGeometry::new(3.))
180 .transformed(Transform::new((4., 6.78, 1.), (PI, 2. * PI, 0.))),
181 String::from(
182 r#"<collision><origin xyz="4 6.78 1" rpy="3.1415927 6.2831855 0"/><geometry><sphere radius="3"/></geometry></collision>"#,
183 ),
184 &URDFConfig::default(),
185 );
186 }
187
188 #[test]
189 fn name_origin() {
190 test_to_urdf_collision(
191 Collision::builder(CylinderGeometry::new(4.5, 75.35))
192 .named("some_col")
193 .transformed(Transform::new_translation(5.4, 9.1, 7.8)),
194 String::from(
195 r#"<collision name="some_col"><origin xyz="5.4 9.1 7.8"/><geometry><cylinder radius="4.5" length="75.35"/></geometry></collision>"#,
196 ),
197 &URDFConfig::default(),
198 );
199 }
200 }
201}