Throw an error if multiple orientation specifiers are used in the same element.

- Applies to [orientation specifiers](https://mujoco.readthedocs.io/en/latest/modeling.html#frame-orientations) in `body`, `inertial`, `geom`, `site`, `camera`.
- Before this change the check was done only for multiple *alternative* specifiers, but not for `quat` and an alternative specifier.
- Moved the check from the compiler to the parser.
- Added tests.

PiperOrigin-RevId: 453201981
Change-Id: I20907361f211dae904e734cd083e9df0efe4f654
This commit is contained in:
Alessio Quaglino
2022-06-06 08:12:32 -07:00
committed by Copybara-Service
parent 652bab3eec
commit 16baac9353
4 changed files with 52 additions and 16 deletions
-10
View File
@@ -120,16 +120,6 @@ mjCAlternative::mjCAlternative() {
// used for geom, site, body and camera frames
const char* mjCAlternative::Set(double* quat, double* inertia,
bool degree, const char* sequence) {
// check for multiple defitions
int ndef = (int)mjuu_defined(axisangle[0]) +
(int)mjuu_defined(xyaxes[0]) +
(int)mjuu_defined(zaxis[0]) +
(int)mjuu_defined(euler[0]) +
(int)mjuu_defined(fullinertia[0]);
if (ndef>1) {
return "too many alternative definitions";
}
// set quat using axisangle
if (mjuu_defined(axisangle[0])) {
// convert to radians if necessary, normalize axis
+8 -5
View File
@@ -52,9 +52,12 @@ void mjXBase::SetModel(mjCModel* _model) {
// read alternative orientation specification
void mjXBase::ReadAlternative(XMLElement* elem, mjCAlternative& alt) {
string text;
ReadAttr(elem, "axisangle", 4, alt.axisangle, text);
ReadAttr(elem, "xyaxes", 6, alt.xyaxes, text);
ReadAttr(elem, "zaxis", 3, alt.zaxis, text);
ReadAttr(elem, "euler", 3, alt.euler, text);
ReadAttr(elem, "fullinertia", 6, alt.fullinertia, text);
int read = (int)(elem->Attribute("quat") != 0) +
(ReadAttr(elem, "axisangle", 4, alt.axisangle, text) ? 1 : 0) +
(ReadAttr(elem, "xyaxes", 6, alt.xyaxes, text) ? 1 : 0) +
(ReadAttr(elem, "zaxis", 3, alt.zaxis, text) ? 1 : 0) +
(ReadAttr(elem, "euler", 3, alt.euler, text) ? 1 : 0) +
(ReadAttr(elem, "fullinertia", 6, alt.fullinertia, text) ? 1 : 0);
if (read > 1)
throw mjXError(elem, "multiple orientation specifiers for the same field are not allowed");
}
+1 -1
View File
@@ -1120,9 +1120,9 @@ void mjXReader::OneGeom(XMLElement* elem, mjCGeom* pgeom) {
ReadAttr(elem, "mass", 1, &pgeom->_mass, text);
ReadAttr(elem, "density", 1, &pgeom->density, text);
ReadAttr(elem, "fromto", 6, pgeom->fromto, text);
ReadAlternative(elem, pgeom->alt);
ReadAttr(elem, "pos", 3, pgeom->pos, text);
ReadAttr(elem, "quat", 4, pgeom->quat, text);
ReadAlternative(elem, pgeom->alt);
GetXMLPos(elem, pgeom);
}
+43
View File
@@ -192,6 +192,49 @@ TEST_F(UserDataTest, AllowsSpaces) {
mj_deleteModel(model);
}
TEST_F(UserDataTest, InvalidDoubleOrientation) {
std::string prefix = "<mujoco><worldbody><";
std::string suffix = "/></worldbody></mujoco>";
std::vector<std::string> orientations = {
R"( quat="0 1 0 0" )",
R"( euler="1.7 2.9 0.1" )",
R"( zaxis="1.7 2.9 0.1" )",
R"( axisangle="1.7 2.9 0.1 0" )",
R"( xyaxes="1.7 2.9 0.1 0.4 1.4 0.6" )",
};
std::vector<std::string> fields = {
"geom", "body", "camera", "site"
};
for (auto const& field : fields) {
for (auto const& orient1 : orientations) {
for (auto const& orient2 : orientations) {
if (orient1 == orient2) continue;
std::string xml = prefix + field + orient1 + orient2 + suffix;
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml.c_str(), error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("multiple orientation specifiers for the same field"));
}
}
}
}
TEST_F(UserDataTest, InvalidInertialOrientation) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<inertial pos="0 0 0" mass="1" quat="1 0 0 0" fullinertia="1 1 1 0 0 0"/>
</body>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("multiple orientation specifiers for the same field"));
}
// ------------- test relative frame sensor parsing ----------------------------
using RelativeFrameSensorParsingTest = MujocoTest;