16
16
17
17
#include <float.h>
18
18
#include <stddef.h>
19
+ #include <stdint.h>
19
20
#include <stdlib.h>
20
21
21
22
#include <mujoco/mjtnum.h>
22
23
#include <mujoco/mjmodel.h>
23
24
#include "engine/engine_collision_convex.h"
24
- #include "engine/engine_io.h"
25
25
#include "engine/engine_util_blas.h"
26
26
#include "engine/engine_util_errmem.h"
27
27
@@ -64,6 +64,12 @@ typedef struct {
64
64
int maxfaces ; // max number of faces that can be stored in polytope
65
65
Face * * map ; // linear map storing faces
66
66
int nmap ; // number of faces in map
67
+ struct Horizon { // polytope boundary edges that can be seen from w
68
+ int * indices ; // indices of faces on horizon
69
+ int * edges ; // corresponding edge of each face on the horizon
70
+ int nedges ; // number of edges in horizon
71
+ mjtNum * w ; // point where horizon is created
72
+ } horizon ;
67
73
} Polytope ;
68
74
69
75
// compute the support point for EPA
@@ -1223,21 +1229,10 @@ static inline mjtNum attachFace(Polytope* pt, int v1, int v2, int v3,
1223
1229
1224
1230
1225
1231
1226
- // horizon: polytope boundary edges that can be seen from w
1227
- typedef struct {
1228
- Polytope * pt ; // polytope for which the horizon is defined
1229
- int * indices ; // indices of faces on horizon
1230
- int * edges ; // corresponding edge of each face on the horizon
1231
- int nedges ; // number of edges in horizon
1232
- mjtNum * w ; // point where horizon is created
1233
- } Horizon ;
1234
-
1235
-
1236
-
1237
1232
// add an edge to the horizon
1238
- static inline void addEdge (Horizon * h , int index , int edge ) {
1239
- h -> edges [h -> nedges ] = edge ;
1240
- h -> indices [h -> nedges ++ ] = index ;
1233
+ static inline void addEdge (Polytope * pt , int index , int edge ) {
1234
+ pt -> horizon . edges [pt -> horizon . nedges ] = edge ;
1235
+ pt -> horizon . indices [pt -> horizon . nedges ++ ] = index ;
1241
1236
}
1242
1237
1243
1238
@@ -1252,21 +1247,21 @@ static inline int getEdge(Face* face, int vertex) {
1252
1247
1253
1248
1254
1249
// recursive call to build horizon; return 1 if face is visible from w otherwise 0
1255
- static int horizonRec (Horizon * h , Face * face , int e ) {
1250
+ static int horizonRec (Polytope * pt , Face * face , int e ) {
1256
1251
mjtNum dist2 = face -> dist * face -> dist ;
1257
1252
1258
1253
// v is visible from w so it is deleted and adjacent faces are checked
1259
- if (dot3 (face -> v , h -> w ) >= dist2 ) {
1260
- deleteFace (h -> pt , face );
1254
+ if (dot3 (face -> v , pt -> horizon . w ) >= dist2 ) {
1255
+ deleteFace (pt , face );
1261
1256
1262
1257
// recursively search the adjacent faces on the next two edges
1263
1258
for (int k = 1 ; k < 3 ; k ++ ) {
1264
1259
int i = (e + k ) % 3 ;
1265
- Face * adjFace = & h -> pt -> faces [face -> adj [i ]];
1260
+ Face * adjFace = & pt -> faces [face -> adj [i ]];
1266
1261
if (adjFace -> index > -2 ) {
1267
1262
int adjEdge = getEdge (adjFace , face -> verts [(i + 1 ) % 3 ]);
1268
- if (!horizonRec (h , adjFace , adjEdge )) {
1269
- addEdge (h , face -> adj [i ], adjEdge );
1263
+ if (!horizonRec (pt , adjFace , adjEdge )) {
1264
+ addEdge (pt , face -> adj [i ], adjEdge );
1270
1265
}
1271
1266
}
1272
1267
}
@@ -1278,28 +1273,28 @@ static int horizonRec(Horizon* h, Face* face, int e) {
1278
1273
1279
1274
1280
1275
// create horizon given the face as starting point
1281
- static void horizon (Horizon * h , Face * face ) {
1282
- deleteFace (h -> pt , face );
1276
+ static void horizon (Polytope * pt , Face * face ) {
1277
+ deleteFace (pt , face );
1283
1278
1284
1279
// first edge
1285
- Face * adjFace = & h -> pt -> faces [face -> adj [0 ]];
1280
+ Face * adjFace = & pt -> faces [face -> adj [0 ]];
1286
1281
int adjEdge = getEdge (adjFace , face -> verts [1 ]);
1287
- if (!horizonRec (h , adjFace , adjEdge )) {
1288
- addEdge (h , face -> adj [0 ], adjEdge );
1282
+ if (!horizonRec (pt , adjFace , adjEdge )) {
1283
+ addEdge (pt , face -> adj [0 ], adjEdge );
1289
1284
}
1290
1285
1291
1286
// second edge
1292
- adjFace = & h -> pt -> faces [face -> adj [1 ]];
1287
+ adjFace = & pt -> faces [face -> adj [1 ]];
1293
1288
adjEdge = getEdge (adjFace , face -> verts [2 ]);
1294
- if (adjFace -> index > -2 && !horizonRec (h , adjFace , adjEdge )) {
1295
- addEdge (h , face -> adj [1 ], adjEdge );
1289
+ if (adjFace -> index > -2 && !horizonRec (pt , adjFace , adjEdge )) {
1290
+ addEdge (pt , face -> adj [1 ], adjEdge );
1296
1291
}
1297
1292
1298
1293
// third edge
1299
- adjFace = & h -> pt -> faces [face -> adj [2 ]];
1294
+ adjFace = & pt -> faces [face -> adj [2 ]];
1300
1295
adjEdge = getEdge (adjFace , face -> verts [0 ]);
1301
- if (adjFace -> index > -2 && !horizonRec (h , adjFace , adjEdge )) {
1302
- addEdge (h , face -> adj [2 ], adjEdge );
1296
+ if (adjFace -> index > -2 && !horizonRec (pt , adjFace , adjEdge )) {
1297
+ addEdge (pt , face -> adj [2 ], adjEdge );
1303
1298
}
1304
1299
}
1305
1300
@@ -1338,17 +1333,8 @@ static void epaWitness(const Polytope* pt, const Face* face, mjtNum x1[3], mjtNu
1338
1333
static Face * epa (mjCCDStatus * status , Polytope * pt , mjCCDObj * obj1 , mjCCDObj * obj2 ) {
1339
1334
mjtNum tolerance = status -> tolerance , lower , upper = FLT_MAX ;
1340
1335
int k , kmax = status -> max_iterations ;
1341
- mjData * d = (mjData * ) obj1 -> data ;
1342
1336
Face * face = NULL , * pface = NULL ; // face closest to origin
1343
1337
1344
- // initialize horizon
1345
- Horizon h ;
1346
- mj_markStack (d );
1347
- h .indices = mjSTACKALLOC (d , 6 + status -> max_iterations , int );
1348
- h .edges = mjSTACKALLOC (d , 6 + status -> max_iterations , int );
1349
- h .nedges = 0 ;
1350
- h .pt = pt ;
1351
-
1352
1338
for (k = 0 ; k < kmax ; k ++ ) {
1353
1339
pface = face ;
1354
1340
@@ -1382,17 +1368,17 @@ static Face* epa(mjCCDStatus* status, Polytope* pt, mjCCDObj* obj1, mjCCDObj* ob
1382
1368
break ;
1383
1369
}
1384
1370
1385
- h .w = w ;
1386
- horizon (& h , face );
1371
+ pt -> horizon .w = w ;
1372
+ horizon (pt , face );
1387
1373
1388
1374
// unrecoverable numerical issue; at least one face was deleted so nedges is 3 or more
1389
- if (h .nedges < 3 ) {
1375
+ if (pt -> horizon .nedges < 3 ) {
1390
1376
face = NULL ;
1391
1377
break ;
1392
1378
}
1393
1379
1394
1380
// insert w as new vertex and attach faces along the horizon
1395
- int nfaces = pt -> nfaces , nedges = h .nedges ;
1381
+ int nfaces = pt -> nfaces , nedges = pt -> horizon .nedges ;
1396
1382
1397
1383
// check if there's enough memory to store new faces
1398
1384
if (nedges > maxFaces (pt )) {
@@ -1401,7 +1387,7 @@ static Face* epa(mjCCDStatus* status, Polytope* pt, mjCCDObj* obj1, mjCCDObj* ob
1401
1387
}
1402
1388
1403
1389
// attach first face
1404
- int horIndex = h .indices [0 ], horEdge = h .edges [0 ];
1390
+ int horIndex = pt -> horizon .indices [0 ], horEdge = pt -> horizon .edges [0 ];
1405
1391
Face * horFace = & pt -> faces [horIndex ];
1406
1392
int v1 = horFace -> verts [horEdge ],
1407
1393
v2 = horFace -> verts [(horEdge + 1 ) % 3 ];
@@ -1426,7 +1412,7 @@ static Face* epa(mjCCDStatus* status, Polytope* pt, mjCCDObj* obj1, mjCCDObj* ob
1426
1412
int cur = nfaces + i ; // index of attached face
1427
1413
int next = nfaces + (i + 1 ) % nedges ; // index of next face
1428
1414
1429
- horIndex = h .indices [i ], horEdge = h .edges [i ];
1415
+ horIndex = pt -> horizon .indices [i ], horEdge = pt -> horizon .edges [i ];
1430
1416
horFace = & pt -> faces [horIndex ];
1431
1417
v1 = horFace -> verts [horEdge ];
1432
1418
v2 = horFace -> verts [(horEdge + 1 ) % 3 ];
@@ -1446,15 +1432,14 @@ static Face* epa(mjCCDStatus* status, Polytope* pt, mjCCDObj* obj1, mjCCDObj* ob
1446
1432
pt -> map [idx ]-> index = idx ;
1447
1433
}
1448
1434
}
1449
- h .nedges = 0 ; // clear horizon
1435
+ pt -> horizon .nedges = 0 ; // clear horizon
1450
1436
1451
1437
// no face candidates left
1452
1438
if (!pt -> nmap || !face ) {
1453
1439
break ;
1454
1440
}
1455
1441
}
1456
1442
1457
- mj_freeStack (d );
1458
1443
status -> epa_iterations = k ;
1459
1444
if (face ) {
1460
1445
epaWitness (pt , face , status -> x1 , status -> x2 );
@@ -2222,6 +2207,14 @@ static inline void inflate(mjCCDStatus* status, mjtNum margin1, mjtNum margin2)
2222
2207
2223
2208
// general convex collision detection
2224
2209
mjtNum mjc_ccd (const mjCCDConfig * config , mjCCDStatus * status , mjCCDObj * obj1 , mjCCDObj * obj2 ) {
2210
+ // pre-allocate static memory for low iterations
2211
+ void * buffer = NULL ;
2212
+ static _Thread_local Vertex vert_data [5 + mjMAX_EPA_ITERATIONS ];
2213
+ static _Thread_local Face face_data [6 * mjMAX_EPA_ITERATIONS ];
2214
+ static _Thread_local Face * map_data [6 * mjMAX_EPA_ITERATIONS ];
2215
+ static _Thread_local int index_data [6 + mjMAX_EPA_ITERATIONS ];
2216
+ static _Thread_local int edge_data [6 + mjMAX_EPA_ITERATIONS ];
2217
+
2225
2218
// setup
2226
2219
obj1 -> center (status -> x1 , obj1 );
2227
2220
obj2 -> center (status -> x2 , obj2 );
@@ -2305,29 +2298,40 @@ mjtNum mjc_ccd(const mjCCDConfig* config, mjCCDStatus* status, mjCCDObj* obj1, m
2305
2298
2306
2299
if (status -> dist <= config -> tolerance && status -> nsimplex > 1 ) {
2307
2300
status -> dist = 0 ; // assume touching
2308
- int N = status -> max_iterations ;
2309
- mjData * d = (mjData * ) obj1 -> data ;
2310
- mj_markStack ((mjData * ) obj1 -> data );
2311
-
2312
2301
Polytope pt ;
2313
- pt .nfaces = pt .nmap = pt .nverts = 0 ;
2314
-
2315
- // allocate memory for vertices
2316
- pt .verts = mjSTACKALLOC (d , 5 + N , Vertex );
2317
-
2318
- // allocate memory for faces
2319
- pt .maxfaces = (6 * N > 1000 ) ? 6 * N : 1000 ; // use 1000 faces as lower bound
2320
- size_t size1 = sizeof (Face ) * pt .maxfaces ;
2321
- size_t size2 = sizeof (Face * ) * pt .maxfaces ;
2302
+ pt .nfaces = pt .nmap = pt .nverts = pt .horizon .nedges = 0 ;
2303
+
2304
+ // allocate memory via static thread-local storage
2305
+ int N = config -> max_iterations ;
2306
+ if (N <= mjMAX_EPA_ITERATIONS ) {
2307
+ pt .maxfaces = 6 * mjMAX_EPA_ITERATIONS ;
2308
+ pt .verts = vert_data ;
2309
+ pt .faces = face_data ;
2310
+ pt .map = map_data ;
2311
+ pt .horizon .indices = index_data ;
2312
+ pt .horizon .edges = edge_data ;
2313
+ }
2322
2314
2323
- // since a generous upper bound is used, we need to rescale stack use if not enough
2324
- // memory is available
2325
- size_t max_size = mj_stackBytesAvailable (d ) - 12 * (N * sizeof (int ));
2326
- if (size1 + size2 > max_size ) {
2327
- pt .maxfaces = max_size / (sizeof (Face ) + sizeof (Face * ));
2315
+ // static storage insufficient, allocate with callback
2316
+ else {
2317
+ size_t nbytes = (sizeof (Face ) * 6 * N ) // faces in polytope
2318
+ + (sizeof (Face * ) * 6 * N ) // map in polytope
2319
+ + (sizeof (Vertex ) * (5 + N )) // vertices in polytope
2320
+ + 2 * (sizeof (int ) * (6 + N )); // horizon data
2321
+
2322
+ pt .maxfaces = 6 * N ;
2323
+ buffer = config -> alloc (config -> context , nbytes );
2324
+ uint8_t * bbuffer = (uint8_t * )buffer ;
2325
+ pt .verts = (Vertex * )bbuffer ;
2326
+ bbuffer += sizeof (Vertex ) * (5 + N );
2327
+ pt .faces = (Face * )bbuffer ;
2328
+ bbuffer += sizeof (Face ) * (6 * N );
2329
+ pt .map = (Face * * )bbuffer ;
2330
+ bbuffer += sizeof (Face * ) * (6 * N );
2331
+ pt .horizon .indices = (int * )bbuffer ;
2332
+ bbuffer += sizeof (int ) * (6 + N );
2333
+ pt .horizon .edges = (int * )bbuffer ;
2328
2334
}
2329
- pt .faces = mjSTACKALLOC (d , pt .maxfaces , Face );
2330
- pt .map = mjSTACKALLOC (d , pt .maxfaces , Face * );
2331
2335
2332
2336
int ret ;
2333
2337
if (status -> nsimplex == 2 ) {
@@ -2346,7 +2350,9 @@ mjtNum mjc_ccd(const mjCCDConfig* config, mjCCDStatus* status, mjCCDObj* obj1, m
2346
2350
multicontact (& pt , face , status , obj1 , obj2 );
2347
2351
}
2348
2352
}
2349
- mj_freeStack (d );
2353
+ }
2354
+ if (buffer ) {
2355
+ config -> free (config -> context , buffer );
2350
2356
}
2351
2357
return status -> dist ;
2352
2358
}
0 commit comments