diff --git a/src/user/user_model.cc b/src/user/user_model.cc index 0d04a9a0..ad993013 100644 --- a/src/user/user_model.cc +++ b/src/user/user_model.cc @@ -329,6 +329,20 @@ void mjCModel::CopyPlugin(std::vector& dest, } mjCModel& mjCModel::operator+=(const mjCModel& other) { + // TODO: use compiler settings stored in specs_ during compilation + std::string msg = "cannot attach mjSpecs with incompatible compiler/"; + if (other.spec.degree != spec.degree) { + throw mjCError(nullptr, (msg + "angle attribute").c_str()); + } + if (other.spec.autolimits != spec.autolimits) { + throw mjCError(nullptr, (msg + "autolimits attribute").c_str()); + } + if (other.spec.eulerseq[0] != spec.eulerseq[0] || + other.spec.eulerseq[1] != spec.eulerseq[1] || + other.spec.eulerseq[2] != spec.eulerseq[2]) { + throw mjCError(nullptr, (msg + "eulerseq attribute").c_str()); + } + // create global lists mjCBody *world = bodies_[0]; if (compiled) { diff --git a/test/user/user_api_test.cc b/test/user/user_api_test.cc index 42123755..be4b5279 100644 --- a/test/user/user_api_test.cc +++ b/test/user/user_api_test.cc @@ -37,6 +37,7 @@ namespace { using ::testing::HasSubstr; using ::testing::NotNull; +using ::testing::IsNull; // -------------------------- test model manipulation ------------------------- @@ -1486,5 +1487,24 @@ TEST_F(MujocoTest, RepeatedAttachKeyframe) { mj_deleteModel(model_2); } +TEST_F(MujocoTest, DifferentUnitsNotAllowed) { + mjSpec* spec_1 = mj_makeSpec(); + mjSpec* spec_2 = mj_makeSpec(); + spec_1->degree = 1; + spec_2->degree = 0; + + mjsBody* body = mjs_addBody(mjs_findBody(spec_1, "world"), 0); + mjsFrame* frame = mjs_addFrame(mjs_findBody(spec_2, "world"), 0); + + constexpr char msg[] = "mjSpecs with incompatible compiler/angle"; + EXPECT_THAT(mjs_attachBody(frame, body, "child-", ""), IsNull()); + EXPECT_THAT(mjs_attachFrame(body, frame, "child-", ""), IsNull()); + EXPECT_THAT(mjs_getError(spec_1), HasSubstr(msg)); + EXPECT_THAT(mjs_getError(spec_2), HasSubstr(msg)); + + mj_deleteSpec(spec_1); + mj_deleteSpec(spec_2); +} + } // namespace } // namespace mujoco