@@ -322,19 +322,46 @@ export class URDFLayout extends PanelLayout {
322322 ) {
323323 const urdfString = this . _context . model . toString ( ) ;
324324 const editorControls = this . _controlsPanel . controls . editor ;
325- const newUrdfString = this . _editor . addJoint ( urdfString , {
326- name : editorControls . name . getValue ( ) ,
327- type : editorControls . type . getValue ( ) ,
328- parent : this . _selectedLinks . parent . name ,
329- child : this . _selectedLinks . child . name ,
330- origin_xyz : editorControls . origin_xyz . getValue ( ) ,
331- origin_rpy : editorControls . origin_rpy . getValue ( ) ,
332- axis_xyz : editorControls . axis_xyz . getValue ( ) ,
333- lower : editorControls . lower . getValue ( ) ,
334- upper : editorControls . upper . getValue ( ) ,
335- effort : editorControls . effort . getValue ( ) ,
336- velocity : editorControls . velocity . getValue ( )
337- } ) ;
325+ const isModifying =
326+ editorControls . selectedJoint . getValue ( ) !== 'New Joint' ;
327+
328+ let newUrdfString ;
329+
330+ if ( isModifying ) {
331+ // Modify existing joint
332+ newUrdfString = this . _editor . modifyJoint (
333+ urdfString ,
334+ editorControls . selectedJoint . getValue ( ) ,
335+ {
336+ type : editorControls . type . getValue ( ) ,
337+ parent : this . _selectedLinks . parent . name ,
338+ child : this . _selectedLinks . child . name ,
339+ origin_xyz : editorControls . origin_xyz . getValue ( ) ,
340+ origin_rpy : editorControls . origin_rpy . getValue ( ) ,
341+ axis_xyz : editorControls . axis_xyz . getValue ( ) ,
342+ lower : editorControls . lower . getValue ( ) ,
343+ upper : editorControls . upper . getValue ( ) ,
344+ effort : editorControls . effort . getValue ( ) ,
345+ velocity : editorControls . velocity . getValue ( )
346+ }
347+ ) ;
348+ } else {
349+ // Add new joint
350+ newUrdfString = this . _editor . addJoint ( urdfString , {
351+ name : editorControls . name . getValue ( ) ,
352+ type : editorControls . type . getValue ( ) ,
353+ parent : this . _selectedLinks . parent . name ,
354+ child : this . _selectedLinks . child . name ,
355+ origin_xyz : editorControls . origin_xyz . getValue ( ) ,
356+ origin_rpy : editorControls . origin_rpy . getValue ( ) ,
357+ axis_xyz : editorControls . axis_xyz . getValue ( ) ,
358+ lower : editorControls . lower . getValue ( ) ,
359+ upper : editorControls . upper . getValue ( ) ,
360+ effort : editorControls . effort . getValue ( ) ,
361+ velocity : editorControls . velocity . getValue ( )
362+ } ) ;
363+ }
364+
338365 this . _context . model . fromString ( newUrdfString ) ;
339366
340367 // Update the robot model and refresh joint controls
@@ -344,23 +371,92 @@ export class URDFLayout extends PanelLayout {
344371 this . _selectedLinks . child = { name : null , obj : null } ;
345372 editorControls . parent . setValue ( 'none' ) ;
346373 editorControls . child . setValue ( 'none' ) ;
374+ editorControls . selectedJoint . setValue ( 'New Joint' ) ;
347375 this . _interactionEditor . clearHighlights ( ) ;
348376 }
349377 } ;
350378
351379 const linkNames = Object . keys ( this . _loader . robotModel . links ) ;
380+ const jointNames = Object . keys ( this . _loader . robotModel . joints ) ;
352381 const editorControls = this . _controlsPanel . createEditorControls (
353382 addJointCallback ,
354- linkNames
383+ linkNames ,
384+ jointNames
355385 ) ;
356386
357- editorControls . mode . onChange ( ( enabled : boolean ) => {
358- this . _interactionEditor . setLinkSelectorMode ( enabled ) ;
359- if ( ! enabled ) {
360- this . _selectedLinks . parent = { name : null , obj : null } ;
361- this . _selectedLinks . child = { name : null , obj : null } ;
387+ // Handle joint selection for modification
388+ editorControls . selectedJoint . onChange ( ( selectedJoint : string ) => {
389+ const isModifying = selectedJoint !== 'New Joint' ;
390+
391+ // Update button text
392+ editorControls . add . __li . querySelector ( '.property-name' ) . textContent =
393+ isModifying ? 'Update Joint' : 'Add Joint' ;
394+
395+ if ( isModifying ) {
396+ const joint = this . _loader . robotModel . joints [ selectedJoint ] ;
397+ const jointElement = this . _getJointElementFromURDF ( selectedJoint ) ;
398+
399+ if ( joint && jointElement ) {
400+ editorControls . type . setValue ( joint . jointType ) ;
401+
402+ // Get parent and child links
403+ const parentLink =
404+ jointElement
405+ . getElementsByTagName ( 'parent' ) [ 0 ]
406+ ?. getAttribute ( 'link' ) || 'none' ;
407+ const childLink =
408+ jointElement
409+ . getElementsByTagName ( 'child' ) [ 0 ]
410+ ?. getAttribute ( 'link' ) || 'none' ;
411+ editorControls . parent . setValue ( parentLink ) ;
412+ editorControls . child . setValue ( childLink ) ;
413+
414+ // Get origin values
415+ const origin = jointElement . getElementsByTagName ( 'origin' ) [ 0 ] ;
416+ editorControls . origin_xyz . setValue (
417+ origin ?. getAttribute ( 'xyz' ) || '0 0 0'
418+ ) ;
419+ editorControls . origin_rpy . setValue (
420+ origin ?. getAttribute ( 'rpy' ) || '0 0 0'
421+ ) ;
422+
423+ // Get axis values
424+ const axis = jointElement . getElementsByTagName ( 'axis' ) [ 0 ] ;
425+ editorControls . axis_xyz . setValue (
426+ axis ?. getAttribute ( 'xyz' ) || '0 0 1'
427+ ) ;
428+
429+ // Get limit, effort and velocity values
430+ const limit = jointElement . getElementsByTagName ( 'limit' ) [ 0 ] ;
431+ editorControls . lower . setValue ( limit ?. getAttribute ( 'lower' ) || '-1.0' ) ;
432+ editorControls . upper . setValue ( limit ?. getAttribute ( 'upper' ) || '1.0' ) ;
433+ editorControls . effort . setValue (
434+ limit ?. getAttribute ( 'effort' ) || '0.0'
435+ ) ;
436+ editorControls . velocity . setValue (
437+ limit ?. getAttribute ( 'velocity' ) || '0.0'
438+ ) ;
439+
440+ // Update selected links for highlighting
441+ this . _updateSelectedLinksFromJoint ( parentLink , childLink ) ;
442+ }
443+ } else {
444+ // Clear fields for new joint
445+ editorControls . name . setValue ( 'new_joint' ) ;
446+ editorControls . type . setValue ( 'revolute' ) ;
362447 editorControls . parent . setValue ( 'none' ) ;
363448 editorControls . child . setValue ( 'none' ) ;
449+ editorControls . origin_xyz . setValue ( '0 0 0' ) ;
450+ editorControls . origin_rpy . setValue ( '0 0 0' ) ;
451+ editorControls . axis_xyz . setValue ( '0 0 1' ) ;
452+ editorControls . lower . setValue ( '-1.0' ) ;
453+ editorControls . upper . setValue ( '1.0' ) ;
454+ editorControls . effort . setValue ( '0.0' ) ;
455+ editorControls . velocity . setValue ( '0.0' ) ;
456+
457+ this . _selectedLinks . parent = { name : null , obj : null } ;
458+ this . _selectedLinks . child = { name : null , obj : null } ;
459+ this . _interactionEditor . clearHighlights ( ) ;
364460 }
365461 } ) ;
366462
@@ -518,6 +614,57 @@ export class URDFLayout extends PanelLayout {
518614 } ) ;
519615 }
520616
617+ /**
618+ * Helper method to get joint element from URDF XML
619+ */
620+ private _getJointElementFromURDF ( jointName : string ) : Element | null {
621+ if ( ! this . _context ) {
622+ return null ;
623+ }
624+
625+ const parser = new DOMParser ( ) ;
626+ const urdf = parser . parseFromString (
627+ this . _context . model . toString ( ) ,
628+ 'application/xml'
629+ ) ;
630+ const joints = urdf . getElementsByTagName ( 'joint' ) ;
631+
632+ for ( let i = 0 ; i < joints . length ; i ++ ) {
633+ if ( joints [ i ] . getAttribute ( 'name' ) === jointName ) {
634+ return joints [ i ] ;
635+ }
636+ }
637+ return null ;
638+ }
639+
640+ /**
641+ * Helper method to update selected links based on joint parent/child
642+ */
643+ private _updateSelectedLinksFromJoint (
644+ parentLink : string ,
645+ childLink : string
646+ ) : void {
647+ if ( parentLink !== 'none' ) {
648+ const link = this . _loader . robotModel . links [ parentLink ] ;
649+ const linkObject = link ?. children . find ( ( c : any ) => c . isURDFVisual )
650+ ?. children [ 0 ] ;
651+ this . _selectedLinks . parent = { name : parentLink , obj : linkObject } ;
652+ if ( linkObject ) {
653+ this . _interactionEditor . highlightLink ( linkObject , 'parent' ) ;
654+ }
655+ }
656+
657+ if ( childLink !== 'none' ) {
658+ const link = this . _loader . robotModel . links [ childLink ] ;
659+ const linkObject = link ?. children . find ( ( c : any ) => c . isURDFVisual )
660+ ?. children [ 0 ] ;
661+ this . _selectedLinks . child = { name : childLink , obj : linkObject } ;
662+ if ( linkObject ) {
663+ this . _interactionEditor . highlightLink ( linkObject , 'child' ) ;
664+ }
665+ }
666+ }
667+
521668 /**
522669 * Refreshes the joint controls by clearing and recreating them
523670 */
0 commit comments