robot_description_builder/
link.rs1pub mod builder;
2mod collision;
3mod geometry;
4pub mod helper_functions;
5mod inertial;
6mod link_parent;
7mod link_shape_data;
8mod visual;
9
10pub(crate) use link_shape_data::LinkShapeData;
11
12#[cfg(feature = "xml")]
13use itertools::Itertools;
14
15#[cfg(feature = "xml")]
16use quick_xml::{events::attributes::Attribute, name::QName};
17
18pub mod link_data {
21 pub use crate::link::collision::Collision;
22 pub use crate::link::inertial::Inertial;
23 pub use crate::link::link_parent::LinkParent;
24 pub use crate::link::visual::Visual;
25
26 pub mod geometry {
29 pub use crate::link::geometry::*;
30 }
31
32 }
42
43use std::sync::{Arc, Weak};
44
45#[cfg(feature = "urdf")]
46use crate::to_rdf::to_urdf::ToURDF;
47use crate::{
48 chained::Chained,
49 cluster_objects::{
50 kinematic_data_errors::AttachChainError, kinematic_data_tree::KinematicDataTree,
51 },
52 identifiers::GroupID,
53 joint::{BuildJoint, BuildJointChain, Joint, JointBuilder},
54 link::{
55 builder::LinkBuilder, collision::Collision, inertial::Inertial, link_parent::LinkParent,
56 visual::Visual,
57 },
58 transform::Transform,
59 utils::{ArcLock, ArcRW, WeakLock},
60 yank_errors::{RebuildBranchError, YankLinkError},
61};
62
63#[derive(Debug)]
87pub struct Link {
88 name: String,
92 pub(crate) tree: Weak<KinematicDataTree>,
93 direct_parent: link_data::LinkParent,
94 child_joints: Vec<ArcLock<Joint>>,
95 inertial: Option<Inertial>,
96 visuals: Vec<link_data::Visual>,
97 colliders: Vec<link_data::Collision>,
98 me: WeakLock<Self>,
102}
103
104impl Link {
105 pub fn builder(name: impl Into<String>) -> LinkBuilder {
107 LinkBuilder::new(name)
108 }
109
110 pub fn get_self(&self) -> ArcLock<Link> {
112 Weak::upgrade(&self.me).unwrap()
114 }
115
116 pub fn get_weak_self(&self) -> WeakLock<Link> {
118 Weak::clone(&self.me)
119 }
120
121 pub fn parent(&self) -> &LinkParent {
123 &self.direct_parent
124 }
125
126 pub fn name(&self) -> &String {
136 &self.name
137 }
138
139 pub fn joints(&self) -> &Vec<ArcLock<Joint>> {
143 &self.child_joints
144 }
145
146 pub(crate) fn joints_mut(&mut self) -> &mut Vec<ArcLock<Joint>> {
150 &mut self.child_joints
151 }
152
153 pub fn try_attach_child<LinkChain>(
164 &mut self,
165 joint_builder: impl BuildJoint,
166 link_chain: LinkChain,
167 ) -> Result<(), AttachChainError>
168 where
169 LinkChain: Into<Chained<LinkBuilder>>,
170 {
171 self.attach_joint_chain(Into::<Chained<JointBuilder>>::into((
172 joint_builder,
173 link_chain.into(),
174 )))
175 }
176
177 pub fn attach_joint_chain_at(
184 &mut self,
185 mut joint_chain: Chained<JointBuilder>,
186 transform: Transform,
187 ) -> Result<(), AttachChainError> {
188 joint_chain.0.with_transform(transform);
189
190 self.attach_joint_chain(joint_chain)
191 }
192
193 pub fn attach_joint_chain(
200 &mut self,
201 joint_chain: Chained<JointBuilder>,
202 ) -> Result<(), AttachChainError> {
203 let joint =
204 joint_chain.build_chain(&self.tree, &self.get_weak_self(), self.get_shape_data());
205
206 self.tree
207 .upgrade()
208 .expect("KinematicDataTree should be initialized")
209 .try_add_joint(&joint)?;
210
211 self.joints_mut().push(joint);
212 Ok(())
213 }
214
215 pub fn inertial(&self) -> Option<&Inertial> {
216 self.inertial.as_ref()
217 }
218
219 pub fn visuals(&self) -> &Vec<Visual> {
224 &self.visuals
225 }
226
227 pub(crate) fn visuals_mut(&mut self) -> &mut Vec<Visual> {
228 &mut self.visuals
229 }
230
231 pub fn colliders(&self) -> &Vec<Collision> {
232 &self.colliders
233 }
234
235 pub fn rebuild(&self) -> LinkBuilder {
241 LinkBuilder {
242 name: self.name.clone(),
243 joints: Vec::new(),
245 visuals: self.visuals.iter().map(Visual::rebuild).collect(),
246 colliders: self.colliders.iter().map(Collision::rebuild).collect(),
247 intertial: self.inertial,
248 }
249 }
250
251 pub(crate) fn rebuild_branch_continued(&self) -> Result<LinkBuilder, RebuildBranchError> {
255 Ok(LinkBuilder {
256 joints: self
257 .child_joints
258 .iter()
259 .map(|joint| -> Result<JointBuilder, RebuildBranchError> {
260 joint.mread()?.rebuild_branch_continued()
261 })
262 .process_results(|iter| iter.collect())?,
263 ..self.rebuild()
264 })
265 }
266
267 pub fn rebuild_branch(&self) -> Result<Chained<LinkBuilder>, RebuildBranchError> {
270 #[cfg(any(feature = "logging", test))]
271 log::info!(target: "LinkBuilder","Starting Branch Rebuilding: {}", self.name());
272 Ok(Chained(self.rebuild_branch_continued()?))
273 }
274
275 pub(crate) fn yank(&self) -> Result<LinkBuilder, YankLinkError> {
279 let builder = self.rebuild_branch_continued()?;
280
281 match self.parent() {
282 LinkParent::Joint(joint) => {
283 let joint = joint.upgrade().unwrap(); let parent_link = &joint.mread()?.parent_link;
285
286 *self.tree.upgrade().unwrap().newest_link.write().unwrap() =
288 Weak::clone(parent_link);
289
290 parent_link
292 .upgrade()
293 .unwrap()
294 .mwrite()?
295 .joints_mut()
296 .retain(|other_joint| !Arc::ptr_eq(&joint, other_joint));
297 }
298 LinkParent::KinematicTree(_) => {
299 #[cfg(any(feature = "logging", test))]
300 log::trace!("The tree should be dropped, but how?")
301 }
302 }
303
304 Ok(builder)
305 }
306
307 pub(crate) fn get_shape_data(&self) -> LinkShapeData {
308 LinkShapeData::new(
309 self.visuals()
310 .iter()
311 .map(|visual| visual.get_geometry_data()),
312 )
313 }
314}
315
316#[cfg(feature = "urdf")]
317impl ToURDF for Link {
318 fn to_urdf(
319 &self,
320 writer: &mut quick_xml::Writer<std::io::Cursor<Vec<u8>>>,
321 urdf_config: &crate::to_rdf::to_urdf::URDFConfig,
322 ) -> Result<(), quick_xml::Error> {
323 let element = writer.create_element("link").with_attribute(Attribute {
324 key: QName(b"name"),
325 value: self.name().display().as_bytes().into(),
326 });
327 element.write_inner_content(|writer| -> Result<(), quick_xml::Error> {
328 if let Some(inertial_data) = self.inertial() {
329 inertial_data.to_urdf(writer, urdf_config)?;
330 }
331
332 self.visuals
333 .iter()
334 .map(|visual| visual.to_urdf(writer, urdf_config))
335 .process_results(|iter| iter.collect())?;
336
337 self.colliders
338 .iter()
339 .map(|collider| collider.to_urdf(writer, urdf_config))
340 .process_results(|iter| iter.collect())?;
341
342 Ok(())
343 })?;
344
345 self.joints()
347 .iter()
348 .map(|joint| joint.read().unwrap().to_urdf(writer, urdf_config))
349 .process_results(|iter| iter.collect())?;
350
351 Ok(())
352 }
353}
354
355impl PartialEq for Link {
356 fn eq(&self, other: &Self) -> bool {
357 Weak::ptr_eq(&self.me, &other.me)
358 && self.name == other.name
359 && self.direct_parent == other.direct_parent
360 && self.tree.ptr_eq(&other.tree)
361 && self.inertial == other.inertial
362 && self.visuals.len() == other.visuals.len()
363 && self.colliders.len() == other.colliders.len()
364 && self.child_joints.len() == other.child_joints.len()
365 && self
366 .visuals
367 .iter()
368 .zip(other.visuals.iter())
369 .all(|(own_visual, other_visual)| own_visual == other_visual)
370 && self
371 .colliders
372 .iter()
373 .zip(other.colliders.iter())
374 .all(|(own_collider, other_collider)| own_collider == other_collider)
375 && self
376 .child_joints
377 .iter()
378 .zip(other.child_joints.iter())
379 .all(|(own_joint, other_joint)| Arc::ptr_eq(own_joint, other_joint))
380 }
381}
382
383#[cfg(test)]
384mod tests {
385 use std::sync::{Arc, Weak};
386 use test_log::test;
387
388 use crate::{
389 cluster_objects::KinematicInterface,
390 joint::{JointBuilder, JointType},
391 link::{builder::LinkBuilder, link_parent::LinkParent, Link},
392 };
393
394 #[test]
395 fn new() {
396 let tree = LinkBuilder::new("Link-on-Park").build_tree();
397
398 let binding = tree.get_root_link();
399 let root_link = binding.try_read().unwrap();
400 assert_eq!(root_link.name, "Link-on-Park".to_string());
401
402 assert!(root_link.direct_parent.is_valid_reference());
403 assert!({
404 match root_link.direct_parent {
405 LinkParent::KinematicTree(_) => true,
406 _ => false,
407 }
408 });
409
410 let newest_link = tree.get_newest_link();
411 assert_eq!(newest_link.try_read().unwrap().name(), root_link.name());
412 assert!(Arc::ptr_eq(&newest_link, &binding));
413
414 assert_eq!(tree.get_links().try_read().unwrap().len(), 1);
415 assert_eq!(tree.get_joints().try_read().unwrap().len(), 0);
416 }
417
418 #[test]
419 fn try_attach_single_child() {
420 let tree = LinkBuilder::new("base_link").build_tree();
421
422 assert_eq!(
423 tree.get_newest_link()
424 .try_write()
425 .unwrap()
426 .try_attach_child(
427 JointBuilder::new("steve", JointType::Fixed),
428 LinkBuilder::new("child_link"),
429 ),
430 Ok(())
431 );
432
433 assert_eq!(tree.get_root_link().try_read().unwrap().name(), "base_link");
434 assert_eq!(
435 tree.get_newest_link().try_read().unwrap().name(),
436 "child_link"
437 );
438
439 assert!(tree
440 .get_links()
441 .try_read()
442 .unwrap()
443 .contains_key("base_link"));
444 assert!(tree
445 .get_links()
446 .try_read()
447 .unwrap()
448 .contains_key("child_link"));
449 assert!(tree.get_joints().try_read().unwrap().contains_key("steve"));
450
451 assert_eq!(
452 tree.get_joint("steve")
453 .unwrap()
454 .try_read()
455 .unwrap()
456 .parent_link()
457 .try_read()
458 .unwrap()
459 .name(),
460 "base_link"
461 );
462 assert_eq!(
463 tree.get_joint("steve")
464 .unwrap()
465 .try_read()
466 .unwrap()
467 .child_link()
468 .try_read()
469 .unwrap()
470 .name(),
471 "child_link"
472 );
473
474 let weak_joint =
475 { Weak::clone(tree.get_joints().try_read().unwrap().get("steve").unwrap()) };
476 assert_eq!(
477 tree.get_link("child_link")
478 .unwrap()
479 .try_read()
480 .unwrap()
481 .direct_parent,
482 LinkParent::Joint(weak_joint)
483 );
484 }
485
486 #[test]
487 fn try_attach_multi_child() {
488 let tree = Link::builder("root").build_tree();
489 let other_tree = Link::builder("other_root").build_tree();
490 let tree_three = Link::builder("3").build_tree();
491
492 other_tree
493 .get_newest_link()
494 .try_write()
495 .unwrap()
496 .try_attach_child(
497 JointBuilder::new("other_joint", JointType::Fixed),
498 LinkBuilder::new("other_child_link"),
499 )
500 .unwrap();
501
502 tree.get_root_link()
503 .try_write()
504 .unwrap()
505 .try_attach_child(
506 JointBuilder::new("initial_joint", JointType::Fixed),
507 other_tree,
508 )
509 .unwrap();
510
511 assert_eq!(
513 tree.get_newest_link().try_read().unwrap().name(),
514 "other_child_link"
515 );
516
517 tree.get_root_link()
518 .try_write()
519 .unwrap()
520 .try_attach_child(JointBuilder::new("joint-3", JointType::Fixed), tree_three)
521 .unwrap();
522
523 assert_eq!(tree.get_root_link().try_read().unwrap().name(), "root");
524 assert_eq!(tree.get_newest_link().try_read().unwrap().name(), "3");
525
526 {
527 let binding = tree.get_links();
528 let links = binding.try_read().unwrap();
529 assert_eq!(links.len(), 4);
530 assert!(links.contains_key("root"));
531 assert!(links.contains_key("other_root"));
532 assert!(links.contains_key("other_child_link"));
533 assert!(links.contains_key("3"));
534 }
535
536 {
537 let binding = tree.get_joints();
538 let joints = binding.try_read().unwrap();
539 assert_eq!(joints.len(), 3);
540 assert!(joints.contains_key("other_joint"));
541 assert!(joints.contains_key("initial_joint"));
542 assert!(joints.contains_key("joint-3"));
543 }
544
545 let binding = tree.get_root_link();
546 let root_link = binding.try_read().unwrap();
547 assert_eq!(
548 root_link.direct_parent,
549 LinkParent::KinematicTree(Weak::clone(&root_link.tree))
550 );
551 assert_eq!(root_link.child_joints.len(), 2);
552 assert_eq!(
553 root_link.child_joints[0].try_read().unwrap().name(),
554 "initial_joint"
555 );
556 assert_eq!(
557 root_link.child_joints[0]
558 .try_read()
559 .unwrap()
560 .child_link()
561 .try_read()
562 .unwrap()
563 .name(),
564 "other_root"
565 );
566 assert_eq!(
567 root_link.child_joints[0]
568 .try_read()
569 .unwrap()
570 .child_link()
571 .try_read()
572 .unwrap()
573 .joints()
574 .len(),
575 1
576 );
577 assert_eq!(
578 root_link.child_joints[0]
579 .try_read()
580 .unwrap()
581 .child_link()
582 .try_read()
583 .unwrap()
584 .joints()[0]
585 .try_read()
586 .unwrap()
587 .name(),
588 "other_joint"
589 );
590 assert_eq!(
591 root_link.child_joints[0]
592 .try_read()
593 .unwrap()
594 .child_link()
595 .try_read()
596 .unwrap()
597 .joints()[0]
598 .try_read()
599 .unwrap()
600 .child_link()
601 .read()
602 .unwrap()
603 .name(),
604 "other_child_link"
605 );
606 assert_eq!(
607 root_link.child_joints[0]
608 .try_read()
609 .unwrap()
610 .child_link()
611 .try_read()
612 .unwrap()
613 .joints()[0]
614 .try_read()
615 .unwrap()
616 .child_link()
617 .try_read()
618 .unwrap()
619 .joints()
620 .len(),
621 0
622 );
623
624 assert_eq!(
625 root_link.child_joints[1].try_read().unwrap().name(),
626 "joint-3"
627 );
628 assert_eq!(
629 root_link.child_joints[1]
630 .try_read()
631 .unwrap()
632 .child_link()
633 .try_read()
634 .unwrap()
635 .name(),
636 "3"
637 );
638 assert_eq!(
639 root_link.child_joints[1]
640 .try_read()
641 .unwrap()
642 .child_link()
643 .try_read()
644 .unwrap()
645 .joints()
646 .len(),
647 0
648 );
649 }
650}