@@ -16,6 +16,7 @@ export class URDFControls extends GUI {
1616 private _workspaceFolder : any ;
1717 private _sceneFolder : any ;
1818 private _jointsFolder : any ;
19+ private _jointsEditorFolder : any ;
1920 private _workingPath = '' ;
2021
2122 controls : any = {
@@ -26,7 +27,8 @@ export class URDFControls extends GUI {
2627 height : { }
2728 } ,
2829 joints : { } ,
29- lights : { }
30+ lights : { } ,
31+ editor : { }
3032 } ;
3133
3234 /**
@@ -51,6 +53,12 @@ export class URDFControls extends GUI {
5153 this . _jointsFolder = this . addFolder ( 'Joints' ) ;
5254 this . _jointsFolder . domElement . setAttribute ( 'class' , 'dg joints-folder' ) ;
5355
56+ this . _jointsEditorFolder = this . addFolder ( 'Joints Editor' ) ;
57+ this . _jointsEditorFolder . domElement . setAttribute (
58+ 'class' ,
59+ 'dg editor-folder'
60+ ) ;
61+
5462 this . _workspaceFolder = this . addFolder ( 'Workspace' ) ;
5563 this . _workspaceFolder . domElement . setAttribute (
5664 'class' ,
@@ -82,6 +90,13 @@ export class URDFControls extends GUI {
8290 return this . _jointsFolder ;
8391 }
8492
93+ /**
94+ * Retrieves the folder with editor settings
95+ */
96+ get jointsEditorFolder ( ) {
97+ return this . _jointsEditorFolder ;
98+ }
99+
85100 /**
86101 * Checks if a given object is empty {}
87102 *
@@ -92,6 +107,28 @@ export class URDFControls extends GUI {
92107 return Object . keys ( obj ) . length === 0 ;
93108 }
94109
110+ /**
111+ * Restricts input on a control to numeric and special characters.
112+ *
113+ * @param control - The dat.gui controller to modify.
114+ */
115+ private _enforceNumericInput ( control : any ) : void {
116+ const inputElement = control . domElement as HTMLInputElement ;
117+
118+ inputElement . addEventListener ( 'input' , ( event : Event ) => {
119+ const target = event . target as HTMLInputElement ;
120+ const originalValue = target . value ;
121+
122+ // Remove any characters that aren't digits, spaces, periods, or minus signs
123+ const filteredValue = originalValue . replace ( / [ ^ \d . \s - ] / g, '' ) ;
124+
125+ if ( originalValue !== filteredValue ) {
126+ target . value = filteredValue ;
127+ control . updateDisplay ( ) ;
128+ }
129+ } ) ;
130+ }
131+
95132 /**
96133 * Creates an input box and a button to modify the working path
97134 *
@@ -155,6 +192,9 @@ export class URDFControls extends GUI {
155192 stepSize
156193 ) ;
157194
195+ // Enforce input validation
196+ this . _enforceNumericInput ( this . controls . scene . height ) ;
197+
158198 this . _sceneFolder . open ( ) ;
159199 }
160200 return this . controls . scene ;
@@ -200,7 +240,7 @@ export class URDFControls extends GUI {
200240 return ;
201241 }
202242
203- const stepSize = ( limitMax - limitMin ) / 100.0 ;
243+ const stepSize = ( limitMax - limitMin ) / 100 ;
204244 const initValue = joints [ name ] . jointValue [ 0 ] ;
205245
206246 this . controls . joints [ name ] = this . _jointsFolder . add (
@@ -210,7 +250,24 @@ export class URDFControls extends GUI {
210250 limitMax ,
211251 stepSize
212252 ) ;
253+ this . _enforceNumericInput ( this . controls . joints [ name ] ) ;
213254 } ) ;
255+
256+ // Add reset button
257+ const resetSettings = {
258+ 'Reset Joints' : ( ) => {
259+ Object . keys ( this . controls . joints ) . forEach ( ( jointName : string ) => {
260+ if ( jointName !== 'reset' && this . controls . joints [ jointName ] ) {
261+ this . controls . joints [ jointName ] . setValue ( 0 ) ;
262+ }
263+ } ) ;
264+ }
265+ } ;
266+ this . controls . joints . reset = this . _jointsFolder . add (
267+ resetSettings ,
268+ 'Reset Joints'
269+ ) ;
270+
214271 this . _jointsFolder . open ( ) ;
215272 }
216273 return this . controls . joints ;
@@ -385,11 +442,118 @@ export class URDFControls extends GUI {
385442 . name ( 'Show Helper' )
386443 } ;
387444
445+ this . _enforceNumericInput (
446+ this . controls . lights . directional . position . altitude
447+ ) ;
448+ this . _enforceNumericInput (
449+ this . controls . lights . directional . position . azimuth
450+ ) ;
451+ this . _enforceNumericInput ( this . controls . lights . directional . intensity ) ;
452+ this . _enforceNumericInput ( this . controls . lights . ambient . intensity ) ;
453+ this . _enforceNumericInput ( this . controls . lights . hemisphere . intensity ) ;
454+
388455 // Open Scene (lights) and directional subfolder
389456 this . _sceneFolder . open ( ) ;
390457 directionalFolder . open ( ) ;
391458 }
392-
393459 return this . controls . lights ;
394460 }
461+
462+ /**
463+ * Creates controls for the editor mode
464+ *
465+ * @returns - The controls to trigger callbacks when editor settings change
466+ */
467+ createEditorControls (
468+ addJointCallback : ( ) => void ,
469+ linkNames : string [ ] = [ ] ,
470+ jointNames : string [ ] = [ ]
471+ ) {
472+ if ( this . _isEmpty ( this . controls . editor ) ) {
473+ const editorSettings = {
474+ 'Cursor Link Selection' : false ,
475+ 'Select Joint' : 'New Joint' ,
476+ 'Parent Link' : 'none' ,
477+ 'Child Link' : 'none' ,
478+ 'Joint Name' : 'new_joint' ,
479+ 'Joint Type' : 'revolute' ,
480+ 'Origin XYZ' : '0 0 0' ,
481+ 'Origin RPY' : '0 0 0' ,
482+ 'Axis XYZ' : '0 0 1' ,
483+ 'Lower Limit' : '-1.0' ,
484+ 'Upper Limit' : '1.0' ,
485+ Effort : '0.0' ,
486+ Velocity : '0.0' ,
487+ 'Add Joint' : addJointCallback
488+ } ;
489+
490+ const dropdownOptions = [ 'none' , ...linkNames ] ;
491+ const jointOptions = [ 'New Joint' , ...jointNames ] ;
492+
493+ this . controls . editor . mode = this . _jointsEditorFolder . add (
494+ editorSettings ,
495+ 'Cursor Link Selection'
496+ ) ;
497+ this . controls . editor . selectedJoint = this . _jointsEditorFolder
498+ . add ( editorSettings , 'Select Joint' , jointOptions )
499+ . name ( 'Select Joint' ) ;
500+ this . controls . editor . parent = this . _jointsEditorFolder
501+ . add ( editorSettings , 'Parent Link' , dropdownOptions )
502+ . listen ( ) ;
503+ this . controls . editor . child = this . _jointsEditorFolder
504+ . add ( editorSettings , 'Child Link' , dropdownOptions )
505+ . listen ( ) ;
506+ this . controls . editor . name = this . _jointsEditorFolder . add (
507+ editorSettings ,
508+ 'Joint Name'
509+ ) ;
510+ this . controls . editor . type = this . _jointsEditorFolder . add (
511+ editorSettings ,
512+ 'Joint Type' ,
513+ [ 'revolute' , 'continuous' , 'prismatic' , 'fixed' , 'floating' , 'planar' ]
514+ ) ;
515+
516+ // Add origin and axis controls
517+ this . controls . editor . origin_xyz = this . _jointsEditorFolder
518+ . add ( editorSettings , 'Origin XYZ' )
519+ . name ( 'Origin XYZ' ) ;
520+ this . controls . editor . origin_rpy = this . _jointsEditorFolder
521+ . add ( editorSettings , 'Origin RPY' )
522+ . name ( 'Origin RPY' ) ;
523+ this . controls . editor . axis_xyz = this . _jointsEditorFolder
524+ . add ( editorSettings , 'Axis XYZ' )
525+ . name ( 'Axis XYZ' ) ;
526+
527+ // Add limit controls
528+ this . controls . editor . lower = this . _jointsEditorFolder
529+ . add ( editorSettings , 'Lower Limit' )
530+ . name ( 'Lower Limit' ) ;
531+ this . controls . editor . upper = this . _jointsEditorFolder
532+ . add ( editorSettings , 'Upper Limit' )
533+ . name ( 'Upper Limit' ) ;
534+ this . controls . editor . effort = this . _jointsEditorFolder
535+ . add ( editorSettings , 'Effort' )
536+ . name ( 'Effort' ) ;
537+ this . controls . editor . velocity = this . _jointsEditorFolder
538+ . add ( editorSettings , 'Velocity' )
539+ . name ( 'Velocity' ) ;
540+
541+ this . _enforceNumericInput ( this . controls . editor . origin_xyz ) ;
542+ this . _enforceNumericInput ( this . controls . editor . origin_rpy ) ;
543+ this . _enforceNumericInput ( this . controls . editor . axis_xyz ) ;
544+ this . _enforceNumericInput ( this . controls . editor . lower ) ;
545+ this . _enforceNumericInput ( this . controls . editor . upper ) ;
546+ this . _enforceNumericInput ( this . controls . editor . effort ) ;
547+ this . _enforceNumericInput ( this . controls . editor . velocity ) ;
548+
549+ this . controls . editor . add = this . _jointsEditorFolder . add (
550+ editorSettings ,
551+ 'Add Joint'
552+ ) ;
553+
554+ this . _jointsEditorFolder . open ( ) ;
555+ }
556+
557+ return this . controls . editor ;
558+ }
395559}
0 commit comments