diff --git a/doc/XMLreference.rst b/doc/XMLreference.rst
index 7c6c8b56..fcd7b54d 100644
--- a/doc/XMLreference.rst
+++ b/doc/XMLreference.rst
@@ -2982,7 +2982,7 @@ coordinates results in compiler error. See :ref:`CComposite` in the modeling gui
.. _body-composite-type:
-:at:`type`: :at-val:`[particle, grid, cable, rope, loop, cloth, box, cylinder, ellipsoid], required`
+:at:`type`: :at-val:`[particle, cable], required`
This attribute determines the type of composite object. The remaining attributes and sub-elements are then
interpreted according to the type. Default settings are also adjusted depending on the type.
@@ -2993,13 +2993,6 @@ coordinates results in compiler error. See :ref:`CComposite` in the modeling gui
and replace the default sphere with a custom geom. Note that the particle composite type is deprecated and might be
removed in a future version. Instead of particle, it is recommended to use :ref:`replicate`.
- The **grid** type creates a 1D or 2D grid of bodies, each having a sphere geom, a sphere site, and 3 orthogonal
- sliding joints by default. The :el:`pin` sub-element can be used to specify that some bodies should not have joints,
- and instead should be pinned to the parent body. Unlike the particle type, here each two neighboring bodies are
- connected with a spatial tendon whose length is equality-constrained to its initial value (the sites are needed to
- define the tendons). The "main" tendons are parallel to the axes of the grid. In addition one can create diagonal
- "shear" tendons, using the :el:`tendon` sub-element. This type is suitable for simulating strings as well as cloth.
-
The **cable** type creates a 1D chain of bodies connected with ball joints, each having a geom with user-defined type
(cylinder, capsule or box). The geometry can either be defined with an array of 3D vertex coordinates :at:`vertex`
or with prescribed functions with the option :at:`curve`. Currently, only linear and trigonometric functions are
@@ -3007,34 +3000,6 @@ coordinates results in compiler error. See :ref:`CComposite` in the modeling gui
:at:`size`, resulting in :math:`f(s)=\{\text{size}[1]\cdot\cos(2\pi\cdot\text{size}[2]),\;
\text{size}[1]\cdot\sin(2\pi\cdot\text{size}[2]),\; \text{size}[0]\cdot s\}`.
- The **cloth** type is a different way to model cloth, beyond type="grid". Here the elements are connected with
- universal joints and form a kinematic spanning tree. The root of the tree is the parent body, and its coordinates in
- the grid are inferred from its name - similar to rope but here the naming format is "CB2_0". Neighboring bodies that
- are not connected with joints are then connected with equality-constrained spatial tendons. The resulting cloth is
- non-homogeneous, because the kinematic constraints cannot be violated while the tendon equality constraints are soft.
- One can make it more homogeneous by adding stretch and twist joints (similar to rope) and adjusting the strength of
- their equality constraints. Shear tendons can also be added. In addition to the different physics, cloth can do
- things that a 2D grid cannot do. This is because the elements of cloth have both position and orientation, while the
- elements of grid can only translate. The geoms used in cloth can be ellipsoids and capsules in addition to spheres.
- When elongated geoms are used, they are rotated and interleaved in a pattern that fills the holes, preventing objects
- from penetrating the cloth. Furthermore the inertia of the cloth elements can be modified with the flatinertia
- attribute, and can then be used with lift and drag forces to simulate ripple effects.
-
- The **box** type creates a 3D arrangement of bodies forming the outer shell of a (soft) box. The parent body is at
- the center of the box. Each element body has a geom (sphere, ellipsoid or capsule) and a single sliding joint
- pointing away from the center of the box. The sliding joints are equality-constrained to their initial value.
- Furthermore, to achieve smooth deformations of the sides of the box, each joint is equality-constrained to remain
- equal to its neighbor joints. To preserve the volume of the soft box approximately, a fixed tendon is used to
- constrain the sum of all joints to remain constant. When the user specifies elongated geoms (capsules or ellipsoids)
- their long axis is aligned with the sliding joint axis. This makes the shell thicker for collision detection
- purposes, preventing objects from penetrating the box. It is important to disable contacts between the elements of
- the box. This is done by setting the default geom contype to 0. The user can change it of course, but if the geoms
- comprising the soft box are allowed to contact each other the model will not work as intended.
-
- The **cylinder** and **ellipsoid** types are the same as box, except the elements are projected on the surface of an
- ellipsoid or a cylinder respectively. Thus the composite soft body shape is different, while everything else is the
- same as in the box type.
-
.. _body-composite-count:
:at:`count`: :at-val:`int(3), required`
diff --git a/doc/changelog.rst b/doc/changelog.rst
index fb5c7389..456651ed 100644
--- a/doc/changelog.rst
+++ b/doc/changelog.rst
@@ -48,6 +48,7 @@ General
Previously, if the volumetric inertia computation failed (for example due to a very flat mesh), the compiler
would silently fall back to surface inertia computation. Now, the compiler will throw an informative error.
+ - Removed the composite type ``grid``. Users should instead use :ref:`flexcomp`.
MJX
^^^
diff --git a/doc/modeling.rst b/doc/modeling.rst
index 4872dc7c..f61dad1f 100644
--- a/doc/modeling.rst
+++ b/doc/modeling.rst
@@ -1193,47 +1193,10 @@ a more complete treatment, see again the :ref:`deformable ` section
flex, see the folder `elasticity/ `__ for
several examples.
-**1D grid**.
+**Grid**.
-|image6| |image7|
-
-.. code-block:: xml
-
-
-
-
-
-
-
-
-
-The grid type can create 1D or 2D grids, depending on the :at:`count` attribute. Here we illustrate 1D grids. These
-are strings of spheres connected with tendons whose length is soft-equality-constrained. The softness can be adjusted.
-Similar to particles, the element bodies here have slider joints but no rotational joints. The plot on the right
-illustrates pinning. The :el:`pin` sub-element is used to specify the grid coordinates of the pinned bodies, and the
-model compiler does not generate joints for these bodies, thereby fixing them rigidly to the parent body (in this case
-the world). This makes the string in the right plot hang in space. The same mechanism can be used to model a whip for
-example; in that case the parent body would be moving, and the first element body would be pinned to the parent.
-
-**2D grid**.
-
-|image8| |image9|
-
-.. code-block:: xml
-
-
-
-
-
-
-
-
-A 2D grid can be used to simulate cloth. What it really simulates is a 2D grid of spheres connected with
-equality-constrained tendons (not shown). The model compiler can also generate skin, enabled with the :el:`skin`
-sub-element in the above XML. Some of the element bodies can also be pinned, similar to 1D grids but using two grid
-coordinates. The plot on the right shows a cloth pinned to the world body at the two corners, and draping over our
-capsule probe. The skin on the right is subdivided using bi-cubic interpolation, which increases visual quality in the
-absence of textures. When textures are present (left) the benefits of subdivision are less visible.
+The grid composite type has been removed. It is recommended to use 2D flex :ref:`deformable objects ` for
+simulating thin elastic structures.
**Cable**.
diff --git a/model/composite/grid2pin.xml b/model/composite/grid2pin.xml
deleted file mode 100644
index c9595d23..00000000
--- a/model/composite/grid2pin.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/model/hammock/hammock.xml b/model/hammock/hammock.xml
index 28e69ff5..b00abcfd 100644
--- a/model/hammock/hammock.xml
+++ b/model/hammock/hammock.xml
@@ -22,7 +22,7 @@
Simple humanoid on a hammock, implemented as a 2D grid composite, pinned at the corners.
-->
-
+
@@ -41,23 +41,22 @@
width="512" height="512" mark="edge" markrgb=".8 .8 .8"/>
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/model/hammock/humanoid_body.xml b/model/hammock/humanoid_body.xml
deleted file mode 100644
index 8de9b880..00000000
--- a/model/hammock/humanoid_body.xml
+++ /dev/null
@@ -1,157 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/user/user_composite.cc b/src/user/user_composite.cc
index b90245cd..8972eca2 100644
--- a/src/user/user_composite.cc
+++ b/src/user/user_composite.cc
@@ -59,9 +59,7 @@ mjCComposite::mjCComposite(void) {
count[0] = count[1] = count[2] = 1;
spacing = 0;
mjuu_setvec(offset, 0, 0, 0);
- pin.clear();
flatinertia = 0;
- mj_defaultSolRefImp(solrefsmooth, solimpsmooth);
// plugin variables
mjs_defaultPlugin(&plugin);
@@ -95,23 +93,6 @@ mjCComposite::mjCComposite(void) {
-// adjust constraint softness
-void mjCComposite::AdjustSoft(mjtNum* solref, mjtNum* solimp, int level) {
- switch (level) {
- case 0:
- solref[0] = 0.01;
- solimp[0] = solimp[1] = 0.99;
- break;
-
- case 1:
- solref[0] = 0.02;
- solimp[0] = solimp[1] = 0.9;
- break;
- }
-}
-
-
-
// create the array of default joint options, append new elements only for particles type
bool mjCComposite::AddDefaultJoint(char* error, int error_sz) {
for (int i=0; i1) {
- tmpdim++;
- }
- }
-
// set all default groups to 3
for (int i=0; igroup = 3;
@@ -152,10 +125,7 @@ void mjCComposite::SetDefault(void) {
// set default geom and tendon group to 0 if needed to be visible
if (!skin ||
type==mjCOMPTYPE_PARTICLE ||
- type==mjCOMPTYPE_ROPE ||
- type==mjCOMPTYPE_LOOP ||
- type==mjCOMPTYPE_CABLE ||
- (type==mjCOMPTYPE_GRID && tmpdim==1)) {
+ type==mjCOMPTYPE_CABLE) {
for (int i=0; igroup = 0;
def[i].spec.tendon->group = 0;
@@ -171,25 +141,7 @@ void mjCComposite::SetDefault(void) {
def[0].spec.geom->priority = 1;
break;
- case mjCOMPTYPE_GRID: // grid
-
- // hard main tendon fix
- AdjustSoft(def[mjCOMPKIND_TENDON].spec.equality->solref,
- def[mjCOMPKIND_TENDON].spec.equality->solimp, 0);
-
- break;
-
case mjCOMPTYPE_CABLE: // cable
- case mjCOMPTYPE_ROPE: // rope
- break;
-
- case mjCOMPTYPE_LOOP: // loop
-
- // hard smoothing
- AdjustSoft(solrefsmooth, solimpsmooth, 0);
- break;
-
- case mjCOMPTYPE_CLOTH: // cloth
break;
default:
@@ -213,11 +165,6 @@ bool mjCComposite::Make(mjSpec* spec, mjsBody* body, char* error, int error_sz)
return comperr(error, "Composite geom type must be sphere, capsule or ellipsoid", error_sz);
}
- // check pin coord number
- if (pin.size()%2) {
- return comperr(error, "Pin coordinate number of must be multiple of 2", error_sz);
- }
-
// check counts
for (int i=0; i<3; i++) {
if (count[i]<1) {
@@ -305,7 +252,10 @@ bool mjCComposite::Make(mjSpec* spec, mjsBody* body, char* error, int error_sz)
return MakeParticle(model, body, error, error_sz);
case mjCOMPTYPE_GRID:
- return MakeGrid(model, body, error, error_sz);
+ return comperr(error,
+ "The \"grid\" composite type is deprecated. Please use "
+ "\"flex\" instead.",
+ error_sz);
case mjCOMPTYPE_ROPE:
return comperr(error,
@@ -413,123 +363,6 @@ bool mjCComposite::MakeParticle(mjCModel* model, mjsBody* body, char* error, int
-// make grid connected with tendons
-bool mjCComposite::MakeGrid(mjCModel* model, mjsBody* body, char* error, int error_sz) {
- char txt[100], txt1[100], txt2[100];
-
- // check dimensionality
- if (dim>2) {
- return comperr(error, "Grid can only be 1D or 2D", error_sz);
- }
-
- // check shear dimensionality
- if (add[mjCOMPKIND_SHEAR] && dim!=2) {
- return comperr(error, "Shear requires 2D grid", error_sz);
- }
-
- // check skin dimensionality
- if (skin && dim!=2) {
- return comperr(error, "Skin requires 2D grid", error_sz);
- }
-
- // create bodies, joints, geoms, sites
- for (int ix=0; ixname, txt);
-
- // set body position
- b->pos[0] = offset[0] + spacing*(ix - 0.5*count[0]);
- b->pos[1] = offset[1] + spacing*(iy - 0.5*count[1]);
- b->pos[2] = offset[2];
-
- // add geom
- mjsGeom* g = mjs_addGeom(b, &def[0].spec);
- mjs_setDefault(g->element, mjs_getDefault(body->element));
- g->type = mjGEOM_SPHERE;
- mju::sprintf_arr(txt, "%sG%d_%d", prefix.c_str(), ix, iy);
- mjs_setString(g->name, txt);
-
- // add site
- mjsSite* s = mjs_addSite(b, &def[0].spec);
- mjs_setDefault(s->element, mjs_getDefault(body->element));
- s->type = mjGEOM_SPHERE;
- mju::sprintf_arr(txt, "%sS%d_%d", prefix.c_str(), ix, iy);
- mjs_setString(s->name, txt);
-
- // skip pinned elements
- bool skip = false;
- for (int ip=0; ipelement, mjs_getDefault(body->element));
- mju::sprintf_arr(txt, "%sJ%d_%d_%d", prefix.c_str(), i, ix, iy);
- mjs_setString(jnt[i]->name, txt);
- jnt[i]->type = mjJNT_SLIDE;
- mjuu_setvec(jnt[i]->pos, 0, 0, 0);
- mjuu_setvec(jnt[i]->axis, 0, 0, 0);
- jnt[i]->axis[i] = 1;
- }
- }
- }
-
- // create tendons and equality constraints
- for (int i=0; i<2; i++) {
- for (int ix=0; ixAddTendon(def + mjCOMPKIND_TENDON);
- ten->classname = model->Default()->name;
- mju::sprintf_arr(txt, "%sT%d_%d_%d", prefix.c_str(), i, ix, iy);
- ten->name = txt;
- ten->WrapSite(txt1);
- ten->WrapSite(txt2);
-
- // add equality constraint
- mjsEquality* eq = mjs_addEquality(&model->spec, &def[mjCOMPKIND_TENDON].spec);
- mjs_setDefault(eq->element, &model->Default()->spec);
- eq->type = mjEQ_TENDON;
- mjs_setString(eq->name1, ten->name.c_str());
- }
- }
- }
-
- // shear for 2D
- if (add[mjCOMPKIND_SHEAR]) {
- MakeShear(model);
- }
-
- // skin
- if (skin) {
- if (skinsubgrid>0) {
- MakeSkin2Subgrid(model, skininflate);
- } else {
- MakeSkin2(model, skininflate);
- }
- }
-
- return true;
-}
-
-
-
bool mjCComposite::MakeCable(mjCModel* model, mjsBody* body, char* error, int error_sz) {
// check dim
if (dim!=1) {
@@ -730,37 +563,6 @@ mjsBody* mjCComposite::AddCableBody(mjCModel* model, mjsBody* body, int ix,
-// add shear tendons to 2D
-void mjCComposite::MakeShear(mjCModel* model) {
- char txt[100], txt1[100], txt2[100];
-
- for (int ix=0; ixAddTendon(def + mjCOMPKIND_SHEAR);
- ten->classname = model->Default()->name;
- ten->WrapSite(txt1);
- ten->WrapSite(txt2);
-
- // name tendon
- mju::sprintf_arr(txt, "%sTS%d_%d", prefix.c_str(), ix, iy);
- ten->name = txt;
-
- // equality constraint
- mjsEquality* eq = mjs_addEquality(&model->spec, &def[mjCOMPKIND_SHEAR].spec);
- mjs_setDefault(eq->element, &model->Default()->spec);
- eq->type = mjEQ_TENDON;
- mjs_setString(eq->name1, txt);
- }
- }
-}
-
-
-
// copy local vectors to skin
void mjCComposite::CopyIntoSkin(mjsSkin* skin) {
mjs_setInt(skin->face, face.data(), face.size());
@@ -875,7 +677,7 @@ void mjCComposite::MakeSkin2(mjCModel* model, mjtNum inflate) {
}
// couple with bones
- if (type==mjCOMPTYPE_PARTICLE || type==mjCOMPTYPE_GRID) {
+ if (type==mjCOMPTYPE_PARTICLE) {
MakeClothBones(model, skin);
} else if (type==mjCOMPTYPE_CABLE) {
MakeCableBones(model, skin);
@@ -1434,7 +1236,7 @@ void mjCComposite::MakeSkin2Subgrid(mjCModel* model, mjtNum inflate) {
face.push_back(NN + iy+1 + (C0-1)*C1);
}
- if (type==mjCOMPTYPE_PARTICLE || type==mjCOMPTYPE_GRID) {
+ if (type==mjCOMPTYPE_PARTICLE) {
MakeClothBonesSubgrid(model, skin);
} else if (type==mjCOMPTYPE_CABLE) {
MakeCableBonesSubgrid(model, skin);
diff --git a/src/user/user_composite.h b/src/user/user_composite.h
index 9e42dba3..101daed9 100644
--- a/src/user/user_composite.h
+++ b/src/user/user_composite.h
@@ -64,14 +64,10 @@ class mjCComposite {
void SetDefault(void);
bool AddDefaultJoint(char* error = NULL, int error_sz = 0);
- void AdjustSoft(mjtNum* solref, mjtNum* solimp, int level);
bool Make(mjSpec* spec, mjsBody* body, char* error, int error_sz);
-
bool MakeParticle(mjCModel* model, mjsBody* body, char* error, int error_sz);
- bool MakeGrid(mjCModel* model, mjsBody* body, char* error, int error_sz);
bool MakeCable(mjCModel* model, mjsBody* body, char* error, int error_sz);
- void MakeShear(mjCModel* model);
void MakeSkin2(mjCModel* model, mjtNum inflate);
void MakeSkin2Subgrid(mjCModel* model, mjtNum inflate);
@@ -86,10 +82,7 @@ class mjCComposite {
int count[3]; // geom count in each dimension
double spacing; // spacing between elements
double offset[3]; // position offset for particle and grid
- std::vector pin; // pin elements of grid (do not create main joint)
double flatinertia; // flatten ineria of cloth elements; 0: disable
- mjtNum solrefsmooth[mjNREF]; // solref for smoothing equality
- mjtNum solimpsmooth[mjNIMP]; // solimp for smoothing equality
// currently used only for cable
std::string initial; // root boundary type
diff --git a/src/xml/xml_native_reader.cc b/src/xml/xml_native_reader.cc
index ec586a92..7e6178cf 100644
--- a/src/xml/xml_native_reader.cc
+++ b/src/xml/xml_native_reader.cc
@@ -2466,10 +2466,6 @@ void mjXReader::OneComposite(XMLElement* elem, mjsBody* body, const mjsDefault*
// set type-specific defaults
comp.SetDefault();
- // parse smooth solver parameters after type-specific defaults are set
- ReadAttr(elem, "solrefsmooth", mjNREF, comp.solrefsmooth, text, false, false);
- ReadAttr(elem, "solimpsmooth", mjNIMP, comp.solimpsmooth, text, false, false);
-
// geom
XMLElement* egeom = FirstChildElement(elem, "geom");
if (egeom) {
@@ -2601,21 +2597,6 @@ void mjXReader::OneComposite(XMLElement* elem, mjsBody* body, const mjsDefault*
eten = NextSiblingElement(eten, "tendon");
}
- // pin
- XMLElement* epin = FirstChildElement(elem, "pin");
- while (epin) {
- // read
- int coord[2] = {0, 0};
- ReadAttr(epin, "coord", 2, coord, text, true, false);
-
- // insert 2 coordinates (2nd may be unused)
- comp.pin.push_back(coord[0]);
- comp.pin.push_back(coord[1]);
-
- // advance
- epin = NextSiblingElement(epin, "pin");
- }
-
// make composite
char error[200];
bool res = comp.Make(spec, body, error, 200);
diff --git a/test/engine/testdata/hammock/hammock.xml b/test/engine/testdata/hammock/hammock.xml
index 28e69ff5..a1a58d9f 100644
--- a/test/engine/testdata/hammock/hammock.xml
+++ b/test/engine/testdata/hammock/hammock.xml
@@ -22,7 +22,7 @@
Simple humanoid on a hammock, implemented as a 2D grid composite, pinned at the corners.
-->
-
+
@@ -41,23 +41,22 @@
width="512" height="512" mark="edge" markrgb=".8 .8 .8"/>
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/test/engine/testdata/skingroup.xml b/test/engine/testdata/skingroup.xml
index 6a2da654..b05be81e 100644
--- a/test/engine/testdata/skingroup.xml
+++ b/test/engine/testdata/skingroup.xml
@@ -26,17 +26,59 @@