robot_description_builder/
link.rs

1pub 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
18/// All datatypes which a link can hold.
19// TODO: Maybe make a link module with everything in it
20pub 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	// TODO: Improve DOC
27	/// All availble geometry types
28	pub mod geometry {
29		pub use crate::link::geometry::*;
30	}
31
32	// /// TODO: Depricate or Implement?
33	// #[derive(Debug, PartialEq, Eq, Clone)]
34	// pub enum ConnectionPoint {
35	// 	/// Point at Link connection point (Link Origin without translation)
36	// 	Begin,
37	// 	CenterOfVolume,
38	// 	CenterOfMass,
39	// 	End,
40	// }
41}
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/// A `Link` in a Kinematic Structure.
64///
65/// A `Link` is an element of a [`KinematicInterface`](crate::cluster_objects::KinematicInterface) Implementor (for now [`KinematicTree`] and [`Robot`](crate::cluster_objects::Robot)).
66///
67/// A `Link` can be created from a [`LinkBuilder`], which can be created by the [`builder`](Self::builder) method.
68///
69/// This will configure most of the link data:
70/// - **`name`**: The [_string identifier_](crate::identifiers) (or name) of this `Link`. For practical purposes, it is recommended to use unique identifiers/names.
71/// - **[`visuals`](Visual)** (0+): The [`Visual`] elements associated with this `Link`.
72/// - **[`colliders`](Collision)** (0+): The [`Collision`] elements associated with this `Link`.
73/// - **[`joints`](Joint)** (0+): The child [`Joints`](Joint) of this `Link`.
74/// A [`Joint`] can be attached together with its child, using the methods mentioned in the [Building](Link#Building) section.
75/// - **[`inertial`](Inertial)** (Optional): The [`Inertial`] data for this `Link`.
76///
77/// # Building
78/// A [`Joint`] and its child `Link` can only be attached to a `Link`/[`KinematicTree`] in one go, to prevent (invalid) leaf [`Joints`](Joint) and disconnected `Links`.
79/// The following methods can be used to attach a branch:
80/// - [`attach_joint_chain`](Self::attach_joint_chain): Attach a [`Chained<JointBuilder>`] to the current `Link`.
81/// - [`attach_joint_chain_at`](Self::attach_joint_chain_at): Attach a [`Chained<JointBuilder>`] to the current `Link` with the specified [`Transform`].
82/// - [`try_attach_child`](Self::try_attach_child): Attach a `Link`(chain) via a specified [`Joint`].
83///
84/// [`KinematicTree`]: crate::cluster_objects::KinematicTree
85// TODO: Check if something is missing?
86#[derive(Debug)]
87pub struct Link {
88	/// The [_string identifier_](crate::identifiers) or name of this `Link`.
89	///
90	/// For practical purposes, it is recommended to use unique identifiers/names.
91	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	// /// TODO: Maybe array, or thing
99	// /// Or calculate when necessary
100	// end_point: Option<(f32, f32, f32)>,
101	me: WeakLock<Self>,
102}
103
104impl Link {
105	/// Create a new [`LinkBuilder`] with the specified `name`.
106	pub fn builder(name: impl Into<String>) -> LinkBuilder {
107		LinkBuilder::new(name)
108	}
109
110	/// Gets a (strong) refence to the current [`Link`]. (An `Arc<RwLock<Link>>`)
111	pub fn get_self(&self) -> ArcLock<Link> {
112		// Unwrapping is Ok here, because if the Link exists, its self refence should exist.
113		Weak::upgrade(&self.me).unwrap()
114	}
115
116	/// Gets a weak refence to the current [`Link`]. (An `Weak<RwLock<Link>>`)
117	pub fn get_weak_self(&self) -> WeakLock<Link> {
118		Weak::clone(&self.me)
119	}
120
121	/// Gets the reference to the [`LinkParent`] of the current [`Link`]
122	pub fn parent(&self) -> &LinkParent {
123		&self.direct_parent
124	}
125
126	/// Gets the reference to the name of the `Link`
127	///
128	/// # Example
129	/// ```rust
130	/// # use robot_description_builder::{KinematicInterface, linkbuilding::LinkBuilder};
131	/// let tree = LinkBuilder::new("my-link").build_tree();
132	///
133	/// assert_eq!(tree.get_root_link().try_read().unwrap().name(), "my-link")
134	/// ```
135	pub fn name(&self) -> &String {
136		&self.name
137	}
138
139	/// Returns a reference to the joints of this [`Link`].
140	///
141	/// The vector contains all [`Joint`]s connected to this [`Link`], wrapped in a `Arc<RwLock<T>>`.
142	pub fn joints(&self) -> &Vec<ArcLock<Joint>> {
143		&self.child_joints
144	}
145
146	/// Returns a mutable reference to joints `Vec` of this [`Link`].
147	///
148	/// The vector contains all [`Joint`]s connected to this [`Link`], wrapped in a `Arc<RwLock<T>>`.
149	pub(crate) fn joints_mut(&mut self) -> &mut Vec<ArcLock<Joint>> {
150		&mut self.child_joints
151	}
152
153	// TODO: DOC
154	// TODO: maybe flip arguments, because then it will be Link ( Joint, Link)
155	//
156	// # DEFINED BEHAVIOR:
157	//  - The newest link get transfered from the child tree. TODO: VERIFY
158	//
159	// ## TODO:
160	//  - DOC
161	//  - Test
162	//  - Doctest
163	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	// TODO: This is not finalized yet
178	//
179	// ## TODO:
180	//  - DOC
181	//  - Test
182	//  - Doctest
183	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	// Not happy with the end of this line
194	// Attach a `Chained<JointBuilder>` to the position set in the root [`JointBuilder`].
195	//
196	// ## TODO:
197	//  - Test
198	//  - Doctest
199	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 get_end_point(&self) -> Option<(f32, f32, f32)> {
220	// 	self.end_point
221	// }
222
223	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	/// Make a `LinkBuilder` to build a 'Clone' of the `Link`.
236	///
237	/// This method does not clone the child joints of the [`Link`], only the `Link` is self.
238	///
239	/// If the whole branch needs to be copied use [`rebuild_branch`](Self::rebuild_branch()).
240	pub fn rebuild(&self) -> LinkBuilder {
241		LinkBuilder {
242			name: self.name.clone(),
243			// Joints is empty, since this method only rebuilds the current Joint
244			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	// Rebuilds everything below this aswell
252	//
253	// TODO: DOCS
254	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	// TODO: DOCS:
268	// TODO: TEST
269	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	// TODO: DOCS:
276	// TODO: ADD ERRORS
277	// TODO: TEST
278	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(); // This unwrap is Ok.
284				let parent_link = &joint.mread()?.parent_link;
285
286				// TODO: This is most-likely Ok, however it could error on the write.
287				*self.tree.upgrade().unwrap().newest_link.write().unwrap() =
288					Weak::clone(parent_link);
289
290				// This unwrap is Ok, since the parent_link on a Joint is initialized while adding to the tree.
291				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		// Write joints
346		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		//TODO: What should be the defined behavior?
512		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}