diff --git a/doc/includes/references.h b/doc/includes/references.h index 6c0c1d41..b7a32e40 100644 --- a/doc/includes/references.h +++ b/doc/includes/references.h @@ -1170,7 +1170,7 @@ struct mjModel_ { int* flex_shell; // shell fragment vertex ids (dim per frag) (nflexshelldata x 1) int* flex_evpair; // (element, vertex) collision pairs (nflexevpair x 2) mjtNum* flex_vert; // vertex positions in local body frames (nflexvert x 3) - mjtNum* flex_xvert0; // Cartesian vertex positions in qpos0 (nflexvert x 3) + mjtNum* flex_vert0; // vertex positions in qpos0 on [0, 1]^d (nflexvert x 3) mjtNum* flexedge_length0; // edge lengths in qpos0 (nflexedge x 1) mjtNum* flexedge_invweight0; // edge inv. weight in qpos0 (nflexedge x 1) mjtNum* flex_radius; // radius around primitive element (nflex x 1) diff --git a/include/mujoco/mjmodel.h b/include/mujoco/mjmodel.h index 7893a8b3..9bea5917 100644 --- a/include/mujoco/mjmodel.h +++ b/include/mujoco/mjmodel.h @@ -877,7 +877,7 @@ struct mjModel_ { int* flex_shell; // shell fragment vertex ids (dim per frag) (nflexshelldata x 1) int* flex_evpair; // (element, vertex) collision pairs (nflexevpair x 2) mjtNum* flex_vert; // vertex positions in local body frames (nflexvert x 3) - mjtNum* flex_xvert0; // Cartesian vertex positions in qpos0 (nflexvert x 3) + mjtNum* flex_vert0; // vertex positions in qpos0 on [0, 1]^d (nflexvert x 3) mjtNum* flexedge_length0; // edge lengths in qpos0 (nflexedge x 1) mjtNum* flexedge_invweight0; // edge inv. weight in qpos0 (nflexedge x 1) mjtNum* flex_radius; // radius around primitive element (nflex x 1) diff --git a/include/mujoco/mjxmacro.h b/include/mujoco/mjxmacro.h index 3ca67c16..a47a0a32 100644 --- a/include/mujoco/mjxmacro.h +++ b/include/mujoco/mjxmacro.h @@ -346,7 +346,7 @@ XMJV( int, flex_shell, nflexshelldata,1 ) \ X ( int, flex_evpair, nflexevpair, 2 ) \ X ( mjtNum, flex_vert, nflexvert, 3 ) \ - X ( mjtNum, flex_xvert0, nflexvert, 3 ) \ + X ( mjtNum, flex_vert0, nflexvert, 3 ) \ X ( mjtNum, flexedge_length0, nflexedge, 1 ) \ X ( mjtNum, flexedge_invweight0, nflexedge, 1 ) \ XMJV( mjtNum, flex_radius, nflex, 1 ) \ diff --git a/introspect/structs.py b/introspect/structs.py index 0776273e..c8993c31 100644 --- a/introspect/structs.py +++ b/introspect/structs.py @@ -2603,11 +2603,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([ array_extent=('nflexvert', 3), ), StructFieldDecl( - name='flex_xvert0', + name='flex_vert0', type=PointerType( inner_type=ValueType(name='mjtNum'), ), - doc='Cartesian vertex positions in qpos0', + doc='vertex positions in qpos0 on [0, 1]^d', array_extent=('nflexvert', 3), ), StructFieldDecl( diff --git a/src/engine/engine_setconst.c b/src/engine/engine_setconst.c index 64d35ff8..f451353b 100644 --- a/src/engine/engine_setconst.c +++ b/src/engine/engine_setconst.c @@ -118,8 +118,19 @@ static void set0(mjModel* m, mjData* d) { m->light_mode[i] = lightmode[i]; } + // compute bounding box coordinates + for (int i=0; i < m->nflex; i++) { + int bvhadr = m->flex_bvhadr[i]; + const mjtNum* bvh = d->bvh_aabb_dyn + 6*(bvhadr - m->nbvhstatic); + for (int j=0; j < m->nflexvert; j++) { + for (int k=0; k < 3; k++) { + mjtNum size = 2*(bvh[3+k] - m->flex_radius[i]); + m->flex_vert0[3*j+k] = (d->flexvert_xpos[3*j+k] - bvh[k]) / size + 0.5; + } + } + } + // copy fields - mju_copy(m->flex_xvert0, d->flexvert_xpos, 3*m->nflexvert); mju_copy(m->flexedge_length0, d->flexedge_length, m->nflexedge); mju_copy(m->tendon_length0, d->ten_length, m->ntendon); mju_copy(m->actuator_length0, d->actuator_length, m->nu); diff --git a/test/user/user_flex_test.cc b/test/user/user_flex_test.cc index 1e2c168d..2f6414d2 100644 --- a/test/user/user_flex_test.cc +++ b/test/user/user_flex_test.cc @@ -242,6 +242,45 @@ TEST_F(UserFlexTest, RigidFlex) { mj_deleteModel(m); mj_deleteData(d); } +TEST_F(UserFlexTest, BoundingBoxCoordinates) { + static constexpr char xml[] = R"( + + + + + + )"; + std::array 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); + + 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); + + // 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); +} TEST_F(UserFlexTest, LoadMSHBinary_41_Success) { const std::string xml_path = @@ -280,14 +319,16 @@ TEST_F(UserFlexTest, LoadMSHSurfaceBinary_41_Success) { mjModel* m = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size()); ASSERT_THAT(m, NotNull()) << error.data(); mjData* d = mj_makeData(m); + mj_kinematics(m, d); + mj_flex(m, d); EXPECT_EQ(m->nflexvert, 14); EXPECT_EQ(m->nflexelem, 24); EXPECT_EQ(m->flex_dim[0], 2); // first node x y z - EXPECT_EQ(m->flex_xvert0[0], -0.5 ); - EXPECT_EQ(m->flex_xvert0[1], -0.5 ); - EXPECT_EQ(m->flex_xvert0[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 ); @@ -306,14 +347,16 @@ TEST_F(UserFlexTest, LoadMSHSurfaceBinary_22_Success) { mjModel* m = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size()); ASSERT_THAT(m, NotNull()) << error.data(); mjData* d = mj_makeData(m); + mj_kinematics(m, d); + mj_flex(m, d); EXPECT_EQ(m->nflexvert, 14); EXPECT_EQ(m->nflexelem, 24); EXPECT_EQ(m->flex_dim[0], 2); // first node x y z - EXPECT_EQ(m->flex_xvert0[0], -0.5 ); - EXPECT_EQ(m->flex_xvert0[1], -0.5 ); - EXPECT_EQ(m->flex_xvert0[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 ); @@ -377,14 +420,16 @@ TEST_F(UserFlexTest, LoadMSHSurfaceASCII_41_Success) { mjModel* m = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size()); ASSERT_THAT(m, NotNull()) << error.data(); mjData* d = mj_makeData(m); + mj_kinematics(m, d); + mj_flex(m, d); EXPECT_EQ(m->nflexvert, 14); EXPECT_EQ(m->nflexelem, 24); EXPECT_EQ(m->flex_dim[0], 2); // first node x y z - EXPECT_EQ(m->flex_xvert0[0], -0.5 ); - EXPECT_EQ(m->flex_xvert0[1], -0.5 ); - EXPECT_EQ(m->flex_xvert0[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 ); @@ -403,14 +448,16 @@ TEST_F(UserFlexTest, LoadMSHSurfaceASCII_22_Success) { mjModel* m = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size()); ASSERT_THAT(m, NotNull()) << error.data(); mjData* d = mj_makeData(m); + mj_kinematics(m, d); + mj_flex(m, d); EXPECT_EQ(m->nflexvert, 14); EXPECT_EQ(m->nflexelem, 24); EXPECT_EQ(m->flex_dim[0], 2); // first node x y z - EXPECT_EQ(m->flex_xvert0[0], -0.5 ); - EXPECT_EQ(m->flex_xvert0[1], -0.5 ); - EXPECT_EQ(m->flex_xvert0[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 ); diff --git a/unity/Runtime/Bindings/MjBindings.cs b/unity/Runtime/Bindings/MjBindings.cs index e963ab1c..262be737 100644 --- a/unity/Runtime/Bindings/MjBindings.cs +++ b/unity/Runtime/Bindings/MjBindings.cs @@ -5428,7 +5428,7 @@ public unsafe struct mjModel_ { public int* flex_shell; public int* flex_evpair; public double* flex_vert; - public double* flex_xvert0; + public double* flex_vert0; public double* flexedge_length0; public double* flexedge_invweight0; public double* flex_radius;