Change LoadModelFromString to return a smart pointer, add MakeData, and update tests to have C++ RAII clean up model and data.
PiperOrigin-RevId: 935980153 Change-Id: I41d25bfab4935494dc984168820cb7cad123cadf
This commit is contained in:
committed by
Copybara-Service
parent
34d142ee50
commit
1490336955
+179
-194
@@ -24,12 +24,12 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <absl/strings/str_format.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <mujoco/mujoco.h>
|
||||
#include <mujoco/mjspec.h>
|
||||
#include <absl/strings/str_format.h>
|
||||
#include <mujoco/mjplugin.h>
|
||||
#include <mujoco/mjspec.h>
|
||||
#include <mujoco/mujoco.h>
|
||||
#include "src/xml/xml_api.h"
|
||||
#include "test/compare_model.h"
|
||||
#include "test/fixture.h"
|
||||
@@ -228,7 +228,6 @@ TEST_F(MujocoTest, OriginSpecInvariantToAttachment) {
|
||||
mjs_findElement(parent_spec, mjOBJ_BODY, "parent_body");
|
||||
EXPECT_EQ(mjs_getOriginSpec(parent_spec_body), parent_spec);
|
||||
|
||||
|
||||
mj_deleteSpec(child_spec);
|
||||
mj_deleteSpec(parent_spec);
|
||||
}
|
||||
@@ -404,10 +403,9 @@ TEST_F(MujocoTest, SetToDCMotorNullable) {
|
||||
double motorconst[2] = {0.05, 0.05};
|
||||
double resistance = 2.0;
|
||||
|
||||
const char* err = mjs_setToDCMotor(actuator, motorconst, resistance,
|
||||
nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr,
|
||||
nullptr, 0);
|
||||
const char* err =
|
||||
mjs_setToDCMotor(actuator, motorconst, resistance, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr, 0);
|
||||
EXPECT_STREQ(err, "");
|
||||
EXPECT_EQ(actuator->gainprm[0], 2.0);
|
||||
EXPECT_EQ(actuator->gainprm[1], 0.05);
|
||||
@@ -427,10 +425,9 @@ TEST_F(MujocoTest, SetToDCMotorDeriveKe) {
|
||||
double resistance = 2.0;
|
||||
double nominal[3] = {12.0, 0, 100.0}; // vn=12, omega0=100
|
||||
|
||||
const char* err = mjs_setToDCMotor(actuator, nullptr, resistance,
|
||||
nominal, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr,
|
||||
nullptr, 0);
|
||||
const char* err =
|
||||
mjs_setToDCMotor(actuator, nullptr, resistance, nominal, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, 0);
|
||||
EXPECT_STREQ(err, "");
|
||||
EXPECT_EQ(actuator->gainprm[0], 2.0);
|
||||
EXPECT_NEAR(actuator->gainprm[1], 0.12, 1e-5);
|
||||
@@ -447,10 +444,9 @@ TEST_F(MujocoTest, SetToDCMotorFull) {
|
||||
double saturation[3] = {1.0, 2.0, 3.0};
|
||||
double controller[6] = {10.0, 20.0, 30.0, 40.0, 50.0, 60.0};
|
||||
|
||||
const char* err = mjs_setToDCMotor(actuator, motorconst, resistance,
|
||||
nullptr, saturation, nullptr,
|
||||
nullptr, controller, nullptr,
|
||||
nullptr, 0);
|
||||
const char* err =
|
||||
mjs_setToDCMotor(actuator, motorconst, resistance, nullptr, saturation,
|
||||
nullptr, nullptr, controller, nullptr, nullptr, 0);
|
||||
EXPECT_STREQ(err, "");
|
||||
EXPECT_EQ(actuator->gainprm[0], 2.0); // resistance
|
||||
EXPECT_EQ(actuator->gainprm[1], 0.05); // K
|
||||
@@ -473,10 +469,9 @@ TEST_F(MujocoTest, SetToDCMotorLuGre) {
|
||||
double resistance = 2.0;
|
||||
double lugre[5] = {100.0, 1.0, 0.5, 0.7, 10.0};
|
||||
|
||||
const char* err = mjs_setToDCMotor(actuator, motorconst, resistance,
|
||||
nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr,
|
||||
lugre, 0);
|
||||
const char* err =
|
||||
mjs_setToDCMotor(actuator, motorconst, resistance, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, lugre, 0);
|
||||
EXPECT_STREQ(err, "");
|
||||
EXPECT_EQ(actuator->dynprm[5], 100.0); // stiffness
|
||||
EXPECT_EQ(actuator->dynprm[6], 1.0); // damping
|
||||
@@ -764,7 +759,6 @@ TEST_F(MujocoTest, ModifyShellInertiaFails) {
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(MujocoTest, RecompileEdit) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
@@ -778,18 +772,18 @@ TEST_F(MujocoTest, RecompileEdit) {
|
||||
)";
|
||||
|
||||
std::array<char, 1000> er;
|
||||
mjSpec *spec = mj_parseXMLString(xml, 0, er.data(), er.size());
|
||||
mjSpec* spec = mj_parseXMLString(xml, 0, er.data(), er.size());
|
||||
EXPECT_THAT(spec, NotNull()) << er.data();
|
||||
mjModel *m1 = mj_compile(spec, nullptr);
|
||||
mjModel* m1 = mj_compile(spec, nullptr);
|
||||
EXPECT_THAT(m1, NotNull());
|
||||
|
||||
// add a geom
|
||||
mjsBody *world = mjs_findBody(spec, "world");
|
||||
mjsGeom *geom = mjs_addGeom(world, nullptr);
|
||||
mjsBody* world = mjs_findBody(spec, "world");
|
||||
mjsGeom* geom = mjs_addGeom(world, nullptr);
|
||||
geom->size[0] = 1;
|
||||
|
||||
// compile again
|
||||
mjModel *m2 = mj_compile(spec, nullptr);
|
||||
mjModel* m2 = mj_compile(spec, nullptr);
|
||||
EXPECT_THAT(m2, NotNull());
|
||||
|
||||
mj_deleteModel(m1);
|
||||
@@ -837,43 +831,40 @@ TEST_F(MujocoTest, RecompileCompareObjCache) {
|
||||
std::array<char, 1024> error;
|
||||
|
||||
// load model once
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size(), vfs.get());
|
||||
MjModelPtr m =
|
||||
LoadModelFromString(xml, error.data(), error.size(), vfs.get());
|
||||
EXPECT_EQ(m->mesh_vert[0], -0.5);
|
||||
mj_deleteModel(m);
|
||||
|
||||
// update cube.obj, load again
|
||||
mj_deleteFileVFS(vfs.get(), "cube.obj");
|
||||
mj_addBufferVFS(vfs.get(), "cube.obj", cube2, sizeof(cube2));
|
||||
m = LoadModelFromString(xml, error.data(), error.size(), vfs.get());
|
||||
EXPECT_EQ(m->mesh_vert[0], -1);
|
||||
mj_deleteModel(m);
|
||||
|
||||
mj_deleteVFS(vfs.get());
|
||||
}
|
||||
|
||||
// tiny RGB 2 x 3 PNG file
|
||||
static constexpr uint8_t tex1[] = {
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
|
||||
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02,
|
||||
0x08, 0x02, 0x00, 0x00, 0x00, 0x12, 0x16, 0xf1, 0x4d, 0x00, 0x00, 0x00,
|
||||
0x1c, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x78, 0xc1, 0xc0, 0xc0,
|
||||
0xc0, 0xf0, 0xbf, 0xb8, 0xb8, 0x98, 0x81, 0xe1, 0x3f, 0xc3, 0xff, 0xff,
|
||||
0xff, 0xc5, 0xc4, 0xc4, 0x00, 0x46, 0xd7, 0x07, 0x7f, 0xd2, 0x52, 0xa1,
|
||||
0x41, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60,
|
||||
0x82
|
||||
};
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x00, 0x02, 0x08, 0x02, 0x00, 0x00, 0x00, 0x12, 0x16, 0xf1, 0x4d,
|
||||
0x00, 0x00, 0x00, 0x1c, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63,
|
||||
0x78, 0xc1, 0xc0, 0xc0, 0xc0, 0xf0, 0xbf, 0xb8, 0xb8, 0x98, 0x81,
|
||||
0xe1, 0x3f, 0xc3, 0xff, 0xff, 0xff, 0xc5, 0xc4, 0xc4, 0x00, 0x46,
|
||||
0xd7, 0x07, 0x7f, 0xd2, 0x52, 0xa1, 0x41, 0x00, 0x00, 0x00, 0x00,
|
||||
0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82};
|
||||
|
||||
// previous PNG file, but rotated by 180 degrees
|
||||
static constexpr uint8_t tex2[] = {
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
|
||||
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02,
|
||||
0x08, 0x02, 0x00, 0x00, 0x00, 0x12, 0x16, 0xf1, 0x4d, 0x00, 0x00, 0x00,
|
||||
0x1c, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x10, 0x13, 0x13, 0xfb,
|
||||
0xff, 0xff, 0x3f, 0xc3, 0x7f, 0x06, 0x96, 0xd8, 0xd8, 0x58, 0x46, 0x46,
|
||||
0x86, 0x17, 0x0c, 0x0c, 0x00, 0x49, 0x22, 0x06, 0x44, 0xe4, 0x91, 0xb8,
|
||||
0x83, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60,
|
||||
0x82
|
||||
};
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x00, 0x02, 0x08, 0x02, 0x00, 0x00, 0x00, 0x12, 0x16, 0xf1, 0x4d,
|
||||
0x00, 0x00, 0x00, 0x1c, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63,
|
||||
0x10, 0x13, 0x13, 0xfb, 0xff, 0xff, 0x3f, 0xc3, 0x7f, 0x06, 0x96,
|
||||
0xd8, 0xd8, 0x58, 0x46, 0x46, 0x86, 0x17, 0x0c, 0x0c, 0x00, 0x49,
|
||||
0x22, 0x06, 0x44, 0xe4, 0x91, 0xb8, 0x83, 0x00, 0x00, 0x00, 0x00,
|
||||
0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82};
|
||||
|
||||
TEST_F(MujocoTest, RecompileComparePngCache) {
|
||||
static constexpr char xml[] = R"(
|
||||
@@ -896,10 +887,10 @@ TEST_F(MujocoTest, RecompileComparePngCache) {
|
||||
std::array<char, 1024> error;
|
||||
|
||||
// load model once
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size(), vfs.get());
|
||||
MjModelPtr m =
|
||||
LoadModelFromString(xml, error.data(), error.size(), vfs.get());
|
||||
EXPECT_EQ(m->ntexdata, 18); // w x h x rgb = 3 x 2 x 3
|
||||
mjtByte byte = m->tex_data[0];
|
||||
mj_deleteModel(m);
|
||||
|
||||
// update tex.png, load again
|
||||
mj_deleteFileVFS(vfs.get(), "tex.png");
|
||||
@@ -907,7 +898,6 @@ TEST_F(MujocoTest, RecompileComparePngCache) {
|
||||
m = LoadModelFromString(xml, error.data(), error.size(), vfs.get());
|
||||
EXPECT_NE(m->tex_data[0], byte);
|
||||
EXPECT_EQ(m->tex_data[15], byte); // first pixel is now last pixel
|
||||
mj_deleteModel(m);
|
||||
|
||||
mj_deleteVFS(vfs.get());
|
||||
}
|
||||
@@ -937,14 +927,13 @@ TEST_F(MujocoTest, DisableCache) {
|
||||
std::array<char, 1024> error;
|
||||
|
||||
// load model once
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size(), vfs.get());
|
||||
MjModelPtr m =
|
||||
LoadModelFromString(xml, error.data(), error.size(), vfs.get());
|
||||
|
||||
EXPECT_EQ(mj_getCacheSize(cache), 0);
|
||||
EXPECT_EQ(m->ntexdata, 18); // w x h x rgb = 3 x 2 x 3
|
||||
|
||||
mj_setCacheCapacity(cache, capacity);
|
||||
|
||||
mj_deleteModel(m);
|
||||
mj_deleteVFS(vfs.get());
|
||||
}
|
||||
|
||||
@@ -1226,16 +1215,16 @@ TEST_F(MujocoTest, AttachSame) {
|
||||
EXPECT_THAT(m_attached->body_parentid[4], 0);
|
||||
|
||||
// compare with expected XML
|
||||
mjModel* m_expected = LoadModelFromString(xml_result, er.data(), er.size());
|
||||
EXPECT_THAT(m_expected, NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(m_attached, m_expected, field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';;
|
||||
MjModelPtr m_expected = LoadModelFromString(xml_result, er.data(), er.size());
|
||||
EXPECT_THAT(m_expected.get(), NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(m_attached, m_expected.get(), field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';
|
||||
;
|
||||
|
||||
// destroy everything
|
||||
mj_deleteSpec(parent);
|
||||
mj_deleteModel(m_attached);
|
||||
mj_deleteModel(m_expected);
|
||||
}
|
||||
|
||||
TEST_F(MujocoTest, AttachSpatialTendonWithoutSidesite) {
|
||||
@@ -1283,13 +1272,15 @@ TEST_F(MujocoTest, AttachSpatialTendonWithoutSidesite) {
|
||||
mjsSite* attach_site = mjs_addSite(parent_body, 0);
|
||||
mjs_setName(attach_site->element, "attach_site");
|
||||
|
||||
mjs_attach(attach_site->element,
|
||||
mjs_findBody(child, "child_body")->element, "", "_child");
|
||||
mjs_attach(attach_site->element, mjs_findBody(child, "child_body")->element,
|
||||
"", "_child");
|
||||
|
||||
EXPECT_THAT(mjs_findElement(parent, mjOBJ_TENDON,
|
||||
"tendon_with_sidesite_child"), NotNull());
|
||||
EXPECT_THAT(mjs_findElement(parent, mjOBJ_TENDON,
|
||||
"tendon_without_sidesite_child"), NotNull());
|
||||
EXPECT_THAT(
|
||||
mjs_findElement(parent, mjOBJ_TENDON, "tendon_with_sidesite_child"),
|
||||
NotNull());
|
||||
EXPECT_THAT(
|
||||
mjs_findElement(parent, mjOBJ_TENDON, "tendon_without_sidesite_child"),
|
||||
NotNull());
|
||||
|
||||
mjModel* model = mj_compile(parent, nullptr);
|
||||
ASSERT_THAT(model, NotNull()) << mjs_getError(parent);
|
||||
@@ -1335,11 +1326,9 @@ TEST_F(MujocoTest, AttachSpatialTendonGitHubIssue3119) {
|
||||
</mujoco>)";
|
||||
|
||||
std::array<char, 1000> er;
|
||||
mjSpec* parent_spec =
|
||||
mj_parseXMLString(parent_xml, 0, er.data(), er.size());
|
||||
mjSpec* parent_spec = mj_parseXMLString(parent_xml, 0, er.data(), er.size());
|
||||
ASSERT_THAT(parent_spec, NotNull()) << er.data();
|
||||
mjSpec* child_spec =
|
||||
mj_parseXMLString(child_xml, 0, er.data(), er.size());
|
||||
mjSpec* child_spec = mj_parseXMLString(child_xml, 0, er.data(), er.size());
|
||||
ASSERT_THAT(child_spec, NotNull()) << er.data();
|
||||
|
||||
mjsBody* parent_body = mjs_findBody(parent_spec, "parent_body");
|
||||
@@ -1348,13 +1337,14 @@ TEST_F(MujocoTest, AttachSpatialTendonGitHubIssue3119) {
|
||||
mjs_setName(attach_site->element, "attach_site");
|
||||
|
||||
mjs_attach(attach_site->element,
|
||||
mjs_findBody(child_spec, "child_body")->element,
|
||||
"", "_child");
|
||||
mjs_findBody(child_spec, "child_body")->element, "", "_child");
|
||||
|
||||
EXPECT_THAT(
|
||||
mjs_findElement(parent_spec, mjOBJ_TENDON, "tendon_with_sidesite_child"),
|
||||
NotNull());
|
||||
EXPECT_THAT(mjs_findElement(parent_spec, mjOBJ_TENDON,
|
||||
"tendon_with_sidesite_child"), NotNull());
|
||||
EXPECT_THAT(mjs_findElement(parent_spec, mjOBJ_TENDON,
|
||||
"tendon_without_sidesite_child"), NotNull());
|
||||
"tendon_without_sidesite_child"),
|
||||
NotNull());
|
||||
|
||||
mjModel* model = mj_compile(parent_spec, nullptr);
|
||||
ASSERT_THAT(model, NotNull()) << mjs_getError(parent_spec);
|
||||
@@ -1498,17 +1488,17 @@ TEST_F(MujocoTest, AttachDifferent) {
|
||||
EXPECT_THAT(mjs_findDefault(parent, "attached-cylinder-1"), NotNull());
|
||||
|
||||
// compare with expected XML
|
||||
mjModel* m_expected = LoadModelFromString(xml_result, er.data(), er.size());
|
||||
EXPECT_THAT(m_expected, NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(m_attached, m_expected, field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';;
|
||||
MjModelPtr m_expected = LoadModelFromString(xml_result, er.data(), er.size());
|
||||
EXPECT_THAT(m_expected.get(), NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(m_attached, m_expected.get(), field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';
|
||||
;
|
||||
|
||||
// destroy everything
|
||||
mj_deleteSpec(parent);
|
||||
mj_deleteSpec(child);
|
||||
mj_deleteModel(m_attached);
|
||||
mj_deleteModel(m_expected);
|
||||
}
|
||||
|
||||
TEST_F(MujocoTest, AttachFrame) {
|
||||
@@ -1633,17 +1623,17 @@ TEST_F(MujocoTest, AttachFrame) {
|
||||
EXPECT_THAT(m_attached->body_parentid[2], 1);
|
||||
|
||||
// compare with expected XML
|
||||
mjModel* m_expected = LoadModelFromString(xml_result, er.data(), er.size());
|
||||
EXPECT_THAT(m_expected, NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(m_attached, m_expected, field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';;
|
||||
MjModelPtr m_expected = LoadModelFromString(xml_result, er.data(), er.size());
|
||||
EXPECT_THAT(m_expected.get(), NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(m_attached, m_expected.get(), field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';
|
||||
;
|
||||
|
||||
// destroy everything
|
||||
mj_deleteSpec(parent);
|
||||
mj_deleteSpec(child);
|
||||
mj_deleteModel(m_attached);
|
||||
mj_deleteModel(m_expected);
|
||||
}
|
||||
|
||||
TEST_F(MujocoTest, AttachCompiled) {
|
||||
@@ -1691,8 +1681,8 @@ TEST_F(MujocoTest, AttachCompiled) {
|
||||
|
||||
// check that attached model can be compiled
|
||||
mjModel* m_attached = mj_compile(parent, 0);
|
||||
EXPECT_THAT(m_attached, NotNull()) <<
|
||||
"Failed to compile attached model" << mjs_getError(parent);
|
||||
EXPECT_THAT(m_attached, NotNull())
|
||||
<< "Failed to compile attached model" << mjs_getError(parent);
|
||||
|
||||
// destroy everything
|
||||
mj_deleteSpec(parent);
|
||||
@@ -1758,24 +1748,23 @@ void TestDetachBody(bool compile) {
|
||||
std::array<char, 1024> s;
|
||||
EXPECT_EQ(mj_saveXMLString(child, s.data(), 1024, e.data(), 1024), -1);
|
||||
EXPECT_THAT(e.data(), compile
|
||||
? HasSubstr("Model has pending keyframes")
|
||||
: HasSubstr("Only compiled model can be written"));
|
||||
? HasSubstr("Model has pending keyframes")
|
||||
: HasSubstr("Only compiled model can be written"));
|
||||
|
||||
// compile new model
|
||||
mjModel* m_detached = mj_compile(child, 0);
|
||||
EXPECT_THAT(m_detached, NotNull());
|
||||
|
||||
// compare with expected XML
|
||||
mjModel* m_expected = LoadModelFromString(xml_result, er.data(), er.size());
|
||||
EXPECT_THAT(m_expected, NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(m_detached, m_expected, field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';
|
||||
MjModelPtr m_expected = LoadModelFromString(xml_result, er.data(), er.size());
|
||||
EXPECT_THAT(m_expected.get(), NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(m_detached, m_expected.get(), field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';
|
||||
|
||||
// destroy everything
|
||||
mj_deleteSpec(child);
|
||||
mj_deleteModel(m_detached);
|
||||
mj_deleteModel(m_expected);
|
||||
if (m_child) mj_deleteModel(m_child);
|
||||
}
|
||||
|
||||
@@ -1836,16 +1825,15 @@ TEST_F(MujocoTest, AttachToSite) {
|
||||
|
||||
mjModel* model = mj_compile(parent, 0);
|
||||
EXPECT_THAT(model, NotNull());
|
||||
mjModel* expected = LoadModelFromString(xml_result, er.data(), er.size());
|
||||
EXPECT_THAT(expected, NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(model, expected, field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';
|
||||
MjModelPtr expected = LoadModelFromString(xml_result, er.data(), er.size());
|
||||
EXPECT_THAT(expected.get(), NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(model, expected.get(), field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';
|
||||
|
||||
mj_deleteSpec(parent);
|
||||
mj_deleteSpec(child);
|
||||
mj_deleteModel(model);
|
||||
mj_deleteModel(expected);
|
||||
}
|
||||
|
||||
TEST_F(MujocoTest, AttachFrameToSite) {
|
||||
@@ -1902,16 +1890,15 @@ TEST_F(MujocoTest, AttachFrameToSite) {
|
||||
|
||||
mjModel* model = mj_compile(parent, 0);
|
||||
EXPECT_THAT(model, NotNull());
|
||||
mjModel* expected = LoadModelFromString(xml_result, er.data(), er.size());
|
||||
EXPECT_THAT(expected, NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(model, expected, field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';
|
||||
MjModelPtr expected = LoadModelFromString(xml_result, er.data(), er.size());
|
||||
EXPECT_THAT(expected.get(), NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(model, expected.get(), field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';
|
||||
|
||||
mj_deleteSpec(parent);
|
||||
mj_deleteSpec(child);
|
||||
mj_deleteModel(model);
|
||||
mj_deleteModel(expected);
|
||||
}
|
||||
|
||||
TEST_F(MujocoTest, BodyToFrame) {
|
||||
@@ -1991,18 +1978,17 @@ TEST_F(MujocoTest, BodyToFrame) {
|
||||
// compile and compare
|
||||
mjModel* model2 = mj_compile(parent, 0);
|
||||
EXPECT_THAT(model2, NotNull());
|
||||
mjModel* expected = LoadModelFromString(xml_result, er.data(), er.size());
|
||||
EXPECT_THAT(expected, NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(model2, expected, field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';
|
||||
MjModelPtr expected = LoadModelFromString(xml_result, er.data(), er.size());
|
||||
EXPECT_THAT(expected.get(), NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(model2, expected.get(), field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';
|
||||
|
||||
mj_deleteSpec(parent);
|
||||
mj_deleteSpec(child1);
|
||||
mj_deleteSpec(child2);
|
||||
mj_deleteModel(model1);
|
||||
mj_deleteModel(model2);
|
||||
mj_deleteModel(expected);
|
||||
}
|
||||
|
||||
TEST_F(MujocoTest, BodyToFrameWithInertial) {
|
||||
@@ -2100,11 +2086,11 @@ TEST_F(MujocoTest, AttachSpecToSite) {
|
||||
// compile and compare
|
||||
mjModel* model = mj_compile(parent, 0);
|
||||
EXPECT_THAT(model, NotNull());
|
||||
mjModel* expected = LoadModelFromString(xml_result, er.data(), er.size());
|
||||
EXPECT_THAT(expected, NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(model, expected, field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';
|
||||
MjModelPtr expected = LoadModelFromString(xml_result, er.data(), er.size());
|
||||
EXPECT_THAT(expected.get(), NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(model, expected.get(), field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';
|
||||
|
||||
// check that the child world still exists
|
||||
mjsBody* child_world = mjs_findBody(child, "world");
|
||||
@@ -2113,7 +2099,6 @@ TEST_F(MujocoTest, AttachSpecToSite) {
|
||||
mj_deleteSpec(parent);
|
||||
mj_deleteSpec(child);
|
||||
mj_deleteModel(model);
|
||||
mj_deleteModel(expected);
|
||||
}
|
||||
|
||||
TEST_F(MujocoTest, AttachSpecToBody) {
|
||||
@@ -2181,11 +2166,11 @@ TEST_F(MujocoTest, AttachSpecToBody) {
|
||||
// compile and compare
|
||||
mjModel* model = mj_compile(parent, 0);
|
||||
EXPECT_THAT(model, NotNull());
|
||||
mjModel* expected = LoadModelFromString(xml_result, er.data(), er.size());
|
||||
EXPECT_THAT(expected, NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(model, expected, field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';
|
||||
MjModelPtr expected = LoadModelFromString(xml_result, er.data(), er.size());
|
||||
EXPECT_THAT(expected.get(), NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(model, expected.get(), field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';
|
||||
|
||||
// check that the child world still exists
|
||||
mjsBody* child_world = mjs_findBody(child, "world");
|
||||
@@ -2194,7 +2179,6 @@ TEST_F(MujocoTest, AttachSpecToBody) {
|
||||
mj_deleteSpec(parent);
|
||||
mj_deleteSpec(child);
|
||||
mj_deleteModel(model);
|
||||
mj_deleteModel(expected);
|
||||
}
|
||||
|
||||
TEST_F(MujocoTest, PreserveState) {
|
||||
@@ -2246,31 +2230,32 @@ TEST_F(MujocoTest, PreserveState) {
|
||||
// compile models
|
||||
mjModel* model = mj_compile(spec, 0);
|
||||
EXPECT_THAT(model, NotNull());
|
||||
mjModel* m_expected = LoadModelFromString(xml_expected, er.data(), er.size());
|
||||
EXPECT_THAT(m_expected, NotNull());
|
||||
MjModelPtr m_expected =
|
||||
LoadModelFromString(xml_expected, er.data(), er.size());
|
||||
EXPECT_THAT(m_expected.get(), NotNull());
|
||||
|
||||
// create data
|
||||
mjData* data = mj_makeData(model);
|
||||
EXPECT_THAT(data, NotNull());
|
||||
mjData* d_expected = mj_makeData(m_expected);
|
||||
EXPECT_THAT(d_expected, NotNull());
|
||||
MjDataPtr d_expected = MakeData(m_expected);
|
||||
EXPECT_THAT(d_expected.get(), NotNull());
|
||||
|
||||
// set ctrl
|
||||
data->ctrl[0] = 1;
|
||||
data->ctrl[1] = 2;
|
||||
d_expected->ctrl[0] = 2;
|
||||
d_expected.get()->ctrl[0] = 2;
|
||||
|
||||
// set mocap
|
||||
data->mocap_pos[3] = 1;
|
||||
data->mocap_quat[4] = 0;
|
||||
data->mocap_quat[5] = 1;
|
||||
d_expected->mocap_pos[0] = 1;
|
||||
d_expected->mocap_quat[0] = 0;
|
||||
d_expected->mocap_quat[1] = 1;
|
||||
d_expected.get()->mocap_pos[0] = 1;
|
||||
d_expected.get()->mocap_quat[0] = 0;
|
||||
d_expected.get()->mocap_quat[1] = 1;
|
||||
|
||||
// step models
|
||||
mj_step(model, data);
|
||||
mj_step(m_expected, d_expected);
|
||||
mj_step(m_expected.get(), d_expected.get());
|
||||
EXPECT_THAT(data->time, model->opt.timestep);
|
||||
|
||||
// detach subtree
|
||||
@@ -2298,7 +2283,7 @@ TEST_F(MujocoTest, PreserveState) {
|
||||
joint->axis[0] = 0;
|
||||
joint->axis[1] = 0;
|
||||
joint->axis[2] = 1;
|
||||
joint->ref = d_expected->qpos[m_expected->nq-1];
|
||||
joint->ref = d_expected.get()->qpos[m_expected->nq - 1];
|
||||
|
||||
// compile new model
|
||||
mj_recompile(spec, 0, model, data);
|
||||
@@ -2308,32 +2293,36 @@ TEST_F(MujocoTest, PreserveState) {
|
||||
// compare qpos
|
||||
EXPECT_EQ(model->nq, m_expected->nq);
|
||||
for (int i = 0; i < model->nq; ++i) {
|
||||
EXPECT_EQ(data->qpos[i], d_expected->qpos[i]) << i;
|
||||
EXPECT_EQ(data->qpos[i], d_expected.get()->qpos[i]) << i;
|
||||
}
|
||||
|
||||
// compare qvel
|
||||
EXPECT_EQ(model->nv, m_expected->nv);
|
||||
for (int i = 0; i < model->nv-1; ++i) {
|
||||
EXPECT_EQ(data->qvel[i], d_expected->qvel[i]) << i;
|
||||
for (int i = 0; i < model->nv - 1; ++i) {
|
||||
EXPECT_EQ(data->qvel[i], d_expected.get()->qvel[i]) << i;
|
||||
}
|
||||
|
||||
// second body was added after stepping so qvel should be zero
|
||||
EXPECT_EQ(data->qvel[model->nv-1], 0);
|
||||
EXPECT_EQ(data->qvel[model->nv - 1], 0);
|
||||
|
||||
// compare act
|
||||
EXPECT_EQ(model->na, m_expected->na);
|
||||
for (int i = 0; i < model->na; ++i) {
|
||||
EXPECT_EQ(data->act[i], d_expected->act[i]) << i;
|
||||
EXPECT_EQ(data->act[i], d_expected.get()->act[i]) << i;
|
||||
}
|
||||
|
||||
// compare mocap
|
||||
EXPECT_EQ(model->nmocap, m_expected->nmocap);
|
||||
for (int i = 0; i < model->nmocap; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
EXPECT_EQ(data->mocap_pos[3*i+j], d_expected->mocap_pos[3*i+j]) << i;
|
||||
EXPECT_EQ(data->mocap_pos[3 * i + j],
|
||||
d_expected.get()->mocap_pos[3 * i + j])
|
||||
<< i;
|
||||
}
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
EXPECT_EQ(data->mocap_quat[4*i+j], d_expected->mocap_quat[4*i+j]) << i;
|
||||
EXPECT_EQ(data->mocap_quat[4 * i + j],
|
||||
d_expected.get()->mocap_quat[4 * i + j])
|
||||
<< i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2342,10 +2331,8 @@ TEST_F(MujocoTest, PreserveState) {
|
||||
mj_recompile(spec, 0, model, nullptr);
|
||||
|
||||
// destroy everything
|
||||
mj_deleteData(d_expected);
|
||||
mj_deleteSpec(spec);
|
||||
mj_deleteModel(model);
|
||||
mj_deleteModel(m_expected);
|
||||
}
|
||||
|
||||
TEST_F(MujocoTest, RecompileAttach) {
|
||||
@@ -2445,15 +2432,15 @@ TEST_F(MujocoTest, AttachMocap) {
|
||||
mjModel* model = mj_compile(spec, 0);
|
||||
EXPECT_THAT(model, NotNull());
|
||||
|
||||
mjModel* m_expected = LoadModelFromString(xml_expected, er.data(), er.size());
|
||||
EXPECT_THAT(m_expected, NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(model, m_expected, field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';
|
||||
MjModelPtr m_expected =
|
||||
LoadModelFromString(xml_expected, er.data(), er.size());
|
||||
EXPECT_THAT(m_expected.get(), NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(model, m_expected.get(), field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';
|
||||
|
||||
mj_deleteSpec(spec);
|
||||
mj_deleteModel(model);
|
||||
mj_deleteModel(m_expected);
|
||||
}
|
||||
|
||||
TEST_F(MujocoTest, ReplicateKeyframe) {
|
||||
@@ -2475,8 +2462,8 @@ TEST_F(MujocoTest, ReplicateKeyframe) {
|
||||
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m, testing::NotNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m.get(), testing::NotNull()) << error.data();
|
||||
EXPECT_THAT(m->ngeom, 1);
|
||||
EXPECT_THAT(m->nbody, 2);
|
||||
|
||||
@@ -2485,10 +2472,8 @@ TEST_F(MujocoTest, ReplicateKeyframe) {
|
||||
EXPECT_THAT(m->nq, 1);
|
||||
EXPECT_THAT(m->key_qpos[0], 1);
|
||||
EXPECT_THAT(m->key_qpos[1], 0);
|
||||
EXPECT_STREQ(mj_id2name(m, mjOBJ_KEY, 0), "keyframe0");
|
||||
EXPECT_STREQ(mj_id2name(m, mjOBJ_KEY, 1), "keyframe");
|
||||
|
||||
mj_deleteModel(m);
|
||||
EXPECT_STREQ(mj_id2name(m.get(), mjOBJ_KEY, 0), "keyframe0");
|
||||
EXPECT_STREQ(mj_id2name(m.get(), mjOBJ_KEY, 1), "keyframe");
|
||||
}
|
||||
|
||||
TEST_F(MujocoTest, AttachUnnamedAssets) {
|
||||
@@ -2690,17 +2675,17 @@ void AttachNestedKeyframe(bool compile) {
|
||||
std::string field = "";
|
||||
mjModel* m_attached = mj_compile(parent, 0);
|
||||
EXPECT_THAT(m_attached, NotNull());
|
||||
mjModel* m_expected = LoadModelFromString(
|
||||
MjModelPtr m_expected = LoadModelFromString(
|
||||
compile ? expected_xml : expected_xml_uncompiled, er.data(), er.size());
|
||||
EXPECT_THAT(m_expected, NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(m_attached, m_expected, field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';;
|
||||
EXPECT_THAT(m_expected.get(), NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(m_attached, m_expected.get(), field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';
|
||||
;
|
||||
|
||||
mj_deleteSpec(parent);
|
||||
mj_deleteSpec(child);
|
||||
mj_deleteSpec(gchild);
|
||||
mj_deleteModel(m_expected);
|
||||
mj_deleteModel(m_attached);
|
||||
mj_deleteModel(m_child);
|
||||
}
|
||||
@@ -2736,30 +2721,30 @@ TEST_F(MujocoTest, RepeatedAttachKeyframe) {
|
||||
</keyframe>
|
||||
</mujoco>)";
|
||||
|
||||
std::array<char, 1000> er;
|
||||
mjSpec* parent = mj_parseXMLString(xml_1, 0, er.data(), er.size());
|
||||
EXPECT_THAT(parent, NotNull()) << er.data();
|
||||
mjSpec* child = mj_parseXMLString(xml_2, 0, er.data(), er.size());
|
||||
EXPECT_THAT(child, NotNull()) << er.data();
|
||||
std::array<char, 1000> er;
|
||||
mjSpec* parent = mj_parseXMLString(xml_1, 0, er.data(), er.size());
|
||||
EXPECT_THAT(parent, NotNull()) << er.data();
|
||||
mjSpec* child = mj_parseXMLString(xml_2, 0, er.data(), er.size());
|
||||
EXPECT_THAT(child, NotNull()) << er.data();
|
||||
|
||||
mjsBody* body_1 = mjs_findBody(parent, "body");
|
||||
mjsElement* attachment_frame = mjs_addFrame(body_1, 0)->element;
|
||||
mjs_attach(attachment_frame, mjs_findBody(child, "b1")->element, "b1-", "");
|
||||
mjModel* model_1 = mj_compile(parent, 0);
|
||||
EXPECT_THAT(model_1, NotNull());
|
||||
mjs_attach(attachment_frame, mjs_findBody(child, "b2")->element, "b2-", "");
|
||||
mjModel* model_2 = mj_compile(parent, 0);
|
||||
EXPECT_THAT(model_2, NotNull());
|
||||
mjsBody* body_1 = mjs_findBody(parent, "body");
|
||||
mjsElement* attachment_frame = mjs_addFrame(body_1, 0)->element;
|
||||
mjs_attach(attachment_frame, mjs_findBody(child, "b1")->element, "b1-", "");
|
||||
mjModel* model_1 = mj_compile(parent, 0);
|
||||
EXPECT_THAT(model_1, NotNull());
|
||||
mjs_attach(attachment_frame, mjs_findBody(child, "b2")->element, "b2-", "");
|
||||
mjModel* model_2 = mj_compile(parent, 0);
|
||||
EXPECT_THAT(model_2, NotNull());
|
||||
|
||||
EXPECT_EQ(model_1->nkey, 1);
|
||||
EXPECT_EQ(model_2->nkey, 2);
|
||||
EXPECT_STREQ(mj_id2name(model_2, mjOBJ_KEY, 0), "b1-home");
|
||||
EXPECT_STREQ(mj_id2name(model_2, mjOBJ_KEY, 1), "b2-home");
|
||||
EXPECT_EQ(model_1->nkey, 1);
|
||||
EXPECT_EQ(model_2->nkey, 2);
|
||||
EXPECT_STREQ(mj_id2name(model_2, mjOBJ_KEY, 0), "b1-home");
|
||||
EXPECT_STREQ(mj_id2name(model_2, mjOBJ_KEY, 1), "b2-home");
|
||||
|
||||
mj_deleteSpec(parent);
|
||||
mj_deleteSpec(child);
|
||||
mj_deleteModel(model_1);
|
||||
mj_deleteModel(model_2);
|
||||
mj_deleteSpec(parent);
|
||||
mj_deleteSpec(child);
|
||||
mj_deleteModel(model_1);
|
||||
mj_deleteModel(model_2);
|
||||
}
|
||||
|
||||
TEST_F(MujocoTest, ResizeParentKeyframe) {
|
||||
@@ -2820,16 +2805,15 @@ TEST_F(MujocoTest, ResizeParentKeyframe) {
|
||||
|
||||
mjtNum tol = 0;
|
||||
std::string field = "";
|
||||
mjModel* expected = LoadModelFromString(xml_expected, er.data(), er.size());
|
||||
EXPECT_THAT(expected, NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(model, expected, field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';
|
||||
MjModelPtr expected = LoadModelFromString(xml_expected, er.data(), er.size());
|
||||
EXPECT_THAT(expected.get(), NotNull()) << er.data();
|
||||
EXPECT_LE(CompareModel(model, expected.get(), field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';
|
||||
|
||||
mj_deleteSpec(parent);
|
||||
mj_deleteSpec(child);
|
||||
mj_deleteModel(model);
|
||||
mj_deleteModel(expected);
|
||||
}
|
||||
|
||||
TEST_F(MujocoTest, KeyframeSizeError) {
|
||||
@@ -2854,8 +2838,10 @@ TEST_F(MujocoTest, KeyframeSizeError) {
|
||||
std::array<char, 1000> er;
|
||||
mjSpec* spec = mj_parseXMLString(xml, 0, er.data(), er.size());
|
||||
EXPECT_THAT(spec, IsNull());
|
||||
EXPECT_THAT(er.data(), HasSubstr(
|
||||
"Keyframe 'invalid_qpos' has invalid qpos size, got 2, should be 1"));
|
||||
EXPECT_THAT(
|
||||
er.data(),
|
||||
HasSubstr(
|
||||
"Keyframe 'invalid_qpos' has invalid qpos size, got 2, should be 1"));
|
||||
}
|
||||
|
||||
TEST_F(MujocoTest, DifferentUnitsAllowed) {
|
||||
@@ -2899,8 +2885,7 @@ TEST_F(MujocoTest, DifferentUnitsAllowed) {
|
||||
)";
|
||||
|
||||
std::array<char, 1024> error;
|
||||
mjSpec* gchild =
|
||||
mj_parseXMLString(gchild_xml, 0, error.data(), error.size());
|
||||
mjSpec* gchild = mj_parseXMLString(gchild_xml, 0, error.data(), error.size());
|
||||
mjSpec* child = mj_parseXMLString(child_xml, 0, error.data(), error.size());
|
||||
mjSpec* spec = mj_parseXMLString(parent_xml, 0, error.data(), error.size());
|
||||
ASSERT_THAT(spec, NotNull()) << error.data();
|
||||
|
||||
@@ -48,9 +48,8 @@ TEST_F(UserCompositeTest, ShapeCanBeOmitted) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m, NotNull()) << error.data();
|
||||
mj_deleteModel(m);
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m.get(), NotNull()) << error.data();
|
||||
}
|
||||
|
||||
TEST_F(UserCompositeTest, InvalidShape) {
|
||||
@@ -64,8 +63,8 @@ TEST_F(UserCompositeTest, InvalidShape) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m, IsNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m.get(), IsNull()) << error.data();
|
||||
EXPECT_THAT(error.data(),
|
||||
HasSubstr("The curve array contains an invalid shape"));
|
||||
}
|
||||
|
||||
+200
-246
@@ -24,19 +24,15 @@
|
||||
#include <mujoco/mujoco.h>
|
||||
#include "test/fixture.h"
|
||||
|
||||
|
||||
|
||||
namespace mujoco {
|
||||
namespace {
|
||||
|
||||
using ::testing::HasSubstr;
|
||||
using ::testing::IsNull;
|
||||
using ::testing::NotNull;
|
||||
using ::testing::HasSubstr;
|
||||
using ::testing::Pointwise;
|
||||
using UserFlexTest = MujocoTest;
|
||||
|
||||
|
||||
|
||||
TEST_F(UserFlexTest, ParentMustHaveName) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
@@ -46,8 +42,8 @@ TEST_F(UserFlexTest, ParentMustHaveName) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m, IsNull());
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m.get(), IsNull());
|
||||
EXPECT_THAT(error.data(), HasSubstr("required attribute missing: 'name'"));
|
||||
}
|
||||
|
||||
@@ -60,8 +56,8 @@ TEST_F(UserFlexTest, InvalidDim) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m, IsNull());
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m.get(), IsNull());
|
||||
EXPECT_THAT(error.data(), HasSubstr("Invalid dim, must be between 1 and 3"));
|
||||
}
|
||||
|
||||
@@ -74,8 +70,8 @@ TEST_F(UserFlexTest, CountTooSmall) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m, IsNull());
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m.get(), IsNull());
|
||||
EXPECT_THAT(error.data(), HasSubstr("Count too small"));
|
||||
}
|
||||
|
||||
@@ -95,8 +91,8 @@ TEST_F(UserFlexTest, CellnumZeroInterpolated) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m, IsNull());
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m.get(), IsNull());
|
||||
EXPECT_THAT(error.data(), HasSubstr("cellcount cannot be 0"));
|
||||
}
|
||||
|
||||
@@ -109,8 +105,8 @@ TEST_F(UserFlexTest, SpacingGreaterThanGeometry) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m, IsNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m.get(), IsNull()) << error.data();
|
||||
EXPECT_THAT(error.data(),
|
||||
HasSubstr("Spacing must be larger than geometry size"));
|
||||
}
|
||||
@@ -124,8 +120,8 @@ TEST_F(UserFlexTest, ScaleMinValue) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m, IsNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m.get(), IsNull()) << error.data();
|
||||
EXPECT_THAT(error.data(), HasSubstr("Scale must be larger than mjMINVAL"));
|
||||
}
|
||||
|
||||
@@ -138,8 +134,8 @@ TEST_F(UserFlexTest, MassMinValue) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m, IsNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m.get(), IsNull()) << error.data();
|
||||
EXPECT_THAT(error.data(),
|
||||
HasSubstr("Mass and inertiabox must be larger than mjMINVAL"));
|
||||
}
|
||||
@@ -153,8 +149,8 @@ TEST_F(UserFlexTest, PointSizeNotMultipleOf3) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m, IsNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m.get(), IsNull()) << error.data();
|
||||
EXPECT_THAT(error.data(), HasSubstr("Point size must be a multiple of 3"));
|
||||
}
|
||||
|
||||
@@ -167,8 +163,8 @@ TEST_F(UserFlexTest, ElementSize) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m, IsNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m.get(), IsNull()) << error.data();
|
||||
EXPECT_THAT(error.data(),
|
||||
HasSubstr("Element size must be a multiple of dim+1"));
|
||||
}
|
||||
@@ -182,8 +178,8 @@ TEST_F(UserFlexTest, PointAndElementNotInDirect) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m, IsNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m.get(), IsNull()) << error.data();
|
||||
EXPECT_THAT(error.data(), HasSubstr("Point and element required"));
|
||||
}
|
||||
|
||||
@@ -196,8 +192,8 @@ TEST_F(UserFlexTest, UnknownFlexCompType) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m, IsNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m.get(), IsNull()) << error.data();
|
||||
EXPECT_THAT(error.data(), HasSubstr("invalid keyword: 'unknown'"));
|
||||
}
|
||||
|
||||
@@ -212,8 +208,8 @@ TEST_F(UserFlexTest, InvalidPinid) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m, IsNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m.get(), IsNull()) << error.data();
|
||||
EXPECT_THAT(error.data(),
|
||||
HasSubstr("element 1 has point id 1, number of points is 1"));
|
||||
}
|
||||
@@ -227,8 +223,8 @@ TEST_F(UserFlexTest, MeshFileMissing) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m, IsNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m.get(), IsNull()) << error.data();
|
||||
EXPECT_THAT(error.data(), HasSubstr("File is required"));
|
||||
}
|
||||
|
||||
@@ -249,8 +245,8 @@ TEST_F(UserFlexTest, CreateBVHSuccess) {
|
||||
ASSERT_THAT(m, NotNull()) << error.data();
|
||||
mjData* d = mj_makeData(m);
|
||||
mj_step(m, d);
|
||||
mj_deleteModel(m);
|
||||
mj_deleteData(d);
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, RigidFlex) {
|
||||
@@ -261,8 +257,8 @@ TEST_F(UserFlexTest, RigidFlex) {
|
||||
ASSERT_THAT(m, NotNull()) << error.data();
|
||||
mjData* d = mj_makeData(m);
|
||||
mj_step(m, d);
|
||||
mj_deleteModel(m);
|
||||
mj_deleteData(d);
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, FlexNotCollide) {
|
||||
@@ -277,17 +273,16 @@ TEST_F(UserFlexTest, FlexNotCollide) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m, NotNull()) << error.data();
|
||||
mjData* d = mj_makeData(m);
|
||||
mj_step(m, d);
|
||||
mj_deleteModel(m);
|
||||
mj_deleteData(d);
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m.get(), NotNull()) << error.data();
|
||||
MjDataPtr d = MakeData(m);
|
||||
mj_step(m.get(), d.get());
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, BoundingBoxCoordinates) {
|
||||
#ifdef mjUSESINGLE
|
||||
GTEST_SKIP() << "Float32 rounding in bounding box centering gives ~3e-8 error";
|
||||
GTEST_SKIP()
|
||||
<< "Float32 rounding in bounding box centering gives ~3e-8 error";
|
||||
#endif
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
@@ -298,34 +293,31 @@ TEST_F(UserFlexTest, BoundingBoxCoordinates) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m, NotNull()) << error.data();
|
||||
mjData* d = mj_makeData(m);
|
||||
mj_kinematics(m, d);
|
||||
mj_flex(m, d);
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m.get(), NotNull()) << error.data();
|
||||
MjDataPtr d = MakeData(m);
|
||||
mj_kinematics(m.get(), d.get());
|
||||
mj_flex(m.get(), d.get());
|
||||
|
||||
EXPECT_EQ(m->nflexvert, 5*5*5);
|
||||
EXPECT_EQ(m->nflexelem, 4*4*4*6);
|
||||
EXPECT_EQ(m->nflexvert, 5 * 5 * 5);
|
||||
EXPECT_EQ(m->nflexelem, 4 * 4 * 4 * 6);
|
||||
EXPECT_EQ(m->flex_dim[0], 3);
|
||||
|
||||
// Cartesian coordinates
|
||||
EXPECT_EQ(d->flexvert_xpos[0], -1);
|
||||
EXPECT_EQ(d->flexvert_xpos[1], -2);
|
||||
EXPECT_EQ(d->flexvert_xpos[2], -3);
|
||||
EXPECT_EQ(d->flexvert_xpos[3*m->nflexvert-3], 3);
|
||||
EXPECT_EQ(d->flexvert_xpos[3*m->nflexvert-2], 2);
|
||||
EXPECT_EQ(d->flexvert_xpos[3*m->nflexvert-1], 1);
|
||||
EXPECT_EQ(d->flexvert_xpos[3 * m->nflexvert - 3], 3);
|
||||
EXPECT_EQ(d->flexvert_xpos[3 * m->nflexvert - 2], 2);
|
||||
EXPECT_EQ(d->flexvert_xpos[3 * m->nflexvert - 1], 1);
|
||||
|
||||
// bounding box coordinates
|
||||
EXPECT_EQ(m->flex_vert0[0], 0);
|
||||
EXPECT_EQ(m->flex_vert0[1], 0);
|
||||
EXPECT_EQ(m->flex_vert0[2], 0);
|
||||
EXPECT_EQ(m->flex_vert0[3*m->nflexvert-3], 1);
|
||||
EXPECT_EQ(m->flex_vert0[3*m->nflexvert-2], 1);
|
||||
EXPECT_EQ(m->flex_vert0[3*m->nflexvert-1], 1);
|
||||
|
||||
mj_deleteModel(m);
|
||||
mj_deleteData(d);
|
||||
EXPECT_EQ(m->flex_vert0[3 * m->nflexvert - 3], 1);
|
||||
EXPECT_EQ(m->flex_vert0[3 * m->nflexvert - 2], 1);
|
||||
EXPECT_EQ(m->flex_vert0[3 * m->nflexvert - 1], 1);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, TrilinearCannotDoSelfCollision) {
|
||||
@@ -339,8 +331,8 @@ TEST_F(UserFlexTest, TrilinearCannotDoSelfCollision) {
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* m1 = LoadModelFromString(xml_selfcoll, error.data(), error.size());
|
||||
EXPECT_THAT(m1, IsNull()) << error.data();
|
||||
MjModelPtr m1 = LoadModelFromString(xml_selfcoll, error.data(), error.size());
|
||||
EXPECT_THAT(m1.get(), IsNull()) << error.data();
|
||||
EXPECT_THAT(error.data(),
|
||||
HasSubstr("trilinear interpolation cannot do self-collision"));
|
||||
static constexpr char xml_internal[] = R"(
|
||||
@@ -352,8 +344,8 @@ TEST_F(UserFlexTest, TrilinearCannotDoSelfCollision) {
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* m2 = LoadModelFromString(xml_internal, error.data(), error.size());
|
||||
EXPECT_THAT(m2, IsNull()) << error.data();
|
||||
MjModelPtr m2 = LoadModelFromString(xml_internal, error.data(), error.size());
|
||||
EXPECT_THAT(m2.get(), IsNull()) << error.data();
|
||||
EXPECT_THAT(error.data(),
|
||||
HasSubstr("trilinear interpolation cannot do internal"));
|
||||
}
|
||||
@@ -370,10 +362,11 @@ TEST_F(UserFlexTest, TrilinearInterpolation) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m1 = LoadModelFromString(xml_trilinear, error.data(), error.size());
|
||||
ASSERT_THAT(m1, NotNull()) << error.data();
|
||||
mjData* d1 = mj_makeData(m1);
|
||||
mj_step(m1, d1);
|
||||
MjModelPtr m1 =
|
||||
LoadModelFromString(xml_trilinear, error.data(), error.size());
|
||||
ASSERT_THAT(m1.get(), NotNull()) << error.data();
|
||||
MjDataPtr d1 = MakeData(m1);
|
||||
mj_step(m1.get(), d1.get());
|
||||
|
||||
static constexpr char xml_linear[] = R"(
|
||||
<mujoco>
|
||||
@@ -385,13 +378,13 @@ TEST_F(UserFlexTest, TrilinearInterpolation) {
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* m2 = LoadModelFromString(xml_linear, error.data(), error.size());
|
||||
ASSERT_THAT(m2, NotNull()) << error.data();
|
||||
mjData* d2 = mj_makeData(m2);
|
||||
mj_step(m2, d2);
|
||||
MjModelPtr m2 = LoadModelFromString(xml_linear, error.data(), error.size());
|
||||
ASSERT_THAT(m2.get(), NotNull()) << error.data();
|
||||
MjDataPtr d2 = MakeData(m2);
|
||||
mj_step(m2.get(), d2.get());
|
||||
|
||||
EXPECT_EQ(m1->nflexvert, m2->nflexvert);
|
||||
for (int i = 0; i < 3*m1->nflexvert; ++i) {
|
||||
for (int i = 0; i < 3 * m1->nflexvert; ++i) {
|
||||
EXPECT_NEAR(m1->flex_vert[i], d2->flexvert_xpos[i], 1e-7);
|
||||
EXPECT_NEAR(m1->flex_vert0[i], m2->flex_vert0[i], 1e-7);
|
||||
EXPECT_NEAR(d1->flexvert_xpos[i], d2->flexvert_xpos[i], 1e-7);
|
||||
@@ -409,11 +402,11 @@ TEST_F(UserFlexTest, TrilinearInterpolation) {
|
||||
}
|
||||
EXPECT_EQ(m1->body_mass[i], m2->body_mass[i]);
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
EXPECT_EQ(m1->body_invweight0[i*2+j], m2->body_invweight0[i*2+j]);
|
||||
EXPECT_EQ(m1->body_invweight0[i * 2 + j], m2->body_invweight0[i * 2 + j]);
|
||||
}
|
||||
for (int j = 0; j < 10; ++j) {
|
||||
EXPECT_NEAR(d1->cinert[10*i+j], d2->cinert[i*10+j], 1e-5) << i;
|
||||
EXPECT_NEAR(d1->crb[10*i+j], d2->crb[i*10+j], 1e-5) << i;
|
||||
EXPECT_NEAR(d1->cinert[10 * i + j], d2->cinert[i * 10 + j], 1e-5) << i;
|
||||
EXPECT_NEAR(d1->crb[10 * i + j], d2->crb[i * 10 + j], 1e-5) << i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,18 +429,13 @@ TEST_F(UserFlexTest, TrilinearInterpolation) {
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(d1->nefc, 4*(d1->contact[0].dim-1)*2);
|
||||
EXPECT_EQ(d2->nefc, 4*(d2->contact[0].dim-1)*2);
|
||||
EXPECT_EQ(d1->nefc, 4 * (d1->contact[0].dim - 1) * 2);
|
||||
EXPECT_EQ(d2->nefc, 4 * (d2->contact[0].dim - 1) * 2);
|
||||
EXPECT_EQ(d1->nJ, d2->nJ);
|
||||
for (int i = 0; i < d1->nefc; ++i) {
|
||||
EXPECT_EQ(d1->efc_diagA[i], d2->efc_diagA[i]);
|
||||
EXPECT_EQ(d1->efc_D[i], d2->efc_D[i]);
|
||||
}
|
||||
|
||||
mj_deleteModel(m1);
|
||||
mj_deleteModel(m2);
|
||||
mj_deleteData(d1);
|
||||
mj_deleteData(d2);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, StiffnessMatrix) {
|
||||
@@ -466,22 +454,20 @@ TEST_F(UserFlexTest, StiffnessMatrix) {
|
||||
)";
|
||||
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m, NotNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m.get(), NotNull()) << error.data();
|
||||
EXPECT_NE(m->flex_stiffness[m->flex_stiffnessadr[0]], 0);
|
||||
EXPECT_EQ(m->nflexnode, 8);
|
||||
|
||||
// constants are in the kernel
|
||||
mjtNum ones[24], zeros[24], res[24];
|
||||
for (int i = 0; i < 3*m->nflexnode; ++i) {
|
||||
for (int i = 0; i < 3 * m->nflexnode; ++i) {
|
||||
zeros[i] = 0;
|
||||
ones[i] = 1;
|
||||
}
|
||||
mju_mulMatVec(res, m->flex_stiffness + m->flex_stiffnessadr[0], ones,
|
||||
3 * m->nflexnode, 3 * m->nflexnode);
|
||||
EXPECT_THAT(res, Pointwise(MjNear(1e-8, 1e-4), zeros));
|
||||
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, StiffnessCacheDiffersByGeometry) {
|
||||
@@ -510,19 +496,18 @@ TEST_F(UserFlexTest, StiffnessCacheDiffersByGeometry) {
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
mjModel* m_small = LoadModelFromString(xml_small, error.data(), error.size());
|
||||
ASSERT_THAT(m_small, NotNull()) << error.data();
|
||||
MjModelPtr m_small =
|
||||
LoadModelFromString(xml_small, error.data(), error.size());
|
||||
ASSERT_THAT(m_small.get(), NotNull()) << error.data();
|
||||
|
||||
mjModel* m_large = LoadModelFromString(xml_large, error.data(), error.size());
|
||||
ASSERT_THAT(m_large, NotNull()) << error.data();
|
||||
MjModelPtr m_large =
|
||||
LoadModelFromString(xml_large, error.data(), error.size());
|
||||
ASSERT_THAT(m_large.get(), NotNull()) << error.data();
|
||||
|
||||
// Same number of nodes but different stiffness due to different geometry
|
||||
EXPECT_EQ(m_small->nflexnode, m_large->nflexnode);
|
||||
EXPECT_NE(m_small->flex_stiffness[m_small->flex_stiffnessadr[0]],
|
||||
m_large->flex_stiffness[m_large->flex_stiffnessadr[0]]);
|
||||
|
||||
mj_deleteModel(m_small);
|
||||
mj_deleteModel(m_large);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, LoadTexture) {
|
||||
@@ -552,8 +537,8 @@ TEST_F(UserFlexTest, LoadMSHBinary_41_Success) {
|
||||
EXPECT_EQ(m->nflexelem, 24);
|
||||
EXPECT_EQ(m->flex_dim[0], 3);
|
||||
mj_step(m, d);
|
||||
mj_deleteModel(m);
|
||||
mj_deleteData(d);
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, LoadMSHBinary_22_Success) {
|
||||
@@ -567,8 +552,8 @@ TEST_F(UserFlexTest, LoadMSHBinary_22_Success) {
|
||||
EXPECT_EQ(m->nflexelem, 24);
|
||||
EXPECT_EQ(m->flex_dim[0], 3);
|
||||
mj_step(m, d);
|
||||
mj_deleteModel(m);
|
||||
mj_deleteData(d);
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, LoadMSHSurfaceBinary_41_Success) {
|
||||
@@ -585,18 +570,18 @@ TEST_F(UserFlexTest, LoadMSHSurfaceBinary_41_Success) {
|
||||
EXPECT_EQ(m->flex_dim[0], 2);
|
||||
|
||||
// first node x y z
|
||||
EXPECT_EQ(d->flexvert_xpos[0], -0.5 );
|
||||
EXPECT_EQ(d->flexvert_xpos[1], -0.5 );
|
||||
EXPECT_EQ(d->flexvert_xpos[2], 0 );
|
||||
EXPECT_EQ(d->flexvert_xpos[0], -0.5);
|
||||
EXPECT_EQ(d->flexvert_xpos[1], -0.5);
|
||||
EXPECT_EQ(d->flexvert_xpos[2], 0);
|
||||
|
||||
// first element
|
||||
EXPECT_EQ(m->flex_elem[0], 9-1 );
|
||||
EXPECT_EQ(m->flex_elem[1], 4-1 );
|
||||
EXPECT_EQ(m->flex_elem[2], 3-1 );
|
||||
EXPECT_EQ(m->flex_elem[0], 9 - 1);
|
||||
EXPECT_EQ(m->flex_elem[1], 4 - 1);
|
||||
EXPECT_EQ(m->flex_elem[2], 3 - 1);
|
||||
|
||||
mj_step(m, d);
|
||||
mj_deleteModel(m);
|
||||
mj_deleteData(d);
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, LoadMSHSurfaceBinary_22_Success) {
|
||||
@@ -613,18 +598,18 @@ TEST_F(UserFlexTest, LoadMSHSurfaceBinary_22_Success) {
|
||||
EXPECT_EQ(m->flex_dim[0], 2);
|
||||
|
||||
// first node x y z
|
||||
EXPECT_EQ(d->flexvert_xpos[0], -0.5 );
|
||||
EXPECT_EQ(d->flexvert_xpos[1], -0.5 );
|
||||
EXPECT_EQ(d->flexvert_xpos[2], 0 );
|
||||
EXPECT_EQ(d->flexvert_xpos[0], -0.5);
|
||||
EXPECT_EQ(d->flexvert_xpos[1], -0.5);
|
||||
EXPECT_EQ(d->flexvert_xpos[2], 0);
|
||||
|
||||
// first element
|
||||
EXPECT_EQ(m->flex_elem[0], 9-1 );
|
||||
EXPECT_EQ(m->flex_elem[1], 4-1 );
|
||||
EXPECT_EQ(m->flex_elem[2], 3-1 );
|
||||
EXPECT_EQ(m->flex_elem[0], 9 - 1);
|
||||
EXPECT_EQ(m->flex_elem[1], 4 - 1);
|
||||
EXPECT_EQ(m->flex_elem[2], 3 - 1);
|
||||
|
||||
mj_step(m, d);
|
||||
mj_deleteModel(m);
|
||||
mj_deleteData(d);
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, LoadMSHBinaryFTETWILD_22_Success) {
|
||||
@@ -638,8 +623,8 @@ TEST_F(UserFlexTest, LoadMSHBinaryFTETWILD_22_Success) {
|
||||
EXPECT_EQ(m->nflexelem, 1073);
|
||||
EXPECT_EQ(m->flex_dim[0], 3);
|
||||
mj_step(m, d);
|
||||
mj_deleteModel(m);
|
||||
mj_deleteData(d);
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, LoadMSHASCII_41_Success) {
|
||||
@@ -653,8 +638,8 @@ TEST_F(UserFlexTest, LoadMSHASCII_41_Success) {
|
||||
EXPECT_EQ(m->nflexelem, 24);
|
||||
EXPECT_EQ(m->flex_dim[0], 3);
|
||||
mj_step(m, d);
|
||||
mj_deleteModel(m);
|
||||
mj_deleteData(d);
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, LoadMSHASCII_22_Success) {
|
||||
@@ -668,8 +653,8 @@ TEST_F(UserFlexTest, LoadMSHASCII_22_Success) {
|
||||
EXPECT_EQ(m->nflexelem, 24);
|
||||
EXPECT_EQ(m->flex_dim[0], 3);
|
||||
mj_step(m, d);
|
||||
mj_deleteModel(m);
|
||||
mj_deleteData(d);
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, LoadMSHSurfaceASCII_41_Success) {
|
||||
@@ -686,18 +671,18 @@ TEST_F(UserFlexTest, LoadMSHSurfaceASCII_41_Success) {
|
||||
EXPECT_EQ(m->flex_dim[0], 2);
|
||||
|
||||
// first node x y z
|
||||
EXPECT_EQ(d->flexvert_xpos[0], -0.5 );
|
||||
EXPECT_EQ(d->flexvert_xpos[1], -0.5 );
|
||||
EXPECT_EQ(d->flexvert_xpos[2], 0 );
|
||||
EXPECT_EQ(d->flexvert_xpos[0], -0.5);
|
||||
EXPECT_EQ(d->flexvert_xpos[1], -0.5);
|
||||
EXPECT_EQ(d->flexvert_xpos[2], 0);
|
||||
|
||||
// first element
|
||||
EXPECT_EQ(m->flex_elem[0], 9-1 );
|
||||
EXPECT_EQ(m->flex_elem[1], 4-1 );
|
||||
EXPECT_EQ(m->flex_elem[2], 3-1 );
|
||||
EXPECT_EQ(m->flex_elem[0], 9 - 1);
|
||||
EXPECT_EQ(m->flex_elem[1], 4 - 1);
|
||||
EXPECT_EQ(m->flex_elem[2], 3 - 1);
|
||||
|
||||
mj_step(m, d);
|
||||
mj_deleteModel(m);
|
||||
mj_deleteData(d);
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, LoadMSHSurfaceASCII_22_Success) {
|
||||
@@ -714,18 +699,18 @@ TEST_F(UserFlexTest, LoadMSHSurfaceASCII_22_Success) {
|
||||
EXPECT_EQ(m->flex_dim[0], 2);
|
||||
|
||||
// first node x y z
|
||||
EXPECT_EQ(d->flexvert_xpos[0], -0.5 );
|
||||
EXPECT_EQ(d->flexvert_xpos[1], -0.5 );
|
||||
EXPECT_EQ(d->flexvert_xpos[2], 0 );
|
||||
EXPECT_EQ(d->flexvert_xpos[0], -0.5);
|
||||
EXPECT_EQ(d->flexvert_xpos[1], -0.5);
|
||||
EXPECT_EQ(d->flexvert_xpos[2], 0);
|
||||
|
||||
// first element
|
||||
EXPECT_EQ(m->flex_elem[0], 9-1 );
|
||||
EXPECT_EQ(m->flex_elem[1], 4-1 );
|
||||
EXPECT_EQ(m->flex_elem[2], 3-1 );
|
||||
EXPECT_EQ(m->flex_elem[0], 9 - 1);
|
||||
EXPECT_EQ(m->flex_elem[1], 4 - 1);
|
||||
EXPECT_EQ(m->flex_elem[2], 3 - 1);
|
||||
|
||||
mj_step(m, d);
|
||||
mj_deleteModel(m);
|
||||
mj_deleteData(d);
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, LoadMSHASCIIFTETWILD_22_Success) {
|
||||
@@ -739,70 +724,69 @@ TEST_F(UserFlexTest, LoadMSHASCIIFTETWILD_22_Success) {
|
||||
EXPECT_EQ(m->nflexelem, 1070);
|
||||
EXPECT_EQ(m->flex_dim[0], 3);
|
||||
mj_step(m, d);
|
||||
mj_deleteModel(m);
|
||||
mj_deleteData(d);
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, LoadMSHASCII_41_MissingNodeHeader_Fail) {
|
||||
const std::string xml_path =
|
||||
GetTestDataFilePath(
|
||||
"user/testdata/malformed_cube_41_ascii_missing_node_header.xml");
|
||||
const std::string xml_path = GetTestDataFilePath(
|
||||
"user/testdata/malformed_cube_41_ascii_missing_node_header.xml");
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size());
|
||||
EXPECT_THAT(error.data(), HasSubstr(
|
||||
"XML Error: Error: All nodes must be in single block"));
|
||||
EXPECT_THAT(error.data(),
|
||||
HasSubstr("XML Error: Error: All nodes must be in single block"));
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, LoadMSHASCII_41_MissingNodeIndex_Fail) {
|
||||
const std::string xml_path =
|
||||
GetTestDataFilePath(
|
||||
"user/testdata/malformed_cube_41_ascii_missing_node_index.xml");
|
||||
const std::string xml_path = GetTestDataFilePath(
|
||||
"user/testdata/malformed_cube_41_ascii_missing_node_index.xml");
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size());
|
||||
EXPECT_THAT(error.data(), HasSubstr(
|
||||
"XML Error: Error: Node tags must be sequential"));
|
||||
EXPECT_THAT(error.data(),
|
||||
HasSubstr("XML Error: Error: Node tags must be sequential"));
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, LoadMSHASCII_41_MissingElementHeader_Fail) {
|
||||
const std::string xml_path =
|
||||
GetTestDataFilePath(
|
||||
"user/testdata/malformed_cube_41_ascii_missing_element_header.xml");
|
||||
const std::string xml_path = GetTestDataFilePath(
|
||||
"user/testdata/malformed_cube_41_ascii_missing_element_header.xml");
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size());
|
||||
EXPECT_THAT(error.data(), HasSubstr(
|
||||
"XML Error: Error: All elements must be in single block"));
|
||||
EXPECT_THAT(
|
||||
error.data(),
|
||||
HasSubstr("XML Error: Error: All elements must be in single block"));
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, LoadMSHASCII_41_MissingElement_Fail) {
|
||||
const std::string xml_path =
|
||||
GetTestDataFilePath(
|
||||
"user/testdata/malformed_cube_41_ascii_missing_element.xml");
|
||||
const std::string xml_path = GetTestDataFilePath(
|
||||
"user/testdata/malformed_cube_41_ascii_missing_element.xml");
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size());
|
||||
EXPECT_THAT(error.data(), HasSubstr(
|
||||
"XML Error: Error: Error reading Elements"));
|
||||
EXPECT_THAT(error.data(),
|
||||
HasSubstr("XML Error: Error: Error reading Elements"));
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest,
|
||||
LoadMSHASCII_41_MismatchBetweenMaxNodesAndNodesInBlock_Fail) {
|
||||
const std::string xml_path =
|
||||
GetTestDataFilePath(
|
||||
"user/testdata/malformed_cube_41_ascii_mismatch_between_max_nodes_and_nodes_in_block.xml");
|
||||
const std::string xml_path = GetTestDataFilePath(
|
||||
"user/testdata/"
|
||||
"malformed_cube_41_ascii_mismatch_between_max_nodes_and_nodes_in_block."
|
||||
"xml");
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size());
|
||||
EXPECT_THAT(error.data(), HasSubstr(
|
||||
"XML Error: Error: Maximum number of nodes must be equal to number of nodes in a block\nElement 'flexcomp', line 22\n"));
|
||||
EXPECT_THAT(
|
||||
error.data(),
|
||||
HasSubstr("XML Error: Error: Maximum number of nodes must be equal to "
|
||||
"number of nodes in a block\nElement 'flexcomp', line 22\n"));
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, LoadMSHASCII_22_MissingNumNodes_Fail) {
|
||||
const std::string xml_path =
|
||||
GetTestDataFilePath(
|
||||
"user/testdata/malformed_cube_22_ascii_missing_num_nodes.xml");
|
||||
const std::string xml_path = GetTestDataFilePath(
|
||||
"user/testdata/malformed_cube_22_ascii_missing_num_nodes.xml");
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size());
|
||||
// TODO(mohammadhamid): Replace with an assertion about the error message. For
|
||||
@@ -812,20 +796,18 @@ TEST_F(UserFlexTest, LoadMSHASCII_22_MissingNumNodes_Fail) {
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, LoadMSHASCII_22_MissingNode_Fail) {
|
||||
const std::string xml_path =
|
||||
GetTestDataFilePath(
|
||||
"user/testdata/malformed_cube_22_ascii_missing_node.xml");
|
||||
const std::string xml_path = GetTestDataFilePath(
|
||||
"user/testdata/malformed_cube_22_ascii_missing_node.xml");
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size());
|
||||
EXPECT_THAT(error.data(), HasSubstr(
|
||||
"XML Error: Error: Error reading node tags"));
|
||||
EXPECT_THAT(error.data(),
|
||||
HasSubstr("XML Error: Error: Error reading node tags"));
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, LoadMSHASCII_22_MissingNumElements_Fail) {
|
||||
const std::string xml_path =
|
||||
GetTestDataFilePath(
|
||||
"user/testdata/malformed_shark_22_ascii_missing_num_elements.xml");
|
||||
const std::string xml_path = GetTestDataFilePath(
|
||||
"user/testdata/malformed_shark_22_ascii_missing_num_elements.xml");
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size());
|
||||
// TODO(mohammadhamid): Replace with an assertion about the error message. For
|
||||
@@ -835,20 +817,18 @@ TEST_F(UserFlexTest, LoadMSHASCII_22_MissingNumElements_Fail) {
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, LoadMSHASCII_22_MissingElement_Fail) {
|
||||
const std::string xml_path =
|
||||
GetTestDataFilePath(
|
||||
"user/testdata/malformed_cube_22_ascii_missing_element.xml");
|
||||
const std::string xml_path = GetTestDataFilePath(
|
||||
"user/testdata/malformed_cube_22_ascii_missing_element.xml");
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size());
|
||||
EXPECT_THAT(error.data(), HasSubstr(
|
||||
"XML Error: Error: Error reading Elements"));
|
||||
EXPECT_THAT(error.data(),
|
||||
HasSubstr("XML Error: Error: Error reading Elements"));
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, LoadMSHASCII_dim_missing_in_xml) {
|
||||
const std::string xml_path =
|
||||
GetTestDataFilePath(
|
||||
"user/testdata/cube_22_ascii_vol_gmshApp_missing_dim.xml");
|
||||
const std::string xml_path = GetTestDataFilePath(
|
||||
"user/testdata/cube_22_ascii_vol_gmshApp_missing_dim.xml");
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size());
|
||||
EXPECT_EQ(m->flex_dim[0], 3);
|
||||
@@ -871,9 +851,8 @@ TEST_F(UserFlexTest, TrilinearUnusedVertices_Crash) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m, testing::NotNull()) << error.data();
|
||||
mj_deleteModel(m);
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m.get(), testing::NotNull()) << error.data();
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, MeshNodePinning) {
|
||||
@@ -891,8 +870,8 @@ TEST_F(UserFlexTest, MeshNodePinning) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m, testing::NotNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m.get(), testing::NotNull()) << error.data();
|
||||
|
||||
// Verify that node 0 (corner) is pinned
|
||||
// Trilinear 3D has 8 nodes.
|
||||
@@ -901,14 +880,11 @@ TEST_F(UserFlexTest, MeshNodePinning) {
|
||||
// m->nbody should reflect this. Flex bodies are added to the model.
|
||||
// Model has 1 world body + flex bodies.
|
||||
EXPECT_EQ(m->nbody, 1 + 7); // 1 world + 7 flex nodes (1 pinned)
|
||||
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, FlexcompMeshLoadsFromVFS) {
|
||||
// read cube.stl from testdata into a buffer
|
||||
const std::string stl_path =
|
||||
GetTestDataFilePath("user/testdata/cube.stl");
|
||||
const std::string stl_path = GetTestDataFilePath("user/testdata/cube.stl");
|
||||
FILE* f = fopen(stl_path.c_str(), "rb");
|
||||
ASSERT_THAT(f, NotNull()) << "Could not open " << stl_path;
|
||||
fseek(f, 0, SEEK_END);
|
||||
@@ -938,12 +914,10 @@ TEST_F(UserFlexTest, FlexcompMeshLoadsFromVFS) {
|
||||
|
||||
// cleanup
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size(), &vfs);
|
||||
ASSERT_THAT(m, NotNull()) << error.data();
|
||||
mjData* d = mj_makeData(m);
|
||||
mj_step(m, d);
|
||||
mj_deleteData(d);
|
||||
mj_deleteModel(m);
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size(), &vfs);
|
||||
ASSERT_THAT(m.get(), NotNull()) << error.data();
|
||||
MjDataPtr d = MakeData(m);
|
||||
mj_step(m.get(), d.get());
|
||||
mj_deleteVFS(&vfs);
|
||||
}
|
||||
|
||||
@@ -986,22 +960,20 @@ TEST_F(UserFlexTest, FlexAttachConstraintPreserved) {
|
||||
|
||||
// First verify the standalone flex model has constraints
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m_standalone =
|
||||
MjModelPtr m_standalone =
|
||||
LoadModelFromString(flex_xml, error.data(), error.size(), vfs.get());
|
||||
ASSERT_THAT(m_standalone, NotNull()) << error.data();
|
||||
mjData* d_standalone = mj_makeData(m_standalone);
|
||||
mj_forward(m_standalone, d_standalone);
|
||||
ASSERT_THAT(m_standalone.get(), NotNull()) << error.data();
|
||||
MjDataPtr d_standalone = MakeData(m_standalone);
|
||||
mj_forward(m_standalone.get(), d_standalone.get());
|
||||
int standalone_neq = m_standalone->neq;
|
||||
EXPECT_GT(standalone_neq, 0) << "Standalone flex should have constraints";
|
||||
mj_deleteData(d_standalone);
|
||||
mj_deleteModel(m_standalone);
|
||||
|
||||
// Now load the parent model which attaches the flex
|
||||
mjModel* m_attached =
|
||||
MjModelPtr m_attached =
|
||||
LoadModelFromString(parent_xml, error.data(), error.size(), vfs.get());
|
||||
ASSERT_THAT(m_attached, NotNull()) << error.data();
|
||||
mjData* d_attached = mj_makeData(m_attached);
|
||||
mj_forward(m_attached, d_attached);
|
||||
ASSERT_THAT(m_attached.get(), NotNull()) << error.data();
|
||||
MjDataPtr d_attached = MakeData(m_attached);
|
||||
mj_forward(m_attached.get(), d_attached.get());
|
||||
|
||||
// THE BUG: flex constraints disappear when attached
|
||||
EXPECT_GT(m_attached->neq, 0)
|
||||
@@ -1009,8 +981,6 @@ TEST_F(UserFlexTest, FlexAttachConstraintPreserved) {
|
||||
EXPECT_EQ(m_attached->neq, standalone_neq)
|
||||
<< "Attached flex should have same number of constraints as standalone";
|
||||
|
||||
mj_deleteData(d_attached);
|
||||
mj_deleteModel(m_attached);
|
||||
mj_deleteVFS(vfs.get());
|
||||
}
|
||||
|
||||
@@ -1024,11 +994,10 @@ TEST_F(UserFlexTest, FlexNoConstraintsWarning) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m, NotNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m.get(), NotNull()) << error.data();
|
||||
EXPECT_THAT(error.data(),
|
||||
HasSubstr("no equality constraints or passive forces"));
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, EmptyCellNodePinning) {
|
||||
@@ -1046,8 +1015,8 @@ TEST_F(UserFlexTest, EmptyCellNodePinning) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m, NotNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m.get(), NotNull()) << error.data();
|
||||
|
||||
// A 2x2x2 grid with trilinear order has (2+1)^3 = 27 node positions.
|
||||
int nadr = m->flex_nodeadr[0];
|
||||
@@ -1065,20 +1034,16 @@ TEST_F(UserFlexTest, EmptyCellNodePinning) {
|
||||
EXPECT_EQ(pinned, 0);
|
||||
|
||||
// Verify simulation works
|
||||
mjData* d = mj_makeData(m);
|
||||
MjDataPtr d = MakeData(m);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
mj_step(m, d);
|
||||
mj_step(m.get(), d.get());
|
||||
}
|
||||
|
||||
mj_deleteData(d);
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, EmptyCellNodePinningMesh) {
|
||||
// Load bunny_multicell.xml which has a 3x3x3 grid.
|
||||
// The bunny mesh only occupies some cells, so many nodes should be pinned.
|
||||
const std::string xml_path =
|
||||
GetModelPath("flex/bunny_multicell.xml");
|
||||
const std::string xml_path = GetModelPath("flex/bunny_multicell.xml");
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size());
|
||||
ASSERT_THAT(m, NotNull()) << error.data();
|
||||
@@ -1152,8 +1117,8 @@ TEST_F(UserFlexTest, EmptyCellNodePinningQuadratic) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m, NotNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m.get(), NotNull()) << error.data();
|
||||
|
||||
// 3x1x1 quadratic grid: (3*2+1) * (1*2+1) * (1*2+1) = 7*3*3 = 63 nodes
|
||||
int nadr = m->flex_nodeadr[0];
|
||||
@@ -1161,7 +1126,7 @@ TEST_F(UserFlexTest, EmptyCellNodePinningQuadratic) {
|
||||
EXPECT_EQ(nnode, 63);
|
||||
|
||||
// Count pinned nodes: pinned nodes are assigned to the parent body.
|
||||
int parent_bid = mj_name2id(m, mjOBJ_BODY, "parent");
|
||||
int parent_bid = mj_name2id(m.get(), mjOBJ_BODY, "parent");
|
||||
ASSERT_GT(parent_bid, 0);
|
||||
int pinned = 0;
|
||||
for (int n = nadr; n < nadr + nnode; n++) {
|
||||
@@ -1175,8 +1140,7 @@ TEST_F(UserFlexTest, EmptyCellNodePinningQuadratic) {
|
||||
// That's 4 * 3 * 3 = 36 nodes.
|
||||
EXPECT_EQ(pinned, 36);
|
||||
|
||||
mj_deleteData(mj_makeData(m));
|
||||
mj_deleteModel(m);
|
||||
mj_deleteData(mj_makeData(m.get()));
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, EmptyCellDetectsElements) {
|
||||
@@ -1208,8 +1172,8 @@ TEST_F(UserFlexTest, EmptyCellDetectsElements) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m, NotNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m.get(), NotNull()) << error.data();
|
||||
|
||||
// 6x6x6 trilinear grid: (6+1)^3 = 343 nodes
|
||||
int nadr = m->flex_nodeadr[0];
|
||||
@@ -1217,7 +1181,7 @@ TEST_F(UserFlexTest, EmptyCellDetectsElements) {
|
||||
ASSERT_EQ(nnode, 343);
|
||||
|
||||
// Count pinned nodes: those assigned to the parent body.
|
||||
int parent_bid = mj_name2id(m, mjOBJ_BODY, "parent");
|
||||
int parent_bid = mj_name2id(m.get(), mjOBJ_BODY, "parent");
|
||||
ASSERT_GT(parent_bid, 0);
|
||||
int pinned = 0;
|
||||
for (int n = nadr; n < nadr + nnode; n++) {
|
||||
@@ -1233,8 +1197,7 @@ TEST_F(UserFlexTest, EmptyCellDetectsElements) {
|
||||
// No cells are empty → 0 nodes pinned.
|
||||
EXPECT_EQ(pinned, 0);
|
||||
|
||||
mj_deleteData(mj_makeData(m));
|
||||
mj_deleteModel(m);
|
||||
mj_deleteData(mj_makeData(m.get()));
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, TotalMassTrilinear) {
|
||||
@@ -1249,8 +1212,8 @@ TEST_F(UserFlexTest, TotalMassTrilinear) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m, NotNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m.get(), NotNull()) << error.data();
|
||||
|
||||
double total_mass = 0;
|
||||
for (int i = 1; i < m->nbody; ++i) {
|
||||
@@ -1258,7 +1221,6 @@ TEST_F(UserFlexTest, TotalMassTrilinear) {
|
||||
}
|
||||
|
||||
EXPECT_NEAR(total_mass, 1.5, 1e-5);
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, TotalMassQuadratic) {
|
||||
@@ -1273,8 +1235,8 @@ TEST_F(UserFlexTest, TotalMassQuadratic) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m, NotNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m.get(), NotNull()) << error.data();
|
||||
|
||||
double total_mass = 0;
|
||||
for (int i = 1; i < m->nbody; ++i) {
|
||||
@@ -1282,7 +1244,6 @@ TEST_F(UserFlexTest, TotalMassQuadratic) {
|
||||
}
|
||||
|
||||
EXPECT_NEAR(total_mass, 2.0, 1e-5);
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, Dof2d) {
|
||||
@@ -1298,7 +1259,8 @@ TEST_F(UserFlexTest, Dof2d) {
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
// same model with dof="full" for comparison: 9 vertices, 3 DOFs each -> nv = 27
|
||||
// same model with dof="full" for comparison: 9 vertices, 3 DOFs each -> nv =
|
||||
// 27
|
||||
static constexpr char xml_full[] = R"(
|
||||
<mujoco>
|
||||
<worldbody>
|
||||
@@ -1313,14 +1275,14 @@ TEST_F(UserFlexTest, Dof2d) {
|
||||
std::array<char, 1024> error;
|
||||
|
||||
// load 2d model
|
||||
mjModel* m_2d = LoadModelFromString(xml_2d, error.data(), error.size());
|
||||
ASSERT_THAT(m_2d, NotNull()) << error.data();
|
||||
mjData* d_2d = mj_makeData(m_2d);
|
||||
MjModelPtr m_2d = LoadModelFromString(xml_2d, error.data(), error.size());
|
||||
ASSERT_THAT(m_2d.get(), NotNull()) << error.data();
|
||||
MjDataPtr d_2d = MakeData(m_2d);
|
||||
|
||||
// load full model
|
||||
mjModel* m_full = LoadModelFromString(xml_full, error.data(), error.size());
|
||||
ASSERT_THAT(m_full, NotNull()) << error.data();
|
||||
mjData* d_full = mj_makeData(m_full);
|
||||
MjModelPtr m_full = LoadModelFromString(xml_full, error.data(), error.size());
|
||||
ASSERT_THAT(m_full.get(), NotNull()) << error.data();
|
||||
MjDataPtr d_full = MakeData(m_full);
|
||||
|
||||
// verify DOF counts
|
||||
EXPECT_EQ(m_2d->nv, 18); // 9 vertices * 2 DOFs
|
||||
@@ -1340,14 +1302,9 @@ TEST_F(UserFlexTest, Dof2d) {
|
||||
|
||||
// simulate a few steps to make sure nothing crashes
|
||||
for (int i = 0; i < 10; i++) {
|
||||
mj_step(m_2d, d_2d);
|
||||
mj_step(m_full, d_full);
|
||||
mj_step(m_2d.get(), d_2d.get());
|
||||
mj_step(m_full.get(), d_full.get());
|
||||
}
|
||||
|
||||
mj_deleteModel(m_2d);
|
||||
mj_deleteModel(m_full);
|
||||
mj_deleteData(d_2d);
|
||||
mj_deleteData(d_full);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, Vert0RotationInvariant) {
|
||||
@@ -1380,11 +1337,12 @@ TEST_F(UserFlexTest, Vert0RotationInvariant) {
|
||||
)";
|
||||
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m1 = LoadModelFromString(xml_unrotated, error.data(), error.size());
|
||||
ASSERT_THAT(m1, NotNull()) << error.data();
|
||||
MjModelPtr m1 =
|
||||
LoadModelFromString(xml_unrotated, error.data(), error.size());
|
||||
ASSERT_THAT(m1.get(), NotNull()) << error.data();
|
||||
|
||||
mjModel* m2 = LoadModelFromString(xml_rotated, error.data(), error.size());
|
||||
ASSERT_THAT(m2, NotNull()) << error.data();
|
||||
MjModelPtr m2 = LoadModelFromString(xml_rotated, error.data(), error.size());
|
||||
ASSERT_THAT(m2.get(), NotNull()) << error.data();
|
||||
|
||||
// same number of vertices
|
||||
ASSERT_EQ(m1->nflexvert, m2->nflexvert);
|
||||
@@ -1394,9 +1352,6 @@ TEST_F(UserFlexTest, Vert0RotationInvariant) {
|
||||
EXPECT_NEAR(m1->flex_vert0[i], m2->flex_vert0[i], 1e-10)
|
||||
<< "vert0 mismatch at index " << i;
|
||||
}
|
||||
|
||||
mj_deleteModel(m1);
|
||||
mj_deleteModel(m2);
|
||||
}
|
||||
|
||||
TEST_F(UserFlexTest, Load1DFlexFromOBJ) {
|
||||
@@ -1413,4 +1368,3 @@ TEST_F(UserFlexTest, Load1DFlexFromOBJ) {
|
||||
|
||||
} // namespace
|
||||
} // namespace mujoco
|
||||
|
||||
|
||||
+188
-237
@@ -37,16 +37,12 @@ namespace {
|
||||
|
||||
using MjCMeshTest = MujocoTest;
|
||||
|
||||
static const char* const kMeshPath =
|
||||
"user/testdata/mesh.xml";
|
||||
static const char* const kMeshPath = "user/testdata/mesh.xml";
|
||||
static const char* const kDuplicateVerticesPath =
|
||||
"user/testdata/duplicate_vertices.xml";
|
||||
static const char* const kCubePath =
|
||||
"user/testdata/cube.xml";
|
||||
static const char* const kCubeCompletePath =
|
||||
"user/testdata/cube_complete.obj";
|
||||
static const char* const kTorusPath =
|
||||
"user/testdata/torus.xml";
|
||||
static const char* const kCubePath = "user/testdata/cube.xml";
|
||||
static const char* const kCubeCompletePath = "user/testdata/cube_complete.obj";
|
||||
static const char* const kTorusPath = "user/testdata/torus.xml";
|
||||
static const char* const kTorusMaxhullVertPath =
|
||||
"user/testdata/torus_maxhullvert.xml";
|
||||
static const char* const kTorusDefaultMaxhullVertPath =
|
||||
@@ -57,18 +53,14 @@ static const char* const kConvexInertiaPath =
|
||||
"user/testdata/inertia_convex.xml";
|
||||
static const char* const kConcaveInertiaPath =
|
||||
"user/testdata/inertia_concave.xml";
|
||||
static const char* const kShellInertiaPath =
|
||||
"user/testdata/inertia_shell.xml";
|
||||
static const char* const kTorusQuadsPath =
|
||||
"user/testdata/torus_quads.xml";
|
||||
static const char* const kShellInertiaPath = "user/testdata/inertia_shell.xml";
|
||||
static const char* const kTorusQuadsPath = "user/testdata/torus_quads.xml";
|
||||
static const char* const kTexturedTorusPath =
|
||||
"user/testdata/textured_torus.xml";
|
||||
static const char* const kDuplicateOBJPath =
|
||||
"user/testdata/duplicate.xml";
|
||||
static const char* const kDuplicateOBJPath = "user/testdata/duplicate.xml";
|
||||
static const char* const kMalformedFaceOBJPath =
|
||||
"user/testdata/malformed_face.xml";
|
||||
static const char* const kCubeSkinPath =
|
||||
"user/testdata/cube_skin.xml";
|
||||
static const char* const kCubeSkinPath = "user/testdata/cube_skin.xml";
|
||||
|
||||
static const char* const kNoDecoderForMeshErrorMsh =
|
||||
"no decoder found for mesh";
|
||||
@@ -94,13 +86,8 @@ TEST_F(MjCMeshTest, UnknownMeshFormat) {
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
std::vector<std::string> invalid_names = {
|
||||
"noextension",
|
||||
"anobj",
|
||||
"f",
|
||||
"mesh.exe",
|
||||
"file%s"
|
||||
};
|
||||
std::vector<std::string> invalid_names = {"noextension", "anobj", "f",
|
||||
"mesh.exe", "file%s"};
|
||||
mjVFS vfs;
|
||||
mj_defaultVFS(&vfs);
|
||||
|
||||
@@ -108,9 +95,9 @@ TEST_F(MjCMeshTest, UnknownMeshFormat) {
|
||||
mj_addBufferVFS(&vfs, name.c_str(), nullptr, 0);
|
||||
std::string xml = absl::StrFormat(xml_format, name);
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model =
|
||||
MjModelPtr model =
|
||||
LoadModelFromString(xml.c_str(), error.data(), error.size(), &vfs);
|
||||
ASSERT_THAT(model, testing::IsNull())
|
||||
ASSERT_THAT(model.get(), testing::IsNull())
|
||||
<< "Should fail to load a mesh named: " << name;
|
||||
EXPECT_THAT(error.data(), HasSubstr(kNoDecoderForMeshErrorMsh));
|
||||
EXPECT_THAT(error.data(), HasSubstr(name));
|
||||
@@ -141,8 +128,8 @@ TEST_F(MjCMeshTest, LoadMSHWithVFS) {
|
||||
mj_defaultVFS(vfs.get());
|
||||
|
||||
// should fallback to OS filesystem
|
||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||
EXPECT_THAT(model, IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||
EXPECT_THAT(model.get(), IsNull());
|
||||
EXPECT_THAT(error, HasSubstr("Error opening file"));
|
||||
mj_deleteVFS(vfs.get());
|
||||
}
|
||||
@@ -167,8 +154,8 @@ TEST_F(MjCMeshTest, LoadOBJWithVFS) {
|
||||
mj_defaultVFS(vfs.get());
|
||||
|
||||
// should fallback to OS filesystem
|
||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||
EXPECT_THAT(model, IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||
EXPECT_THAT(model.get(), IsNull());
|
||||
EXPECT_THAT(error, HasSubstr("Error opening file"));
|
||||
mj_deleteVFS(vfs.get());
|
||||
}
|
||||
@@ -193,8 +180,8 @@ TEST_F(MjCMeshTest, LoadSTLWithVFS) {
|
||||
mj_defaultVFS(vfs.get());
|
||||
|
||||
// should fallback to OS filesystem
|
||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||
EXPECT_THAT(model, IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||
EXPECT_THAT(model.get(), IsNull());
|
||||
EXPECT_THAT(error, HasSubstr("Error opening file"));
|
||||
mj_deleteVFS(vfs.get());
|
||||
}
|
||||
@@ -221,8 +208,8 @@ TEST_F(MjCMeshTest, LoadMSHWithContentType) {
|
||||
mj_defaultVFS(vfs.get());
|
||||
|
||||
// should try opening the file (not found obviously)
|
||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||
EXPECT_THAT(model, IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||
EXPECT_THAT(model.get(), IsNull());
|
||||
EXPECT_THAT(error, HasSubstr("Error opening file"));
|
||||
mj_deleteVFS(vfs.get());
|
||||
}
|
||||
@@ -247,8 +234,8 @@ TEST_F(MjCMeshTest, LoadOBJWithContentType) {
|
||||
mj_defaultVFS(vfs.get());
|
||||
|
||||
// should try opening the file (not found obviously)
|
||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||
EXPECT_THAT(model, IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||
EXPECT_THAT(model.get(), IsNull());
|
||||
EXPECT_THAT(error, HasSubstr("Error opening file"));
|
||||
mj_deleteVFS(vfs.get());
|
||||
}
|
||||
@@ -273,8 +260,8 @@ TEST_F(MjCMeshTest, LoadSTLWithContentType) {
|
||||
mj_defaultVFS(vfs.get());
|
||||
|
||||
// should try opening the file (not found obviously)
|
||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||
EXPECT_THAT(model, IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||
EXPECT_THAT(model.get(), IsNull());
|
||||
EXPECT_THAT(error, HasSubstr("Error opening file"));
|
||||
mj_deleteVFS(vfs.get());
|
||||
}
|
||||
@@ -300,8 +287,8 @@ TEST_F(MjCMeshTest, LoadMSHWithContentTypeError) {
|
||||
mj_addBufferVFS(&vfs, "some_file", nullptr, 0);
|
||||
|
||||
// should error with unknown file type
|
||||
mjModel* model = LoadModelFromString(xml, error, error_sz, &vfs);
|
||||
EXPECT_THAT(model, IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error, error_sz, &vfs);
|
||||
EXPECT_THAT(model.get(), IsNull());
|
||||
EXPECT_THAT(error, HasSubstr(kNoDecoderForMeshErrorMsh));
|
||||
mj_deleteVFS(&vfs);
|
||||
}
|
||||
@@ -327,8 +314,8 @@ TEST_F(MjCMeshTest, LoadMSHWithInvalidContentType) {
|
||||
mj_addBufferVFS(&vfs, "some_file", nullptr, 0);
|
||||
|
||||
// should error with unknown file type
|
||||
mjModel* model = LoadModelFromString(xml, error, error_sz, &vfs);
|
||||
EXPECT_THAT(model, IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error, error_sz, &vfs);
|
||||
EXPECT_THAT(model.get(), IsNull());
|
||||
EXPECT_THAT(error, HasSubstr(kNoDecoderForMeshErrorMsh));
|
||||
mj_deleteVFS(&vfs);
|
||||
}
|
||||
@@ -353,8 +340,8 @@ TEST_F(MjCMeshTest, LoadMSHWithContentTypeParam) {
|
||||
mj_defaultVFS(vfs.get());
|
||||
|
||||
// should try opening the file (not found obviously)
|
||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||
EXPECT_THAT(model, IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||
EXPECT_THAT(model.get(), IsNull());
|
||||
EXPECT_THAT(error, HasSubstr("Error opening file"));
|
||||
mj_deleteVFS(vfs.get());
|
||||
}
|
||||
@@ -438,8 +425,7 @@ TEST_F(MjCMeshTest, SaveMeshOnce) {
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size());
|
||||
// Confirm the mesh file is loaded and stored in paths
|
||||
EXPECT_EQ(
|
||||
std::string(&model->paths[model->mesh_pathadr[0]]), "cube.obj");
|
||||
EXPECT_EQ(std::string(&model->paths[model->mesh_pathadr[0]]), "cube.obj");
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, Not(testing::HasSubstr("vertex")));
|
||||
mj_deleteModel(model);
|
||||
@@ -457,9 +443,8 @@ TEST_F(MjCMeshTest, TinyMeshLoads) {
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model, NotNull()) << error;
|
||||
mj_deleteModel(model);
|
||||
MjModelPtr model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model.get(), NotNull()) << error;
|
||||
}
|
||||
|
||||
// ------------- test max hull vert -------------------------------------------
|
||||
@@ -498,9 +483,8 @@ TEST_F(MjCMeshTest, FaceNormalAutogenerated) {
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model, NotNull()) << error;
|
||||
mj_deleteModel(model);
|
||||
MjModelPtr model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model.get(), NotNull()) << error;
|
||||
}
|
||||
|
||||
// ------------- test inertia -------------------------------------------------
|
||||
@@ -521,9 +505,8 @@ TEST_F(MjCMeshTest, SmallInertiaLoads) {
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model, NotNull()) << error;
|
||||
mj_deleteModel(model);
|
||||
MjModelPtr model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model.get(), NotNull()) << error;
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, TinyInertiaFails) {
|
||||
@@ -586,11 +569,13 @@ TEST_F(MjCMeshTest, FlippedFaceFailsExactInertia) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model, testing::IsNull());
|
||||
EXPECT_THAT(error.data(), HasSubstr(
|
||||
"Error: faces of mesh 'example_mesh' have inconsistent orientation. "
|
||||
"Please check the faces containing the vertices 1 and 2."));
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model.get(), testing::IsNull());
|
||||
EXPECT_THAT(
|
||||
error.data(),
|
||||
HasSubstr(
|
||||
"Error: faces of mesh 'example_mesh' have inconsistent orientation. "
|
||||
"Please check the faces containing the vertices 1 and 2."));
|
||||
}
|
||||
|
||||
void CheckTetrahedronWasRescaled(mjModel* model) {
|
||||
@@ -598,12 +583,12 @@ void CheckTetrahedronWasRescaled(mjModel* model) {
|
||||
// with vertices (0, 0, 0), (1, 0, 0), (0, 2, 0), (0, 0, 3)
|
||||
// after mesh preprocessing is performed
|
||||
std::vector<mjtNum> vert = {
|
||||
-0.51610732078552246, -0.57402724027633667, -0.5283237099647522,
|
||||
0.42337465286254883, -0.90627568960189819, -0.61189728975296021,
|
||||
0.065528042614459991, 1.2306677103042603, -1.1645441055297852,
|
||||
0.027204651385545731, 0.24963514506816864, 2.3047652244567871};
|
||||
-0.51610732078552246, -0.57402724027633667, -0.5283237099647522,
|
||||
0.42337465286254883, -0.90627568960189819, -0.61189728975296021,
|
||||
0.065528042614459991, 1.2306677103042603, -1.1645441055297852,
|
||||
0.027204651385545731, 0.24963514506816864, 2.3047652244567871};
|
||||
mjtNum tolerance = std::numeric_limits<float>::epsilon();
|
||||
for (int i=0; i < 12; ++i) {
|
||||
for (int i = 0; i < 12; ++i) {
|
||||
EXPECT_NEAR(model->mesh_vert[i], vert[i], tolerance);
|
||||
}
|
||||
}
|
||||
@@ -622,10 +607,9 @@ TEST_F(MjCMeshTest, FlippedFaceAllowedWorld) {
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model, NotNull()) << error;
|
||||
CheckTetrahedronWasRescaled(model);
|
||||
mj_deleteModel(model);
|
||||
MjModelPtr model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model.get(), NotNull()) << error;
|
||||
CheckTetrahedronWasRescaled(model.get());
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, FlippedFaceAllowedNoMass) {
|
||||
@@ -644,10 +628,9 @@ TEST_F(MjCMeshTest, FlippedFaceAllowedNoMass) {
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model, NotNull()) << error;
|
||||
CheckTetrahedronWasRescaled(model);
|
||||
mj_deleteModel(model);
|
||||
MjModelPtr model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model.get(), NotNull()) << error;
|
||||
CheckTetrahedronWasRescaled(model.get());
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, FlippedFaceAllowedInertial) {
|
||||
@@ -667,10 +650,9 @@ TEST_F(MjCMeshTest, FlippedFaceAllowedInertial) {
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model, NotNull()) << error;
|
||||
CheckTetrahedronWasRescaled(model);
|
||||
mj_deleteModel(model);
|
||||
MjModelPtr model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model.get(), NotNull()) << error;
|
||||
CheckTetrahedronWasRescaled(model.get());
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, FlippedFaceAllowedNegligibleArea) {
|
||||
@@ -689,10 +671,9 @@ TEST_F(MjCMeshTest, FlippedFaceAllowedNegligibleArea) {
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model, NotNull()) << error;
|
||||
CheckTetrahedronWasRescaled(model);
|
||||
mj_deleteModel(model);
|
||||
MjModelPtr model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model.get(), NotNull()) << error;
|
||||
CheckTetrahedronWasRescaled(model.get());
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, AreaTooSmall) {
|
||||
@@ -711,8 +692,8 @@ TEST_F(MjCMeshTest, AreaTooSmall) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model, IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model.get(), IsNull());
|
||||
EXPECT_THAT(error.data(), HasSubstr("mesh surface area is too small"));
|
||||
}
|
||||
|
||||
@@ -732,10 +713,9 @@ TEST_F(MjCMeshTest, VolumeTooSmall) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model, testing::IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model.get(), testing::IsNull());
|
||||
EXPECT_THAT(error.data(), HasSubstr("mesh volume is too small"));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, VisualVolumeTooSmall) {
|
||||
@@ -759,10 +739,9 @@ TEST_F(MjCMeshTest, VisualVolumeTooSmall) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model, testing::IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model.get(), testing::IsNull());
|
||||
EXPECT_THAT(error.data(), HasSubstr("mesh volume is too small"));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, VisualVolumeSmallAllowedShell) {
|
||||
@@ -786,12 +765,11 @@ TEST_F(MjCMeshTest, VisualVolumeSmallAllowedShell) {
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model, NotNull()) << error;
|
||||
MjModelPtr model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model.get(), NotNull()) << error;
|
||||
EXPECT_LE(mju_abs(model->geom_size[0]), 1);
|
||||
EXPECT_LE(mju_abs(model->geom_size[1]), 1);
|
||||
EXPECT_LE(mju_abs(model->geom_size[2]), 1);
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, VolumeSmallAllowedShell) {
|
||||
@@ -810,12 +788,11 @@ TEST_F(MjCMeshTest, VolumeSmallAllowedShell) {
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model, NotNull()) << error;
|
||||
MjModelPtr model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model.get(), NotNull()) << error;
|
||||
EXPECT_LE(mju_abs(model->geom_size[0]), 1);
|
||||
EXPECT_LE(mju_abs(model->geom_size[1]), 1);
|
||||
EXPECT_LE(mju_abs(model->geom_size[2]), 1);
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, Flex2DElasticityRequiresPositiveThickness) {
|
||||
@@ -829,8 +806,8 @@ TEST_F(MjCMeshTest, Flex2DElasticityRequiresPositiveThickness) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model, testing::IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model.get(), testing::IsNull());
|
||||
EXPECT_THAT(error.data(),
|
||||
HasSubstr("2d elasticity requires positive thickness"));
|
||||
}
|
||||
@@ -847,9 +824,8 @@ TEST_F(MjCMeshTest, InterpolatedFlexSupportsBendElasticityWithWarning) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model, testing::NotNull()) << error.data();
|
||||
mj_deleteModel(model);
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model.get(), testing::NotNull()) << error.data();
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, InterpolatedFlexSupportsBothElasticityWithWarning) {
|
||||
@@ -864,9 +840,8 @@ TEST_F(MjCMeshTest, InterpolatedFlexSupportsBothElasticityWithWarning) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model, testing::NotNull()) << error.data();
|
||||
mj_deleteModel(model);
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model.get(), testing::NotNull()) << error.data();
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, Flex2DElasticityRequires2DFlex) {
|
||||
@@ -880,8 +855,8 @@ TEST_F(MjCMeshTest, Flex2DElasticityRequires2DFlex) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model, testing::IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model.get(), testing::IsNull());
|
||||
EXPECT_THAT(error.data(), HasSubstr("2d elasticity requires 2d flex"));
|
||||
}
|
||||
|
||||
@@ -908,23 +883,24 @@ TEST_F(MjCMeshTest, VolumeNegativeThrowsError) {
|
||||
|
||||
for (int nmesh : {3, 16, 17, 50}) {
|
||||
std::string mesh_definitions = "";
|
||||
for (int i = 1; i < nmesh+1; i++) {
|
||||
for (int i = 1; i < nmesh + 1; i++) {
|
||||
mesh_definitions += absl::StrFormat(bad_mesh, i);
|
||||
}
|
||||
|
||||
std::string geom_definitions = "";
|
||||
for (int i = 1; i < nmesh+1; i++) {
|
||||
for (int i = 1; i < nmesh + 1; i++) {
|
||||
geom_definitions += absl::StrFormat(geom, i);
|
||||
}
|
||||
|
||||
std::string xml_str = xml;
|
||||
absl::StrReplaceAll({{"MESH_DEFINITIONS", mesh_definitions},
|
||||
{"GEOM_DEFINITIONS", geom_definitions}}, &xml_str);
|
||||
{"GEOM_DEFINITIONS", geom_definitions}},
|
||||
&xml_str);
|
||||
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml_str.c_str(),
|
||||
error.data(), error.size());
|
||||
EXPECT_THAT(model, IsNull());
|
||||
MjModelPtr model =
|
||||
LoadModelFromString(xml_str.c_str(), error.data(), error.size());
|
||||
EXPECT_THAT(model.get(), IsNull());
|
||||
EXPECT_THAT(error.data(), HasSubstr("mesh volume is negative"));
|
||||
}
|
||||
}
|
||||
@@ -964,22 +940,22 @@ TEST_F(MjCMeshTest, ExactConcaveInertia) {
|
||||
mjtNum m_hole = .9 * .8 * .8 * density;
|
||||
mjtNum m_cube = 1. * density;
|
||||
mjtNum m_concave_cube = m_cube - m_hole;
|
||||
mjtNum I_cube = m_cube/6.;
|
||||
mjtNum I_cube = m_cube / 6.;
|
||||
// due to the asymmetric hole, the com position has changed
|
||||
// so we need to use https://en.wikipedia.org/wiki/Parallel_axis_theorem
|
||||
mjtNum d_cube = .5 - model->body_ipos[5];
|
||||
mjtNum d_hole = .55 - model->body_ipos[5];
|
||||
mjtNum I1 = I_cube - m_hole*(.8*.8 + .8*.8)/12;
|
||||
mjtNum I2 = I_cube - m_hole*(.8*.8 + .9*.9)/12
|
||||
+ m_cube*d_cube*d_cube - m_hole*d_hole*d_hole;
|
||||
mjtNum I1 = I_cube - m_hole * (.8 * .8 + .8 * .8) / 12;
|
||||
mjtNum I2 = I_cube - m_hole * (.8 * .8 + .9 * .9) / 12 +
|
||||
m_cube * d_cube * d_cube - m_hole * d_hole * d_hole;
|
||||
EXPECT_NEAR(model->body_mass[1], m_concave_cube, kMaxAbsErr);
|
||||
EXPECT_NEAR(model->body_mass[2], m_concave_cube, kMaxAbsErr);
|
||||
EXPECT_NEAR(model->body_mass[3], m_concave_cube, kMaxAbsErr);
|
||||
EXPECT_NEAR(model->body_mass[4], m_concave_cube, kMaxAbsErr);
|
||||
for (int i = 3; i < 15; i += 3) {
|
||||
EXPECT_NEAR(model->body_inertia[i], I1, kMaxAbsErr);
|
||||
EXPECT_NEAR(model->body_inertia[i+1], I2, kMaxAbsErr);
|
||||
EXPECT_NEAR(model->body_inertia[i+2], I2, kMaxAbsErr);
|
||||
EXPECT_NEAR(model->body_inertia[i + 1], I2, kMaxAbsErr);
|
||||
EXPECT_NEAR(model->body_inertia[i + 2], I2, kMaxAbsErr);
|
||||
}
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
@@ -990,7 +966,7 @@ TEST_F(MjCMeshTest, ExactConvexInertia) {
|
||||
mjModel* model = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size());
|
||||
// https://en.wikipedia.org/wiki/List_of_moments_of_inertia
|
||||
mjtNum m_solid_cube = 1.;
|
||||
mjtNum I_solid_cube = 1./6. * m_solid_cube;
|
||||
mjtNum I_solid_cube = 1. / 6. * m_solid_cube;
|
||||
EXPECT_LE(mju_abs(model->body_mass[1] - m_solid_cube), kMaxAbsErr);
|
||||
EXPECT_LE(mju_abs(model->body_mass[2] - m_solid_cube), kMaxAbsErr);
|
||||
for (int i = 3; i < 9; i++) {
|
||||
@@ -1005,7 +981,7 @@ TEST_F(MjCMeshTest, ExactShellInertia) {
|
||||
mjModel* model = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size());
|
||||
// see https://en.wikipedia.org/wiki/List_of_moments_of_inertia
|
||||
mjtNum m_hollow_cube = 6.;
|
||||
mjtNum I_hollow_cube = 5./18. * m_hollow_cube;
|
||||
mjtNum I_hollow_cube = 5. / 18. * m_hollow_cube;
|
||||
EXPECT_LE(mju_abs(model->body_mass[1] - m_hollow_cube), kMaxAbsErr);
|
||||
EXPECT_LE(mju_abs(model->body_inertia[3] - I_hollow_cube), kMaxAbsErr);
|
||||
EXPECT_LE(mju_abs(model->body_inertia[4] - I_hollow_cube), kMaxAbsErr);
|
||||
@@ -1026,8 +1002,8 @@ TEST_F(MjCMeshTest, MeshPosQuat) {
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model, NotNull()) << error;
|
||||
MjModelPtr model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model.get(), NotNull()) << error;
|
||||
// loading the mesh results in an offset of the geom's pos and quat due to the
|
||||
// fact that the geom's center is not the volumetric center of the mesh. To
|
||||
// recover the geom's originally specified pose, the offset used is stored in
|
||||
@@ -1035,16 +1011,15 @@ TEST_F(MjCMeshTest, MeshPosQuat) {
|
||||
// and orientation, first invert the specified mesh_pos and mesh_quat
|
||||
mjtNum inverse_mesh_pos[3];
|
||||
mjtNum inverse_mesh_quat[4];
|
||||
mju_negPose(inverse_mesh_pos, inverse_mesh_quat,
|
||||
&model->mesh_pos[0], &model->mesh_quat[0]);
|
||||
mju_negPose(inverse_mesh_pos, inverse_mesh_quat, &model->mesh_pos[0],
|
||||
&model->mesh_quat[0]);
|
||||
|
||||
// apply the inverted mesh_pos and inverted mesh_quat to the geom's pos and
|
||||
// quat. It should match the originally specified values
|
||||
mjtNum recovered_pos[3];
|
||||
mjtNum recovered_quat[4];
|
||||
mju_mulPose(recovered_pos, recovered_quat,
|
||||
&model->geom_pos[0], &model->geom_quat[0],
|
||||
inverse_mesh_pos, inverse_mesh_quat);
|
||||
mju_mulPose(recovered_pos, recovered_quat, &model->geom_pos[0],
|
||||
&model->geom_quat[0], inverse_mesh_pos, inverse_mesh_quat);
|
||||
EXPECT_NEAR(recovered_pos[0], 0, MjTol(1e-12, 1e-6));
|
||||
EXPECT_NEAR(recovered_pos[1], 0, MjTol(1e-12, 1e-6));
|
||||
EXPECT_NEAR(recovered_pos[2], 0, MjTol(1e-12, 1e-6));
|
||||
@@ -1055,11 +1030,10 @@ TEST_F(MjCMeshTest, MeshPosQuat) {
|
||||
EXPECT_NEAR(recovered_quat[3], 0, MjTol(1e-12, 1e-6));
|
||||
|
||||
// same test on the other geom
|
||||
mju_negPose(inverse_mesh_pos, inverse_mesh_quat,
|
||||
&model->mesh_pos[0], &model->mesh_quat[0]);
|
||||
mju_mulPose(recovered_pos, recovered_quat,
|
||||
&model->geom_pos[3], &model->geom_quat[4],
|
||||
inverse_mesh_pos, inverse_mesh_quat);
|
||||
mju_negPose(inverse_mesh_pos, inverse_mesh_quat, &model->mesh_pos[0],
|
||||
&model->mesh_quat[0]);
|
||||
mju_mulPose(recovered_pos, recovered_quat, &model->geom_pos[3],
|
||||
&model->geom_quat[4], inverse_mesh_pos, inverse_mesh_quat);
|
||||
EXPECT_NEAR(recovered_pos[0], 1, MjTol(1e-12, 1e-6));
|
||||
EXPECT_NEAR(recovered_pos[1], 2, MjTol(1e-12, 1e-6));
|
||||
EXPECT_NEAR(recovered_pos[2], 3, MjTol(1e-12, 1e-6));
|
||||
@@ -1068,8 +1042,6 @@ TEST_F(MjCMeshTest, MeshPosQuat) {
|
||||
EXPECT_NEAR(recovered_quat[1], 0.5, MjTol(1e-12, 1e-6));
|
||||
EXPECT_NEAR(recovered_quat[2], 0.5, MjTol(1e-12, 1e-6));
|
||||
EXPECT_NEAR(recovered_quat[3], 0.5, MjTol(1e-12, 1e-6));
|
||||
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, MeshPosQuatShellInertia) {
|
||||
@@ -1085,8 +1057,8 @@ TEST_F(MjCMeshTest, MeshPosQuatShellInertia) {
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model, NotNull()) << error;
|
||||
MjModelPtr model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model.get(), NotNull()) << error;
|
||||
// loading the mesh results in an offset of the geom's pos and quat due to the
|
||||
// fact that the geom's center is not the volumetric center of the mesh. To
|
||||
// recover the geom's originally specified pose, the offset used is stored in
|
||||
@@ -1094,16 +1066,15 @@ TEST_F(MjCMeshTest, MeshPosQuatShellInertia) {
|
||||
// and orientation, first invert the specified mesh_pos and mesh_quat
|
||||
mjtNum inverse_mesh_pos[3];
|
||||
mjtNum inverse_mesh_quat[4];
|
||||
mju_negPose(inverse_mesh_pos, inverse_mesh_quat,
|
||||
&model->mesh_pos[0], &model->mesh_quat[0]);
|
||||
mju_negPose(inverse_mesh_pos, inverse_mesh_quat, &model->mesh_pos[0],
|
||||
&model->mesh_quat[0]);
|
||||
|
||||
// apply the inverted mesh_pos and inverted mesh_quat to the geom's pos and
|
||||
// quat. It should match the originally specified values
|
||||
mjtNum recovered_pos[3];
|
||||
mjtNum recovered_quat[4];
|
||||
mju_mulPose(recovered_pos, recovered_quat,
|
||||
&model->geom_pos[0], &model->geom_quat[0],
|
||||
inverse_mesh_pos, inverse_mesh_quat);
|
||||
mju_mulPose(recovered_pos, recovered_quat, &model->geom_pos[0],
|
||||
&model->geom_quat[0], inverse_mesh_pos, inverse_mesh_quat);
|
||||
EXPECT_NEAR(recovered_pos[0], 0, MjTol(1e-12, 1e-6));
|
||||
EXPECT_NEAR(recovered_pos[1], 0, MjTol(1e-12, 1e-6));
|
||||
EXPECT_NEAR(recovered_pos[2], 0, MjTol(1e-12, 1e-6));
|
||||
@@ -1114,11 +1085,10 @@ TEST_F(MjCMeshTest, MeshPosQuatShellInertia) {
|
||||
EXPECT_NEAR(recovered_quat[3], 0, MjTol(1e-12, 1e-6));
|
||||
|
||||
// same test on the other geom
|
||||
mju_negPose(inverse_mesh_pos, inverse_mesh_quat,
|
||||
&model->mesh_pos[0], &model->mesh_quat[0]);
|
||||
mju_mulPose(recovered_pos, recovered_quat,
|
||||
&model->geom_pos[3], &model->geom_quat[4],
|
||||
inverse_mesh_pos, inverse_mesh_quat);
|
||||
mju_negPose(inverse_mesh_pos, inverse_mesh_quat, &model->mesh_pos[0],
|
||||
&model->mesh_quat[0]);
|
||||
mju_mulPose(recovered_pos, recovered_quat, &model->geom_pos[3],
|
||||
&model->geom_quat[4], inverse_mesh_pos, inverse_mesh_quat);
|
||||
EXPECT_NEAR(recovered_pos[0], 1, MjTol(1e-12, 1e-6));
|
||||
EXPECT_NEAR(recovered_pos[1], 2, MjTol(1e-12, 1e-6));
|
||||
EXPECT_NEAR(recovered_pos[2], 3, MjTol(1e-12, 1e-6));
|
||||
@@ -1127,7 +1097,6 @@ TEST_F(MjCMeshTest, MeshPosQuatShellInertia) {
|
||||
EXPECT_NEAR(recovered_quat[1], 0.5, MjTol(1e-12, 1e-6));
|
||||
EXPECT_NEAR(recovered_quat[2], 0.5, MjTol(1e-12, 1e-6));
|
||||
EXPECT_NEAR(recovered_quat[3], 0.5, MjTol(1e-12, 1e-6));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, MeshScale) {
|
||||
@@ -1144,12 +1113,11 @@ TEST_F(MjCMeshTest, MeshScale) {
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model, NotNull()) << error;
|
||||
MjModelPtr model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model.get(), NotNull()) << error;
|
||||
|
||||
EXPECT_THAT(AsVector(model->mesh_scale + 0, 3), ElementsAre(1, 1, 1));
|
||||
EXPECT_THAT(AsVector(model->mesh_scale + 3, 3), ElementsAre(0.9, 1, -1));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, NegativeScaleUserMeshCompiles) {
|
||||
@@ -1166,9 +1134,8 @@ TEST_F(MjCMeshTest, NegativeScaleUserMeshCompiles) {
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model, NotNull()) << error;
|
||||
mj_deleteModel(model);
|
||||
MjModelPtr model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model.get(), NotNull()) << error;
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, NegativeScaleUserMeshMatchesPositiveScale) {
|
||||
@@ -1199,22 +1166,19 @@ TEST_F(MjCMeshTest, NegativeScaleUserMeshMatchesPositiveScale) {
|
||||
)";
|
||||
|
||||
char error[1024];
|
||||
mjModel* pos_model = LoadModelFromString(pos_xml, error, sizeof(error));
|
||||
ASSERT_THAT(pos_model, NotNull()) << error;
|
||||
MjModelPtr pos_model = LoadModelFromString(pos_xml, error, sizeof(error));
|
||||
ASSERT_THAT(pos_model.get(), NotNull()) << error;
|
||||
|
||||
mjModel* neg_model = LoadModelFromString(neg_xml, error, sizeof(error));
|
||||
ASSERT_THAT(neg_model, NotNull()) << error;
|
||||
MjModelPtr neg_model = LoadModelFromString(neg_xml, error, sizeof(error));
|
||||
ASSERT_THAT(neg_model.get(), NotNull()) << error;
|
||||
|
||||
ASSERT_EQ(pos_model->nmeshface, neg_model->nmeshface);
|
||||
|
||||
for (int i = 0; i < pos_model->nmeshface; i++) {
|
||||
EXPECT_EQ(pos_model->mesh_face[3*i + 0], neg_model->mesh_face[3*i + 0]);
|
||||
EXPECT_EQ(pos_model->mesh_face[3*i + 1], neg_model->mesh_face[3*i + 2]);
|
||||
EXPECT_EQ(pos_model->mesh_face[3*i + 2], neg_model->mesh_face[3*i + 1]);
|
||||
EXPECT_EQ(pos_model->mesh_face[3 * i + 0], neg_model->mesh_face[3 * i + 0]);
|
||||
EXPECT_EQ(pos_model->mesh_face[3 * i + 1], neg_model->mesh_face[3 * i + 2]);
|
||||
EXPECT_EQ(pos_model->mesh_face[3 * i + 2], neg_model->mesh_face[3 * i + 1]);
|
||||
}
|
||||
|
||||
mj_deleteModel(pos_model);
|
||||
mj_deleteModel(neg_model);
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, ShellInertiaTest) {
|
||||
@@ -1231,12 +1195,11 @@ TEST_F(MjCMeshTest, ShellInertiaTest) {
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model, NotNull()) << error;
|
||||
MjModelPtr model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model.get(), NotNull()) << error;
|
||||
|
||||
EXPECT_THAT(AsVector(model->mesh_scale + 0, 3), ElementsAre(1, 1, 1));
|
||||
EXPECT_THAT(AsVector(model->mesh_scale + 3, 3), ElementsAre(0.9, 1, -1));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
// ----------------------------- texcoord -------------------------------------
|
||||
@@ -1251,9 +1214,8 @@ TEST_F(MjCMeshTest, CreateFaceTexCoord) {
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model, NotNull()) << error;
|
||||
mj_deleteModel(model);
|
||||
MjModelPtr model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model.get(), NotNull()) << error;
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, UseFaceTexCoord) {
|
||||
@@ -1267,21 +1229,20 @@ TEST_F(MjCMeshTest, UseFaceTexCoord) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model, NotNull()) << error.data();
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[ 0]], .0);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[ 1]], .2);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[ 2]], .1);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[ 3]], .0);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[ 4]], .1);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[ 5]], .3);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[ 6]], .2);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[ 7]], .0);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[ 8]], .3);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[ 9]], .1);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[10]], .2);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[11]], .3);
|
||||
mj_deleteModel(model);
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model.get(), NotNull()) << error.data();
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2 * model->mesh_facetexcoord[0]], .0);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2 * model->mesh_facetexcoord[1]], .2);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2 * model->mesh_facetexcoord[2]], .1);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2 * model->mesh_facetexcoord[3]], .0);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2 * model->mesh_facetexcoord[4]], .1);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2 * model->mesh_facetexcoord[5]], .3);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2 * model->mesh_facetexcoord[6]], .2);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2 * model->mesh_facetexcoord[7]], .0);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2 * model->mesh_facetexcoord[8]], .3);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2 * model->mesh_facetexcoord[9]], .1);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2 * model->mesh_facetexcoord[10]], .2);
|
||||
EXPECT_FLOAT_EQ(model->mesh_texcoord[2 * model->mesh_facetexcoord[11]], .3);
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, MissingTexCoord) {
|
||||
@@ -1294,8 +1255,8 @@ TEST_F(MjCMeshTest, MissingTexCoord) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model, testing::IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model.get(), testing::IsNull());
|
||||
EXPECT_THAT(error.data(), HasSubstr("texcoord must be 2*nv"));
|
||||
}
|
||||
|
||||
@@ -1312,10 +1273,9 @@ TEST_F(MjCMeshTest, NaNConvexHullDisallowed) {
|
||||
MockWarningHandler warning_handler;
|
||||
warning_handler.ExpectWarnings();
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model, testing::IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model.get(), testing::IsNull());
|
||||
EXPECT_THAT(error.data(), HasSubstr("vertex coordinate 0 is not finite"));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, InvalidIndexInFace) {
|
||||
@@ -1333,10 +1293,9 @@ TEST_F(MjCMeshTest, InvalidIndexInFace) {
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model, IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model.get(), IsNull());
|
||||
EXPECT_THAT(error, HasSubstr("in face 0, vertex index 6 does not exist"));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, QhullCache) {
|
||||
@@ -1351,7 +1310,7 @@ TEST_F(MjCMeshTest, QhullCache) {
|
||||
</worldbody>
|
||||
</mujoco>)";
|
||||
|
||||
static constexpr char xml2[] = R"(
|
||||
static constexpr char xml2[] = R"(
|
||||
<mujoco>
|
||||
<asset>
|
||||
<mesh name="box" file="cube_complete.obj"/>
|
||||
@@ -1367,17 +1326,16 @@ TEST_F(MjCMeshTest, QhullCache) {
|
||||
mj_addFileVFS(&vfs, "", GetTestDataFilePath(kCubeCompletePath).c_str());
|
||||
|
||||
std::array<char, 1000> error;
|
||||
mjModel* model = LoadModelFromString(xml1, error.data(), error.size(), &vfs);
|
||||
ASSERT_THAT(model, NotNull()) << "Failed to load model: " << error.data();
|
||||
MjModelPtr model =
|
||||
LoadModelFromString(xml1, error.data(), error.size(), &vfs);
|
||||
ASSERT_THAT(model.get(), NotNull())
|
||||
<< "Failed to load model: " << error.data();
|
||||
EXPECT_THAT(model->mesh_graphadr[0], -1);
|
||||
|
||||
mj_deleteModel(model);
|
||||
|
||||
model = LoadModelFromString(xml2, error.data(), error.size(), &vfs);
|
||||
ASSERT_THAT(model, NotNull()) << "Failed to load model: " << error.data();
|
||||
ASSERT_THAT(model.get(), NotNull())
|
||||
<< "Failed to load model: " << error.data();
|
||||
EXPECT_GT(model->mesh_graphadr[0], -1);
|
||||
|
||||
mj_deleteModel(model);
|
||||
mj_deleteVFS(&vfs);
|
||||
}
|
||||
|
||||
@@ -1395,8 +1353,8 @@ TEST_F(MjCMeshTest, ColocatedMeshError) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model, IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model.get(), IsNull());
|
||||
EXPECT_THAT(error.data(), HasSubstr("colocated"));
|
||||
}
|
||||
|
||||
@@ -1414,8 +1372,8 @@ TEST_F(MjCMeshTest, CollinearMeshError) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model, IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model.get(), IsNull());
|
||||
EXPECT_THAT(error.data(), HasSubstr("collinear"));
|
||||
}
|
||||
|
||||
@@ -1433,8 +1391,8 @@ TEST_F(MjCMeshTest, CoplanarMeshError) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model, IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model.get(), IsNull());
|
||||
EXPECT_THAT(error.data(), HasSubstr("coplanar"));
|
||||
}
|
||||
|
||||
@@ -1478,8 +1436,7 @@ bool AreAabbsAdjacent(const mjtNum* aabb1, const mjtNum* aabb2) {
|
||||
const mjtNum half_size1 = aabb1[dim + 3];
|
||||
const mjtNum center2 = aabb2[dim];
|
||||
const mjtNum half_size2 = aabb2[dim + 3];
|
||||
const mjtNum gap =
|
||||
std::abs(center1 - center2) - (half_size1 + half_size2);
|
||||
const mjtNum gap = std::abs(center1 - center2) - (half_size1 + half_size2);
|
||||
if (std::abs(gap) < kEps) {
|
||||
touching_dims++;
|
||||
} else if (gap < -kEps) {
|
||||
@@ -1533,15 +1490,15 @@ TEST_F(MjCMeshTest, OctreeIsBalanced) {
|
||||
const int level2 = model->oct_depth[octree_adr + node2_idx];
|
||||
if (std::abs(level1 - level2) > 1) {
|
||||
if (unbalanced_pairs < 10) {
|
||||
ADD_FAILURE()
|
||||
<< "Nodes " << node1_idx << " (level " << level1 << ") and "
|
||||
<< node2_idx << " (level " << level2 << ") are not balanced."
|
||||
<< "\nAABB1: center=(" << aabb1[0] << ", " << aabb1[1] << ", "
|
||||
<< aabb1[2] << "), half_size=(" << aabb1[3] << ", "
|
||||
<< aabb1[4] << ", " << aabb1[5] << ")"
|
||||
<< "\nAABB2: center=(" << aabb2[0] << ", " << aabb2[1] << ", "
|
||||
<< aabb2[2] << "), half_size=(" << aabb2[3] << ", "
|
||||
<< aabb2[4] << ", " << aabb2[5] << ")";
|
||||
ADD_FAILURE() << "Nodes " << node1_idx << " (level " << level1
|
||||
<< ") and " << node2_idx << " (level " << level2
|
||||
<< ") are not balanced."
|
||||
<< "\nAABB1: center=(" << aabb1[0] << ", " << aabb1[1]
|
||||
<< ", " << aabb1[2] << "), half_size=(" << aabb1[3]
|
||||
<< ", " << aabb1[4] << ", " << aabb1[5] << ")"
|
||||
<< "\nAABB2: center=(" << aabb2[0] << ", " << aabb2[1]
|
||||
<< ", " << aabb2[2] << "), half_size=(" << aabb2[3]
|
||||
<< ", " << aabb2[4] << ", " << aabb2[5] << ")";
|
||||
}
|
||||
unbalanced_pairs++;
|
||||
}
|
||||
@@ -1610,8 +1567,7 @@ TEST_F(MjCMeshTest, OctreeHangingNodeInterpolation) {
|
||||
|
||||
// decide which node is finer and which is coarser
|
||||
const int finer_node_idx = (level1 > level2) ? node1_idx : node2_idx;
|
||||
const int coarser_node_idx =
|
||||
(level1 > level2) ? node2_idx : node1_idx;
|
||||
const int coarser_node_idx = (level1 > level2) ? node2_idx : node1_idx;
|
||||
const mjtNum* coarser_aabb =
|
||||
&model->oct_aabb[(octree_adr + coarser_node_idx) * 6];
|
||||
const mjtNum* finer_aabb =
|
||||
@@ -1729,12 +1685,11 @@ TEST_F(MjCMeshTest, OctreeNotComputedForNonSDF) {
|
||||
}
|
||||
|
||||
mjtNum CubeSDF(mjtNum p[3], mjtNum b[3]) {
|
||||
mjtNum q[3] = {mju_abs(p[0]) - b[0],
|
||||
mju_abs(p[1]) - b[1],
|
||||
mjtNum q[3] = {mju_abs(p[0]) - b[0], mju_abs(p[1]) - b[1],
|
||||
mju_abs(p[2]) - b[2]};
|
||||
return mju_sqrt(std::pow(std::max(q[0], (mjtNum)0), 2) +
|
||||
std::pow(std::max(q[1], (mjtNum)0), 2) +
|
||||
std::pow(std::max(q[2], (mjtNum)0), 2)) +
|
||||
std::pow(std::max(q[1], (mjtNum)0), 2) +
|
||||
std::pow(std::max(q[2], (mjtNum)0), 2)) +
|
||||
std::min(std::max(q[0], std::max(q[1], q[2])), (mjtNum)0);
|
||||
}
|
||||
|
||||
@@ -1751,12 +1706,12 @@ TEST_F(MjCMeshTest, OctreeCube) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m, NotNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m.get(), NotNull()) << error.data();
|
||||
EXPECT_EQ(m->noct, 63497);
|
||||
mjData* d = mj_makeData(m);
|
||||
MjDataPtr d = MakeData(m);
|
||||
ASSERT_THAT(d, NotNull());
|
||||
mj_forward(m, d);
|
||||
mj_forward(m.get(), d.get());
|
||||
mjSDF sdf;
|
||||
int instance = 0;
|
||||
mjtGeom geomtype = mjGEOM_SDF;
|
||||
@@ -1768,11 +1723,10 @@ TEST_F(MjCMeshTest, OctreeCube) {
|
||||
mjtNum pnt[3][3] = {{1, 1, 1}, {.5, .5, .5}, {.5, 0, 0}};
|
||||
mjtNum size[3] = {1, 1, 1};
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
EXPECT_NEAR(mjc_distance(m, d, &sdf, pnt[i]), CubeSDF(pnt[i], size), 1e-1)
|
||||
EXPECT_NEAR(mjc_distance(m.get(), d.get(), &sdf, pnt[i]),
|
||||
CubeSDF(pnt[i], size), 1e-1)
|
||||
<< "i = " << i;
|
||||
}
|
||||
mj_deleteModel(m);
|
||||
mj_deleteData(d);
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, HemisphereSizes) {
|
||||
@@ -1786,15 +1740,14 @@ TEST_F(MjCMeshTest, HemisphereSizes) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(model, NotNull()) << error.data();
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(model.get(), NotNull()) << error.data();
|
||||
EXPECT_EQ(model->mesh_vertnum[0], 2 * (0 + 1) * (0 + 2) + 2);
|
||||
EXPECT_EQ(model->mesh_vertnum[1], 2 * (1 + 1) * (1 + 2) + 2);
|
||||
EXPECT_EQ(model->mesh_vertnum[2], 2 * (2 + 1) * (2 + 2) + 2);
|
||||
EXPECT_EQ(model->mesh_facenum[0], 4 * (0 + 1) * (0 + 2));
|
||||
EXPECT_EQ(model->mesh_facenum[1], 4 * (1 + 1) * (1 + 2));
|
||||
EXPECT_EQ(model->mesh_facenum[2], 4 * (2 + 1) * (2 + 2));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, SphereSizes) {
|
||||
@@ -1808,15 +1761,14 @@ TEST_F(MjCMeshTest, SphereSizes) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(model, NotNull()) << error.data();
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(model.get(), NotNull()) << error.data();
|
||||
EXPECT_EQ(model->mesh_vertnum[0], 2 + 10 * std::pow(4, 0));
|
||||
EXPECT_EQ(model->mesh_vertnum[1], 2 + 10 * std::pow(4, 1));
|
||||
EXPECT_EQ(model->mesh_vertnum[2], 2 + 10 * std::pow(4, 2));
|
||||
EXPECT_EQ(model->mesh_facenum[0], 20 * std::pow(4, 0));
|
||||
EXPECT_EQ(model->mesh_facenum[1], 20 * std::pow(4, 1));
|
||||
EXPECT_EQ(model->mesh_facenum[2], 20 * std::pow(4, 2));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(MjCMeshTest, MeshMaterial) {
|
||||
@@ -1835,11 +1787,10 @@ TEST_F(MjCMeshTest, MeshMaterial) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(model, NotNull()) << error.data();
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(model.get(), NotNull()) << error.data();
|
||||
EXPECT_EQ(model->geom_matid[0], 1);
|
||||
EXPECT_EQ(model->geom_matid[1], 0);
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
+77
-116
@@ -95,15 +95,13 @@ TEST_F(UserModelTest, WeldRootID) {
|
||||
)";
|
||||
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model, NotNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model.get(), NotNull());
|
||||
|
||||
EXPECT_THAT(AsVector(model->body_rootid, model->nbody),
|
||||
ElementsAre(0, 1, 1, 3, 3, 5, 5, 7, 7, 9, 9));
|
||||
EXPECT_THAT(AsVector(model->body_weldid, model->nbody),
|
||||
ElementsAre(0, 1, 2, 3, 3, 0, 0, 0, 0, 0, 10));
|
||||
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(UserModelTest, RepeatedNames) {
|
||||
@@ -119,8 +117,8 @@ TEST_F(UserModelTest, RepeatedNames) {
|
||||
</mujoco>)";
|
||||
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model, IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model.get(), IsNull());
|
||||
EXPECT_THAT(error.data(), HasSubstr("repeated name 'geom1' in geom"));
|
||||
}
|
||||
|
||||
@@ -143,8 +141,8 @@ TEST_F(UserModelTest, SameFrame) {
|
||||
</mujoco>)";
|
||||
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(model, NotNull()) << error.data();
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(model.get(), NotNull()) << error.data();
|
||||
EXPECT_EQ(model->geom_sameframe[0], mjSAMEFRAME_NONE);
|
||||
EXPECT_EQ(model->geom_sameframe[1], mjSAMEFRAME_BODY);
|
||||
EXPECT_EQ(model->geom_sameframe[2], mjSAMEFRAME_INERTIA);
|
||||
@@ -152,27 +150,24 @@ TEST_F(UserModelTest, SameFrame) {
|
||||
EXPECT_EQ(model->geom_sameframe[4], mjSAMEFRAME_INERTIAROT);
|
||||
|
||||
// make data, get geom_xpos
|
||||
mjData* data = mj_makeData(model);
|
||||
mj_kinematics(model, data);
|
||||
auto geom_xpos = AsVector(data->geom_xpos, model->ngeom*3);
|
||||
auto geom_xmat = AsVector(data->geom_xmat, model->ngeom*9);
|
||||
MjDataPtr data = MakeData(model);
|
||||
mj_kinematics(model.get(), data.get());
|
||||
auto geom_xpos = AsVector(data->geom_xpos, model->ngeom * 3);
|
||||
auto geom_xmat = AsVector(data->geom_xmat, model->ngeom * 9);
|
||||
|
||||
// set all geom_sameframe to 0, call kinematics again
|
||||
for (int i = 0; i < model->ngeom; i++) {
|
||||
model->geom_sameframe[i] = mjSAMEFRAME_NONE;
|
||||
}
|
||||
mj_resetData(model, data);
|
||||
mj_kinematics(model, data);
|
||||
auto geom_xpos2 = AsVector(data->geom_xpos, model->ngeom*3);
|
||||
auto geom_xmat2 = AsVector(data->geom_xmat, model->ngeom*9);
|
||||
mj_resetData(model.get(), data.get());
|
||||
mj_kinematics(model.get(), data.get());
|
||||
auto geom_xpos2 = AsVector(data->geom_xpos, model->ngeom * 3);
|
||||
auto geom_xmat2 = AsVector(data->geom_xmat, model->ngeom * 9);
|
||||
|
||||
// expect them to be equal
|
||||
constexpr double eps = 1e-6;
|
||||
EXPECT_THAT(geom_xpos, Pointwise(MjNear(eps, eps), geom_xpos2));
|
||||
EXPECT_THAT(geom_xmat, Pointwise(MjNear(eps, eps), geom_xmat2));
|
||||
|
||||
mj_deleteData(data);
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(UserModelTest, ActuatorSparsity) {
|
||||
@@ -194,9 +189,8 @@ TEST_F(UserModelTest, ActuatorSparsity) {
|
||||
</actuator>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* m = LoadModelFromString(xml);
|
||||
MjModelPtr m = LoadModelFromString(xml);
|
||||
ASSERT_EQ(m->nJmom, 2);
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserModelTest, FixedTendonSparsity) {
|
||||
@@ -226,8 +220,8 @@ TEST_F(UserModelTest, FixedTendonSparsity) {
|
||||
</tendon>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* m = LoadModelFromString(xml);
|
||||
ASSERT_THAT(m, NotNull());
|
||||
MjModelPtr m = LoadModelFromString(xml);
|
||||
ASSERT_THAT(m.get(), NotNull());
|
||||
|
||||
EXPECT_EQ(m->nJten, 3);
|
||||
EXPECT_EQ(m->ten_J_rownnz[0], 3);
|
||||
@@ -237,8 +231,6 @@ TEST_F(UserModelTest, FixedTendonSparsity) {
|
||||
int rowadr = m->ten_J_rowadr[0];
|
||||
int* colind = m->ten_J_colind + rowadr;
|
||||
EXPECT_THAT(std::vector<int>(colind, colind + 3), ElementsAre(0, 1, 2));
|
||||
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserModelTest, NestedZeroMassBodiesOK) {
|
||||
@@ -259,9 +251,8 @@ TEST_F(UserModelTest, NestedZeroMassBodiesOK) {
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model, NotNull()) << error;
|
||||
mj_deleteModel(model);
|
||||
MjModelPtr model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model.get(), NotNull()) << error;
|
||||
}
|
||||
|
||||
TEST_F(UserModelTest, NestedZeroMassBodiesWithJointOK) {
|
||||
@@ -286,9 +277,8 @@ TEST_F(UserModelTest, NestedZeroMassBodiesWithJointOK) {
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model, NotNull()) << error;
|
||||
mj_deleteModel(model);
|
||||
MjModelPtr model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model.get(), NotNull()) << error;
|
||||
}
|
||||
|
||||
TEST_F(UserModelTest, NestedZeroMassBodiesFail) {
|
||||
@@ -309,14 +299,13 @@ TEST_F(UserModelTest, NestedZeroMassBodiesFail) {
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model, IsNull());
|
||||
MjModelPtr model = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(model.get(), IsNull());
|
||||
EXPECT_THAT(
|
||||
error,
|
||||
HasSubstr(
|
||||
"mass and inertia of moving bodies must be larger than mjMINVAL"));
|
||||
EXPECT_THAT(error, HasSubstr("Element name 'bad'"));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(UserModelTest, ConvexHullForCollisionMeshes) {
|
||||
@@ -338,14 +327,14 @@ TEST_F(UserModelTest, ConvexHullForCollisionMeshes) {
|
||||
</mujoco>)";
|
||||
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(model, NotNull()) << error.data();
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(model.get(), NotNull()) << error.data();
|
||||
|
||||
int no_hull_id = mj_name2id(model, mjOBJ_MESH, "mesh_no_hull");
|
||||
int no_hull_id = mj_name2id(model.get(), mjOBJ_MESH, "mesh_no_hull");
|
||||
int with_hull_contype_id =
|
||||
mj_name2id(model, mjOBJ_MESH, "mesh_with_hull_contype");
|
||||
mj_name2id(model.get(), mjOBJ_MESH, "mesh_with_hull_contype");
|
||||
int with_hull_conaffinity_id =
|
||||
mj_name2id(model, mjOBJ_MESH, "mesh_with_hull_conaffinity");
|
||||
mj_name2id(model.get(), mjOBJ_MESH, "mesh_with_hull_conaffinity");
|
||||
|
||||
EXPECT_NE(no_hull_id, -1);
|
||||
EXPECT_NE(with_hull_contype_id, -1);
|
||||
@@ -359,8 +348,6 @@ TEST_F(UserModelTest, ConvexHullForCollisionMeshes) {
|
||||
|
||||
// mesh_with_hull_conaffinity should have a convex hull.
|
||||
EXPECT_NE(model->mesh_graphadr[with_hull_conaffinity_id], -1);
|
||||
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(UserModelTest, ConvexHullForPairCollisionMeshes) {
|
||||
@@ -380,17 +367,15 @@ TEST_F(UserModelTest, ConvexHullForPairCollisionMeshes) {
|
||||
</mujoco>)";
|
||||
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(model, NotNull()) << error.data();
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(model.get(), NotNull()) << error.data();
|
||||
|
||||
int mesh_in_pair_id = mj_name2id(model, mjOBJ_MESH, "mesh");
|
||||
int mesh_in_pair_id = mj_name2id(model.get(), mjOBJ_MESH, "mesh");
|
||||
|
||||
EXPECT_NE(mesh_in_pair_id, -1);
|
||||
|
||||
// mesh_in_pair should have a convex hull because it is in a collision pair.
|
||||
EXPECT_NE(model->mesh_graphadr[mesh_in_pair_id], -1);
|
||||
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
// ------------- test automatic inference of nuser_xxx -------------------------
|
||||
@@ -406,11 +391,10 @@ TEST_F(UserDataTest, AutoNUserBody) {
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* m = LoadModelFromString(xml);
|
||||
MjModelPtr m = LoadModelFromString(xml);
|
||||
ASSERT_EQ(m->nuser_body, 3);
|
||||
EXPECT_THAT(GetRow(m->body_user, m->nuser_body, 1), ElementsAre(1, 2, 3));
|
||||
EXPECT_THAT(GetRow(m->body_user, m->nuser_body, 2), ElementsAre(2, 3, 0));
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserDataTest, AutoNUserJoint) {
|
||||
@@ -425,11 +409,10 @@ TEST_F(UserDataTest, AutoNUserJoint) {
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* m = LoadModelFromString(xml);
|
||||
MjModelPtr m = LoadModelFromString(xml);
|
||||
ASSERT_EQ(m->nuser_jnt, 3);
|
||||
EXPECT_THAT(GetRow(m->jnt_user, m->nuser_jnt, 0), ElementsAre(1, 2, 3));
|
||||
EXPECT_THAT(GetRow(m->jnt_user, m->nuser_jnt, 1), ElementsAre(2, 3, 0));
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserDataTest, AutoNUserGeom) {
|
||||
@@ -441,11 +424,10 @@ TEST_F(UserDataTest, AutoNUserGeom) {
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* m = LoadModelFromString(xml);
|
||||
MjModelPtr m = LoadModelFromString(xml);
|
||||
ASSERT_EQ(m->nuser_geom, 3);
|
||||
EXPECT_THAT(GetRow(m->geom_user, m->nuser_geom, 0), ElementsAre(1, 2, 3));
|
||||
EXPECT_THAT(GetRow(m->geom_user, m->nuser_geom, 1), ElementsAre(2, 3, 0));
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserDataTest, AutoNUserSite) {
|
||||
@@ -457,11 +439,10 @@ TEST_F(UserDataTest, AutoNUserSite) {
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* m = LoadModelFromString(xml);
|
||||
MjModelPtr m = LoadModelFromString(xml);
|
||||
ASSERT_EQ(m->nuser_site, 3);
|
||||
EXPECT_THAT(GetRow(m->site_user, m->nuser_site, 0), ElementsAre(1, 2, 3));
|
||||
EXPECT_THAT(GetRow(m->site_user, m->nuser_site, 1), ElementsAre(2, 3, 0));
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserDataTest, AutoNUserCamera) {
|
||||
@@ -473,11 +454,10 @@ TEST_F(UserDataTest, AutoNUserCamera) {
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* m = LoadModelFromString(xml);
|
||||
MjModelPtr m = LoadModelFromString(xml);
|
||||
ASSERT_EQ(m->nuser_cam, 3);
|
||||
EXPECT_THAT(GetRow(m->cam_user, m->nuser_cam, 0), ElementsAre(1, 2, 3));
|
||||
EXPECT_THAT(GetRow(m->cam_user, m->nuser_cam, 1), ElementsAre(2, 3, 0));
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserDataTest, AutoNUserTendon) {
|
||||
@@ -499,11 +479,10 @@ TEST_F(UserDataTest, AutoNUserTendon) {
|
||||
</tendon>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* m = LoadModelFromString(xml);
|
||||
MjModelPtr m = LoadModelFromString(xml);
|
||||
ASSERT_EQ(m->nuser_tendon, 3);
|
||||
EXPECT_THAT(GetRow(m->tendon_user, m->nuser_tendon, 0), ElementsAre(1, 2, 3));
|
||||
EXPECT_THAT(GetRow(m->tendon_user, m->nuser_tendon, 1), ElementsAre(2, 3, 0));
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserDataTest, AutoNUserActuator) {
|
||||
@@ -521,13 +500,12 @@ TEST_F(UserDataTest, AutoNUserActuator) {
|
||||
</actuator>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* m = LoadModelFromString(xml);
|
||||
MjModelPtr m = LoadModelFromString(xml);
|
||||
ASSERT_EQ(m->nuser_actuator, 3);
|
||||
EXPECT_THAT(GetRow(m->actuator_user, m->nuser_actuator, 0),
|
||||
ElementsAre(1, 2, 3));
|
||||
EXPECT_THAT(GetRow(m->actuator_user, m->nuser_actuator, 1),
|
||||
ElementsAre(2, 3, 0));
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(UserDataTest, AutoNUserSensor) {
|
||||
@@ -542,11 +520,10 @@ TEST_F(UserDataTest, AutoNUserSensor) {
|
||||
</sensor>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* m = LoadModelFromString(xml);
|
||||
MjModelPtr m = LoadModelFromString(xml);
|
||||
ASSERT_EQ(m->nuser_sensor, 3);
|
||||
EXPECT_THAT(GetRow(m->sensor_user, m->nuser_sensor, 0), ElementsAre(1, 2, 3));
|
||||
EXPECT_THAT(GetRow(m->sensor_user, m->nuser_sensor, 1), ElementsAre(2, 3, 0));
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
// ------------- test duplicate names ------------------------------------------
|
||||
@@ -584,10 +561,10 @@ TEST_F(FuseStaticTest, FuseStaticEquivalent) {
|
||||
std::string fuse = absl::StrFormat(xml_template, "true");
|
||||
std::string no_fuse = absl::StrFormat(xml_template, "false");
|
||||
|
||||
mjModel* m_fuse = LoadModelFromString(fuse.c_str());
|
||||
mjModel* m_no_fuse = LoadModelFromString(no_fuse.c_str());
|
||||
ASSERT_THAT(m_fuse, NotNull());
|
||||
ASSERT_THAT(m_no_fuse, NotNull());
|
||||
MjModelPtr m_fuse = LoadModelFromString(fuse.c_str());
|
||||
MjModelPtr m_no_fuse = LoadModelFromString(no_fuse.c_str());
|
||||
ASSERT_THAT(m_fuse.get(), NotNull());
|
||||
ASSERT_THAT(m_no_fuse.get(), NotNull());
|
||||
|
||||
EXPECT_EQ(m_fuse->nbody, 2) << "Expecting a world body and one other body";
|
||||
EXPECT_EQ(m_no_fuse->nbody, 3) << "Expecting a world body and two others";
|
||||
@@ -600,20 +577,16 @@ TEST_F(FuseStaticTest, FuseStaticEquivalent) {
|
||||
EXPECT_EQ(m_no_fuse->body_bvhnum[2], 3);
|
||||
EXPECT_EQ(m_fuse->body_bvhnum[1], 3);
|
||||
|
||||
mjData* d_fuse = mj_makeData(m_fuse);
|
||||
mjData* d_no_fuse = mj_makeData(m_no_fuse);
|
||||
MjDataPtr d_fuse = MakeData(m_fuse);
|
||||
MjDataPtr d_no_fuse = MakeData(m_no_fuse);
|
||||
|
||||
mj_step(m_fuse, d_fuse);
|
||||
mj_step(m_no_fuse, d_no_fuse);
|
||||
mj_step(m_fuse.get(), d_fuse.get());
|
||||
mj_step(m_no_fuse.get(), d_no_fuse.get());
|
||||
|
||||
EXPECT_NEAR(d_fuse->qvel[0], d_no_fuse->qvel[0], MjTol(2e-17, 1e-8))
|
||||
EXPECT_NEAR(d_fuse.get()->qvel[0], d_no_fuse.get()->qvel[0],
|
||||
MjTol(2e-17, 1e-8))
|
||||
<< "Velocity should be the same after 1 step";
|
||||
EXPECT_NE(d_fuse->qvel[0], 0);
|
||||
|
||||
mj_deleteData(d_fuse);
|
||||
mj_deleteData(d_no_fuse);
|
||||
mj_deleteModel(m_fuse);
|
||||
mj_deleteModel(m_no_fuse);
|
||||
EXPECT_NE(d_fuse.get()->qvel[0], 0);
|
||||
}
|
||||
|
||||
TEST_F(FuseStaticTest, FuseStaticActuatorReferencedBody) {
|
||||
@@ -642,10 +615,9 @@ TEST_F(FuseStaticTest, FuseStaticActuatorReferencedBody) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml_template, error.data(), error.size());
|
||||
ASSERT_THAT(m, NotNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml_template, error.data(), error.size());
|
||||
ASSERT_THAT(m.get(), NotNull()) << error.data();
|
||||
EXPECT_EQ(m->nbody, 3) << "Expecting a world body and two others";
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(FuseStaticTest, FuseStaticLightReferencedBody) {
|
||||
@@ -671,10 +643,9 @@ TEST_F(FuseStaticTest, FuseStaticLightReferencedBody) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml_template, error.data(), error.size());
|
||||
ASSERT_THAT(m, NotNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml_template, error.data(), error.size());
|
||||
ASSERT_THAT(m.get(), NotNull()) << error.data();
|
||||
EXPECT_EQ(m->nbody, 3) << "Expecting a world body and two others";
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(FuseStaticTest, FuseStaticForceSensorReferencedBody) {
|
||||
@@ -704,10 +675,9 @@ TEST_F(FuseStaticTest, FuseStaticForceSensorReferencedBody) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml_template, error.data(), error.size());
|
||||
ASSERT_THAT(m, NotNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml_template, error.data(), error.size());
|
||||
ASSERT_THAT(m.get(), NotNull()) << error.data();
|
||||
EXPECT_EQ(m->nbody, 3) << "Expecting a world body and two others";
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(FuseStaticTest, FuseStaticCameraInBody) {
|
||||
@@ -727,11 +697,10 @@ TEST_F(FuseStaticTest, FuseStaticCameraInBody) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m, NotNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m.get(), NotNull()) << error.data();
|
||||
EXPECT_EQ(m->nbody, 2) << "Static body should be fused";
|
||||
EXPECT_EQ(m->ncam, 1);
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
TEST_F(FuseStaticTest, FuseStaticLightInBody) {
|
||||
@@ -750,11 +719,10 @@ TEST_F(FuseStaticTest, FuseStaticLightInBody) {
|
||||
</mujoco>
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m, NotNull()) << error.data();
|
||||
MjModelPtr m = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(m.get(), NotNull()) << error.data();
|
||||
EXPECT_EQ(m->nbody, 2) << "Static body should be fused";
|
||||
EXPECT_EQ(m->nlight, 1);
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
// ------------- test discardvisual --------------------------------------------
|
||||
@@ -789,13 +757,12 @@ TEST_F(DiscardVisualTest, DiscardVisualKeepsInertia) {
|
||||
)";
|
||||
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model, NotNull()) << error.data();
|
||||
MjModelPtr model = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(model.get(), NotNull()) << error.data();
|
||||
EXPECT_THAT(model->nmesh, 1);
|
||||
EXPECT_THAT(model->body_inertia[3], model->body_inertia[6]);
|
||||
EXPECT_THAT(model->body_inertia[4], model->body_inertia[7]);
|
||||
EXPECT_THAT(model->body_inertia[5], model->body_inertia[8]);
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(DiscardVisualTest, DiscardVisualEquivalent) {
|
||||
@@ -818,8 +785,8 @@ TEST_F(DiscardVisualTest, DiscardVisualEquivalent) {
|
||||
EXPECT_THAT(model1->nq, model2->nq);
|
||||
EXPECT_THAT(model1->nmat, 0);
|
||||
EXPECT_THAT(model1->ntex, 0);
|
||||
EXPECT_THAT(model2->ngeom-model1->ngeom, 3);
|
||||
EXPECT_THAT(model2->nmesh-model1->nmesh, 2);
|
||||
EXPECT_THAT(model2->ngeom - model1->ngeom, 3);
|
||||
EXPECT_THAT(model2->nmesh - model1->nmesh, 2);
|
||||
EXPECT_THAT(model1->npair, model2->npair);
|
||||
EXPECT_THAT(model1->nsensor, model2->nsensor);
|
||||
EXPECT_THAT(model1->nwrap, model2->nwrap);
|
||||
@@ -851,8 +818,8 @@ TEST_F(DiscardVisualTest, DiscardVisualEquivalent) {
|
||||
EXPECT_STREQ(model1->names + adr1, model2->names + adr2);
|
||||
}
|
||||
|
||||
mjData *d1 = mj_makeData(model1);
|
||||
mjData *d2 = mj_makeData(model2);
|
||||
mjData* d1 = mj_makeData(model1);
|
||||
mjData* d2 = mj_makeData(model2);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
mj_step(model1, d1);
|
||||
mj_step(model2, d2);
|
||||
@@ -877,8 +844,7 @@ TEST_F(LengthRangeTest, LengthRangeThreading) {
|
||||
size_t error_sz = 1024;
|
||||
std::string field = "";
|
||||
|
||||
static const char* const kLengthrangePath =
|
||||
"user/testdata/lengthrange.xml";
|
||||
static const char* const kLengthrangePath = "user/testdata/lengthrange.xml";
|
||||
|
||||
const std::string xml_path1 = GetTestDataFilePath(kLengthrangePath);
|
||||
mjSpec* spec = mj_parseXML(xml_path1.c_str(), 0, error, error_sz);
|
||||
@@ -1022,20 +988,17 @@ TEST_F(MujocoTest, NestedMeshDir) {
|
||||
sizeof(cube));
|
||||
|
||||
std::array<char, 1024> error;
|
||||
mjModel* child_model = LoadModelFromString(child_xml, error.data(),
|
||||
error.size(), vfs.get());
|
||||
EXPECT_THAT(child_model, NotNull()) << error.data();
|
||||
mj_deleteModel(child_model);
|
||||
MjModelPtr child_model =
|
||||
LoadModelFromString(child_xml, error.data(), error.size(), vfs.get());
|
||||
EXPECT_THAT(child_model.get(), NotNull()) << error.data();
|
||||
|
||||
mjModel* parent_model = LoadModelFromString(parent_xml, error.data(),
|
||||
error.size(), vfs.get());
|
||||
EXPECT_THAT(parent_model, NotNull()) << error.data();
|
||||
mj_deleteModel(parent_model);
|
||||
MjModelPtr parent_model =
|
||||
LoadModelFromString(parent_xml, error.data(), error.size(), vfs.get());
|
||||
EXPECT_THAT(parent_model.get(), NotNull()) << error.data();
|
||||
|
||||
mjModel* grandparent_model = LoadModelFromString(
|
||||
MjModelPtr grandparent_model = LoadModelFromString(
|
||||
grandparent_xml, error.data(), error.size(), vfs.get());
|
||||
EXPECT_THAT(grandparent_model, NotNull()) << error.data();
|
||||
mj_deleteModel(grandparent_model);
|
||||
EXPECT_THAT(grandparent_model.get(), NotNull()) << error.data();
|
||||
|
||||
mj_deleteVFS(vfs.get());
|
||||
}
|
||||
@@ -1087,8 +1050,8 @@ TEST_F(DelayBufferTest, ActuatorDelayBufferSizes) {
|
||||
</actuator>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* m = LoadModelFromString(xml);
|
||||
ASSERT_THAT(m, NotNull());
|
||||
MjModelPtr m = LoadModelFromString(xml);
|
||||
ASSERT_THAT(m.get(), NotNull());
|
||||
ASSERT_EQ(m->nu, 3);
|
||||
|
||||
// nhistory = (2+2*3) + (2+2*10) = 8 + 22 = 30
|
||||
@@ -1101,8 +1064,6 @@ TEST_F(DelayBufferTest, ActuatorDelayBufferSizes) {
|
||||
EXPECT_EQ(m->actuator_historyadr[0], -1);
|
||||
EXPECT_EQ(m->actuator_historyadr[1], 0);
|
||||
EXPECT_EQ(m->actuator_historyadr[2], 8);
|
||||
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
+235
-302
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user