diff --git a/doc/XMLschema.rst b/doc/XMLschema.rst index e940fb5f..e8fd477d 100644 --- a/doc/XMLschema.rst +++ b/doc/XMLschema.rst @@ -167,6 +167,9 @@ .. grid-item:: :ref:`island` + .. grid-item:: + :ref:`multiccd` + .. grid-item:: :ref:`override` @@ -179,9 +182,6 @@ .. grid-item:: :ref:`invdiscrete` - .. grid-item:: - :ref:`multiccd` - .. grid-item:: :ref:`sleep` @@ -692,9 +692,6 @@ .. grid-item:: :ref:`quat` - .. grid-item:: - :ref:`mocap` - .. grid-item:: :ref:`axisangle` @@ -707,6 +704,9 @@ .. grid-item:: :ref:`euler` + .. grid-item:: + :ref:`mocap` + .. grid-item:: :ref:`gravcomp` @@ -1022,15 +1022,6 @@ .. grid-item:: :ref:`quat` - .. grid-item:: - :ref:`material` - - .. grid-item:: - :ref:`size` - - .. grid-item:: - :ref:`fromto` - .. grid-item:: :ref:`axisangle` @@ -1043,6 +1034,15 @@ .. grid-item:: :ref:`euler` + .. grid-item:: + :ref:`material` + + .. grid-item:: + :ref:`size` + + .. grid-item:: + :ref:`fromto` + .. grid-item:: :ref:`rgba` @@ -1910,6 +1910,15 @@ .. grid-item:: :ref:`class` + .. grid-item:: + :ref:`active` + + .. grid-item:: + :ref:`solref` + + .. grid-item:: + :ref:`solimp` + .. grid-item:: :ref:`body1` @@ -1925,15 +1934,6 @@ .. grid-item:: :ref:`site2` - .. grid-item:: - :ref:`active` - - .. grid-item:: - :ref:`solref` - - .. grid-item:: - :ref:`solimp` - .. dropdown:: :ref:`weld` |*| @@ -1946,6 +1946,15 @@ .. grid-item:: :ref:`class` + .. grid-item:: + :ref:`active` + + .. grid-item:: + :ref:`solref` + + .. grid-item:: + :ref:`solimp` + .. grid-item:: :ref:`body1` @@ -1964,15 +1973,6 @@ .. grid-item:: :ref:`site2` - .. grid-item:: - :ref:`active` - - .. grid-item:: - :ref:`solref` - - .. grid-item:: - :ref:`solimp` - .. grid-item:: :ref:`torquescale` @@ -1988,15 +1988,6 @@ .. grid-item:: :ref:`class` - .. grid-item:: - :ref:`joint1` - - .. grid-item:: - :ref:`joint2` - - .. grid-item:: - :ref:`polycoef` - .. grid-item:: :ref:`active` @@ -2006,6 +1997,15 @@ .. grid-item:: :ref:`solimp` + .. grid-item:: + :ref:`joint1` + + .. grid-item:: + :ref:`joint2` + + .. grid-item:: + :ref:`polycoef` + .. dropdown:: :ref:`tendon` |*| @@ -2018,15 +2018,6 @@ .. grid-item:: :ref:`class` - .. grid-item:: - :ref:`tendon1` - - .. grid-item:: - :ref:`tendon2` - - .. grid-item:: - :ref:`polycoef` - .. grid-item:: :ref:`active` @@ -2036,6 +2027,15 @@ .. grid-item:: :ref:`solimp` + .. grid-item:: + :ref:`tendon1` + + .. grid-item:: + :ref:`tendon2` + + .. grid-item:: + :ref:`polycoef` + .. dropdown:: :ref:`flex` |*| @@ -2048,9 +2048,6 @@ .. grid-item:: :ref:`class` - .. grid-item:: - :ref:`flex` - .. grid-item:: :ref:`active` @@ -2060,6 +2057,9 @@ .. grid-item:: :ref:`solimp` + .. grid-item:: + :ref:`flex` + .. dropdown:: :ref:`flexvert` |*| @@ -2072,9 +2072,6 @@ .. grid-item:: :ref:`class` - .. grid-item:: - :ref:`flex` - .. grid-item:: :ref:`active` @@ -2084,6 +2081,9 @@ .. grid-item:: :ref:`solimp` + .. grid-item:: + :ref:`flex` + .. dropdown:: :ref:`flexstrain` |*| @@ -2096,12 +2096,6 @@ .. grid-item:: :ref:`class` - .. grid-item:: - :ref:`flex` - - .. grid-item:: - :ref:`cell` - .. grid-item:: :ref:`active` @@ -2111,6 +2105,12 @@ .. grid-item:: :ref:`solimp` + .. grid-item:: + :ref:`flex` + + .. grid-item:: + :ref:`cell` + .. dropdown:: :ref:`tendon` |*| @@ -2312,6 +2312,12 @@ .. grid-item:: :ref:`delay` + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`user` + .. grid-item:: :ref:`ctrllimited` @@ -2321,9 +2327,6 @@ .. grid-item:: :ref:`actlimited` - .. grid-item:: - :ref:`ctrlrange` - .. grid-item:: :ref:`forcerange` @@ -2345,9 +2348,6 @@ .. grid-item:: :ref:`cranklength` - .. grid-item:: - :ref:`user` - .. grid-item:: :ref:`joint` @@ -2429,15 +2429,18 @@ .. grid-item:: :ref:`delay` + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`user` + .. grid-item:: :ref:`ctrllimited` .. grid-item:: :ref:`forcelimited` - .. grid-item:: - :ref:`ctrlrange` - .. grid-item:: :ref:`forcerange` @@ -2456,9 +2459,6 @@ .. grid-item:: :ref:`cranklength` - .. grid-item:: - :ref:`user` - .. grid-item:: :ref:`joint` @@ -2504,15 +2504,18 @@ .. grid-item:: :ref:`delay` + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`user` + .. grid-item:: :ref:`ctrllimited` .. grid-item:: :ref:`forcelimited` - .. grid-item:: - :ref:`ctrlrange` - .. grid-item:: :ref:`inheritrange` @@ -2534,9 +2537,6 @@ .. grid-item:: :ref:`cranklength` - .. grid-item:: - :ref:`user` - .. grid-item:: :ref:`joint` @@ -2594,15 +2594,18 @@ .. grid-item:: :ref:`delay` + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`user` + .. grid-item:: :ref:`ctrllimited` .. grid-item:: :ref:`forcelimited` - .. grid-item:: - :ref:`ctrlrange` - .. grid-item:: :ref:`forcerange` @@ -2621,9 +2624,6 @@ .. grid-item:: :ref:`cranklength` - .. grid-item:: - :ref:`user` - .. grid-item:: :ref:`joint` @@ -2672,6 +2672,12 @@ .. grid-item:: :ref:`delay` + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`user` + .. grid-item:: :ref:`ctrllimited` @@ -2681,9 +2687,6 @@ .. grid-item:: :ref:`actlimited` - .. grid-item:: - :ref:`ctrlrange` - .. grid-item:: :ref:`forcerange` @@ -2708,9 +2711,6 @@ .. grid-item:: :ref:`cranklength` - .. grid-item:: - :ref:`user` - .. grid-item:: :ref:`joint` @@ -2765,17 +2765,17 @@ .. grid-item:: :ref:`delay` - .. grid-item:: - :ref:`forcelimited` - .. grid-item:: :ref:`ctrlrange` .. grid-item:: - :ref:`forcerange` + :ref:`user` .. grid-item:: - :ref:`user` + :ref:`forcelimited` + + .. grid-item:: + :ref:`forcerange` .. grid-item:: :ref:`joint` @@ -2822,15 +2822,18 @@ .. grid-item:: :ref:`delay` + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`user` + .. grid-item:: :ref:`ctrllimited` .. grid-item:: :ref:`forcelimited` - .. grid-item:: - :ref:`ctrlrange` - .. grid-item:: :ref:`posrange` @@ -2861,9 +2864,6 @@ .. grid-item:: :ref:`cranklength` - .. grid-item:: - :ref:`user` - .. grid-item:: :ref:`joint` @@ -2931,10 +2931,13 @@ :ref:`delay` .. grid-item:: - :ref:`forcelimited` + :ref:`ctrlrange` .. grid-item:: - :ref:`ctrlrange` + :ref:`user` + + .. grid-item:: + :ref:`forcelimited` .. grid-item:: :ref:`forcerange` @@ -2954,9 +2957,6 @@ .. grid-item:: :ref:`cranklength` - .. grid-item:: - :ref:`user` - .. grid-item:: :ref:`joint` @@ -3005,15 +3005,18 @@ .. grid-item:: :ref:`delay` + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`user` + .. grid-item:: :ref:`ctrllimited` .. grid-item:: :ref:`forcelimited` - .. grid-item:: - :ref:`ctrlrange` - .. grid-item:: :ref:`forcerange` @@ -3032,9 +3035,6 @@ .. grid-item:: :ref:`cranklength` - .. grid-item:: - :ref:`user` - .. grid-item:: :ref:`joint` @@ -3092,15 +3092,18 @@ .. grid-item:: :ref:`delay` + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`user` + .. grid-item:: :ref:`ctrllimited` .. grid-item:: :ref:`forcelimited` - .. grid-item:: - :ref:`ctrlrange` - .. grid-item:: :ref:`forcerange` @@ -3119,9 +3122,6 @@ .. grid-item:: :ref:`cranklength` - .. grid-item:: - :ref:`user` - .. grid-item:: :ref:`joint` @@ -3191,17 +3191,17 @@ .. grid-item:: :ref:`delay` - .. grid-item:: - :ref:`forcelimited` - .. grid-item:: :ref:`ctrlrange` .. grid-item:: - :ref:`forcerange` + :ref:`user` .. grid-item:: - :ref:`user` + :ref:`forcelimited` + + .. grid-item:: + :ref:`forcerange` .. grid-item:: :ref:`body` @@ -3234,10 +3234,13 @@ :ref:`delay` .. grid-item:: - :ref:`ctrllimited` + :ref:`ctrlrange` .. grid-item:: - :ref:`ctrlrange` + :ref:`user` + + .. grid-item:: + :ref:`ctrllimited` .. grid-item:: :ref:`lengthrange` @@ -3254,9 +3257,6 @@ .. grid-item:: :ref:`cranklength` - .. grid-item:: - :ref:`user` - .. grid-item:: :ref:`joint` @@ -3320,12 +3320,6 @@ .. grid-item:: :ref:`class` - .. grid-item:: - :ref:`plugin` - - .. grid-item:: - :ref:`instance` - .. grid-item:: :ref:`group` @@ -3338,6 +3332,18 @@ .. grid-item:: :ref:`delay` + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`user` + + .. grid-item:: + :ref:`plugin` + + .. grid-item:: + :ref:`instance` + .. grid-item:: :ref:`ctrllimited` @@ -3347,9 +3353,6 @@ .. grid-item:: :ref:`actlimited` - .. grid-item:: - :ref:`ctrlrange` - .. grid-item:: :ref:`forcerange` @@ -3398,9 +3401,6 @@ .. grid-item:: :ref:`slidersite` - .. grid-item:: - :ref:`user` - .. grid-item:: :ref:`actearly` @@ -3428,9 +3428,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`site` - .. grid-item:: :ref:`nsample` @@ -3452,6 +3449,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`site` + .. dropdown:: :ref:`accelerometer` |*| @@ -3461,9 +3461,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`site` - .. grid-item:: :ref:`nsample` @@ -3485,6 +3482,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`site` + .. dropdown:: :ref:`velocimeter` |*| @@ -3494,9 +3494,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`site` - .. grid-item:: :ref:`nsample` @@ -3518,6 +3515,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`site` + .. dropdown:: :ref:`gyro` |*| @@ -3527,9 +3527,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`site` - .. grid-item:: :ref:`nsample` @@ -3551,6 +3548,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`site` + .. dropdown:: :ref:`force` |*| @@ -3560,9 +3560,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`site` - .. grid-item:: :ref:`nsample` @@ -3584,6 +3581,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`site` + .. dropdown:: :ref:`torque` |*| @@ -3593,9 +3593,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`site` - .. grid-item:: :ref:`nsample` @@ -3617,6 +3614,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`site` + .. dropdown:: :ref:`magnetometer` |*| @@ -3626,9 +3626,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`site` - .. grid-item:: :ref:`nsample` @@ -3650,6 +3647,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`site` + .. dropdown:: :ref:`camprojection` |*| @@ -3659,12 +3659,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`site` - - .. grid-item:: - :ref:`camera` - .. grid-item:: :ref:`nsample` @@ -3686,6 +3680,12 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`site` + + .. grid-item:: + :ref:`camera` + .. dropdown:: :ref:`rangefinder` |*| @@ -3695,15 +3695,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`site` - - .. grid-item:: - :ref:`camera` - - .. grid-item:: - :ref:`data` - .. grid-item:: :ref:`nsample` @@ -3725,6 +3716,15 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`site` + + .. grid-item:: + :ref:`camera` + + .. grid-item:: + :ref:`data` + .. dropdown:: :ref:`jointpos` |*| @@ -3734,9 +3734,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`joint` - .. grid-item:: :ref:`nsample` @@ -3758,6 +3755,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`joint` + .. dropdown:: :ref:`jointvel` |*| @@ -3767,9 +3767,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`joint` - .. grid-item:: :ref:`nsample` @@ -3791,6 +3788,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`joint` + .. dropdown:: :ref:`tendonpos` |*| @@ -3800,9 +3800,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`tendon` - .. grid-item:: :ref:`nsample` @@ -3824,6 +3821,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`tendon` + .. dropdown:: :ref:`tendonvel` |*| @@ -3833,9 +3833,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`tendon` - .. grid-item:: :ref:`nsample` @@ -3857,6 +3854,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`tendon` + .. dropdown:: :ref:`actuatorpos` |*| @@ -3866,9 +3866,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`actuator` - .. grid-item:: :ref:`nsample` @@ -3890,6 +3887,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`actuator` + .. dropdown:: :ref:`actuatorvel` |*| @@ -3899,9 +3899,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`actuator` - .. grid-item:: :ref:`nsample` @@ -3923,6 +3920,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`actuator` + .. dropdown:: :ref:`actuatorfrc` |*| @@ -3932,9 +3932,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`actuator` - .. grid-item:: :ref:`nsample` @@ -3956,6 +3953,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`actuator` + .. dropdown:: :ref:`jointactuatorfrc` |*| @@ -3965,9 +3965,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`joint` - .. grid-item:: :ref:`nsample` @@ -3989,6 +3986,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`joint` + .. dropdown:: :ref:`tendonactuatorfrc` |*| @@ -3998,9 +3998,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`tendon` - .. grid-item:: :ref:`nsample` @@ -4022,6 +4019,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`tendon` + .. dropdown:: :ref:`ballquat` |*| @@ -4031,9 +4031,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`joint` - .. grid-item:: :ref:`nsample` @@ -4055,6 +4052,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`joint` + .. dropdown:: :ref:`ballangvel` |*| @@ -4064,9 +4064,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`joint` - .. grid-item:: :ref:`nsample` @@ -4088,6 +4085,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`joint` + .. dropdown:: :ref:`jointlimitpos` |*| @@ -4097,9 +4097,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`joint` - .. grid-item:: :ref:`nsample` @@ -4121,6 +4118,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`joint` + .. dropdown:: :ref:`jointlimitvel` |*| @@ -4130,9 +4130,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`joint` - .. grid-item:: :ref:`nsample` @@ -4154,6 +4151,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`joint` + .. dropdown:: :ref:`jointlimitfrc` |*| @@ -4163,9 +4163,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`joint` - .. grid-item:: :ref:`nsample` @@ -4187,6 +4184,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`joint` + .. dropdown:: :ref:`tendonlimitpos` |*| @@ -4196,9 +4196,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`tendon` - .. grid-item:: :ref:`nsample` @@ -4220,6 +4217,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`tendon` + .. dropdown:: :ref:`tendonlimitvel` |*| @@ -4229,9 +4229,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`tendon` - .. grid-item:: :ref:`nsample` @@ -4253,6 +4250,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`tendon` + .. dropdown:: :ref:`tendonlimitfrc` |*| @@ -4262,9 +4262,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`tendon` - .. grid-item:: :ref:`nsample` @@ -4286,6 +4283,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`tendon` + .. dropdown:: :ref:`framepos` |*| @@ -4295,18 +4295,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`objtype` - - .. grid-item:: - :ref:`objname` - - .. grid-item:: - :ref:`reftype` - - .. grid-item:: - :ref:`refname` - .. grid-item:: :ref:`nsample` @@ -4328,6 +4316,18 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`objtype` + + .. grid-item:: + :ref:`objname` + + .. grid-item:: + :ref:`reftype` + + .. grid-item:: + :ref:`refname` + .. dropdown:: :ref:`framequat` |*| @@ -4337,18 +4337,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`objtype` - - .. grid-item:: - :ref:`objname` - - .. grid-item:: - :ref:`reftype` - - .. grid-item:: - :ref:`refname` - .. grid-item:: :ref:`nsample` @@ -4370,6 +4358,18 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`objtype` + + .. grid-item:: + :ref:`objname` + + .. grid-item:: + :ref:`reftype` + + .. grid-item:: + :ref:`refname` + .. dropdown:: :ref:`framexaxis` |*| @@ -4379,18 +4379,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`objtype` - - .. grid-item:: - :ref:`objname` - - .. grid-item:: - :ref:`reftype` - - .. grid-item:: - :ref:`refname` - .. grid-item:: :ref:`nsample` @@ -4412,6 +4400,18 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`objtype` + + .. grid-item:: + :ref:`objname` + + .. grid-item:: + :ref:`reftype` + + .. grid-item:: + :ref:`refname` + .. dropdown:: :ref:`frameyaxis` |*| @@ -4421,18 +4421,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`objtype` - - .. grid-item:: - :ref:`objname` - - .. grid-item:: - :ref:`reftype` - - .. grid-item:: - :ref:`refname` - .. grid-item:: :ref:`nsample` @@ -4454,6 +4442,18 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`objtype` + + .. grid-item:: + :ref:`objname` + + .. grid-item:: + :ref:`reftype` + + .. grid-item:: + :ref:`refname` + .. dropdown:: :ref:`framezaxis` |*| @@ -4463,18 +4463,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`objtype` - - .. grid-item:: - :ref:`objname` - - .. grid-item:: - :ref:`reftype` - - .. grid-item:: - :ref:`refname` - .. grid-item:: :ref:`nsample` @@ -4496,6 +4484,18 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`objtype` + + .. grid-item:: + :ref:`objname` + + .. grid-item:: + :ref:`reftype` + + .. grid-item:: + :ref:`refname` + .. dropdown:: :ref:`framelinvel` |*| @@ -4505,18 +4505,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`objtype` - - .. grid-item:: - :ref:`objname` - - .. grid-item:: - :ref:`reftype` - - .. grid-item:: - :ref:`refname` - .. grid-item:: :ref:`nsample` @@ -4538,6 +4526,18 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`objtype` + + .. grid-item:: + :ref:`objname` + + .. grid-item:: + :ref:`reftype` + + .. grid-item:: + :ref:`refname` + .. dropdown:: :ref:`frameangvel` |*| @@ -4547,18 +4547,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`objtype` - - .. grid-item:: - :ref:`objname` - - .. grid-item:: - :ref:`reftype` - - .. grid-item:: - :ref:`refname` - .. grid-item:: :ref:`nsample` @@ -4580,6 +4568,18 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`objtype` + + .. grid-item:: + :ref:`objname` + + .. grid-item:: + :ref:`reftype` + + .. grid-item:: + :ref:`refname` + .. dropdown:: :ref:`framelinacc` |*| @@ -4589,12 +4589,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`objtype` - - .. grid-item:: - :ref:`objname` - .. grid-item:: :ref:`nsample` @@ -4616,6 +4610,12 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`objtype` + + .. grid-item:: + :ref:`objname` + .. dropdown:: :ref:`frameangacc` |*| @@ -4625,12 +4625,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`objtype` - - .. grid-item:: - :ref:`objname` - .. grid-item:: :ref:`nsample` @@ -4652,6 +4646,12 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`objtype` + + .. grid-item:: + :ref:`objname` + .. dropdown:: :ref:`subtreecom` |*| @@ -4661,9 +4661,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`body` - .. grid-item:: :ref:`nsample` @@ -4685,6 +4682,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`body` + .. dropdown:: :ref:`subtreelinvel` |*| @@ -4694,9 +4694,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`body` - .. grid-item:: :ref:`nsample` @@ -4718,6 +4715,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`body` + .. dropdown:: :ref:`subtreeangmom` |*| @@ -4727,9 +4727,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`body` - .. grid-item:: :ref:`nsample` @@ -4751,6 +4748,9 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`body` + .. dropdown:: :ref:`insidesite` |*| @@ -4760,15 +4760,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`site` - - .. grid-item:: - :ref:`objtype` - - .. grid-item:: - :ref:`objname` - .. grid-item:: :ref:`nsample` @@ -4790,6 +4781,15 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`site` + + .. grid-item:: + :ref:`objtype` + + .. grid-item:: + :ref:`objname` + .. dropdown:: :ref:`distance` |*| @@ -4799,18 +4799,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`geom1` - - .. grid-item:: - :ref:`geom2` - - .. grid-item:: - :ref:`body1` - - .. grid-item:: - :ref:`body2` - .. grid-item:: :ref:`nsample` @@ -4832,6 +4820,18 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`geom1` + + .. grid-item:: + :ref:`geom2` + + .. grid-item:: + :ref:`body1` + + .. grid-item:: + :ref:`body2` + .. dropdown:: :ref:`normal` |*| @@ -4841,18 +4841,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`geom1` - - .. grid-item:: - :ref:`geom2` - - .. grid-item:: - :ref:`body1` - - .. grid-item:: - :ref:`body2` - .. grid-item:: :ref:`nsample` @@ -4874,6 +4862,18 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`geom1` + + .. grid-item:: + :ref:`geom2` + + .. grid-item:: + :ref:`body1` + + .. grid-item:: + :ref:`body2` + .. dropdown:: :ref:`fromto` |*| @@ -4883,18 +4883,6 @@ .. grid-item:: :ref:`name` - .. grid-item:: - :ref:`geom1` - - .. grid-item:: - :ref:`geom2` - - .. grid-item:: - :ref:`body1` - - .. grid-item:: - :ref:`body2` - .. grid-item:: :ref:`nsample` @@ -4916,6 +4904,18 @@ .. grid-item:: :ref:`user` + .. grid-item:: + :ref:`geom1` + + .. grid-item:: + :ref:`geom2` + + .. grid-item:: + :ref:`body1` + + .. grid-item:: + :ref:`body2` + .. dropdown:: :ref:`contact` |*| @@ -4925,6 +4925,27 @@ .. grid-item:: :ref:`name` + .. grid-item:: + :ref:`nsample` + + .. grid-item:: + :ref:`interp` + + .. grid-item:: + :ref:`delay` + + .. grid-item:: + :ref:`interval` + + .. grid-item:: + :ref:`cutoff` + + .. grid-item:: + :ref:`noise` + + .. grid-item:: + :ref:`user` + .. grid-item:: :ref:`geom1` @@ -4955,27 +4976,6 @@ .. grid-item:: :ref:`reduce` - .. grid-item:: - :ref:`nsample` - - .. grid-item:: - :ref:`interp` - - .. grid-item:: - :ref:`delay` - - .. grid-item:: - :ref:`interval` - - .. grid-item:: - :ref:`cutoff` - - .. grid-item:: - :ref:`noise` - - .. grid-item:: - :ref:`user` - .. dropdown:: :ref:`e_potential` |*| @@ -5510,6 +5510,12 @@ .. grid-item:: :ref:`texture` + .. grid-item:: + :ref:`texrepeat` + + .. grid-item:: + :ref:`texuniform` + .. grid-item:: :ref:`emission` @@ -5531,12 +5537,6 @@ .. grid-item:: :ref:`rgba` - .. grid-item:: - :ref:`texrepeat` - - .. grid-item:: - :ref:`texuniform` - .. dropdown:: :ref:`layer` |*| @@ -5630,12 +5630,6 @@ .. grid-item:: :ref:`type` - .. grid-item:: - :ref:`pos` - - .. grid-item:: - :ref:`quat` - .. grid-item:: :ref:`contype` @@ -5693,6 +5687,12 @@ .. grid-item:: :ref:`fromto` + .. grid-item:: + :ref:`pos` + + .. grid-item:: + :ref:`quat` + .. grid-item:: :ref:`axisangle` @@ -5744,15 +5744,6 @@ .. grid-item:: :ref:`quat` - .. grid-item:: - :ref:`material` - - .. grid-item:: - :ref:`size` - - .. grid-item:: - :ref:`fromto` - .. grid-item:: :ref:`axisangle` @@ -5765,6 +5756,15 @@ .. grid-item:: :ref:`euler` + .. grid-item:: + :ref:`material` + + .. grid-item:: + :ref:`size` + + .. grid-item:: + :ref:`fromto` + .. grid-item:: :ref:`rgba` @@ -5837,6 +5837,18 @@ .. grid:: 2 3 4 4 :gutter: 0 + .. grid-item:: + :ref:`directional` + + .. grid-item:: + :ref:`type` + + .. grid-item:: + :ref:`castshadow` + + .. grid-item:: + :ref:`active` + .. grid-item:: :ref:`pos` @@ -5852,18 +5864,6 @@ .. grid-item:: :ref:`range` - .. grid-item:: - :ref:`directional` - - .. grid-item:: - :ref:`type` - - .. grid-item:: - :ref:`castshadow` - - .. grid-item:: - :ref:`active` - .. grid-item:: :ref:`attenuation` @@ -5990,6 +5990,24 @@ .. grid:: 2 3 4 4 :gutter: 0 + .. grid-item:: + :ref:`group` + + .. grid-item:: + :ref:`nsample` + + .. grid-item:: + :ref:`interp` + + .. grid-item:: + :ref:`delay` + + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`user` + .. grid-item:: :ref:`ctrllimited` @@ -5999,9 +6017,6 @@ .. grid-item:: :ref:`actlimited` - .. grid-item:: - :ref:`ctrlrange` - .. grid-item:: :ref:`forcerange` @@ -6020,21 +6035,6 @@ .. grid-item:: :ref:`cranklength` - .. grid-item:: - :ref:`user` - - .. grid-item:: - :ref:`group` - - .. grid-item:: - :ref:`nsample` - - .. grid-item:: - :ref:`interp` - - .. grid-item:: - :ref:`delay` - .. grid-item:: :ref:`actdim` @@ -6074,15 +6074,30 @@ .. grid:: 2 3 4 4 :gutter: 0 + .. grid-item:: + :ref:`group` + + .. grid-item:: + :ref:`nsample` + + .. grid-item:: + :ref:`interp` + + .. grid-item:: + :ref:`delay` + + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`user` + .. grid-item:: :ref:`ctrllimited` .. grid-item:: :ref:`forcelimited` - .. grid-item:: - :ref:`ctrlrange` - .. grid-item:: :ref:`forcerange` @@ -6098,36 +6113,36 @@ .. grid-item:: :ref:`cranklength` - .. grid-item:: - :ref:`user` - - .. grid-item:: - :ref:`group` - - .. grid-item:: - :ref:`nsample` - - .. grid-item:: - :ref:`interp` - - .. grid-item:: - :ref:`delay` - .. dropdown:: :ref:`position` :octicon:`dot` .. grid:: 2 3 4 4 :gutter: 0 + .. grid-item:: + :ref:`group` + + .. grid-item:: + :ref:`nsample` + + .. grid-item:: + :ref:`interp` + + .. grid-item:: + :ref:`delay` + + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`user` + .. grid-item:: :ref:`ctrllimited` .. grid-item:: :ref:`forcelimited` - .. grid-item:: - :ref:`ctrlrange` - .. grid-item:: :ref:`inheritrange` @@ -6146,21 +6161,6 @@ .. grid-item:: :ref:`cranklength` - .. grid-item:: - :ref:`user` - - .. grid-item:: - :ref:`group` - - .. grid-item:: - :ref:`nsample` - - .. grid-item:: - :ref:`interp` - - .. grid-item:: - :ref:`delay` - .. grid-item:: :ref:`kp` @@ -6179,15 +6179,30 @@ .. grid:: 2 3 4 4 :gutter: 0 + .. grid-item:: + :ref:`group` + + .. grid-item:: + :ref:`nsample` + + .. grid-item:: + :ref:`interp` + + .. grid-item:: + :ref:`delay` + + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`user` + .. grid-item:: :ref:`ctrllimited` .. grid-item:: :ref:`forcelimited` - .. grid-item:: - :ref:`ctrlrange` - .. grid-item:: :ref:`forcerange` @@ -6203,21 +6218,6 @@ .. grid-item:: :ref:`cranklength` - .. grid-item:: - :ref:`user` - - .. grid-item:: - :ref:`group` - - .. grid-item:: - :ref:`nsample` - - .. grid-item:: - :ref:`interp` - - .. grid-item:: - :ref:`delay` - .. grid-item:: :ref:`kv` @@ -6227,6 +6227,24 @@ .. grid:: 2 3 4 4 :gutter: 0 + .. grid-item:: + :ref:`group` + + .. grid-item:: + :ref:`nsample` + + .. grid-item:: + :ref:`interp` + + .. grid-item:: + :ref:`delay` + + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`user` + .. grid-item:: :ref:`ctrllimited` @@ -6236,9 +6254,6 @@ .. grid-item:: :ref:`actlimited` - .. grid-item:: - :ref:`ctrlrange` - .. grid-item:: :ref:`forcerange` @@ -6260,21 +6275,6 @@ .. grid-item:: :ref:`cranklength` - .. grid-item:: - :ref:`user` - - .. grid-item:: - :ref:`group` - - .. grid-item:: - :ref:`nsample` - - .. grid-item:: - :ref:`interp` - - .. grid-item:: - :ref:`delay` - .. grid-item:: :ref:`kp` @@ -6290,18 +6290,6 @@ .. grid:: 2 3 4 4 :gutter: 0 - .. grid-item:: - :ref:`forcelimited` - - .. grid-item:: - :ref:`ctrlrange` - - .. grid-item:: - :ref:`forcerange` - - .. grid-item:: - :ref:`user` - .. grid-item:: :ref:`group` @@ -6314,6 +6302,18 @@ .. grid-item:: :ref:`delay` + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`user` + + .. grid-item:: + :ref:`forcelimited` + + .. grid-item:: + :ref:`forcerange` + .. grid-item:: :ref:`kp` @@ -6332,15 +6332,30 @@ .. grid:: 2 3 4 4 :gutter: 0 + .. grid-item:: + :ref:`group` + + .. grid-item:: + :ref:`nsample` + + .. grid-item:: + :ref:`interp` + + .. grid-item:: + :ref:`delay` + + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`user` + .. grid-item:: :ref:`ctrllimited` .. grid-item:: :ref:`forcelimited` - .. grid-item:: - :ref:`ctrlrange` - .. grid-item:: :ref:`posrange` @@ -6368,21 +6383,6 @@ .. grid-item:: :ref:`cranklength` - .. grid-item:: - :ref:`user` - - .. grid-item:: - :ref:`group` - - .. grid-item:: - :ref:`nsample` - - .. grid-item:: - :ref:`interp` - - .. grid-item:: - :ref:`delay` - .. grid-item:: :ref:`kp` @@ -6411,11 +6411,26 @@ :gutter: 0 .. grid-item:: - :ref:`forcelimited` + :ref:`group` + + .. grid-item:: + :ref:`nsample` + + .. grid-item:: + :ref:`interp` + + .. grid-item:: + :ref:`delay` .. grid-item:: :ref:`ctrlrange` + .. grid-item:: + :ref:`user` + + .. grid-item:: + :ref:`forcelimited` + .. grid-item:: :ref:`forcerange` @@ -6431,21 +6446,6 @@ .. grid-item:: :ref:`cranklength` - .. grid-item:: - :ref:`user` - - .. grid-item:: - :ref:`group` - - .. grid-item:: - :ref:`nsample` - - .. grid-item:: - :ref:`interp` - - .. grid-item:: - :ref:`delay` - .. grid-item:: :ref:`kv` @@ -6455,15 +6455,30 @@ .. grid:: 2 3 4 4 :gutter: 0 + .. grid-item:: + :ref:`group` + + .. grid-item:: + :ref:`nsample` + + .. grid-item:: + :ref:`interp` + + .. grid-item:: + :ref:`delay` + + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`user` + .. grid-item:: :ref:`ctrllimited` .. grid-item:: :ref:`forcelimited` - .. grid-item:: - :ref:`ctrlrange` - .. grid-item:: :ref:`forcerange` @@ -6479,21 +6494,6 @@ .. grid-item:: :ref:`cranklength` - .. grid-item:: - :ref:`user` - - .. grid-item:: - :ref:`group` - - .. grid-item:: - :ref:`nsample` - - .. grid-item:: - :ref:`interp` - - .. grid-item:: - :ref:`delay` - .. grid-item:: :ref:`timeconst` @@ -6512,15 +6512,30 @@ .. grid:: 2 3 4 4 :gutter: 0 + .. grid-item:: + :ref:`group` + + .. grid-item:: + :ref:`nsample` + + .. grid-item:: + :ref:`interp` + + .. grid-item:: + :ref:`delay` + + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`user` + .. grid-item:: :ref:`ctrllimited` .. grid-item:: :ref:`forcelimited` - .. grid-item:: - :ref:`ctrlrange` - .. grid-item:: :ref:`forcerange` @@ -6536,21 +6551,6 @@ .. grid-item:: :ref:`cranklength` - .. grid-item:: - :ref:`user` - - .. grid-item:: - :ref:`group` - - .. grid-item:: - :ref:`nsample` - - .. grid-item:: - :ref:`interp` - - .. grid-item:: - :ref:`delay` - .. grid-item:: :ref:`timeconst` @@ -6584,21 +6584,6 @@ .. grid:: 2 3 4 4 :gutter: 0 - .. grid-item:: - :ref:`forcelimited` - - .. grid-item:: - :ref:`ctrlrange` - - .. grid-item:: - :ref:`forcerange` - - .. grid-item:: - :ref:`gain` - - .. grid-item:: - :ref:`user` - .. grid-item:: :ref:`group` @@ -6611,33 +6596,27 @@ .. grid-item:: :ref:`delay` + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`user` + + .. grid-item:: + :ref:`forcelimited` + + .. grid-item:: + :ref:`forcerange` + + .. grid-item:: + :ref:`gain` + .. dropdown:: :ref:`dcmotor` :octicon:`dot` .. grid:: 2 3 4 4 :gutter: 0 - .. grid-item:: - :ref:`ctrllimited` - - .. grid-item:: - :ref:`ctrlrange` - - .. grid-item:: - :ref:`gear` - - .. grid-item:: - :ref:`damping` - - .. grid-item:: - :ref:`armature` - - .. grid-item:: - :ref:`cranklength` - - .. grid-item:: - :ref:`user` - .. grid-item:: :ref:`group` @@ -6650,6 +6629,27 @@ .. grid-item:: :ref:`delay` + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`user` + + .. grid-item:: + :ref:`ctrllimited` + + .. grid-item:: + :ref:`gear` + + .. grid-item:: + :ref:`damping` + + .. grid-item:: + :ref:`armature` + + .. grid-item:: + :ref:`cranklength` + .. grid-item:: :ref:`motorconst` @@ -6671,15 +6671,15 @@ .. grid-item:: :ref:`controller` - .. grid-item:: - :ref:`input` - .. grid-item:: :ref:`thermal` .. grid-item:: :ref:`lugre` + .. grid-item:: + :ref:`input` + .. dropdown:: :ref:`custom` |*| @@ -6766,5 +6766,3 @@ .. grid-item:: :ref:`value` - - diff --git a/doc/generate/generate_mjcf_table.py b/doc/generate/generate_mjcf_table.py new file mode 100644 index 00000000..b2f5e537 --- /dev/null +++ b/doc/generate/generate_mjcf_table.py @@ -0,0 +1,181 @@ +# Copyright 2026 DeepMind Technologies Limited +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Generates the MJCF[] grammar table from src/xml/mjcf.schema. + +The table (src/xml/mjcf_table.inc) is the element tree consumed by the +mjXSchema validator: rows of {name, cardinality, attributes...} with +{"<"}/{">"} nesting markers. It is checked in and gated by +test/doc/doc_test.py, which regenerates it from the schema and diffs. +""" + +import sys + +import os +_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, _SCRIPT_DIR) +import mjcf_schema +_REPO_ROOT = os.path.dirname(os.path.dirname(_SCRIPT_DIR)) +SCHEMA_PATH = os.path.join(_REPO_ROOT, 'src', 'xml', 'mjcf.schema') + +_HEADER = '''\ +// Copyright 2026 DeepMind Technologies Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// GENERATED FILE, DO NOT EDIT. Generated from src/xml/mjcf.schema by +// doc/generate/generate_mjcf_table.py; test/doc/doc_test.py checks freshness. +// +// The MJCF grammar table consumed by mjXSchema: rows of {name, cardinality, +// attributes...} with {"<"}/{">"} nesting markers. worldbody, frame and +// replicate have no rows: mjXSchema::NameMatch validates them against the +// body row (see the alias= facets in mjcf.schema). + +// clang-format off +''' + +_WIDTH = 100 + + +def _wrap_row(parts: list[str], indent: int) -> list[str]: + """One {...}, initializer, wrapped at _WIDTH with hanging indent.""" + lines = [] + line = ' ' * indent + '{' + parts[0] + for part in parts[1:]: + candidate = f'{line}, {part}' + if len(candidate) + 2 > _WIDTH: # room for "}," + lines.append(line + ',') + line = ' ' * (indent + 4) + part + else: + line = candidate + lines.append(line + '},') + return lines + + +KIND_CHAR = {'exclusive': 'e', 'together': 't', 'requires': 'r', + 'oneof': 'o'} + + +def _element_constraints(schema, element): + """Element's own constraints plus those of transitively used groups.""" + cons = list(element.constraints()) + visited = set() + stack = [m.group for m in element.members + if isinstance(m, mjcf_schema.Use)] + while stack: + name = stack.pop() + if name in visited: + continue + visited.add(name) + group = schema.groups[name] + for member in group.members: + if isinstance(member, mjcf_schema.Constraint): + cons.append(member) + elif isinstance(member, mjcf_schema.Use): + stack.append(member.group) + return cons + + +def generate() -> str: + """Generates the C++ grammar table header file contents from mjcf.schema.""" + schema = mjcf_schema.parse_file(SCHEMA_PATH) + out = [] + constraints = [] + count = 0 + + def emit_entry(lines: list[str]): + nonlocal count + out.extend(lines) + count += 1 + + def visit(element: mjcf_schema.Element, card: str, indent: int, + project: bool): + # a row in default context is the element's defaultable projection + attrs = [a for a in schema.expanded_attrs(element)] + if project: + attrs = [a for a in attrs + if a.name not in ('name', 'class') + and not a.facets.get('nodefault')] + parts = [f'"{element.xml_name()}"', f'"{card}"'] + parts += [f'"{a.name}"' for a in attrs] + row_index = count + emit_entry(_wrap_row(parts, indent)) + + # presence constraints whose attributes all survive in this row + row_attrs = {a.name for a in attrs} + for con in _element_constraints(schema, element): + if all(all(n in row_attrs for n in b) for b in con.bundles): + spec = '|'.join(' '.join(b) for b in con.bundles) + constraints.append(f" {{{row_index}, '{KIND_CHAR[con.kind]}', " + f'"{spec}"}},') + + children = [c for c in element.children() if c.name != element.name] + if project: + # plugin configuration is not settable per-class + children = [c for c in children if c.name != 'plugin'] + if not children: + return + emit_entry([' ' * indent + '{"<"},']) + for child in children: + decl = schema.elements[child.name] + child_project = project or ( + element.name == 'default' and not child.name.startswith('default_')) + visit(decl, child.card, indent + 4, child_project) + if indent == 0: + out.append('') + emit_entry([' ' * indent + '{">"},']) + + visit(schema.elements['mujoco'], '!', 0, False) + + body = '\n'.join(out) + con_body = '\n'.join(constraints) + return (_HEADER + + 'std::vector MJCF[] = {\n' + body + '\n};\n' + '// clang-format on\n\n' + 'const int nMJCF = sizeof(MJCF) / sizeof(MJCF[0]);\n\n' + '// presence constraints, indexed into MJCF[]; enforced by\n' + '// mjXSchema::Check. spec: attribute bundles, space-joined,\n' + "// '|'-separated; kind: e=exclusive t=together r=requires o=oneof\n" + '// clang-format off\n' + 'const mjXConstraintDef MJCF_constraints[] = {\n' + con_body + + '\n};\n' + '// clang-format on\n\n' + 'const int nMJCF_constraints = ' + 'sizeof(MJCF_constraints) / sizeof(MJCF_constraints[0]);\n') + + +def main() -> int: + if len(sys.argv) > 2: + sys.exit('usage: generate_mjcf_table.py [output.inc]') + text = generate() + if len(sys.argv) == 2: + with open(sys.argv[1], 'w', encoding='utf-8') as file: + file.write(text) + else: + sys.stdout.write(text) + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/doc/generate/generate_schema.py b/doc/generate/generate_schema.py index 71a1e8c1..ba213cc7 100644 --- a/doc/generate/generate_schema.py +++ b/doc/generate/generate_schema.py @@ -113,18 +113,18 @@ def generate_dropdown( def generate() -> str: - """Generates XMLschema.rst by parsing xml_native_reader.cc. + """Generates XMLschema.rst by parsing mjcf_table.inc. - The schema is defined in xml_native_reader.cc as a nested structure called - MJCF[nMJCF]. This function parses that structure and generates nested - dropdown directives with list-tables for attributes. + The schema is defined in mjcf_table.inc (generated from mjcf.schema) as a + nested structure called MJCF[]. This function parses that structure and + generates nested dropdown directives with list-tables for attributes. Returns: RST content with nested dropdown directives for the MJCF schema. """ script_dir = os.path.dirname(os.path.abspath(__file__)) repo_root = os.path.dirname(os.path.dirname(script_dir)) - filepath = os.path.join(repo_root, 'src', 'xml', 'xml_native_reader.cc') + filepath = os.path.join(repo_root, 'src', 'xml', 'mjcf_table.inc') xmlfile = os.path.join(repo_root, 'doc', 'XMLreference.rst') # Collect all link targets from XMLreference.rst for validation. @@ -159,7 +159,7 @@ def generate() -> str: # Skip to the MJCF schema definition in the C++ source. for line in file: - if 'std::vector MJCF[nMJCF] = {' in line.strip(): + if 'std::vector MJCF[] = {' in line.strip(): break # Parse the schema structure. @@ -224,7 +224,8 @@ def generate() -> str: parent[level + 1] = element[0] element = [] - return output + # single newline at end of file + return output.rstrip('\n') + '\n' def main() -> int: diff --git a/src/xml/mjcf_table.inc b/src/xml/mjcf_table.inc new file mode 100644 index 00000000..ebc97710 --- /dev/null +++ b/src/xml/mjcf_table.inc @@ -0,0 +1,542 @@ +// Copyright 2026 DeepMind Technologies Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// GENERATED FILE, DO NOT EDIT. Generated from src/xml/mjcf.schema by +// doc/generate/generate_mjcf_table.py; test/doc/doc_test.py checks freshness. +// +// The MJCF grammar table consumed by mjXSchema: rows of {name, cardinality, +// attributes...} with {"<"}/{">"} nesting markers. worldbody, frame and +// replicate have no rows: mjXSchema::NameMatch validates them against the +// body row (see the alias= facets in mjcf.schema). + +// clang-format off +std::vector MJCF[] = { +{"mujoco", "!", "model"}, +{"<"}, + {"compiler", "*", "autolimits", "boundmass", "boundinertia", "settotalmass", "balanceinertia", + "strippath", "coordinate", "angle", "fitaabb", "eulerseq", "meshdir", "texturedir", + "discardvisual", "usethread", "fusestatic", "inertiafromgeom", "inertiagrouprange", + "saveinertial", "assetdir", "alignfree", "conflict"}, + {"<"}, + {"lengthrange", "?", "mode", "useexisting", "uselimit", "accel", "maxforce", "timeconst", + "timestep", "inttotal", "interval", "tolrange"}, + {">"}, + + {"option", "*", "timestep", "impratio", "tolerance", "ls_tolerance", "noslip_tolerance", + "ccd_tolerance", "sleep_tolerance", "gravity", "wind", "magnetic", "density", "viscosity", + "o_margin", "o_solref", "o_solimp", "o_friction", "integrator", "cone", "jacobian", + "solver", "iterations", "ls_iterations", "noslip_iterations", "ccd_iterations", + "sdf_iterations", "sdf_initpoints", "actuatorgroupdisable"}, + {"<"}, + {"flag", "?", "constraint", "equality", "frictionloss", "limit", "contact", "spring", + "damper", "gravity", "clampctrl", "warmstart", "filterparent", "actuation", "refsafe", + "sensor", "midphase", "eulerdamp", "autoreset", "nativeccd", "island", "multiccd", + "override", "energy", "fwdinv", "invdiscrete", "sleep", "diagexact"}, + {">"}, + + {"size", "*", "memory", "njmax", "nconmax", "nstack", "nuserdata", "nkey", "nuser_body", + "nuser_jnt", "nuser_geom", "nuser_site", "nuser_cam", "nuser_tendon", "nuser_actuator", + "nuser_sensor"}, + + {"statistic", "*", "meaninertia", "meanmass", "meansize", "extent", "center"}, + + {"visual", "*"}, + {"<"}, + {"global", "?", "cameraid", "orthographic", "fovy", "ipd", "azimuth", "elevation", + "linewidth", "glow", "offwidth", "offheight", "realtime", "ellipsoidinertia", + "bvactive"}, + {"quality", "?", "shadowsize", "offsamples", "numslices", "numstacks", "numquads"}, + {"headlight", "?", "ambient", "diffuse", "specular", "active"}, + {"map", "?", "stiffness", "stiffnessrot", "force", "torque", "alpha", "fogstart", "fogend", + "znear", "zfar", "haze", "shadowclip", "shadowscale", "actuatortendon"}, + {"scale", "?", "forcewidth", "contactwidth", "contactheight", "connect", "com", "camera", + "light", "selectpoint", "jointlength", "jointwidth", "actuatorlength", "actuatorwidth", + "framelength", "framewidth", "constraint", "slidercrank", "frustum"}, + {"rgba", "?", "fog", "haze", "force", "inertia", "joint", "actuator", "actuatornegative", + "actuatorpositive", "com", "camera", "light", "selectpoint", "connect", "contactpoint", + "contactforce", "contactfriction", "contacttorque", "contactgap", "rangefinder", + "constraint", "slidercrank", "crankbroken", "frustum", "bv", "bvactive"}, + {">"}, + + {"default", "R", "class"}, + {"<"}, + {"mesh", "?", "scale", "maxhullvert", "inertia"}, + {"material", "?", "texture", "texrepeat", "texuniform", "emission", "specular", + "shininess", "reflectance", "metallic", "roughness", "rgba"}, + {"<"}, + {"layer", "*", "texture", "role"}, + {">"}, + {"joint", "?", "type", "group", "pos", "axis", "springdamper", "limited", + "actuatorfrclimited", "solreflimit", "solimplimit", "solreffriction", "solimpfriction", + "stiffness", "range", "actuatorfrcrange", "actuatorgravcomp", "margin", "ref", + "springref", "armature", "damping", "frictionloss", "user"}, + {"geom", "?", "type", "contype", "conaffinity", "condim", "group", "priority", "size", + "material", "friction", "mass", "density", "shellinertia", "solmix", "solref", + "solimp", "margin", "gap", "surfacevel", "adhesion", "fromto", "pos", "quat", + "axisangle", "xyaxes", "zaxis", "euler", "hfield", "mesh", "fitscale", "rgba", + "fluidshape", "fluidcoef", "user"}, + {"site", "?", "type", "group", "pos", "quat", "axisangle", "xyaxes", "zaxis", "euler", + "material", "size", "fromto", "rgba", "user"}, + {"camera", "?", "projection", "fovy", "ipd", "resolution", "output", "pos", "quat", + "axisangle", "xyaxes", "zaxis", "euler", "mode", "focal", "focalpixel", "principal", + "principalpixel", "sensorsize", "user"}, + {"light", "?", "directional", "type", "castshadow", "active", "pos", "dir", "bulbradius", + "intensity", "range", "attenuation", "cutoff", "exponent", "ambient", "diffuse", + "specular", "mode"}, + {"pair", "?", "condim", "friction", "solref", "solreffriction", "solimp", "gap", "margin", + "adhesion"}, + {"equality", "?", "active", "solref", "solimp"}, + {"tendon", "?", "group", "limited", "range", "solreflimit", "solimplimit", + "solreffriction", "solimpfriction", "frictionloss", "springlength", "width", + "material", "margin", "stiffness", "damping", "rgba", "user"}, + {"general", "?", "group", "nsample", "interp", "delay", "ctrlrange", "user", "ctrllimited", + "forcelimited", "actlimited", "forcerange", "actrange", "gear", "damping", "armature", + "cranklength", "actdim", "input", "velrange", "ffrange", "dyntype", "gaintype", + "biastype", "dynprm", "gainprm", "biasprm", "actearly"}, + {"motor", "?", "group", "nsample", "interp", "delay", "ctrlrange", "user", "ctrllimited", + "forcelimited", "forcerange", "gear", "damping", "armature", "cranklength"}, + {"position", "?", "group", "nsample", "interp", "delay", "ctrlrange", "user", + "ctrllimited", "forcelimited", "inheritrange", "forcerange", "gear", "damping", + "armature", "cranklength", "kp", "kv", "dampratio", "timeconst"}, + {"velocity", "?", "group", "nsample", "interp", "delay", "ctrlrange", "user", + "ctrllimited", "forcelimited", "forcerange", "gear", "damping", "armature", + "cranklength", "kv"}, + {"intvelocity", "?", "group", "nsample", "interp", "delay", "ctrlrange", "user", + "ctrllimited", "forcelimited", "actlimited", "forcerange", "actrange", "inheritrange", + "gear", "damping", "armature", "cranklength", "kp", "kv", "dampratio"}, + {"orientation", "?", "group", "nsample", "interp", "delay", "ctrlrange", "user", + "forcelimited", "forcerange", "kp", "kv", "dampratio", "input"}, + {"pid", "?", "group", "nsample", "interp", "delay", "ctrlrange", "user", "ctrllimited", + "forcelimited", "posrange", "velrange", "ffrange", "forcerange", "inheritrange", + "gear", "damping", "armature", "cranklength", "kp", "kv", "dampratio", "ki", "imax", + "slewmax", "input"}, + {"damper", "?", "group", "nsample", "interp", "delay", "ctrlrange", "user", "forcelimited", + "forcerange", "gear", "damping", "armature", "cranklength", "kv"}, + {"cylinder", "?", "group", "nsample", "interp", "delay", "ctrlrange", "user", + "ctrllimited", "forcelimited", "forcerange", "gear", "damping", "armature", + "cranklength", "timeconst", "area", "diameter", "bias"}, + {"muscle", "?", "group", "nsample", "interp", "delay", "ctrlrange", "user", "ctrllimited", + "forcelimited", "forcerange", "gear", "damping", "armature", "cranklength", + "timeconst", "range", "force", "scale", "lmin", "lmax", "vmax", "fpmax", "fvmax"}, + {"adhesion", "?", "group", "nsample", "interp", "delay", "ctrlrange", "user", + "forcelimited", "forcerange", "gain"}, + {"dcmotor", "?", "group", "nsample", "interp", "delay", "ctrlrange", "user", "ctrllimited", + "gear", "damping", "armature", "cranklength", "motorconst", "resistance", "nominal", + "saturation", "inductance", "cogging", "controller", "thermal", "lugre", "input"}, + {">"}, + + {"extension", "*"}, + {"<"}, + {"plugin", "*", "plugin"}, + {"<"}, + {"instance", "*", "name"}, + {"<"}, + {"config", "*", "key", "value"}, + {">"}, + {">"}, + {">"}, + + {"asset", "*"}, + {"<"}, + {"mesh", "*", "name", "class", "content_type", "file", "vertex", "normal", "texcoord", + "face", "refpos", "refquat", "scale", "smoothnormal", "maxhullvert", "inertia", + "builtin", "params", "material"}, + {"<"}, + {"plugin", "*", "plugin", "instance"}, + {"<"}, + {"config", "*", "key", "value"}, + {">"}, + {">"}, + {"hfield", "*", "name", "content_type", "file", "nrow", "ncol", "size", "elevation"}, + {"skin", "*", "name", "file", "material", "rgba", "inflate", "vertex", "texcoord", "face", + "group"}, + {"<"}, + {"bone", "*", "body", "bindpos", "bindquat", "vertid", "vertweight"}, + {">"}, + {"texture", "*", "name", "type", "colorspace", "content_type", "file", "gridsize", + "gridlayout", "fileright", "fileleft", "fileup", "filedown", "filefront", "fileback", + "builtin", "rgb1", "rgb2", "mark", "markrgb", "random", "width", "height", "hflip", + "vflip", "nchannel"}, + {"material", "*", "name", "class", "texture", "texrepeat", "texuniform", "emission", + "specular", "shininess", "reflectance", "metallic", "roughness", "rgba"}, + {"<"}, + {"layer", "*", "texture", "role"}, + {">"}, + {"model", "*", "name", "file", "content_type"}, + {">"}, + + {"body", "R", "name", "childclass", "pos", "quat", "axisangle", "xyaxes", "zaxis", "euler", + "mocap", "gravcomp", "sleep", "simple", "user"}, + {"<"}, + {"inertial", "?", "pos", "quat", "mass", "diaginertia", "axisangle", "xyaxes", "zaxis", + "euler", "fullinertia"}, + {"joint", "*", "name", "class", "type", "group", "pos", "axis", "springdamper", "limited", + "actuatorfrclimited", "solreflimit", "solimplimit", "solreffriction", "solimpfriction", + "stiffness", "range", "actuatorfrcrange", "actuatorgravcomp", "margin", "ref", + "springref", "armature", "damping", "frictionloss", "user"}, + {"freejoint", "*", "name", "group", "align"}, + {"geom", "*", "name", "class", "type", "contype", "conaffinity", "condim", "group", + "priority", "size", "material", "friction", "mass", "density", "shellinertia", + "solmix", "solref", "solimp", "margin", "gap", "surfacevel", "adhesion", "fromto", + "pos", "quat", "axisangle", "xyaxes", "zaxis", "euler", "hfield", "mesh", "fitscale", + "rgba", "fluidshape", "fluidcoef", "user"}, + {"<"}, + {"plugin", "*", "plugin", "instance"}, + {"<"}, + {"config", "*", "key", "value"}, + {">"}, + {">"}, + {"attach", "*", "model", "body", "frame", "prefix"}, + {"site", "*", "name", "class", "type", "group", "pos", "quat", "axisangle", "xyaxes", + "zaxis", "euler", "material", "size", "fromto", "rgba", "user"}, + {"camera", "*", "name", "class", "projection", "fovy", "ipd", "resolution", "output", + "pos", "quat", "axisangle", "xyaxes", "zaxis", "euler", "mode", "target", "focal", + "focalpixel", "principal", "principalpixel", "sensorsize", "user"}, + {"light", "*", "name", "class", "directional", "type", "castshadow", "active", "pos", + "dir", "bulbradius", "intensity", "range", "attenuation", "cutoff", "exponent", + "ambient", "diffuse", "specular", "mode", "target", "texture"}, + {"plugin", "*", "plugin", "instance"}, + {"<"}, + {"config", "*", "key", "value"}, + {">"}, + {"composite", "*", "prefix", "type", "count", "offset", "vertex", "initial", "curve", + "size", "quat"}, + {"<"}, + {"joint", "*", "kind", "group", "stiffness", "damping", "armature", "solreffix", + "solimpfix", "type", "axis", "limited", "range", "margin", "solreflimit", + "solimplimit", "frictionloss", "solreffriction", "solimpfriction"}, + {"skin", "?", "texcoord", "material", "group", "rgba", "inflate", "subgrid"}, + {"geom", "?", "type", "contype", "conaffinity", "condim", "group", "priority", "size", + "material", "rgba", "friction", "mass", "density", "solmix", "solref", "solimp", + "margin", "gap", "surfacevel", "adhesion"}, + {"site", "?", "group", "size", "material", "rgba"}, + {"plugin", "*", "plugin", "instance"}, + {"<"}, + {"config", "*", "key", "value"}, + {">"}, + {">"}, + {"flexcomp", "*", "name", "type", "group", "dim", "dof", "count", "cellcount", "spacing", + "radius", "rigid", "mass", "inertiabox", "scale", "file", "point", "element", + "texcoord", "material", "rgba", "flatskin", "pos", "quat", "axisangle", "xyaxes", + "zaxis", "euler", "origin"}, + {"<"}, + {"edge", "?", "equality", "solref", "solimp", "stiffness", "damping"}, + {"elasticity", "?", "young", "poisson", "damping", "thickness", "elastic2d"}, + {"contact", "?", "contype", "conaffinity", "condim", "priority", "friction", "solmix", + "solref", "solimp", "margin", "gap", "internal", "selfcollide", "activelayers", + "passive"}, + {"pin", "*", "id", "range", "grid", "gridrange"}, + {"plugin", "*", "plugin", "instance"}, + {"<"}, + {"config", "*", "key", "value"}, + {">"}, + {">"}, + {">"}, + + {"deformable", "*"}, + {"<"}, + {"flex", "*", "name", "group", "dim", "radius", "material", "rgba", "flatskin", "body", + "vertex", "element", "texcoord", "elemtexcoord", "node", "cellcount", "dof"}, + {"<"}, + {"contact", "?", "contype", "conaffinity", "condim", "priority", "friction", "solmix", + "solref", "solimp", "margin", "gap", "internal", "selfcollide", "activelayers", + "passive"}, + {"edge", "?", "stiffness", "damping"}, + {"elasticity", "?", "young", "poisson", "damping", "thickness", "elastic2d"}, + {">"}, + {"skin", "*", "name", "file", "material", "rgba", "inflate", "vertex", "texcoord", "face", + "group"}, + {"<"}, + {"bone", "*", "body", "bindpos", "bindquat", "vertid", "vertweight"}, + {">"}, + {">"}, + + {"contact", "*"}, + {"<"}, + {"pair", "*", "name", "class", "geom1", "geom2", "condim", "friction", "solref", + "solreffriction", "solimp", "gap", "margin", "adhesion"}, + {"exclude", "*", "name", "body1", "body2"}, + {">"}, + + {"tendon", "*"}, + {"<"}, + {"spatial", "*", "name", "class", "group", "limited", "actuatorfrclimited", "range", + "actuatorfrcrange", "solreflimit", "solimplimit", "solreffriction", "solimpfriction", + "frictionloss", "springlength", "width", "material", "margin", "stiffness", "damping", + "armature", "rgba", "user"}, + {"<"}, + {"site", "*", "site"}, + {"geom", "*", "geom", "sidesite"}, + {"pulley", "*", "divisor"}, + {">"}, + {"fixed", "*", "name", "class", "group", "limited", "actuatorfrclimited", "range", + "actuatorfrcrange", "solreflimit", "solimplimit", "solreffriction", "solimpfriction", + "frictionloss", "springlength", "margin", "stiffness", "damping", "armature", "user"}, + {"<"}, + {"joint", "*", "joint", "coef"}, + {">"}, + {">"}, + + {"equality", "*"}, + {"<"}, + {"connect", "*", "name", "class", "active", "solref", "solimp", "body1", "body2", "anchor", + "site1", "site2"}, + {"weld", "*", "name", "class", "active", "solref", "solimp", "body1", "body2", "relpose", + "anchor", "site1", "site2", "torquescale"}, + {"joint", "*", "name", "class", "active", "solref", "solimp", "joint1", "joint2", + "polycoef"}, + {"tendon", "*", "name", "class", "active", "solref", "solimp", "tendon1", "tendon2", + "polycoef"}, + {"flex", "*", "name", "class", "active", "solref", "solimp", "flex"}, + {"flexvert", "*", "name", "class", "active", "solref", "solimp", "flex"}, + {"flexstrain", "*", "name", "class", "active", "solref", "solimp", "flex", "cell"}, + {">"}, + + {"actuator", "*"}, + {"<"}, + {"general", "*", "name", "class", "group", "nsample", "interp", "delay", "ctrlrange", + "user", "ctrllimited", "forcelimited", "actlimited", "forcerange", "actrange", + "lengthrange", "gear", "damping", "armature", "cranklength", "joint", "jointinparent", + "tendon", "slidersite", "cranksite", "site", "refsite", "body", "actdim", "input", + "velrange", "ffrange", "dyntype", "gaintype", "biastype", "dynprm", "gainprm", + "biasprm", "actearly"}, + {"motor", "*", "name", "class", "group", "nsample", "interp", "delay", "ctrlrange", "user", + "ctrllimited", "forcelimited", "forcerange", "lengthrange", "gear", "damping", + "armature", "cranklength", "joint", "jointinparent", "tendon", "slidersite", + "cranksite", "site", "refsite"}, + {"position", "*", "name", "class", "group", "nsample", "interp", "delay", "ctrlrange", + "user", "ctrllimited", "forcelimited", "inheritrange", "forcerange", "lengthrange", + "gear", "damping", "armature", "cranklength", "joint", "jointinparent", "tendon", + "slidersite", "cranksite", "site", "refsite", "kp", "kv", "dampratio", "timeconst"}, + {"velocity", "*", "name", "class", "group", "nsample", "interp", "delay", "ctrlrange", + "user", "ctrllimited", "forcelimited", "forcerange", "lengthrange", "gear", "damping", + "armature", "cranklength", "joint", "jointinparent", "tendon", "slidersite", + "cranksite", "site", "refsite", "kv"}, + {"intvelocity", "*", "name", "class", "group", "nsample", "interp", "delay", "ctrlrange", + "user", "ctrllimited", "forcelimited", "actlimited", "forcerange", "actrange", + "inheritrange", "lengthrange", "gear", "damping", "armature", "cranklength", "joint", + "jointinparent", "tendon", "slidersite", "cranksite", "site", "refsite", "kp", "kv", + "dampratio"}, + {"orientation", "*", "name", "class", "group", "nsample", "interp", "delay", "ctrlrange", + "user", "forcelimited", "forcerange", "joint", "site", "refsite", "kp", "kv", + "dampratio", "input"}, + {"pid", "*", "name", "class", "group", "nsample", "interp", "delay", "ctrlrange", "user", + "ctrllimited", "forcelimited", "posrange", "velrange", "ffrange", "forcerange", + "inheritrange", "lengthrange", "gear", "damping", "armature", "cranklength", "joint", + "jointinparent", "tendon", "slidersite", "cranksite", "site", "refsite", "kp", "kv", + "dampratio", "ki", "imax", "slewmax", "input"}, + {"damper", "*", "name", "class", "group", "nsample", "interp", "delay", "ctrlrange", + "user", "forcelimited", "forcerange", "lengthrange", "gear", "damping", "armature", + "cranklength", "joint", "jointinparent", "tendon", "slidersite", "cranksite", "site", + "refsite", "kv"}, + {"cylinder", "*", "name", "class", "group", "nsample", "interp", "delay", "ctrlrange", + "user", "ctrllimited", "forcelimited", "forcerange", "lengthrange", "gear", "damping", + "armature", "cranklength", "joint", "jointinparent", "tendon", "slidersite", + "cranksite", "site", "refsite", "timeconst", "area", "diameter", "bias"}, + {"muscle", "*", "name", "class", "group", "nsample", "interp", "delay", "ctrlrange", + "user", "ctrllimited", "forcelimited", "forcerange", "lengthrange", "gear", "damping", + "armature", "cranklength", "joint", "jointinparent", "tendon", "slidersite", + "cranksite", "timeconst", "tausmooth", "range", "force", "scale", "lmin", "lmax", + "vmax", "fpmax", "fvmax"}, + {"adhesion", "*", "name", "class", "group", "nsample", "interp", "delay", "ctrlrange", + "user", "forcelimited", "forcerange", "body", "gain"}, + {"dcmotor", "*", "name", "class", "group", "nsample", "interp", "delay", "ctrlrange", + "user", "ctrllimited", "lengthrange", "gear", "damping", "armature", "cranklength", + "joint", "jointinparent", "tendon", "slidersite", "cranksite", "site", "refsite", + "motorconst", "resistance", "nominal", "saturation", "inductance", "cogging", + "controller", "thermal", "lugre", "input"}, + {"plugin", "*", "name", "class", "group", "nsample", "interp", "delay", "ctrlrange", + "user", "plugin", "instance", "ctrllimited", "forcelimited", "actlimited", + "forcerange", "actrange", "lengthrange", "gear", "damping", "armature", "cranklength", + "joint", "jointinparent", "site", "actdim", "dyntype", "dynprm", "tendon", "cranksite", + "slidersite", "actearly"}, + {"<"}, + {"config", "*", "key", "value"}, + {">"}, + {">"}, + + {"sensor", "*"}, + {"<"}, + {"touch", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user", + "site"}, + {"accelerometer", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "site"}, + {"velocimeter", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "site"}, + {"gyro", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user", + "site"}, + {"force", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user", + "site"}, + {"torque", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "site"}, + {"magnetometer", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "site"}, + {"camprojection", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "site", "camera"}, + {"rangefinder", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "site", "camera", "data"}, + {"jointpos", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "joint"}, + {"jointvel", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "joint"}, + {"tendonpos", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "tendon"}, + {"tendonvel", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "tendon"}, + {"actuatorpos", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "actuator"}, + {"actuatorvel", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "actuator"}, + {"actuatorfrc", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "actuator"}, + {"jointactuatorfrc", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", + "noise", "user", "joint"}, + {"tendonactuatorfrc", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", + "noise", "user", "tendon"}, + {"ballquat", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "joint"}, + {"ballangvel", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "joint"}, + {"jointlimitpos", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "joint"}, + {"jointlimitvel", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "joint"}, + {"jointlimitfrc", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "joint"}, + {"tendonlimitpos", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", + "noise", "user", "tendon"}, + {"tendonlimitvel", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", + "noise", "user", "tendon"}, + {"tendonlimitfrc", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", + "noise", "user", "tendon"}, + {"framepos", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "objtype", "objname", "reftype", "refname"}, + {"framequat", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "objtype", "objname", "reftype", "refname"}, + {"framexaxis", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "objtype", "objname", "reftype", "refname"}, + {"frameyaxis", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "objtype", "objname", "reftype", "refname"}, + {"framezaxis", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "objtype", "objname", "reftype", "refname"}, + {"framelinvel", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "objtype", "objname", "reftype", "refname"}, + {"frameangvel", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "objtype", "objname", "reftype", "refname"}, + {"framelinacc", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "objtype", "objname"}, + {"frameangacc", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "objtype", "objname"}, + {"subtreecom", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "body"}, + {"subtreelinvel", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "body"}, + {"subtreeangmom", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "body"}, + {"insidesite", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "site", "objtype", "objname"}, + {"distance", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "geom1", "geom2", "body1", "body2"}, + {"normal", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "geom1", "geom2", "body1", "body2"}, + {"fromto", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "geom1", "geom2", "body1", "body2"}, + {"contact", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user", "geom1", "geom2", "body1", "body2", "subtree1", "subtree2", "site", "num", + "data", "reduce"}, + {"e_potential", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user"}, + {"e_kinetic", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", + "user"}, + {"clock", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, + {"tactile", "*", "name", "geom", "mesh", "nsample", "interp", "delay", "interval", "user"}, + {"user", "*", "name", "objtype", "objname", "datatype", "needstage", "dim", "cutoff", + "noise", "user"}, + {"plugin", "*", "name", "plugin", "instance", "cutoff", "objtype", "objname", "reftype", + "refname", "user"}, + {"<"}, + {"config", "*", "key", "value"}, + {">"}, + {">"}, + + {"custom", "*"}, + {"<"}, + {"numeric", "*", "name", "size", "data"}, + {"text", "*", "name", "data"}, + {"tuple", "*", "name"}, + {"<"}, + {"element", "*", "objtype", "objname", "prm"}, + {">"}, + {">"}, + + {"keyframe", "*"}, + {"<"}, + {"key", "*", "name", "time", "qpos", "qvel", "act", "mpos", "mquat", "ctrl"}, + {">"}, + +{">"}, +}; +// clang-format on + +const int nMJCF = sizeof(MJCF) / sizeof(MJCF[0]); + +// presence constraints, indexed into MJCF[]; enforced by +// mjXSchema::Check. spec: attribute bundles, space-joined, +// '|'-separated; kind: e=exclusive t=together r=requires o=oneof +// clang-format off +const mjXConstraintDef MJCF_constraints[] = { + {10, 'e', "memory|nstack"}, + {10, 'e', "memory|njmax"}, + {31, 'e', "fovy|sensorsize"}, + {32, 'e', "directional|type"}, + {61, 'e', "builtin|file"}, + {61, 'e', "builtin|vertex"}, + {82, 'e', "fullinertia|quat|axisangle|xyaxes|zaxis|euler"}, + {92, 'e', "body|frame"}, + {94, 'e', "fovy|sensorsize"}, + {95, 'e', "directional|type"}, + {156, 'e', "site1 site2|body1 body2 anchor"}, + {156, 'o', "site1 site2|body1 anchor"}, + {156, 't', "site1|site2"}, + {157, 'e', "site1 site2|body1 body2 anchor relpose"}, + {157, 'o', "site1 site2|body1"}, + {157, 't', "site1|site2"}, + {193, 'e', "site|camera"}, + {193, 'o', "site|camera"}, + {211, 't', "reftype|refname"}, + {212, 't', "reftype|refname"}, + {213, 't', "reftype|refname"}, + {214, 't', "reftype|refname"}, + {215, 't', "reftype|refname"}, + {216, 't', "reftype|refname"}, + {217, 't', "reftype|refname"}, + {224, 'e', "geom1|body1"}, + {224, 'o', "geom1|body1"}, + {224, 'e', "geom2|body2"}, + {224, 'o', "geom2|body2"}, + {225, 'e', "geom1|body1"}, + {225, 'o', "geom1|body1"}, + {225, 'e', "geom2|body2"}, + {225, 'o', "geom2|body2"}, + {226, 'e', "geom1|body1"}, + {226, 'o', "geom1|body1"}, + {226, 'e', "geom2|body2"}, + {226, 'o', "geom2|body2"}, + {227, 'e', "geom1|body1|subtree1|site"}, + {227, 'e', "geom2|body2|subtree2"}, + {232, 't', "objtype|objname"}, +}; +// clang-format on + +const int nMJCF_constraints = sizeof(MJCF_constraints) / sizeof(MJCF_constraints[0]); diff --git a/src/xml/xml_native_reader.cc b/src/xml/xml_native_reader.cc index 9855c85d..4e85a412 100644 --- a/src/xml/xml_native_reader.cc +++ b/src/xml/xml_native_reader.cc @@ -165,457 +165,7 @@ static void UpdateString(string& psuffix, int count, int i) { //---------------------------------- MJCF schema --------------------------------------------------- - -// clang-format off -std::vector MJCF[nMJCF] = { -{"mujoco", "!", "model"}, -{"<"}, - {"compiler", "*", "autolimits", "boundmass", "boundinertia", "settotalmass", - "balanceinertia", "strippath", "coordinate", "angle", "fitaabb", "eulerseq", - "meshdir", "texturedir", "discardvisual", "usethread", "fusestatic", "inertiafromgeom", - "inertiagrouprange", "saveinertial", "assetdir", "alignfree", "conflict"}, - {"<"}, - {"lengthrange", "?", "mode", "useexisting", "uselimit", - "accel", "maxforce", "timeconst", "timestep", - "inttotal", "interval", "tolrange"}, - {">"}, - - {"option", "*", - "timestep", "impratio", "tolerance", "ls_tolerance", "noslip_tolerance", - "ccd_tolerance", "sleep_tolerance", "gravity", "wind", "magnetic", "density", "viscosity", - "o_margin", "o_solref", "o_solimp", "o_friction", - "integrator", "cone", "jacobian", - "solver", "iterations", "ls_iterations", "noslip_iterations", "ccd_iterations", - "sdf_iterations", "sdf_initpoints", "actuatorgroupdisable"}, - {"<"}, - {"flag", "?", "constraint", "equality", "frictionloss", "limit", "contact", - "spring", "damper", "gravity", "clampctrl", "warmstart", "filterparent", "actuation", - "refsafe", "sensor", "midphase", "eulerdamp", "autoreset", "nativeccd", "island", - "override", "energy", "fwdinv", "invdiscrete", "multiccd", "sleep", - "diagexact"}, - {">"}, - - {"size", "*", "memory", "njmax", "nconmax", "nstack", "nuserdata", "nkey", - "nuser_body", "nuser_jnt", "nuser_geom", "nuser_site", "nuser_cam", - "nuser_tendon", "nuser_actuator", "nuser_sensor"}, - - {"visual", "*"}, - {"<"}, - {"global", "?", "cameraid", "orthographic", "fovy", "ipd", "azimuth", "elevation", - "linewidth", "glow", "offwidth", "offheight", "realtime", "ellipsoidinertia", - "bvactive"}, - {"quality", "?", "shadowsize", "offsamples", "numslices", "numstacks", - "numquads"}, - {"headlight", "?", "ambient", "diffuse", "specular", "active"}, - {"map", "?", "stiffness", "stiffnessrot", "force", "torque", "alpha", - "fogstart", "fogend", "znear", "zfar", "haze", "shadowclip", "shadowscale", - "actuatortendon"}, - {"scale", "?", "forcewidth", "contactwidth", "contactheight", "connect", "com", - "camera", "light", "selectpoint", "jointlength", "jointwidth", "actuatorlength", - "actuatorwidth", "framelength", "framewidth", "constraint", "slidercrank", "frustum"}, - {"rgba", "?", "fog", "haze", "force", "inertia", "joint", - "actuator", "actuatornegative", "actuatorpositive", "com", - "camera", "light", "selectpoint", "connect", "contactpoint", "contactforce", - "contactfriction", "contacttorque", "contactgap", "rangefinder", - "constraint", "slidercrank", "crankbroken", "frustum", "bv", "bvactive"}, - {">"}, - - {"statistic", "*", "meaninertia", "meanmass", "meansize", "extent", "center"}, - - {"default", "R", "class"}, - {"<"}, - {"mesh", "?", "scale", "maxhullvert", "inertia"}, - {"material", "?", "texture", "emission", "specular", "shininess", - "reflectance", "metallic", "roughness", "rgba", "texrepeat", "texuniform"}, - {"<"}, - {"layer", "*", "texture", "role"}, - {">"}, - {"joint", "?", "type", "group", "pos", "axis", "springdamper", - "limited", "actuatorfrclimited", "solreflimit", "solimplimit", - "solreffriction", "solimpfriction", "stiffness", "range", "actuatorfrcrange", - "actuatorgravcomp", "margin", "ref", "springref", "armature", "damping", - "frictionloss", "user"}, - {"geom", "?", "type", "pos", "quat", "contype", "conaffinity", "condim", - "group", "priority", "size", "material", "friction", "mass", "density", - "shellinertia", "solmix", "solref", "solimp", - "margin", "gap", "surfacevel", "adhesion", "fromto", "axisangle", "xyaxes", "zaxis", - "euler", - "hfield", "mesh", "fitscale", "rgba", "fluidshape", "fluidcoef", "user"}, - {"site", "?", "type", "group", "pos", "quat", "material", - "size", "fromto", "axisangle", "xyaxes", "zaxis", "euler", "rgba", "user"}, - {"camera", "?", "projection", "fovy", "ipd", "resolution", "output", "pos", "quat", - "axisangle", "xyaxes", "zaxis", "euler", "mode", "focal", "focalpixel", - "principal", "principalpixel", "sensorsize", "user"}, - {"light", "?", "pos", "dir", "bulbradius", "intensity", "range", - "directional", "type", "castshadow", "active", "attenuation", "cutoff", "exponent", - "ambient", "diffuse", "specular", "mode"}, - {"pair", "?", "condim", "friction", "solref", "solreffriction", "solimp", - "gap", "margin", "adhesion"}, - {"equality", "?", "active", "solref", "solimp"}, - {"tendon", "?", "group", "limited", "range", - "solreflimit", "solimplimit", "solreffriction", "solimpfriction", - "frictionloss", "springlength", "width", "material", - "margin", "stiffness", "damping", "rgba", "user"}, - {"general", "?", "ctrllimited", "forcelimited", "actlimited", "ctrlrange", "forcerange", - "actrange", "gear", "damping", "armature", "cranklength", "user", "group", "nsample", - "interp", "delay", "actdim", "input", "velrange", "ffrange", "dyntype", "gaintype", "biastype", "dynprm", "gainprm", - "biasprm", "actearly"}, - {"motor", "?", "ctrllimited", "forcelimited", "ctrlrange", "forcerange", - "gear", "damping", "armature", "cranklength", "user", "group", "nsample", "interp", "delay"}, - {"position", "?", "ctrllimited", "forcelimited", "ctrlrange", "inheritrange", "forcerange", - "gear", "damping", "armature", "cranklength", "user", "group", "nsample", "interp", - "delay", "kp", "kv", "dampratio", "timeconst"}, - {"velocity", "?", "ctrllimited", "forcelimited", "ctrlrange", "forcerange", "gear", - "damping", "armature", "cranklength", "user", "group", "nsample", "interp", "delay", "kv"}, - {"intvelocity", "?", "ctrllimited", "forcelimited", "actlimited", "ctrlrange", "forcerange", - "actrange", "inheritrange", "gear", "damping", "armature", "cranklength", "user", "group", - "nsample", "interp", "delay", "kp", "kv", "dampratio"}, - {"orientation", "?", "forcelimited", "ctrlrange", "forcerange", "user", "group", - "nsample", "interp", "delay", "kp", "kv", "dampratio", "input"}, - {"pid", "?", "ctrllimited", "forcelimited", "ctrlrange", "posrange", "velrange", "ffrange", - "forcerange", "inheritrange", "gear", "damping", "armature", "cranklength", "user", - "group", "nsample", "interp", "delay", "kp", "kv", "dampratio", "ki", "imax", "slewmax", - "input"}, - {"damper", "?", "forcelimited", "ctrlrange", "forcerange", - "gear", "damping", "armature", "cranklength", "user", "group", "nsample", "interp", "delay", "kv"}, - {"cylinder", "?", "ctrllimited", "forcelimited", "ctrlrange", "forcerange", - "gear", "damping", "armature", "cranklength", "user", "group", "nsample", "interp", "delay", - "timeconst", "area", "diameter", "bias"}, - {"muscle", "?", "ctrllimited", "forcelimited", "ctrlrange", "forcerange", - "gear", "damping", "armature", "cranklength", "user", "group", "nsample", "interp", "delay", - "timeconst", "range", "force", "scale", - "lmin", "lmax", "vmax", "fpmax", "fvmax"}, - {"adhesion", "?", "forcelimited", "ctrlrange", "forcerange", - "gain", "user", "group", "nsample", "interp", "delay"}, - {"dcmotor", "?", "ctrllimited", "ctrlrange", - "gear", "damping", "armature", "cranklength", "user", "group", "nsample", "interp", "delay", - "motorconst", "resistance", "nominal", "saturation", - "inductance", "cogging", "controller", "input", "thermal", "lugre"}, - {">"}, - - {"extension", "*"}, - {"<"}, - {"plugin", "*", "plugin"}, - {"<"}, - {"instance", "*", "name"}, - {"<"}, - {"config", "*", "key", "value"}, - {">"}, - {">"}, - {">"}, - - {"custom", "*"}, - {"<"}, - {"numeric", "*", "name", "size", "data"}, - {"text", "*", "name", "data"}, - {"tuple", "*", "name"}, - {"<"}, - {"element", "*", "objtype", "objname", "prm"}, - {">"}, - {">"}, - - {"asset", "*"}, - {"<"}, - {"mesh", "*", "name", "class", "content_type", "file", "vertex", "normal", - "texcoord", "face", "refpos", "refquat", "scale", "smoothnormal", - "maxhullvert", "inertia", "builtin", "params", "material"}, - {"<"}, - {"plugin", "*", "plugin", "instance"}, - {"<"}, - {"config", "*", "key", "value"}, - {">"}, - {">"}, - {"hfield", "*", "name", "content_type", "file", "nrow", "ncol", "size", "elevation"}, - {"skin", "*", "name", "file", "material", "rgba", "inflate", - "vertex", "texcoord", "face", "group"}, - {"<"}, - {"bone", "*", "body", "bindpos", "bindquat", "vertid", "vertweight"}, - {">"}, - {"texture", "*", "name", "type", "colorspace", "content_type", "file", "gridsize", - "gridlayout", "fileright", "fileleft", "fileup", "filedown", "filefront", "fileback", - "builtin", "rgb1", "rgb2", "mark", "markrgb", "random", "width", "height", - "hflip", "vflip", "nchannel"}, - {"material", "*", "name", "class", "texture", "texrepeat", "texuniform", - "emission", "specular", "shininess", "reflectance", "metallic", "roughness", "rgba"}, - {"<"}, - {"layer", "*", "texture", "role"}, - {">"}, - {"model", "*", "name", "file", "content_type"}, - {">"}, - {"body", "R", "name", "childclass", "pos", "quat", "mocap", "axisangle", - "xyaxes", "zaxis", "euler", "gravcomp", "sleep", "simple", "user"}, - {"<"}, - {"inertial", "?", "pos", "quat", "mass", "diaginertia", - "axisangle", "xyaxes", "zaxis", "euler", "fullinertia"}, - {"joint", "*", "name", "class", "type", "group", "pos", "axis", - "springdamper", "limited", "actuatorfrclimited", - "solreflimit", "solimplimit", "solreffriction", "solimpfriction", - "stiffness", "range", "actuatorfrcrange", "actuatorgravcomp", "margin", "ref", - "springref", "armature", "damping", "frictionloss", "user"}, - {"freejoint", "*", "name", "group", "align"}, - {"geom", "*", "name", "class", "type", "contype", "conaffinity", "condim", - "group", "priority", "size", "material", "friction", "mass", "density", - "shellinertia", "solmix", "solref", "solimp", - "margin", "gap", "surfacevel", "adhesion", "fromto", "pos", "quat", "axisangle", - "xyaxes", "zaxis", "euler", "hfield", "mesh", "fitscale", "rgba", "fluidshape", - "fluidcoef", "user"}, - {"<"}, - {"plugin", "*", "plugin", "instance"}, - {"<"}, - {"config", "*", "key", "value"}, - {">"}, - {">"}, - {"attach", "*", "model", "body", "frame", "prefix"}, - {"site", "*", "name", "class", "type", "group", "pos", "quat", - "material", "size", "fromto", "axisangle", "xyaxes", "zaxis", "euler", "rgba", "user"}, - {"camera", "*", "name", "class", "projection", "fovy", "ipd", "resolution", "output", "pos", - "quat", "axisangle", "xyaxes", "zaxis", "euler", "mode", "target", - "focal", "focalpixel", "principal", "principalpixel", "sensorsize", "user"}, - {"light", "*", "name", "class", "directional", "type", "castshadow", "active", - "pos", "dir", "bulbradius", "intensity", "range", "attenuation", "cutoff", - "exponent", "ambient", "diffuse", "specular", "mode", "target", "texture"}, - {"plugin", "*", "plugin", "instance"}, - {"<"}, - {"config", "*", "key", "value"}, - {">"}, - {"composite", "*", "prefix", "type", "count", "offset", - "vertex", "initial", "curve", "size", "quat"}, - {"<"}, - {"joint", "*", "kind", "group", "stiffness", "damping", "armature", - "solreffix", "solimpfix", "type", "axis", - "limited", "range", "margin", "solreflimit", "solimplimit", - "frictionloss", "solreffriction", "solimpfriction"}, - {"skin", "?", "texcoord", "material", "group", "rgba", "inflate", "subgrid"}, - {"geom", "?", "type", "contype", "conaffinity", "condim", - "group", "priority", "size", "material", "rgba", "friction", "mass", - "density", "solmix", "solref", "solimp", "margin", "gap", "surfacevel", - "adhesion"}, - {"site", "?", "group", "size", "material", "rgba"}, - {"plugin", "*", "plugin", "instance"}, - {"<"}, - {"config", "*", "key", "value"}, - {">"}, - {">"}, - {"flexcomp", "*", "name", "type", "group", "dim", "dof", - "count", "cellcount", "spacing", "radius", "rigid", "mass", "inertiabox", - "scale", "file", "point", "element", "texcoord", "material", "rgba", - "flatskin", "pos", "quat", "axisangle", "xyaxes", "zaxis", "euler", "origin"}, - {"<"}, - {"edge", "?", "equality", "solref", "solimp", "stiffness", "damping"}, - {"elasticity", "?", "young", "poisson", "damping", "thickness", "elastic2d"}, - {"contact", "?", "contype", "conaffinity", "condim", "priority", - "friction", "solmix", "solref", "solimp", "margin", "gap", - "internal", "selfcollide", "activelayers", "passive"}, - {"pin", "*", "id", "range", "grid", "gridrange"}, - {"plugin", "*", "plugin", "instance"}, - {"<"}, - {"config", "*", "key", "value"}, - {">"}, - {">"}, - {">"}, - - {"deformable", "*"}, - {"<"}, - {"flex", "*", "name", "group", "dim", "radius", "material", "rgba", "flatskin", "body", - "vertex", "element", "texcoord", "elemtexcoord", "node", "cellcount", "dof"}, - {"<"}, - {"contact", "?", "contype", "conaffinity", "condim", "priority", - "friction", "solmix", "solref", "solimp", "margin", "gap", - "internal", "selfcollide", "activelayers", "passive"}, - {"edge", "?", "stiffness", "damping"}, - {"elasticity", "?", "young", "poisson", "damping", "thickness", "elastic2d"}, - {">"}, - {"skin", "*", "name", "file", "material", "rgba", "inflate", - "vertex", "texcoord", "face", "group"}, - {"<"}, - {"bone", "*", "body", "bindpos", "bindquat", "vertid", "vertweight"}, - {">"}, - {">"}, - - {"contact", "*"}, - {"<"}, - {"pair", "*", "name", "class", "geom1", "geom2", "condim", "friction", - "solref", "solreffriction", "solimp", "gap", "margin", "adhesion"}, - {"exclude", "*", "name", "body1", "body2"}, - {">"}, - - {"equality", "*"}, - {"<"}, - {"connect", "*", "name", "class", "body1", "body2", "anchor", - "site1", "site2", "active", "solref", "solimp"}, - {"weld", "*", "name", "class", "body1", "body2", "relpose", "anchor", - "site1", "site2", "active", "solref", "solimp", "torquescale"}, - {"joint", "*", "name", "class", "joint1", "joint2", "polycoef", - "active", "solref", "solimp"}, - {"tendon", "*", "name", "class", "tendon1", "tendon2", "polycoef", - "active", "solref", "solimp"}, - {"flex", "*", "name", "class", "flex", - "active", "solref", "solimp"}, - {"flexvert", "*", "name", "class", "flex", - "active", "solref", "solimp"}, - {"flexstrain", "*", "name", "class", "flex", "cell", - "active", "solref", "solimp"}, - {">"}, - - {"tendon", "*"}, - {"<"}, - {"spatial", "*", "name", "class", "group", "limited", "actuatorfrclimited", "range", - "actuatorfrcrange", "solreflimit", "solimplimit", "solreffriction", "solimpfriction", - "frictionloss", "springlength", "width", "material", - "margin", "stiffness", "damping", "armature", "rgba", "user"}, - {"<"}, - {"site", "*", "site"}, - {"geom", "*", "geom", "sidesite"}, - {"pulley", "*", "divisor"}, - {">"}, - {"fixed", "*", "name", "class", "group", "limited", "actuatorfrclimited", "range", - "actuatorfrcrange", "solreflimit", "solimplimit", "solreffriction", "solimpfriction", - "frictionloss", "springlength", "margin", "stiffness", "damping", "armature", "user"}, - {"<"}, - {"joint", "*", "joint", "coef"}, - {">"}, - {">"}, - - {"actuator", "*"}, - {"<"}, - {"general", "*", "name", "class", "group", "nsample", "interp", "delay", - "ctrllimited", "forcelimited", "actlimited", "ctrlrange", "forcerange", "actrange", - "lengthrange", "gear", "damping", "armature", "cranklength", "user", - "joint", "jointinparent", "tendon", "slidersite", "cranksite", "site", "refsite", - "body", "actdim", "input", "velrange", "ffrange", "dyntype", "gaintype", "biastype", "dynprm", "gainprm", "biasprm", - "actearly"}, - {"motor", "*", "name", "class", "group", "nsample", "interp", "delay", - "ctrllimited", "forcelimited", "ctrlrange", "forcerange", - "lengthrange", "gear", "damping", "armature", "cranklength", "user", - "joint", "jointinparent", "tendon", "slidersite", "cranksite", "site", "refsite"}, - {"position", "*", "name", "class", "group", "nsample", "interp", "delay", - "ctrllimited", "forcelimited", "ctrlrange", "inheritrange", "forcerange", - "lengthrange", "gear", "damping", "armature", "cranklength", "user", - "joint", "jointinparent", "tendon", "slidersite", "cranksite", "site", "refsite", - "kp", "kv", "dampratio", "timeconst"}, - {"velocity", "*", "name", "class", "group", "nsample", "interp", "delay", - "ctrllimited", "forcelimited", "ctrlrange", "forcerange", - "lengthrange", "gear", "damping", "armature", "cranklength", "user", - "joint", "jointinparent", "tendon", "slidersite", "cranksite", "site", "refsite", - "kv"}, - {"intvelocity", "*", "name", "class", "group", "nsample", "interp", "delay", - "ctrllimited", "forcelimited", "actlimited", - "ctrlrange", "forcerange", "actrange", "inheritrange", "lengthrange", - "gear", "damping", "armature", "cranklength", "user", - "joint", "jointinparent", "tendon", "slidersite", "cranksite", "site", "refsite", - "kp", "kv", "dampratio"}, - {"orientation", "*", "name", "class", "group", "nsample", "interp", "delay", - "forcelimited", "ctrlrange", "forcerange", "user", - "joint", "site", "refsite", - "kp", "kv", "dampratio", "input"}, - {"pid", "*", "name", "class", "group", "nsample", "interp", "delay", - "ctrllimited", "forcelimited", "ctrlrange", "posrange", "velrange", "ffrange", - "forcerange", "inheritrange", "lengthrange", "gear", "damping", "armature", - "cranklength", "user", - "joint", "jointinparent", "tendon", "slidersite", "cranksite", "site", "refsite", - "kp", "kv", "dampratio", "ki", "imax", "slewmax", "input"}, - {"damper", "*", "name", "class", "group", "nsample", "interp", "delay", - "forcelimited", "ctrlrange", "forcerange", - "lengthrange", "gear", "damping", "armature", "cranklength", "user", - "joint", "jointinparent", "tendon", "slidersite", "cranksite", "site", "refsite", - "kv"}, - {"cylinder", "*", "name", "class", "group", "nsample", "interp", "delay", - "ctrllimited", "forcelimited", "ctrlrange", "forcerange", - "lengthrange", "gear", "damping", "armature", "cranklength", "user", - "joint", "jointinparent", "tendon", "slidersite", "cranksite", "site", "refsite", - "timeconst", "area", "diameter", "bias"}, - {"muscle", "*", "name", "class", "group", "nsample", "interp", "delay", - "ctrllimited", "forcelimited", "ctrlrange", "forcerange", - "lengthrange", "gear", "damping", "armature", "cranklength", "user", - "joint", "jointinparent", "tendon", "slidersite", "cranksite", - "timeconst", "tausmooth", "range", "force", "scale", - "lmin", "lmax", "vmax", "fpmax", "fvmax"}, - {"adhesion", "*", "name", "class", "group", "nsample", "interp", "delay", - "forcelimited", "ctrlrange", "forcerange", "user", "body", "gain"}, - {"dcmotor", "*", "name", "class", "group", "nsample", "interp", "delay", - "ctrllimited", "ctrlrange", - "lengthrange", "gear", "damping", "armature", "cranklength", "user", - "joint", "jointinparent", "tendon", "slidersite", "cranksite", "site", "refsite", - "motorconst", "resistance", "nominal", "saturation", - "inductance", "cogging", "controller", "thermal", "lugre", "input"}, - {"plugin", "*", "name", "class", "plugin", "instance", "group", "nsample", "interp", "delay", - "ctrllimited", "forcelimited", "actlimited", "ctrlrange", "forcerange", "actrange", - "lengthrange", "gear", "damping", "armature", "cranklength", "joint", "jointinparent", - "site", "actdim", "dyntype", "dynprm", "tendon", "cranksite", "slidersite", "user", - "actearly"}, - {"<"}, - {"config", "*", "key", "value"}, - {">"}, - {">"}, - - {"sensor", "*"}, - {"<"}, - {"touch", "*", "name", "site", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"accelerometer", "*", "name", "site", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"velocimeter", "*", "name", "site", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"gyro", "*", "name", "site", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"force", "*", "name", "site", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"torque", "*", "name", "site", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"magnetometer", "*", "name", "site", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"camprojection", "*", "name", "site", "camera", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"rangefinder", "*", "name", "site", "camera", "data", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"jointpos", "*", "name", "joint", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"jointvel", "*", "name", "joint", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"tendonpos", "*", "name", "tendon", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"tendonvel", "*", "name", "tendon", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"actuatorpos", "*", "name", "actuator", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"actuatorvel", "*", "name", "actuator", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"actuatorfrc", "*", "name", "actuator", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"jointactuatorfrc", "*", "name", "joint", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"tendonactuatorfrc", "*", "name", "tendon", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"ballquat", "*", "name", "joint", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"ballangvel", "*", "name", "joint", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"jointlimitpos", "*", "name", "joint", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"jointlimitvel", "*", "name", "joint", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"jointlimitfrc", "*", "name", "joint", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"tendonlimitpos", "*", "name", "tendon", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"tendonlimitvel", "*", "name", "tendon", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"tendonlimitfrc", "*", "name", "tendon", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"framepos", "*", "name", "objtype", "objname", "reftype", "refname", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"framequat", "*", "name", "objtype", "objname", "reftype", "refname", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"framexaxis", "*", "name", "objtype", "objname", "reftype", "refname", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"frameyaxis", "*", "name", "objtype", "objname", "reftype", "refname", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"framezaxis", "*", "name", "objtype", "objname", "reftype", "refname", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"framelinvel", "*", "name", "objtype", "objname", "reftype", "refname", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"frameangvel", "*", "name", "objtype", "objname", "reftype", "refname", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"framelinacc", "*", "name", "objtype", "objname", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"frameangacc", "*", "name", "objtype", "objname", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"subtreecom", "*", "name", "body", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"subtreelinvel", "*", "name", "body", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"subtreeangmom", "*", "name", "body", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"insidesite", "*", "name", "site", "objtype", "objname", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"distance", "*", "name", "geom1", "geom2", "body1", "body2", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"normal", "*", "name", "geom1", "geom2", "body1", "body2", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"fromto", "*", "name", "geom1", "geom2", "body1", "body2", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"contact", "*", "name", "geom1", "geom2", "body1", "body2", "subtree1", "subtree2", "site", - "num", "data", "reduce", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"e_potential", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"e_kinetic", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"clock", "*", "name", "nsample", "interp", "delay", "interval", "cutoff", "noise", "user"}, - {"tactile", "*", "name", "geom", "mesh", "nsample", "interp", "delay", "interval", "user"}, - {"user", "*", "name", "objtype", "objname", "datatype", "needstage", - "dim", "cutoff", "noise", "user"}, - {"plugin", "*", "name", "plugin", "instance", "cutoff", "objtype", "objname", "reftype", "refname", - "user"}, - {"<"}, - {"config", "*", "key", "value"}, - {">"}, - {">"}, - - {"keyframe", "*"}, - {"<"}, - {"key", "*", "name", "time", "qpos", "qvel", "act", "mpos", "mquat", "ctrl"}, - {">"}, -{">"} -}; -// clang-format on - - +#include "mjcf_table.inc" //---------------------------------- MJCF keywords used in attributes ------------------------------ @@ -1121,7 +671,8 @@ const mjMap flexeq_map[4] = { //---------------------------------- class mjXReader implementation -------------------------------- // constructor -mjXReader::mjXReader() : schema(MJCF, nMJCF) { +mjXReader::mjXReader() + : schema(MJCF, nMJCF, MJCF_constraints, nMJCF_constraints) { readingdefaults = false; } @@ -1541,33 +1092,16 @@ void mjXReader::Size(XMLElement* section, mjSpec* s) { ReadAttrInt(section, "nconmax", &s->nconmax); if (s->nconmax < -1) throw mjXError(section, "nconmax must be >= -1"); + // memory/nstack and memory/njmax exclusivity is enforced by the schema { int nstack = -1; - const bool has_nstack = ReadAttrInt(section, "nstack", &nstack); - if (has_nstack) { - if (s->nstack < -1) { - throw mjXError(section, "nstack must be >= -1"); - } - if (s->memory != -1 && nstack != -1) { - throw mjXError(section, - "either 'memory' and 'nstack' attribute can be specified, not both"); - } + if (ReadAttrInt(section, "nstack", &nstack)) { + if (nstack < -1) throw mjXError(section, "nstack must be >= -1"); s->nstack = nstack; } } - { - int njmax = -1; - const bool has_njmax = ReadAttrInt(section, "njmax", &njmax); - if (has_njmax) { - if (s->njmax < -1) { - throw mjXError(section, "njmax must be >= -1"); - } - if (s->memory != -1 && njmax != -1) { - throw mjXError(section, - "either 'memory' and 'njmax' attribute can be specified, not both"); - } - s->njmax = njmax; - } + if (ReadAttrInt(section, "njmax", &s->njmax)) { + if (s->njmax < -1) throw mjXError(section, "njmax must be >= -1"); } ReadAttrInt(section, "nuser_body", &s->nuser_body); @@ -1794,12 +1328,6 @@ void mjXReader::OneMesh(XMLElement* elem, mjsMesh* mesh, const mjVFS* vfs) { if (MapValue(elem, "builtin", &n, meshbuiltin_map, meshbuiltin_sz)) { std::vector params; int nparams = ReadVector(elem, "params", params, text, /*required*/ true); - if (file) { - throw mjXError(elem, "builtin cannot be used with a mesh file"); - } - if (!mesh->uservert->empty()) { - throw mjXError(elem, "builtin mesh cannot be used with user vertex data"); - } if (mjs_makeMesh(mesh, (mjtMeshBuiltin)n, params.data(), nparams)) { throw mjXError(elem, "%s", mjs_getError(spec)); } @@ -2166,11 +1694,8 @@ void mjXReader::OneCamera(XMLElement* elem, mjsCamera* camera) { } } - bool sensorsize = ReadAttr(elem, "sensorsize", 2, camera->sensor_size, text); - bool fovy = ReadAttr(elem, "fovy", 1, &camera->fovy, text); - if (fovy && sensorsize) { - throw mjXError(elem, "either 'fovy' or 'sensorsize' attribute can be specified, not both"); - } + ReadAttr(elem, "sensorsize", 2, camera->sensor_size, text); + ReadAttr(elem, "fovy", 1, &camera->fovy, text); // read userdata ReadVector(elem, "user", userdata, text); @@ -2185,7 +1710,6 @@ void mjXReader::OneCamera(XMLElement* elem, mjsCamera* camera) { // light element parser void mjXReader::OneLight(XMLElement* elem, mjsLight* light) { int n; - bool has_directional = false; string text, name, texture, targetbody; // read attributes @@ -2205,12 +1729,8 @@ void mjXReader::OneLight(XMLElement* elem, mjsLight* light) { } if (MapValue(elem, "directional", &n, bool_map, 2)) { light->type = (n == 1) ? mjLIGHT_DIRECTIONAL : mjLIGHT_SPOT; - has_directional = true; } if (MapValue(elem, "type", &n, lighttype_map, lighttype_sz)) { - if (has_directional) { - throw mjXError(elem, "type and directional cannot both be defined"); - } light->type = (mjtLightType)n; } if (MapValue(elem, "castshadow", &n, bool_map, 2)) { @@ -2297,19 +1817,7 @@ void mjXReader::OneEquality(XMLElement* elem, mjsEquality* equality) { auto maybe_body2 = ReadAttrStr(elem, "body2"); bool has_anchor = ReadAttr(elem, "anchor", 3, equality->data, text); - bool maybe_site = maybe_site1.has_value() || maybe_site2.has_value(); - bool maybe_body = maybe_body1.has_value() || maybe_body2.has_value() || has_anchor; - - if (maybe_site && maybe_body) { - throw mjXError(elem, "body and site semantics cannot be mixed"); - } - - bool site_semantic = maybe_site1.has_value() && maybe_site2.has_value(); bool body_semantic = maybe_body1.has_value() && has_anchor; - if (site_semantic == body_semantic) { - throw mjXError(elem, "either both body1 and anchor must be defined," - " or both site1 and site2 must be defined"); - } if (body_semantic) { name1 = maybe_body1.value(); @@ -2331,28 +1839,10 @@ void mjXReader::OneEquality(XMLElement* elem, mjsEquality* equality) { auto maybe_body1 = ReadAttrStr(elem, "body1"); auto maybe_body2 = ReadAttrStr(elem, "body2"); bool has_anchor = ReadAttr(elem, "anchor", 3, equality->data, text); - bool has_relpose = ReadAttr(elem, "relpose", 7, equality->data+3, text); + ReadAttr(elem, "relpose", 7, equality->data+3, text); - bool maybe_site = maybe_site1.has_value() || maybe_site2.has_value(); - bool maybe_body = maybe_body1.has_value() || - maybe_body2.has_value() || - has_anchor || - has_relpose; - - if (maybe_site && maybe_body) { - throw mjXError(elem, "body and site semantics cannot be mixed"); - } - - bool site_semantic = maybe_site1.has_value() && maybe_site2.has_value(); bool body_semantic = maybe_body1.has_value(); - if (site_semantic == body_semantic) { - throw mjXError( - elem, - "either body1 must be defined and optionally {body2, anchor, relpose}," - " or site1 and site2 must be defined"); - } - if (body_semantic) { name1 = maybe_body1.value(); if (maybe_body2.has_value()) { @@ -2496,42 +1986,30 @@ void mjXReader::OneActuator(XMLElement* elem, mjsActuator* actuator) { ReadAttr(elem, "armature", 1, &actuator->armature, text, false, false); // transmission target and type - int cnt = 0; if (ReadAttrTxt(elem, "joint", target)) { mjs_setString(actuator->target, target.c_str()); actuator->trntype = mjTRN_JOINT; - cnt++; } if (ReadAttrTxt(elem, "jointinparent", target)) { mjs_setString(actuator->target, target.c_str()); actuator->trntype = mjTRN_JOINTINPARENT; - cnt++; } if (ReadAttrTxt(elem, "tendon", target)) { mjs_setString(actuator->target, target.c_str()); actuator->trntype = mjTRN_TENDON; - cnt++; } if (ReadAttrTxt(elem, "cranksite", target)) { mjs_setString(actuator->target, target.c_str()); actuator->trntype = mjTRN_SLIDERCRANK; - cnt++; } if (ReadAttrTxt(elem, "site", target)) { mjs_setString(actuator->target, target.c_str()); actuator->trntype = mjTRN_SITE; - cnt++; } if (ReadAttrTxt(elem, "body", target)) { mjs_setString(actuator->target, target.c_str()); actuator->trntype = mjTRN_BODY; - cnt++; } - // check for repeated transmission - if (cnt > 1) { - throw mjXError(elem, "actuator can have at most one of transmission target"); - } - // slidercrank-specific parameters int r1 = ReadAttr(elem, "cranklength", 1, &actuator->cranklength, text); int r2 = ReadAttrTxt(elem, "slidersite", slidersite); @@ -3843,11 +3321,8 @@ void mjXReader::Body(XMLElement* section, mjsBody* body, mjsFrame* frame, ReadQuat(elem, "quat", body->iquat, text); ReadAttr(elem, "mass", 1, &body->mass, text, true); ReadAttr(elem, "diaginertia", 3, body->inertia, text); - bool alt = ReadAlternative(elem, body->ialt); - bool full = ReadAttr(elem, "fullinertia", 6, body->fullinertia, text); - if (alt && full) { - throw mjXError(elem, "fullinertia and inertial orientation cannot both be specified"); - } + ReadAlternative(elem, body->ialt); + ReadAttr(elem, "fullinertia", 6, body->fullinertia, text); } // joint sub-element @@ -4100,9 +3575,6 @@ void mjXReader::Body(XMLElement* section, mjsBody* body, mjsFrame* frame, bool has_frame = ReadAttrTxt(elem, "frame", child_name, /*required=*/false); ReadAttrTxt(elem, "prefix", prefix, /*required=*/true); - if (has_body && has_frame) { - throw mjXError(elem, "only one of body or frame can be specified in attach"); - } mjtObj type = mjOBJ_UNKNOWN; if (has_body) type = mjOBJ_BODY; else if (has_frame) type = mjOBJ_FRAME; @@ -4444,10 +3916,7 @@ void mjXReader::Sensor(XMLElement* section) { } else if (type == "rangefinder") { sensor->type = mjSENS_RANGEFINDER; bool use_site = ReadAttrTxt(elem, "site", objname, false); - bool use_camera = ReadAttrTxt(elem, "camera", objname, false); - if (use_site == use_camera) { - throw mjXError(elem, "rangefinder requires exactly one of 'site' or 'camera'"); - } + ReadAttrTxt(elem, "camera", objname, false); sensor->objtype = use_site ? mjOBJ_SITE : mjOBJ_CAMERA; // process data specification (intprm[0]) @@ -4559,8 +4028,6 @@ void mjXReader::Sensor(XMLElement* section) { if (ReadAttrTxt(elem, "reftype", text)) { sensor->reftype = (mjtObj)mju_str2Type(text.c_str()); ReadAttrTxt(elem, "refname", refname, true); - } else if (ReadAttrTxt(elem, "refname", text)) { - throw mjXError(elem, "refname '%s' given but reftype is missing", text.c_str()); } } else if (type == "framequat") { sensor->type = mjSENS_FRAMEQUAT; @@ -4570,8 +4037,6 @@ void mjXReader::Sensor(XMLElement* section) { if (ReadAttrTxt(elem, "reftype", text)) { sensor->reftype = (mjtObj)mju_str2Type(text.c_str()); ReadAttrTxt(elem, "refname", refname, true); - } else if (ReadAttrTxt(elem, "refname", text)) { - throw mjXError(elem, "refname '%s' given but reftype is missing", text.c_str()); } } else if (type == "framexaxis") { sensor->type = mjSENS_FRAMEXAXIS; @@ -4581,8 +4046,6 @@ void mjXReader::Sensor(XMLElement* section) { if (ReadAttrTxt(elem, "reftype", text)) { sensor->reftype = (mjtObj)mju_str2Type(text.c_str()); ReadAttrTxt(elem, "refname", refname, true); - } else if (ReadAttrTxt(elem, "refname", text)) { - throw mjXError(elem, "refname '%s' given but reftype is missing", text.c_str()); } } else if (type == "frameyaxis") { sensor->type = mjSENS_FRAMEYAXIS; @@ -4592,8 +4055,6 @@ void mjXReader::Sensor(XMLElement* section) { if (ReadAttrTxt(elem, "reftype", text)) { sensor->reftype = (mjtObj)mju_str2Type(text.c_str()); ReadAttrTxt(elem, "refname", refname, true); - } else if (ReadAttrTxt(elem, "refname", text)) { - throw mjXError(elem, "refname '%s' given but reftype is missing", text.c_str()); } } else if (type == "framezaxis") { sensor->type = mjSENS_FRAMEZAXIS; @@ -4603,8 +4064,6 @@ void mjXReader::Sensor(XMLElement* section) { if (ReadAttrTxt(elem, "reftype", text)) { sensor->reftype = (mjtObj)mju_str2Type(text.c_str()); ReadAttrTxt(elem, "refname", refname, true); - } else if (ReadAttrTxt(elem, "refname", text)) { - throw mjXError(elem, "refname '%s' given but reftype is missing", text.c_str()); } } else if (type == "framelinvel") { sensor->type = mjSENS_FRAMELINVEL; @@ -4614,8 +4073,6 @@ void mjXReader::Sensor(XMLElement* section) { if (ReadAttrTxt(elem, "reftype", text)) { sensor->reftype = (mjtObj)mju_str2Type(text.c_str()); ReadAttrTxt(elem, "refname", refname, true); - } else if (ReadAttrTxt(elem, "refname", text)) { - throw mjXError(elem, "refname '%s' given but reftype is missing", text.c_str()); } } else if (type == "frameangvel") { sensor->type = mjSENS_FRAMEANGVEL; @@ -4625,8 +4082,6 @@ void mjXReader::Sensor(XMLElement* section) { if (ReadAttrTxt(elem, "reftype", text)) { sensor->reftype = (mjtObj)mju_str2Type(text.c_str()); ReadAttrTxt(elem, "refname", refname, true); - } else if (ReadAttrTxt(elem, "refname", text)) { - throw mjXError(elem, "refname '%s' given but reftype is missing", text.c_str()); } } else if (type == "framelinacc") { sensor->type = mjSENS_FRAMELINACC; @@ -4665,16 +4120,10 @@ void mjXReader::Sensor(XMLElement* section) { // sensors for geometric distance; attached to geoms or bodies else if (type == "distance" || type == "normal" || type == "fromto") { bool has_body1 = ReadAttrTxt(elem, "body1", objname); - bool has_geom1 = ReadAttrTxt(elem, "geom1", objname); - if (has_body1 == has_geom1) { - throw mjXError(elem, "exactly one of (geom1, body1) must be specified"); - } + ReadAttrTxt(elem, "geom1", objname); sensor->objtype = has_body1 ? mjOBJ_BODY : mjOBJ_GEOM; bool has_body2 = ReadAttrTxt(elem, "body2", refname); - bool has_geom2 = ReadAttrTxt(elem, "geom2", refname); - if (has_body2 == has_geom2) { - throw mjXError(elem, "exactly one of (geom2, body2) must be specified"); - } + ReadAttrTxt(elem, "geom2", refname); sensor->reftype = has_body2 ? mjOBJ_BODY : mjOBJ_GEOM; if (type == "distance") { sensor->type = mjSENS_GEOMDIST; @@ -4692,9 +4141,6 @@ void mjXReader::Sensor(XMLElement* section) { bool has_body1 = ReadAttrTxt(elem, "body1", objname); bool has_subtree1 = ReadAttrTxt(elem, "subtree1", objname); bool has_geom1 = ReadAttrTxt(elem, "geom1", objname); - if (has_site + has_body1 + has_subtree1 + has_geom1 > 1) { - throw mjXError(elem, "at most one of (geom1, body1, subtree1, site) can be specified"); - } if (has_site) { sensor->objtype = mjOBJ_SITE; } else if (has_body1) { sensor->objtype = mjOBJ_BODY; } else if (has_subtree1) { sensor->objtype = mjOBJ_XBODY; } @@ -4705,9 +4151,6 @@ void mjXReader::Sensor(XMLElement* section) { bool has_body2 = ReadAttrTxt(elem, "body2", refname); bool has_subtree2 = ReadAttrTxt(elem, "subtree2", refname); bool has_geom2 = ReadAttrTxt(elem, "geom2", refname); - if (has_body2 + has_subtree2 + has_geom2 > 1) { - throw mjXError(elem, "at most one of (geom2, body2, subtree2) can be specified"); - } if (has_body2) { sensor->reftype = mjOBJ_BODY; } else if (has_subtree2) { sensor->reftype = mjOBJ_XBODY; } else if (has_geom2) { sensor->reftype = mjOBJ_GEOM; } @@ -4767,14 +4210,9 @@ void mjXReader::Sensor(XMLElement* section) { // user-defined sensor else if (type == "user") { sensor->type = mjSENS_USER; - bool objname_given = ReadAttrTxt(elem, "objname", objname); + ReadAttrTxt(elem, "objname", objname); if (ReadAttrTxt(elem, "objtype", text)) { - if (!objname_given) { - throw mjXError(elem, "objtype '%s' given but objname is missing", text.c_str()); - } sensor->objtype = (mjtObj)mju_str2Type(text.c_str()); - } else if (objname_given) { - throw mjXError(elem, "objname '%s' given but objtype is missing", objname.c_str()); } ReadAttrInt(elem, "dim", &sensor->dim, true); diff --git a/src/xml/xml_native_reader.h b/src/xml/xml_native_reader.h index a70c74d5..3511f31a 100644 --- a/src/xml/xml_native_reader.h +++ b/src/xml/xml_native_reader.h @@ -101,8 +101,10 @@ class mjXReader : public mjXBase { mujoco::user::FilePath texturedir_; }; -// MJCF schema -#define nMJCF 252 -extern std::vector MJCF[nMJCF]; +// MJCF schema table, generated from mjcf.schema into mjcf_table.inc +extern const int nMJCF; +extern std::vector MJCF[]; +extern const mjXConstraintDef MJCF_constraints[]; +extern const int nMJCF_constraints; #endif // MUJOCO_SRC_XML_XML_NATIVE_READER_H_ diff --git a/src/xml/xml_util.cc b/src/xml/xml_util.cc index 14dcdb41..aa45b429 100644 --- a/src/xml/xml_util.cc +++ b/src/xml/xml_util.cc @@ -333,11 +333,20 @@ XMLElement* NextSiblingElement(XMLElement* e, const char* name) { } // constructor -mjXSchema::mjXSchema(std::vector schema[], unsigned nrow) { +mjXSchema::mjXSchema(std::vector schema[], unsigned nrow, + const mjXConstraintDef* constraints, int nconstraint, + int first_row) { // set name and type name_ = schema[0][0]; type_ = schema[0][1][0]; + // adopt the presence constraints declared for this row + for (int i = 0; i < nconstraint; i++) { + if (constraints[i].row == first_row) { + constraints_.push_back(&constraints[i]); + } + } + // set attributes int nattr = schema[0].size() - 2; for (int i = 0; i < nattr; i++) { @@ -370,7 +379,8 @@ mjXSchema::mjXSchema(std::vector schema[], unsigned nrow) { } // add child element - subschema_.emplace_back(schema+start, end-start+1); + subschema_.emplace_back(schema+start, end-start+1, constraints, + nconstraint, first_row+start); // proceed with next subelement start = end+1; @@ -380,6 +390,102 @@ mjXSchema::mjXSchema(std::vector schema[], unsigned nrow) { +// quoted list of constraint bundles: 'a' or ('a', 'b'), comma-joined +static std::string BundleList(const std::vector>& bundles) { + std::string out; + for (size_t i = 0; i < bundles.size(); i++) { + if (i) { + out += ", "; + } + if (bundles[i].size() == 1) { + out += "'" + bundles[i][0] + "'"; + } else { + out += '('; + for (size_t j = 0; j < bundles[i].size(); j++) { + out += (j ? ", '" : "'") + bundles[i][j] + "'"; + } + out += ')'; + } + } + return out; +} + + + +// enforce the presence constraints declared for this element +XMLElement* mjXSchema::CheckConstraints(XMLElement* elem) { + for (const mjXConstraintDef* con : constraints_) { + // split the spec into bundles of attribute names + std::vector> bundles(1); + std::string token; + for (const char* c = con->spec;; c++) { + if (*c == ' ' || *c == '|' || *c == '\0') { + if (!token.empty()) { + bundles.back().push_back(token); + token.clear(); + } + if (*c == '|') { + bundles.emplace_back(); + } + if (*c == '\0') { + break; + } + } else { + token += *c; + } + } + + // per-bundle presence: any member present / all members present + int n_any = 0, n_all = 0, n_attr = 0, n_present = 0; + for (const auto& bundle : bundles) { + bool any = false, all = true; + for (const std::string& attr : bundle) { + bool present = elem->Attribute(attr.c_str()) != nullptr; + any |= present; + all &= present; + n_attr++; + n_present += present; + } + n_any += any; + n_all += all; + } + + switch (con->kind) { + case 'e': // at most one bundle may be present + if (n_any > 1) { + error = "at most one of " + BundleList(bundles) + + " can be specified"; + return elem; + } + break; + case 't': // all listed attributes appear together or not at all + if (n_present != 0 && n_present != n_attr) { + error = "attributes " + BundleList(bundles) + + " must be specified together"; + return elem; + } + break; + case 'r': // first attribute requires the second + if (n_any && elem->Attribute(bundles[0][0].c_str()) && + !elem->Attribute(bundles[1][0].c_str())) { + error = "attribute '" + bundles[0][0] + "' requires attribute '" + + bundles[1][0] + "'"; + return elem; + } + break; + case 'o': // at least one bundle must be complete + if (n_all == 0) { + error = "one of " + BundleList(bundles) + " must be specified"; + return elem; + } + break; + } + } + return nullptr; +} + + + // get pointer to error message std::string mjXSchema::GetError() { return error; @@ -525,6 +631,11 @@ XMLElement* mjXSchema::Check(XMLElement* elem, int level) { } } + // check presence constraints + if ((bad = CheckConstraints(elem))) { + return bad; + } + // handle recursion if (type_ == 'R') { // check child elements with same name diff --git a/src/xml/xml_util.h b/src/xml/xml_util.h index d8af121e..7817b89c 100644 --- a/src/xml/xml_util.h +++ b/src/xml/xml_util.h @@ -49,10 +49,25 @@ class [[nodiscard]] mjXError { }; +// presence constraint over an element's attributes, generated from the +// schema into the grammar table's companion array. spec holds attribute +// bundles, space-joined within a bundle and '|'-separated between them; +// kind: e=exclusive (at most one bundle present), t=together (all or +// none), r=requires (first needs second), o=oneof (at least one bundle +// complete). +struct mjXConstraintDef { + int row; // index of the element's row in the grammar table + char kind; + const char* spec; +}; + + // Custom XML file validation class mjXSchema { public: - mjXSchema(std::vector schema[], unsigned nrow); + mjXSchema(std::vector schema[], unsigned nrow, + const mjXConstraintDef* constraints = nullptr, + int nconstraint = 0, int first_row = 0); std::string GetError(); // return error void Print(std::stringstream& str, int level) const; // print schema @@ -67,6 +82,9 @@ class mjXSchema { std::set attr_; // allowed attributes std::vector subschema_; // allowed child elements + std::vector constraints_; // constraints here + tinyxml2::XMLElement* CheckConstraints(tinyxml2::XMLElement* elem); + int refcnt_ = 0; // refcount used for validation std::string error; // error from constructor or Check }; diff --git a/test/doc/doc_test.py b/test/doc/doc_test.py index 3e5888a1..3e2b3669 100644 --- a/test/doc/doc_test.py +++ b/test/doc/doc_test.py @@ -24,7 +24,9 @@ _REPO_ROOT = os.path.dirname(os.path.dirname(_SCRIPT_DIR)) sys.path.insert(0, os.path.join(_REPO_ROOT, 'doc', 'generate')) import generate_api_header import generate_functions +import generate_mjcf_table import generate_schema +import mjcf_schema # Functions in headers that are intentionally not in functions.rst. _FUNCTIONS_TO_SKIP = set() @@ -81,6 +83,14 @@ class DocTest(googletest.TestCase): if source != file.read(): self.fail("The file 'references.h' needs to be updated.") + def test_mjcf_table(self): + """Checks that mjcf_table.inc matches the schema-generated output.""" + table_file = os.path.join(_REPO_ROOT, 'src', 'xml', 'mjcf_table.inc') + source = generate_mjcf_table.generate() + with open(table_file, 'r', encoding='utf-8') as file: + if source != file.read(): + self.fail("The file 'mjcf_table.inc' needs to be updated.") + def test_schema(self): """Checks that XMLschema.rst matches the generated output.""" schema_file = os.path.join(_REPO_ROOT, 'doc', 'XMLschema.rst') @@ -91,7 +101,9 @@ class DocTest(googletest.TestCase): def test_functions(self): """Checks that functions.rst matches the generated output.""" - functions_file = os.path.join(_REPO_ROOT, 'doc', 'APIreference', 'functions.rst') + functions_file = os.path.join( + _REPO_ROOT, 'doc', 'APIreference', 'functions.rst' + ) source = generate_functions.generate() with open(functions_file, 'r', encoding='utf-8') as file: if source != file.read(): @@ -100,7 +112,9 @@ class DocTest(googletest.TestCase): def test_all_functions_included(self): """Checks that every public C function has an entry in functions.rst.""" - functions_file = os.path.join(_REPO_ROOT, 'doc', 'APIreference', 'functions.rst') + functions_file = os.path.join( + _REPO_ROOT, 'doc', 'APIreference', 'functions.rst' + ) with open(functions_file, 'r', encoding='utf-8') as file: content = file.read() @@ -125,7 +139,9 @@ class DocTest(googletest.TestCase): def test_all_types_included(self): """Checks that every public struct and enum has an entry in APItypes.rst.""" - types_file = os.path.join(_REPO_ROOT, 'doc', 'APIreference', 'APItypes.rst') + types_file = os.path.join( + _REPO_ROOT, 'doc', 'APIreference', 'APItypes.rst' + ) with open(types_file, 'r', encoding='utf-8') as file: content = file.read() @@ -151,6 +167,30 @@ class DocTest(googletest.TestCase): msg = 'APItypes.rst mismatches:\n' + '\n'.join(errors) self.fail(msg) + def test_element_constraints_diamond_inheritance(self): + con = mjcf_schema.Constraint( + kind='exclusive', bundles=(('a',), ('b',)), doc=None, line=1) + common_group = mjcf_schema.Group( + name='common', variant=False, members=[con], doc=None, line=1) + group1 = mjcf_schema.Group( + name='group1', variant=False, + members=[mjcf_schema.Use(group='common', line=1)], doc=None, line=1) + group2 = mjcf_schema.Group( + name='group2', variant=False, + members=[mjcf_schema.Use(group='common', line=1)], doc=None, line=1) + elem = mjcf_schema.Element( + name='elem', spec=None, facets={}, + members=[mjcf_schema.Use(group='group1', line=1), + mjcf_schema.Use(group='group2', line=1)], + doc=None, line=1) + schema = mjcf_schema.Schema( + enums={}, + groups={'common': common_group, 'group1': group1, 'group2': group2}, + elements={'elem': elem}, + path='') + cons = generate_mjcf_table._element_constraints(schema, elem) + self.assertEqual(len(cons), 1) # pylint: disable=g-generic-assert + if __name__ == '__main__': googletest.main() diff --git a/test/engine/engine_sensor_test.cc b/test/engine/engine_sensor_test.cc index 9ec922ed..c92d96f5 100644 --- a/test/engine/engine_sensor_test.cc +++ b/test/engine/engine_sensor_test.cc @@ -698,9 +698,9 @@ TEST_F(SensorTest, BadContact) { {"geom1='sphere1' geom2='sphere2' num='-3'", "'num' must be positive in sensor"}, {"geom1='sphere1' geom2='sphere2' site='site'", - "at most one of (geom1, body1, subtree1, site) can be specified"}, + "at most one of 'geom1', 'body1', 'subtree1', 'site' can be specified"}, {"geom2='sphere1' body2='body'", - "at most one of (geom2, body2, subtree2) can be specified"}, + "at most one of 'geom2', 'body2', 'subtree2' can be specified"}, }; for (const auto& test : test_cases) { diff --git a/test/user/user_objects_test.cc b/test/user/user_objects_test.cc index 73789e24..03c396f8 100644 --- a/test/user/user_objects_test.cc +++ b/test/user/user_objects_test.cc @@ -2461,8 +2461,8 @@ TEST_F(UserObjectsTest, BadConnect) { EXPECT_THAT(AsVector(m->eq_data, 6), ElementsAre(0, 0, 0, 0, 0, 0)); char error_missing[] = - "either both body1 and anchor must be defined," - " or both site1 and site2 must be defined\nElement 'connect', line 12"; + "one of ('site1', 'site2'), ('body1', 'anchor') must be specified" + "\nElement 'connect', line 12"; // bad model (missing anchor) xml = base.replace(pos, len, ""); @@ -2471,8 +2471,8 @@ TEST_F(UserObjectsTest, BadConnect) { EXPECT_THAT(error, HasSubstr(error_missing)); char error_mixed[] = - "body and site semantics cannot be mixed" - "\nElement 'connect', line 12"; + "at most one of ('site1', 'site2'), ('body1', 'body2', 'anchor')" + " can be specified\nElement 'connect', line 12"; // bad model (mixing body and site) xml = base.replace(pos, len, ""); @@ -2540,8 +2540,8 @@ TEST_F(UserObjectsTest, BadWeld) { ElementsAre(0, 1, 0, 0, 0, 0, 0, 0, 0, 0)); char error_mixed[] = - "body and site semantics cannot be mixed" - "\nElement 'weld', line 12"; + "at most one of ('site1', 'site2'), ('body1', 'body2', 'anchor', " + "'relpose') can be specified\nElement 'weld', line 12"; // bad model (mixing body and site) xml = base.replace(pos, len, ""); @@ -2568,8 +2568,8 @@ TEST_F(UserObjectsTest, BadWeld) { EXPECT_THAT(error, HasSubstr(error_mixed)); char error_underspecified[] = - "either body1 must be defined and optionally {body2, anchor, " - "relpose}, or site1 and site2 must be defined\nElement 'weld', line 12"; + "one of ('site1', 'site2'), 'body1' must be specified" + "\nElement 'weld', line 12"; // bad model (underspecified body semantics) xml = base.replace(pos, len, ""); @@ -2663,7 +2663,7 @@ TEST_F(UserObjectsTest, Inertial) { )"; m = LoadModelFromString(bad_xml2.c_str(), error, sizeof(error)); ASSERT_THAT(m.get(), IsNull()); - EXPECT_THAT(error, HasSubstr("fullinertia and inertial orientation cannot")); + EXPECT_THAT(error, HasSubstr("at most one of 'fullinertia', 'quat'")); } // Merged COM must be correct when a fused-static child has a non-identity diff --git a/test/xml/xml_native_reader_test.cc b/test/xml/xml_native_reader_test.cc index c1b0cfa1..a2aa3c67 100644 --- a/test/xml/xml_native_reader_test.cc +++ b/test/xml/xml_native_reader_test.cc @@ -2024,7 +2024,7 @@ TEST_F(XMLReaderTest, CameraInvalidFovyAndSensorsize) { std::array error; MjModelPtr m = LoadModelFromString(xml, error.data(), error.size()); EXPECT_THAT(m.get(), IsNull()); - EXPECT_THAT(error.data(), HasSubstr("either 'fovy' or 'sensorsize'")); + EXPECT_THAT(error.data(), HasSubstr("at most one of 'fovy', 'sensorsize'")); EXPECT_THAT(error.data(), HasSubstr("line 6")); } @@ -2081,8 +2081,8 @@ TEST_F(XMLReaderTest, InvalidInertialOrientation) { ASSERT_THAT(model.get(), IsNull()); EXPECT_THAT( error.data(), - HasSubstr( - "fullinertia and inertial orientation cannot both be specified")); + HasSubstr("at most one of 'fullinertia', 'quat', 'axisangle', " + "'xyaxes', 'zaxis', 'euler' can be specified")); } TEST_F(XMLReaderTest, ReadShellParameter) { @@ -2137,7 +2137,7 @@ TEST_F(XMLReaderTest, BuiltinAndFile) { MjModelPtr model = LoadModelFromString(xml, error.data(), error.size()); ASSERT_THAT(model.get(), IsNull()); EXPECT_THAT(error.data(), - HasSubstr("builtin mesh cannot be used with user vertex data")); + HasSubstr("at most one of 'builtin', 'vertex' can be specified")); } TEST_F(XMLReaderTest, MakePlateNoParameters) { @@ -2422,7 +2422,9 @@ TEST_F(RelativeFrameSensorParsingTest, RefNameButNoType) { )"; std::array error; LoadModelFromString(xml, error.data(), error.size()); - EXPECT_THAT(error.data(), HasSubstr("but reftype is missing")); + EXPECT_THAT( + error.data(), + HasSubstr("attributes 'reftype', 'refname' must be specified together")); EXPECT_THAT(error.data(), HasSubstr("line 8")); } @@ -2440,7 +2442,9 @@ TEST_F(RelativeFrameSensorParsingTest, RefTypeButNoName) { )"; std::array error; LoadModelFromString(xml, error.data(), error.size()); - EXPECT_THAT(error.data(), HasSubstr("attribute missing: 'refname'")); + EXPECT_THAT( + error.data(), + HasSubstr("attributes 'reftype', 'refname' must be specified together")); EXPECT_THAT(error.data(), HasSubstr("line 8")); } @@ -3563,7 +3567,9 @@ TEST_F(SensorParseTest, UserObjTypeNoName) { std::array error; MjModelPtr model = LoadModelFromString(xml, error.data(), error.size()); ASSERT_THAT(model.get(), IsNull()); - EXPECT_THAT(error.data(), HasSubstr("objtype 'site' given but")); + EXPECT_THAT( + error.data(), + HasSubstr("attributes 'objtype', 'objname' must be specified together")); EXPECT_THAT(error.data(), HasSubstr("line 4")); } @@ -3578,7 +3584,9 @@ TEST_F(SensorParseTest, UserObjNameNoType) { std::array error; MjModelPtr model = LoadModelFromString(xml, error.data(), error.size()); ASSERT_THAT(model.get(), IsNull()); - EXPECT_THAT(error.data(), HasSubstr("objname 'kevin' given but")); + EXPECT_THAT( + error.data(), + HasSubstr("attributes 'objtype', 'objname' must be specified together")); EXPECT_THAT(error.data(), HasSubstr("line 4")); }