add mjs_detachDefault to delete a default class from mjSpec
PiperOrigin-RevId: 738452369 Change-Id: I5a53a6dc8f89e1e8136aeefc09d7d9b7b7204e1f
This commit is contained in:
committed by
Copybara-Service
parent
a1b9ffd124
commit
be64747166
@@ -3851,7 +3851,16 @@ Attach child frame to a parent site, return the attached frame if success or NUL
|
|||||||
|
|
||||||
.. mujoco-include:: mjs_detachBody
|
.. mujoco-include:: mjs_detachBody
|
||||||
|
|
||||||
Detach body from mjSpec, remove all references and delete the body, return 0 on success.
|
Delete body and descendants from mjSpec, remove all references, return 0 on success.
|
||||||
|
|
||||||
|
.. _mjs_detachDefault:
|
||||||
|
|
||||||
|
`mjs_detachDefault <#mjs_detachDefault>`__
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. mujoco-include:: mjs_detachDefault
|
||||||
|
|
||||||
|
Delete default class and descendants from mjSpec, remove all references, return 0 on success.
|
||||||
|
|
||||||
.. _AddTreeElements:
|
.. _AddTreeElements:
|
||||||
|
|
||||||
@@ -3936,7 +3945,8 @@ Add frame to body.
|
|||||||
|
|
||||||
.. mujoco-include:: mjs_delete
|
.. mujoco-include:: mjs_delete
|
||||||
|
|
||||||
Delete object corresponding to the given element, return 0 on success.
|
Delete object corresponding to the given element, return 0 on success. This function should only be used for element
|
||||||
|
types that cannot have children, i.e. excluding bodies and default classes.
|
||||||
|
|
||||||
.. _AddNonTreeElements:
|
.. _AddNonTreeElements:
|
||||||
|
|
||||||
|
|||||||
@@ -704,3 +704,8 @@ to the inputs. Below, :math:`\bar q` denotes the pre-modified quaternion:
|
|||||||
|
|
||||||
Note that derivatives depend only on :math:`h` and :math:`v` (in fact, on :math:`s = h v`).
|
Note that derivatives depend only on :math:`h` and :math:`v` (in fact, on :math:`s = h v`).
|
||||||
All outputs are optional.
|
All outputs are optional.
|
||||||
|
|
||||||
|
.. _mjs_delete:
|
||||||
|
|
||||||
|
Delete object corresponding to the given element, return 0 on success. This function should only be used for element
|
||||||
|
types that cannot have children, i.e. excluding bodies and default classes.
|
||||||
|
|||||||
@@ -603,7 +603,9 @@ typedef enum mjtObj_ { // type of MujoCo object
|
|||||||
mjNOBJECT, // number of object types
|
mjNOBJECT, // number of object types
|
||||||
|
|
||||||
// meta elements, do not appear in mjModel
|
// meta elements, do not appear in mjModel
|
||||||
mjOBJ_FRAME = 100 // frame
|
mjOBJ_FRAME = 100, // frame
|
||||||
|
mjOBJ_DEFAULT // default
|
||||||
|
|
||||||
} mjtObj;
|
} mjtObj;
|
||||||
typedef enum mjtConstraint_ { // type of constraint
|
typedef enum mjtConstraint_ { // type of constraint
|
||||||
mjCNSTR_EQUALITY = 0, // equality constraint
|
mjCNSTR_EQUALITY = 0, // equality constraint
|
||||||
@@ -3612,6 +3614,7 @@ mjsBody* mjs_attachToSite(mjsSite* parent, const mjsBody* child,
|
|||||||
mjsFrame* mjs_attachFrameToSite(mjsSite* parent, const mjsFrame* child,
|
mjsFrame* mjs_attachFrameToSite(mjsSite* parent, const mjsFrame* child,
|
||||||
const char* prefix, const char* suffix);
|
const char* prefix, const char* suffix);
|
||||||
int mjs_detachBody(mjSpec* s, mjsBody* b);
|
int mjs_detachBody(mjSpec* s, mjsBody* b);
|
||||||
|
int mjs_detachDefault(mjSpec* s, mjsDefault* d);
|
||||||
mjsBody* mjs_addBody(mjsBody* body, const mjsDefault* def);
|
mjsBody* mjs_addBody(mjsBody* body, const mjsDefault* def);
|
||||||
mjsSite* mjs_addSite(mjsBody* body, const mjsDefault* def);
|
mjsSite* mjs_addSite(mjsBody* body, const mjsDefault* def);
|
||||||
mjsJoint* mjs_addJoint(mjsBody* body, const mjsDefault* def);
|
mjsJoint* mjs_addJoint(mjsBody* body, const mjsDefault* def);
|
||||||
@@ -3652,7 +3655,7 @@ mjsBody* mjs_getParent(mjsElement* element);
|
|||||||
mjsFrame* mjs_getFrame(mjsElement* element);
|
mjsFrame* mjs_getFrame(mjsElement* element);
|
||||||
mjsFrame* mjs_findFrame(mjSpec* s, const char* name);
|
mjsFrame* mjs_findFrame(mjSpec* s, const char* name);
|
||||||
mjsDefault* mjs_getDefault(mjsElement* element);
|
mjsDefault* mjs_getDefault(mjsElement* element);
|
||||||
const mjsDefault* mjs_findDefault(mjSpec* s, const char* classname);
|
mjsDefault* mjs_findDefault(mjSpec* s, const char* classname);
|
||||||
mjsDefault* mjs_getSpecDefault(mjSpec* s);
|
mjsDefault* mjs_getSpecDefault(mjSpec* s);
|
||||||
int mjs_getId(mjsElement* element);
|
int mjs_getId(mjsElement* element);
|
||||||
mjsElement* mjs_firstChild(mjsBody* body, mjtObj type, int recurse);
|
mjsElement* mjs_firstChild(mjsBody* body, mjtObj type, int recurse);
|
||||||
|
|||||||
@@ -268,7 +268,9 @@ typedef enum mjtObj_ { // type of MujoCo object
|
|||||||
mjNOBJECT, // number of object types
|
mjNOBJECT, // number of object types
|
||||||
|
|
||||||
// meta elements, do not appear in mjModel
|
// meta elements, do not appear in mjModel
|
||||||
mjOBJ_FRAME = 100 // frame
|
mjOBJ_FRAME = 100, // frame
|
||||||
|
mjOBJ_DEFAULT // default
|
||||||
|
|
||||||
} mjtObj;
|
} mjtObj;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1430,9 +1430,11 @@ MJAPI mjsBody* mjs_attachToSite(mjsSite* parent, const mjsBody* child,
|
|||||||
MJAPI mjsFrame* mjs_attachFrameToSite(mjsSite* parent, const mjsFrame* child,
|
MJAPI mjsFrame* mjs_attachFrameToSite(mjsSite* parent, const mjsFrame* child,
|
||||||
const char* prefix, const char* suffix);
|
const char* prefix, const char* suffix);
|
||||||
|
|
||||||
// Detach body from mjSpec, remove all references and delete the body, return 0 on success.
|
// Delete body and descendants from mjSpec, remove all references, return 0 on success.
|
||||||
MJAPI int mjs_detachBody(mjSpec* s, mjsBody* b);
|
MJAPI int mjs_detachBody(mjSpec* s, mjsBody* b);
|
||||||
|
|
||||||
|
// Delete default class and descendants from mjSpec, remove all references, return 0 on success.
|
||||||
|
MJAPI int mjs_detachDefault(mjSpec* s, mjsDefault* d);
|
||||||
|
|
||||||
//---------------------------------- Tree elements -------------------------------------------------
|
//---------------------------------- Tree elements -------------------------------------------------
|
||||||
|
|
||||||
@@ -1566,7 +1568,7 @@ MJAPI mjsFrame* mjs_findFrame(mjSpec* s, const char* name);
|
|||||||
MJAPI mjsDefault* mjs_getDefault(mjsElement* element);
|
MJAPI mjsDefault* mjs_getDefault(mjsElement* element);
|
||||||
|
|
||||||
// Find default in model by class name.
|
// Find default in model by class name.
|
||||||
MJAPI const mjsDefault* mjs_findDefault(mjSpec* s, const char* classname);
|
MJAPI mjsDefault* mjs_findDefault(mjSpec* s, const char* classname);
|
||||||
|
|
||||||
// Get global default from model.
|
// Get global default from model.
|
||||||
MJAPI mjsDefault* mjs_getSpecDefault(mjSpec* s);
|
MJAPI mjsDefault* mjs_getSpecDefault(mjSpec* s);
|
||||||
|
|||||||
@@ -287,6 +287,7 @@ ENUMS: Mapping[str, EnumDecl] = dict([
|
|||||||
('mjOBJ_PLUGIN', 25),
|
('mjOBJ_PLUGIN', 25),
|
||||||
('mjNOBJECT', 26),
|
('mjNOBJECT', 26),
|
||||||
('mjOBJ_FRAME', 100),
|
('mjOBJ_FRAME', 100),
|
||||||
|
('mjOBJ_DEFAULT', 101),
|
||||||
]),
|
]),
|
||||||
)),
|
)),
|
||||||
('mjtConstraint',
|
('mjtConstraint',
|
||||||
|
|||||||
@@ -9154,7 +9154,27 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
doc='Detach body from mjSpec, remove all references and delete the body, return 0 on success.', # pylint: disable=line-too-long
|
doc='Delete body and descendants from mjSpec, remove all references, return 0 on success.', # pylint: disable=line-too-long
|
||||||
|
)),
|
||||||
|
('mjs_detachDefault',
|
||||||
|
FunctionDecl(
|
||||||
|
name='mjs_detachDefault',
|
||||||
|
return_type=ValueType(name='int'),
|
||||||
|
parameters=(
|
||||||
|
FunctionParameterDecl(
|
||||||
|
name='s',
|
||||||
|
type=PointerType(
|
||||||
|
inner_type=ValueType(name='mjSpec'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
FunctionParameterDecl(
|
||||||
|
name='d',
|
||||||
|
type=PointerType(
|
||||||
|
inner_type=ValueType(name='mjsDefault'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
doc='Delete default class and descendants from mjSpec, remove all references, return 0 on success.', # pylint: disable=line-too-long
|
||||||
)),
|
)),
|
||||||
('mjs_addBody',
|
('mjs_addBody',
|
||||||
FunctionDecl(
|
FunctionDecl(
|
||||||
@@ -9954,7 +9974,7 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
|
|||||||
FunctionDecl(
|
FunctionDecl(
|
||||||
name='mjs_findDefault',
|
name='mjs_findDefault',
|
||||||
return_type=PointerType(
|
return_type=PointerType(
|
||||||
inner_type=ValueType(name='mjsDefault', is_const=True),
|
inner_type=ValueType(name='mjsDefault'),
|
||||||
),
|
),
|
||||||
parameters=(
|
parameters=(
|
||||||
FunctionParameterDecl(
|
FunctionParameterDecl(
|
||||||
|
|||||||
@@ -448,7 +448,7 @@ PYBIND11_MODULE(_specs, m) {
|
|||||||
py::return_value_policy::reference_internal);
|
py::return_value_policy::reference_internal);
|
||||||
mjSpec.def(
|
mjSpec.def(
|
||||||
"find_default",
|
"find_default",
|
||||||
[](MjSpec& self, std::string& classname) -> const raw::MjsDefault* {
|
[](MjSpec& self, std::string& classname) -> raw::MjsDefault* {
|
||||||
return mjs_findDefault(self.ptr, classname.c_str());
|
return mjs_findDefault(self.ptr, classname.c_str());
|
||||||
},
|
},
|
||||||
py::return_value_policy::reference_internal);
|
py::return_value_policy::reference_internal);
|
||||||
@@ -499,6 +499,11 @@ PYBIND11_MODULE(_specs, m) {
|
|||||||
return mjs_addDefault(spec->ptr, classname.c_str(), parent);
|
return mjs_addDefault(spec->ptr, classname.c_str(), parent);
|
||||||
},
|
},
|
||||||
py::return_value_policy::reference_internal);
|
py::return_value_policy::reference_internal);
|
||||||
|
mjSpec.def("detach_default", [](MjSpec& self, raw::MjsDefault& def) {
|
||||||
|
if (mjs_detachDefault(self.ptr, &def) != 0) {
|
||||||
|
throw pybind11::value_error(mjs_getError(self.ptr));
|
||||||
|
}
|
||||||
|
});
|
||||||
mjSpec.def_property_readonly(
|
mjSpec.def_property_readonly(
|
||||||
"default",
|
"default",
|
||||||
[](MjSpec& self) -> raw::MjsDefault* {
|
[](MjSpec& self) -> raw::MjsDefault* {
|
||||||
|
|||||||
@@ -589,6 +589,12 @@ class SpecsTest(absltest.TestCase):
|
|||||||
spec.compile()
|
spec.compile()
|
||||||
self.assertEqual(spec.to_xml(), XML)
|
self.assertEqual(spec.to_xml(), XML)
|
||||||
|
|
||||||
|
# test delete default
|
||||||
|
def1 = spec.find_default('def1')
|
||||||
|
spec.detach_default(def1)
|
||||||
|
def1 = spec.find_default('def1')
|
||||||
|
self.assertIsNone(def1)
|
||||||
|
|
||||||
def test_element_list(self):
|
def test_element_list(self):
|
||||||
spec = mujoco.MjSpec()
|
spec = mujoco.MjSpec()
|
||||||
sensor1 = spec.add_sensor()
|
sensor1 = spec.add_sensor()
|
||||||
|
|||||||
@@ -2137,6 +2137,7 @@ static int sensorSize(mjtSensor sensor_type, int sensor_dim) {
|
|||||||
// -2: invalid objtype
|
// -2: invalid objtype
|
||||||
static int numObjects(const mjModel* m, mjtObj objtype) {
|
static int numObjects(const mjModel* m, mjtObj objtype) {
|
||||||
switch (objtype) {
|
switch (objtype) {
|
||||||
|
case mjOBJ_DEFAULT:
|
||||||
case mjOBJ_FRAME:
|
case mjOBJ_FRAME:
|
||||||
case mjOBJ_UNKNOWN:
|
case mjOBJ_UNKNOWN:
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
+26
-7
@@ -227,7 +227,7 @@ const char* mjs_getError(mjSpec* s) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Detach body from mjSpec, return 0 if success.
|
// detach body from mjSpec, return 0 on success
|
||||||
int mjs_detachBody(mjSpec* s, mjsBody* b) {
|
int mjs_detachBody(mjSpec* s, mjsBody* b) {
|
||||||
mjCModel* model = static_cast<mjCModel*>(s->element);
|
mjCModel* model = static_cast<mjCModel*>(s->element);
|
||||||
mjCBody* body = static_cast<mjCBody*>(b->element);
|
mjCBody* body = static_cast<mjCBody*>(b->element);
|
||||||
@@ -241,7 +241,22 @@ int mjs_detachBody(mjSpec* s, mjsBody* b) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// detach default from mjSpec, return 0 on success
|
||||||
|
int mjs_detachDefault(mjSpec* s, mjsDefault* def) {
|
||||||
|
mjCModel* modelC = static_cast<mjCModel*>(s->element);
|
||||||
|
if (!def) {
|
||||||
|
modelC->SetError(mjCError(0, "Cannot detach, default is null"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
mjCDef* defC = static_cast<mjCDef*>(def->element);
|
||||||
|
try {
|
||||||
|
*modelC -= *defC;
|
||||||
|
} catch (mjCError& e) {
|
||||||
|
modelC->SetError(e);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// check if model has warnings
|
// check if model has warnings
|
||||||
int mjs_isWarning(mjSpec* s) {
|
int mjs_isWarning(mjSpec* s) {
|
||||||
@@ -292,15 +307,19 @@ int mjs_setDeepCopy(mjSpec* s, int deepcopy) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// delete object, return 0 if success
|
// delete object, return 0 on success
|
||||||
int mjs_delete(mjsElement* element) {
|
int mjs_delete(mjsElement* element) {
|
||||||
mjCBase* object = static_cast<mjCBase*>(element);
|
mjCModel* model;
|
||||||
|
if (element->elemtype == mjOBJ_DEFAULT)
|
||||||
|
model = static_cast<mjCDef*>(element)->model;
|
||||||
|
else
|
||||||
|
model = static_cast<mjCBase*>(element)->model;
|
||||||
try {
|
try {
|
||||||
// it will call the appropriate destructor since ~mjCBase is virtual
|
// it will call the appropriate destructor since ~mjCBase is virtual
|
||||||
object->model->DeleteElement(element);
|
model->DeleteElement(element);
|
||||||
return 0;
|
return 0;
|
||||||
} catch (mjCError& e) {
|
} catch (mjCError& e) {
|
||||||
object->model->SetError(e);
|
model->SetError(e);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -625,7 +644,7 @@ mjsDefault* mjs_getDefault(mjsElement* element) {
|
|||||||
|
|
||||||
|
|
||||||
// Find default with given name in model.
|
// Find default with given name in model.
|
||||||
const mjsDefault* mjs_findDefault(mjSpec* s, const char* classname) {
|
mjsDefault* mjs_findDefault(mjSpec* s, const char* classname) {
|
||||||
mjCModel* modelC = static_cast<mjCModel*>(s->element);
|
mjCModel* modelC = static_cast<mjCModel*>(s->element);
|
||||||
mjCDef* cdef = modelC->FindDefault(classname);
|
mjCDef* cdef = modelC->FindDefault(classname);
|
||||||
if (!cdef) {
|
if (!cdef) {
|
||||||
|
|||||||
+3
-1
@@ -88,6 +88,8 @@ MJAPI mjsFrame* mjs_attachFrameToSite(mjsSite* parent, const mjsFrame* child,
|
|||||||
// Detach body from mjSpec, remove all references and delete the body, return 0 on success.
|
// Detach body from mjSpec, remove all references and delete the body, return 0 on success.
|
||||||
MJAPI int mjs_detachBody(mjSpec* s, mjsBody* b);
|
MJAPI int mjs_detachBody(mjSpec* s, mjsBody* b);
|
||||||
|
|
||||||
|
// Detach default from mjSpec, remove all references and delete the default, return 0 on success.
|
||||||
|
MJAPI int mjs_detachDefault(mjSpec* s, mjsDefault* d);
|
||||||
|
|
||||||
//---------------------------------- Add tree elements ---------------------------------------------
|
//---------------------------------- Add tree elements ---------------------------------------------
|
||||||
|
|
||||||
@@ -221,7 +223,7 @@ MJAPI mjsFrame* mjs_findFrame(mjSpec* s, const char* name);
|
|||||||
MJAPI mjsDefault* mjs_getDefault(mjsElement* element);
|
MJAPI mjsDefault* mjs_getDefault(mjsElement* element);
|
||||||
|
|
||||||
// Find default in model by class name.
|
// Find default in model by class name.
|
||||||
MJAPI const mjsDefault* mjs_findDefault(mjSpec* s, const char* classname);
|
MJAPI mjsDefault* mjs_findDefault(mjSpec* s, const char* classname);
|
||||||
|
|
||||||
// Get global default from model.
|
// Get global default from model.
|
||||||
MJAPI mjsDefault* mjs_getSpecDefault(mjSpec* s);
|
MJAPI mjsDefault* mjs_getSpecDefault(mjSpec* s);
|
||||||
|
|||||||
+60
-2
@@ -24,6 +24,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
#include <functional>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
@@ -144,7 +145,7 @@ mjCModel::mjCModel() {
|
|||||||
Clear();
|
Clear();
|
||||||
|
|
||||||
//------------------------ master default set
|
//------------------------ master default set
|
||||||
defaults_.push_back(new mjCDef);
|
defaults_.push_back(new mjCDef(this));
|
||||||
defaults_.back()->name = "main";
|
defaults_.back()->name = "main";
|
||||||
|
|
||||||
// point to model from spec
|
// point to model from spec
|
||||||
@@ -564,6 +565,7 @@ mjCModel& mjCModel::operator-=(const mjCBody& subtree) {
|
|||||||
mjCModel_& mjCModel::operator+=(mjCDef& subtree) {
|
mjCModel_& mjCModel::operator+=(mjCDef& subtree) {
|
||||||
defaults_.push_back(&subtree);
|
defaults_.push_back(&subtree);
|
||||||
def_map[subtree.name] = &subtree;
|
def_map[subtree.name] = &subtree;
|
||||||
|
subtree.model = this;
|
||||||
|
|
||||||
// set parent to the main default if this is not the only default in the model
|
// set parent to the main default if this is not the only default in the model
|
||||||
if (!subtree.parent && &subtree != defaults_[0]) {
|
if (!subtree.parent && &subtree != defaults_[0]) {
|
||||||
@@ -579,6 +581,58 @@ mjCModel_& mjCModel::operator+=(mjCDef& subtree) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// remove default class from array
|
||||||
|
mjCModel& mjCModel::operator-=(const mjCDef& subtree) {
|
||||||
|
|
||||||
|
// check we aren't trying to remove the 'main' default
|
||||||
|
if (subtree.id == 0) {
|
||||||
|
throw mjCError(0, "cannot remove the global default ('main')");
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove this default from parent's child list
|
||||||
|
mjCDef* parent = subtree.parent;
|
||||||
|
if (parent) {
|
||||||
|
for (int i = 0; i < parent->child.size(); ++i) {
|
||||||
|
if (parent->child[i] == &subtree) {
|
||||||
|
parent->child.erase(parent->child.begin() + i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// traverse tree to find all descendants starting from subtree.id
|
||||||
|
std::vector<int> default_ids_to_remove;
|
||||||
|
std::vector<int> stack;
|
||||||
|
stack.push_back(subtree.id);
|
||||||
|
while (!stack.empty()) {
|
||||||
|
int id = stack.back();
|
||||||
|
stack.pop_back();
|
||||||
|
default_ids_to_remove.push_back(id);
|
||||||
|
for (int i=0; i<defaults_[id]->child.size(); i++) {
|
||||||
|
stack.push_back(defaults_[id]->child[i]->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove from the tree
|
||||||
|
std::sort(default_ids_to_remove.begin(),
|
||||||
|
default_ids_to_remove.end(),
|
||||||
|
std::greater<int>());
|
||||||
|
|
||||||
|
for (int id : default_ids_to_remove) {
|
||||||
|
delete defaults_[id];
|
||||||
|
defaults_.erase(defaults_.begin() + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset default ids
|
||||||
|
for (int i = 0; i < defaults_.size(); ++i) {
|
||||||
|
defaults_[i]->id = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void deletefromlist(std::vector<T*>* list, mjsElement* element) {
|
void deletefromlist(std::vector<T*>* list, mjsElement* element) {
|
||||||
if (!list) {
|
if (!list) {
|
||||||
@@ -609,6 +663,10 @@ void mjCModel::DeleteElement(mjsElement* el) {
|
|||||||
throw mjCError(nullptr, "bodies cannot be deleted, use detach instead");
|
throw mjCError(nullptr, "bodies cannot be deleted, use detach instead");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case mjOBJ_DEFAULT:
|
||||||
|
throw mjCError(nullptr, "defaults cannot be deleted, use detach instead");
|
||||||
|
break;
|
||||||
|
|
||||||
case mjOBJ_GEOM:
|
case mjOBJ_GEOM:
|
||||||
{
|
{
|
||||||
mjCGeom* geom = static_cast<mjCGeom*>(el);
|
mjCGeom* geom = static_cast<mjCGeom*>(el);
|
||||||
@@ -1180,7 +1238,7 @@ mjCDef* mjCModel::AddDefault(string name, mjCDef* parent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create new object
|
// create new object
|
||||||
mjCDef* def = new mjCDef;
|
mjCDef* def = new mjCDef(parent->model);
|
||||||
defaults_.push_back(def);
|
defaults_.push_back(def);
|
||||||
def->id = thisid;
|
def->id = thisid;
|
||||||
|
|
||||||
|
|||||||
@@ -183,10 +183,11 @@ class mjCModel : public mjCModel_, private mjSpec {
|
|||||||
void CopyFromSpec(); // copy spec to private attributes
|
void CopyFromSpec(); // copy spec to private attributes
|
||||||
void PointToLocal();
|
void PointToLocal();
|
||||||
|
|
||||||
mjCModel& operator=(const mjCModel& other); // copy other into this, if they are not the same
|
mjCModel& operator=(const mjCModel& other); // copy other into this, if they are not the same
|
||||||
mjCModel& operator+=(const mjCModel& other); // add other into this, even if they are the same
|
mjCModel& operator+=(const mjCModel& other); // add other into this, even if they are the same
|
||||||
mjCModel& operator-=(const mjCBody& subtree); // remove subtree and all references from model
|
mjCModel& operator-=(const mjCBody& subtree); // remove subtree and all references from model
|
||||||
mjCModel_& operator+=(mjCDef& subtree); // add default tree to this model
|
mjCModel_& operator+=(mjCDef& subtree); // add default tree to this model
|
||||||
|
mjCModel& operator-=(const mjCDef& subtree); // remove default tree from this model
|
||||||
|
|
||||||
mjSpec spec;
|
mjSpec spec;
|
||||||
|
|
||||||
@@ -225,6 +226,9 @@ class mjCModel : public mjCModel_, private mjSpec {
|
|||||||
// delete object from the corresponding list
|
// delete object from the corresponding list
|
||||||
void DeleteElement(mjsElement* el);
|
void DeleteElement(mjsElement* el);
|
||||||
|
|
||||||
|
// delete default and all descendants
|
||||||
|
void RemoveDefault(mjCDef* def);
|
||||||
|
|
||||||
// detach subtree from model
|
// detach subtree from model
|
||||||
void Detach(mjCBody* subtree);
|
void Detach(mjCBody* subtree);
|
||||||
|
|
||||||
|
|||||||
@@ -536,12 +536,16 @@ int mjCBoundingVolumeHierarchy::MakeBVH(
|
|||||||
|
|
||||||
//------------------------- class mjCDef implementation --------------------------------------------
|
//------------------------- class mjCDef implementation --------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// constructor
|
// constructor
|
||||||
mjCDef::mjCDef() {
|
mjCDef::mjCDef() {
|
||||||
name.clear();
|
name.clear();
|
||||||
id = 0;
|
id = 0;
|
||||||
parent = nullptr;
|
parent = nullptr;
|
||||||
|
model = 0;
|
||||||
child.clear();
|
child.clear();
|
||||||
|
elemtype = mjOBJ_DEFAULT;
|
||||||
mjs_defaultJoint(&joint_.spec);
|
mjs_defaultJoint(&joint_.spec);
|
||||||
mjs_defaultGeom(&geom_.spec);
|
mjs_defaultGeom(&geom_.spec);
|
||||||
mjs_defaultSite(&site_.spec);
|
mjs_defaultSite(&site_.spec);
|
||||||
@@ -561,6 +565,13 @@ mjCDef::mjCDef() {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// constructor with model
|
||||||
|
mjCDef::mjCDef(mjCModel* _model) : mjCDef() {
|
||||||
|
model = _model;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// copy constructor
|
// copy constructor
|
||||||
mjCDef::mjCDef(const mjCDef& other) {
|
mjCDef::mjCDef(const mjCDef& other) {
|
||||||
*this = other;
|
*this = other;
|
||||||
|
|||||||
@@ -1866,6 +1866,7 @@ class mjCDef : public mjsElement {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
mjCDef();
|
mjCDef();
|
||||||
|
mjCDef(mjCModel*);
|
||||||
mjCDef(const mjCDef& other);
|
mjCDef(const mjCDef& other);
|
||||||
mjCDef& operator=(const mjCDef& other);
|
mjCDef& operator=(const mjCDef& other);
|
||||||
mjCDef& operator+=(const mjCDef& other);
|
mjCDef& operator+=(const mjCDef& other);
|
||||||
@@ -1898,6 +1899,7 @@ class mjCDef : public mjsElement {
|
|||||||
std::vector<mjCDef*> child; // child classes
|
std::vector<mjCDef*> child; // child classes
|
||||||
|
|
||||||
mjsDefault spec;
|
mjsDefault spec;
|
||||||
|
mjCModel* model; // pointer to model that owns object
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mjCJoint joint_;
|
mjCJoint joint_;
|
||||||
|
|||||||
@@ -2544,6 +2544,91 @@ TEST_F(MujocoTest, ApplyNameSpaceToDefaults) {
|
|||||||
mj_deleteVFS(vfs.get());
|
mj_deleteVFS(vfs.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(MujocoTest, DetachDefault) {
|
||||||
|
static constexpr char xml_c[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<default>
|
||||||
|
<default class="parent">
|
||||||
|
<default class="child1">
|
||||||
|
<mesh scale="0.001 0.001 0.001"/>
|
||||||
|
</default>
|
||||||
|
<default class="child2">
|
||||||
|
<mesh scale="0.001 0.001 0.001"/>
|
||||||
|
</default>
|
||||||
|
</default>
|
||||||
|
</default>
|
||||||
|
<asset>
|
||||||
|
<mesh file="cube.obj" class="child2"/>
|
||||||
|
</asset>
|
||||||
|
<worldbody>
|
||||||
|
<body name="body">
|
||||||
|
<geom type="mesh" mesh="cube"/>
|
||||||
|
</body>
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>)";
|
||||||
|
|
||||||
|
static constexpr char cube[] = R"(
|
||||||
|
v -0.500000 -0.500000 0.500000
|
||||||
|
v 0.500000 -0.500000 0.500000
|
||||||
|
v -0.500000 0.500000 0.500000
|
||||||
|
v 0.500000 0.500000 0.500000
|
||||||
|
v -0.500000 0.500000 -0.500000
|
||||||
|
v 0.500000 0.500000 -0.500000
|
||||||
|
v -0.500000 -0.500000 -0.500000
|
||||||
|
v 0.500000 -0.500000 -0.500000)";
|
||||||
|
|
||||||
|
auto vfs = std::make_unique<mjVFS>();
|
||||||
|
mj_defaultVFS(vfs.get());
|
||||||
|
mj_addBufferVFS(vfs.get(), "cube.obj", cube, sizeof(cube));
|
||||||
|
|
||||||
|
std::array<char, 1024> err;
|
||||||
|
mjSpec* spec = mj_parseXMLString(xml_c, vfs.get(), err.data(), err.size());
|
||||||
|
EXPECT_THAT(spec, NotNull()) << err.data();
|
||||||
|
|
||||||
|
// get default
|
||||||
|
mjsDefault* child = mjs_findDefault(spec, "child1");
|
||||||
|
EXPECT_THAT(child, NotNull());
|
||||||
|
|
||||||
|
// try using mjs_delete to remove default, should fail
|
||||||
|
EXPECT_EQ(mjs_delete(child->element), -1);
|
||||||
|
|
||||||
|
// detach default
|
||||||
|
EXPECT_EQ(mjs_detachDefault(spec, child), 0);
|
||||||
|
child = mjs_findDefault(spec, "child1");
|
||||||
|
EXPECT_THAT(child, IsNull());
|
||||||
|
|
||||||
|
// try and detach previously detached default, should fail
|
||||||
|
EXPECT_EQ(mjs_detachDefault(spec, child), -1);
|
||||||
|
child = mjs_findDefault(spec, "child1");
|
||||||
|
EXPECT_THAT(child, IsNull());
|
||||||
|
EXPECT_THAT(mjs_getError(spec),
|
||||||
|
HasSubstr("Cannot detach, default is null"));
|
||||||
|
|
||||||
|
// detach parent
|
||||||
|
mjsDefault* parent = mjs_findDefault(spec, "parent");
|
||||||
|
EXPECT_THAT(parent, NotNull());
|
||||||
|
mjs_detachDefault(spec, parent);
|
||||||
|
|
||||||
|
// both parent and remaining child should be removed
|
||||||
|
parent = mjs_findDefault(spec, "parent");
|
||||||
|
EXPECT_THAT(parent, IsNull());
|
||||||
|
child = mjs_findDefault(spec, "child2");
|
||||||
|
EXPECT_THAT(child, IsNull());
|
||||||
|
|
||||||
|
// error when trying to detach the 'main' default
|
||||||
|
mjsDefault* main = mjs_findDefault(spec, "main");
|
||||||
|
EXPECT_THAT(main, NotNull());
|
||||||
|
EXPECT_EQ(mjs_detachDefault(spec, main), -1);
|
||||||
|
EXPECT_THAT(mjs_getError(spec),
|
||||||
|
HasSubstr("cannot remove the global default ('main')"));
|
||||||
|
|
||||||
|
main = mjs_findDefault(spec, "main");
|
||||||
|
EXPECT_THAT(main, NotNull());
|
||||||
|
|
||||||
|
mj_deleteVFS(vfs.get());
|
||||||
|
mj_deleteSpec(spec);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(MujocoTest, ErrorWhenCompilingOrphanedSpec) {
|
TEST_F(MujocoTest, ErrorWhenCompilingOrphanedSpec) {
|
||||||
static constexpr char xml[] = R"(
|
static constexpr char xml[] = R"(
|
||||||
<mujoco>
|
<mujoco>
|
||||||
|
|||||||
@@ -319,6 +319,7 @@ public enum mjtObj : int{
|
|||||||
mjOBJ_PLUGIN = 25,
|
mjOBJ_PLUGIN = 25,
|
||||||
mjNOBJECT = 26,
|
mjNOBJECT = 26,
|
||||||
mjOBJ_FRAME = 100,
|
mjOBJ_FRAME = 100,
|
||||||
|
mjOBJ_DEFAULT = 101,
|
||||||
}
|
}
|
||||||
public enum mjtConstraint : int{
|
public enum mjtConstraint : int{
|
||||||
mjCNSTR_EQUALITY = 0,
|
mjCNSTR_EQUALITY = 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user