Skip to content

Commit 4e206c2

Browse files
quaglacopybara-github
authored andcommitted
Keep tree lists updated at all times.
This simplifies the compiler logic since an updated tree list was necessary at many stages (e.g. attach and keyframes resizing) and it will be anyway required when computing the mjSpec signature. PiperOrigin-RevId: 740356447 Change-Id: I7f2ec25b27b8d4ca4364801c9a401c40c6d84569
1 parent 12b40b9 commit 4e206c2

File tree

3 files changed

+56
-64
lines changed

3 files changed

+56
-64
lines changed

src/user/user_model.cc

+14-58
Original file line numberDiff line numberDiff line change
@@ -449,9 +449,8 @@ static bool IsPluginActive(
449449

450450
mjCModel& mjCModel::operator+=(const mjCModel& other) {
451451
// create global lists
452-
mjCBody *world = bodies_[0];
453452
ResetTreeLists();
454-
MakeLists(world);
453+
MakeTreeLists();
455454
ProcessLists(/*checkrepeat=*/false);
456455

457456
// copy all elements not in the tree
@@ -500,11 +499,6 @@ mjCModel& mjCModel::operator+=(const mjCModel& other) {
500499
nq = nv = na = nu = nmocap = 0;
501500
}
502501

503-
// restore to the original state
504-
if (!compiled) {
505-
ResetTreeLists();
506-
}
507-
508502
PointToLocal();
509503
return *this;
510504
}
@@ -609,13 +603,11 @@ mjCModel& mjCModel::operator-=(const mjCBody& subtree) {
609603

610604
// create global lists in the old model if not compiled
611605
if (!oldmodel.IsCompiled()) {
612-
oldmodel.MakeLists(oldmodel.bodies_[0]);
613606
oldmodel.ProcessLists(/*checkrepeat=*/false);
614607
}
615608

616609
// create global lists in this model if not compiled
617610
if (!IsCompiled()) {
618-
MakeLists(bodies_[0]);
619611
ProcessLists(/*checkrepeat=*/false);
620612
}
621613

@@ -629,7 +621,7 @@ mjCModel& mjCModel::operator-=(const mjCBody& subtree) {
629621

630622
// update global lists
631623
ResetTreeLists();
632-
MakeLists(world);
624+
MakeTreeLists();
633625
ProcessLists(/*checkrepeat=*/false);
634626

635627
// check if we have to remove anything else
@@ -641,11 +633,6 @@ mjCModel& mjCModel::operator-=(const mjCBody& subtree) {
641633
RemoveFromList(sensors_, oldmodel);
642634
RemovePlugins();
643635

644-
// restore to the original state
645-
if (!compiled) {
646-
ResetTreeLists();
647-
}
648-
649636
return *this;
650637
}
651638

@@ -742,18 +729,16 @@ void deletefromlist(std::vector<T*>* list, mjsElement* element) {
742729

743730
// discard all invalid elements from all lists
744731
void mjCModel::DeleteElement(mjsElement* el) {
745-
mjCBody *world = nullptr;
746-
if (compiled) {
747-
world = bodies_[0];
748-
ResetTreeLists();
749-
}
732+
ResetTreeLists();
750733

751734
switch (el->elemtype) {
752735
case mjOBJ_BODY:
736+
MakeTreeLists(); // rebuild lists that were reset at the beginning of the function
753737
throw mjCError(nullptr, "bodies cannot be deleted, use detach instead");
754738
break;
755739

756740
case mjOBJ_DEFAULT:
741+
MakeTreeLists(); // rebuild lists that were reset at the beginning of the function
757742
throw mjCError(nullptr, "defaults cannot be deleted, use detach instead");
758743
break;
759744

@@ -818,11 +803,9 @@ void mjCModel::DeleteElement(mjsElement* el) {
818803
break;
819804
}
820805

821-
if (compiled) {
822-
ResetTreeLists(); // in case of a nested delete
823-
MakeLists(world);
824-
ProcessLists(/*checkrepeat=*/false);
825-
}
806+
ResetTreeLists(); // in case of a nested delete
807+
MakeTreeLists();
808+
ProcessLists(/*checkrepeat=*/false);
826809
}
827810

828811

@@ -1020,15 +1003,6 @@ void mjCModel::Clear() {
10201003
nconmax = -1;
10211004
nmocap = 0;
10221005

1023-
// pointer lists created by Compile
1024-
bodies_.clear();
1025-
joints_.clear();
1026-
geoms_.clear();
1027-
sites_.clear();
1028-
cameras_.clear();
1029-
lights_.clear();
1030-
frames_.clear();
1031-
10321006
// internal variables
10331007
hasImplicitPluginElem = false;
10341008
compiled = false;
@@ -1486,7 +1460,11 @@ mjSpec* mjCModel::GetSourceSpec() const {
14861460
//------------------------------- COMPILER PHASES --------------------------------------------------
14871461

14881462
// make lists of objects in tree: bodies, geoms, joints, sites, cameras, lights
1489-
void mjCModel::MakeLists(mjCBody* body) {
1463+
void mjCModel::MakeTreeLists(mjCBody* body) {
1464+
if (body == nullptr) {
1465+
body = bodies_[0];
1466+
}
1467+
14901468
// add this body if not world
14911469
if (body != bodies_[0]) {
14921470
bodies_.push_back(body);
@@ -1501,7 +1479,7 @@ void mjCModel::MakeLists(mjCBody* body) {
15011479
for (mjCFrame *frame : body->frames) frames_.push_back(frame);
15021480

15031481
// recursive call to all child bodies
1504-
for (mjCBody* body : body->bodies) MakeLists(body);
1482+
for (mjCBody* body : body->bodies) MakeTreeLists(body);
15051483
}
15061484

15071485

@@ -3657,21 +3635,12 @@ template void mjCModel::RestoreState<mjtNum>(
36573635

36583636
// resolve keyframe references
36593637
void mjCModel::StoreKeyframes(mjCModel* dest) {
3660-
bool resetlists = false;
3661-
36623638
if (this != dest && !key_pending_.empty()) {
36633639
mju_warning(
36643640
"Child model has pending keyframes. They will not be namespaced correctly. "
36653641
"To prevent this, compile the child model before attaching it again.");
36663642
}
36673643

3668-
// create tree lists if they are empty, occurs if an uncompiled model is attached
3669-
if (bodies_.size() == 1 && geoms_.empty() && sites_.empty() && joints_.empty() &&
3670-
cameras_.empty() && lights_.empty() && frames_.empty()) {
3671-
MakeLists(bodies_[0]);
3672-
resetlists = true;
3673-
}
3674-
36753644
// do not change compilation quantities in case the user wants to recompile preserving the state
36763645
if (!compiled) {
36773646
SaveDofOffsets(/*computesize=*/true);
@@ -3719,10 +3688,6 @@ void mjCModel::StoreKeyframes(mjCModel* dest) {
37193688
key->spec_mpos_.data(), key->spec_mquat_.data());
37203689
}
37213690

3722-
if (resetlists) {
3723-
ResetTreeLists();
3724-
}
3725-
37263691
if (!compiled) {
37273692
nq = nv = na = nu = nmocap = 0;
37283693
}
@@ -4054,11 +4019,7 @@ static void warninghandler(const char* msg) {
40544019
// compiler
40554020
mjModel* mjCModel::Compile(const mjVFS* vfs, mjModel** m) {
40564021
if (compiled) {
4057-
// clear kinematic tree
4058-
mjCBody* world = bodies_[0];
4059-
ResetTreeLists();
40604022
Clear();
4061-
bodies_.push_back(world);
40624023
}
40634024

40644025
CopyFromSpec();
@@ -4105,9 +4066,7 @@ mjModel* mjCModel::Compile(const mjVFS* vfs, mjModel** m) {
41054066
// deallocate everything allocated in Compile
41064067
mj_deleteModel(model);
41074068
mj_deleteData(data);
4108-
mjCBody* world = bodies_[0];
41094069
Clear();
4110-
bodies_.push_back(world);
41114070

41124071
// save error info
41134072
errInfo = err;
@@ -4354,9 +4313,6 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) {
43544313
AddKey();
43554314
}
43564315

4357-
// make lists of objects created in kinematic tree
4358-
MakeLists(bodies_[0]);
4359-
43604316
// clear subtreedofs
43614317
for (int i=0; i < bodies_.size(); i++) {
43624318
bodies_[i]->subtreedofs = 0;

src/user/user_model.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -334,9 +334,11 @@ class mjCModel : public mjCModel_, private mjSpec {
334334
// list of active plugins
335335
std::vector<std::pair<const mjpPlugin*, int>> active_plugins_;
336336

337+
// make lists of bodies and children
338+
void MakeTreeLists(mjCBody* body = nullptr);
339+
337340
// compile phases
338341
void TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs);
339-
void MakeLists(mjCBody* body); // make lists of bodies, geoms, joints, sites
340342
void SetNuser(); // set nuser fields
341343
void IndexAssets(bool discard); // convert asset names into indices
342344
void CheckEmptyNames(); // check empty names

src/user/user_objects.cc

+39-5
Original file line numberDiff line numberDiff line change
@@ -1231,6 +1231,11 @@ mjCBody* mjCBody::AddBody(mjCDef* _def) {
12311231
obj->classname = _def ? _def->name : classname;
12321232

12331233
bodies.push_back(obj);
1234+
1235+
// recompute lists
1236+
model->ResetTreeLists();
1237+
model->MakeTreeLists();
1238+
12341239
obj->parent = this;
12351240
return obj;
12361241
}
@@ -1241,6 +1246,8 @@ mjCBody* mjCBody::AddBody(mjCDef* _def) {
12411246
mjCFrame* mjCBody::AddFrame(mjCFrame* _frame) {
12421247
mjCFrame* obj = new mjCFrame(model, _frame ? _frame : NULL);
12431248
frames.push_back(obj);
1249+
model->ResetTreeLists();
1250+
model->MakeTreeLists();
12441251
return obj;
12451252
}
12461253

@@ -1256,6 +1263,11 @@ mjCJoint* mjCBody::AddFreeJoint() {
12561263
obj->body = this;
12571264

12581265
joints.push_back(obj);
1266+
1267+
// recompute lists
1268+
model->ResetTreeLists();
1269+
model->MakeTreeLists();
1270+
12591271
return obj;
12601272
}
12611273

@@ -1270,6 +1282,11 @@ mjCJoint* mjCBody::AddJoint(mjCDef* _def) {
12701282
obj->body = this;
12711283

12721284
joints.push_back(obj);
1285+
1286+
// recompute lists
1287+
model->ResetTreeLists();
1288+
model->MakeTreeLists();
1289+
12731290
return obj;
12741291
}
12751292

@@ -1284,6 +1301,11 @@ mjCGeom* mjCBody::AddGeom(mjCDef* _def) {
12841301
obj->body = this;
12851302

12861303
geoms.push_back(obj);
1304+
1305+
// recompute lists
1306+
model->ResetTreeLists();
1307+
model->MakeTreeLists();
1308+
12871309
return obj;
12881310
}
12891311

@@ -1298,6 +1320,11 @@ mjCSite* mjCBody::AddSite(mjCDef* _def) {
12981320
obj->body = this;
12991321

13001322
sites.push_back(obj);
1323+
1324+
// recompute lists
1325+
model->ResetTreeLists();
1326+
model->MakeTreeLists();
1327+
13011328
return obj;
13021329
}
13031330

@@ -1312,6 +1339,11 @@ mjCCamera* mjCBody::AddCamera(mjCDef* _def) {
13121339
obj->body = this;
13131340

13141341
cameras.push_back(obj);
1342+
1343+
// recompute lists
1344+
model->ResetTreeLists();
1345+
model->MakeTreeLists();
1346+
13151347
return obj;
13161348
}
13171349

@@ -1326,6 +1358,11 @@ mjCLight* mjCBody::AddLight(mjCDef* _def) {
13261358
obj->body = this;
13271359

13281360
lights.push_back(obj);
1361+
1362+
// recompute lists
1363+
model->ResetTreeLists();
1364+
model->MakeTreeLists();
1365+
13291366
return obj;
13301367
}
13311368

@@ -1347,11 +1384,8 @@ mjCFrame* mjCBody::ToFrame() {
13471384
std::remove_if(parent->bodies.begin(), parent->bodies.end(),
13481385
[this](mjCBody* body) { return body == this; }),
13491386
parent->bodies.end());
1350-
if (model->IsCompiled()) {
1351-
mjCBody *world = model->bodies_[0];
1352-
model->ResetTreeLists();
1353-
model->MakeLists(world);
1354-
}
1387+
model->ResetTreeLists();
1388+
model->MakeTreeLists();
13551389
return newframe;
13561390
}
13571391

0 commit comments

Comments
 (0)