@@ -9,7 +9,7 @@ export class LinkManager {
99 private _frameHelpers : THREE . Group ;
1010 private _redrawCallback : ( ) => void ;
1111 private _linkToMeshes : Map < string , THREE . Mesh [ ] > = new Map ( ) ;
12- private _correctLinkMap : Map < string , THREE . Object3D > = new Map ( ) ; // Use base Object3D for flexibility
12+ private _correctLinkMap : Map < string , THREE . Object3D > = new Map ( ) ;
1313
1414 constructor ( scene : THREE . Scene , redrawCallback : ( ) => void ) {
1515 this . _frameHelpers = new THREE . Group ( ) ;
@@ -139,6 +139,17 @@ export class LinkManager {
139139 this . _redrawCallback ( ) ;
140140 }
141141
142+ /**
143+ * Retrieves the visual object for a given link name.
144+ * @param linkName - The name of the link.
145+ * @returns The THREE.Object3D associated with the link's visual, or null.
146+ */
147+ public getLinkObject ( linkName : string ) : THREE . Object3D | null {
148+ const meshes = this . _linkToMeshes . get ( linkName ) ;
149+ // Return the first mesh if it exists, otherwise null.
150+ return meshes && meshes . length > 0 ? meshes [ 0 ] : null ;
151+ }
152+
142153 /**
143154 * Disposes of managed resources.
144155 */
@@ -162,8 +173,7 @@ export class LinkManager {
162173 return ;
163174 }
164175
165- // Step 1: Build a map from the <link> XML Element to the THREE.URDFVisual object.
166- // This is the bridge from the XML world to the THREE.js world.
176+ // Step 1: Build a map from the <link> XML Element to the THREE.URDFVisual object
167177 const linkXmlToVisualMap = new Map < Element , URDFVisual > ( ) ;
168178 robot . traverse ( node => {
169179 if ( ( node as any ) . isURDFVisual ) {
@@ -176,10 +186,10 @@ export class LinkManager {
176186 }
177187 } ) ;
178188
179- // Step 2: Get all <link> tags from the XML. This is our ground truth list of links.
189+ // Step 2: Get all <link> tags from the XML
180190 const allLinkElements = rootXml . querySelectorAll ( 'link' ) ;
181191
182- // Step 3: Iterate through the ground truth list and populate our maps.
192+ // Step 3: Iterate through the list and populate our maps
183193 allLinkElements . forEach ( linkElement => {
184194 const linkName = linkElement . getAttribute ( 'name' ) ;
185195 if ( ! linkName ) {
@@ -199,23 +209,23 @@ export class LinkManager {
199209
200210 // Map the transform object.
201211 if ( visual . parent && visual . parent !== robot ) {
202- // Jointed link: the parent is the distinct URDFLink object.
212+ // Jointed link: the parent is the distinct URDFLink object
203213 this . _correctLinkMap . set ( linkName , visual . parent ) ;
204214 } else {
205- // Jointless link: the visual itself is the best object representing the transform.
215+ // Jointless link: the visual itself is the best object representing the transform
206216 this . _correctLinkMap . set ( linkName , visual ) ;
207217 }
208218 } else {
209- // This link has no visual component (like 'world').
219+ // This link has no visual component (like 'world')
210220 this . _linkToMeshes . set ( linkName , [ ] ) ;
211- // The root URDFRobot object itself acts as the 'world' link.
221+ // The root URDFRobot object itself acts as the 'world' link
212222 if ( linkName === 'world' ) {
213223 this . _correctLinkMap . set ( linkName , robot ) ;
214224 }
215225 }
216226 } ) ;
217227
218- // Step 4: Clone materials for all found meshes to ensure uniqueness.
228+ // Step 4: Clone materials for all found meshes to ensure uniqueness
219229 for ( const meshes of this . _linkToMeshes . values ( ) ) {
220230 meshes . forEach ( mesh => {
221231 if ( Array . isArray ( mesh . material ) ) {
@@ -228,7 +238,7 @@ export class LinkManager {
228238 }
229239
230240 /**
231- * Creates a custom axes helper.
241+ * Creates a custom axes helper
232242 */
233243 private _createCustomAxesHelper ( size = 0.3 ) : THREE . Group {
234244 const axesGroup = new THREE . Group ( ) ;
0 commit comments