00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00030 #include <math.h>
00031 #include <string.h>
00032
00033 #include "gws.h"
00034 #include "grasp.h"
00035 #include "mytools.h"
00036 #include "body.h"
00037
00038
00039 #include "debug.h"
00040
00041 extern "C" {
00042 #include "qhull_a.h"
00043 }
00044 #include "qhull_mutex.h"
00045
00047 QMutex qhull_mutex;
00048
00049 char qh_version[] = "GraspIt 2.0b";
00050
00051 #ifdef USE_DMALLOC
00052 #include "dmalloc.h"
00053 #endif
00054
00055 #define IVTOL 1e-5
00056
00057 const char *GWS::TYPE_LIST[] = {"L1 Norm","LInfinity Norm",NULL};
00058 const char *L1GWS::type = "L1 Norm";
00059 const char *LInfGWS::type = "LInfinity Norm";
00060
00061 typedef double *doublePtr;
00062
00064 const std::vector<int> GWS::ALL_DIMENSIONS = std::vector<int>(6, 1);
00065
00069 GWS::~GWS()
00070 {
00071 DBGA("deleting GWS");
00072 clearGWS();
00073 }
00074
00075 void
00076 GWS::clearGWS()
00077 {
00078 if (hyperPlanes) {
00079 for (int i=0;i<numHyperPlanes;i++)
00080 delete [] hyperPlanes[i];
00081 delete [] hyperPlanes;
00082 hyperPlanes=NULL;
00083 }
00084 numHyperPlanes = 0;
00085 hullArea = hullVolume = 0.0;
00086 forceClosure = false;
00087 }
00088
00092 GWS *
00093 GWS::createInstance(const char *desiredType,Grasp *g)
00094 {
00095 if (!strcmp(desiredType,L1GWS::getClassType()))
00096 return new L1GWS(g);
00097
00098 if (!strcmp(desiredType,LInfGWS::getClassType()))
00099 return new LInfGWS(g);
00100
00101 return NULL;
00102 }
00103
00104
00113 int
00114 GWS::projectTo3D(double *projCoords, std::set<int> fixedCoordSet,
00115 std::vector<position> &hullCoords, std::vector<int> &hullIndices)
00116 {
00117 int i,j,k,validPlanes,numCoords,numInLoop;
00118 double **planes;
00119 int freeCoord[3],fixedCoord[3];
00120
00121
00122 boolT ismalloc;
00123 int curlong,totlong,exitcode;
00124 char options[200];
00125 facetT *facet;
00126
00127 if (numHyperPlanes == 0) {
00128 DBGP("No hyperplanes");
00129 return SUCCESS;
00130 }
00131
00132 planes = (double **) malloc(numHyperPlanes * sizeof(double *));
00133 if (!planes) {
00134 #ifdef GRASPITDBG
00135 pr_error("GWS::ProjectTo3D,Out of memory allocating planes array");
00136 printf("NumHyperplanes: %d\n",numHyperPlanes);
00137 #endif
00138 return FAILURE;
00139 }
00140
00141 validPlanes = 0;
00142
00143
00144
00145 for (i=0,j=0,k=0;i<6;i++) {
00146 if (fixedCoordSet.find(i) == fixedCoordSet.end()) {
00147 freeCoord[k++] = i;
00148 } else {
00149 fixedCoord[j++] = i;
00150 }
00151 }
00152
00153
00154 for (i=0;i<numHyperPlanes;i++) {
00155 double len = sqrt(hyperPlanes[i][freeCoord[0]]*hyperPlanes[i][freeCoord[0]] +
00156 hyperPlanes[i][freeCoord[1]]*hyperPlanes[i][freeCoord[1]] +
00157 hyperPlanes[i][freeCoord[2]]*hyperPlanes[i][freeCoord[2]]);
00158
00159 if (len>1e-11) {
00160 planes[validPlanes] = (double *) malloc(4 * sizeof(double));
00161 if (!planes[validPlanes]) {
00162 pr_error("Out of memory allocating planes array");
00163 DBGP("Out of memory allocating planes array");
00164 return FAILURE;
00165 }
00166 planes[validPlanes][0] = hyperPlanes[i][freeCoord[0]]/len;
00167 planes[validPlanes][1] = hyperPlanes[i][freeCoord[1]]/len;
00168 planes[validPlanes][2] = hyperPlanes[i][freeCoord[2]]/len;
00169 planes[validPlanes][3] = (hyperPlanes[i][6] +
00170 hyperPlanes[i][fixedCoord[0]]*projCoords[fixedCoord[0]] +
00171 hyperPlanes[i][fixedCoord[1]]*projCoords[fixedCoord[1]] +
00172 hyperPlanes[i][fixedCoord[2]]*projCoords[fixedCoord[2]])/len;
00173
00174 validPlanes++;
00175 }
00176 }
00177
00178 if (validPlanes<numHyperPlanes) {
00179 DBGP("Ignored " << numHyperPlanes-validPlanes <<
00180 " hyperplanes which did not intersect this 3-space");
00181 }
00182 if (!validPlanes) {
00183 DBGA("No valid planes in 3D projection!");
00184 return FAILURE;
00185 }
00186
00187
00188
00189
00190
00191 coordT *array = new coordT[validPlanes*3];
00192 coordT *p = &array[0];
00193
00194 boolT zerodiv;
00195 coordT *point, *normp, *coordp, **pointp, *feasiblep;
00196 vertexT *vertex, **vertexp;
00197
00198 #ifdef GRASPITDBG
00199 printf("Calling qhull to perform a 3D halfspace intersection of %d planes...\n",validPlanes);
00200 #endif
00201
00202 ismalloc = False;
00203
00204
00205
00206 FILE *qhfp = fopen("logfile","w");
00207
00208 if (!qhfp) {
00209 fprintf(stderr,"Could not open qhull logfile!\n");
00210 qh_init_A(NULL, stdout, stderr, 0, NULL);
00211 }
00212 else
00213 qh_init_A(NULL, qhfp, qhfp, 0, NULL);
00214
00215 if ((exitcode = setjmp(qh errexit))) {
00216 delete [] array;
00217 qh NOerrexit= True;
00218 qh_freeqhull(!qh_ALL);
00219 qh_memfreeshort (&curlong, &totlong);
00220 if (curlong || totlong)
00221 fprintf (stderr, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n",
00222 totlong, curlong);
00223 for (i=0;i<validPlanes;i++)
00224 free(planes[i]);
00225 free(planes);
00226 if (qhfp) fclose(qhfp);
00227 DBGP("Qhull forces the exit; probably no valid intersection");
00228 return FAILURE;
00229 }
00230 sprintf(options, "qhull -H0,0,0 Pp");
00231 qh_initflags(options);
00232 qh_setfeasible(3);
00233 if (!(qh feasible_point)) printf("why is qh_qh NULL?\n");
00234 for(i=0;i<validPlanes;i++) {
00235 qh_sethalfspace (3, p, &p, planes[i],&(planes[i][3]), qh feasible_point);
00236 }
00237
00238 qh_init_B(&array[0], validPlanes, 3, ismalloc);
00239 qh_qhull();
00240 qh_check_output();
00241 if (qhfp) fclose(qhfp);
00242
00243
00244
00245
00246 hullCoords.clear();
00247 numCoords = qh num_facets;
00248 hullCoords.reserve(numCoords);
00249 int *indices = new int[numCoords];
00250
00251 double scale = grasp->getMaxRadius();
00252
00253 point= (pointT*)qh_memalloc (qh normal_size);
00254
00255 FORALLfacets {
00256 coordp = point;
00257 if (facet->offset > 0)
00258 goto LABELprintinfinite;
00259
00260 normp= facet->normal;
00261 feasiblep= qh feasible_point;
00262 if (facet->offset < -qh MINdenom) {
00263 for (k= qh hull_dim; k--; )
00264 *(coordp++)= (*(normp++) / - facet->offset) + *(feasiblep++);
00265 }else {
00266 for (k= qh hull_dim; k--; ) {
00267 *(coordp++)= qh_divzero (*(normp++), facet->offset, qh MINdenom_1,&zerodiv) + *(feasiblep++);
00268 if (zerodiv) {
00269 goto LABELprintinfinite;
00270 }
00271 }
00272 }
00273 hullCoords.push_back(position(point[0]*scale,point[1]*scale,
00274 point[2]*scale));
00275 continue;
00276 LABELprintinfinite:
00277 hullCoords.push_back(position(qh_INFINITE,qh_INFINITE,qh_INFINITE));
00278 fprintf(stderr,"intersection at infinity!\n");
00279 }
00280 qh_memfree (point, qh normal_size);
00281
00282
00283
00284
00285
00286 double dot;
00287 vec3 testNormal, refNormal;
00288
00289 int numfacets, numsimplicial, numridges, totneighbors, numneighbors, numcoplanars;
00290 setT *vertices, *vertex_points, *coplanar_points;
00291 int numpoints= qh num_points + qh_setsize (qh other_points);
00292 int vertex_i, vertex_n;
00293 facetT *neighbor, **neighborp;
00294
00295 qh_countfacets (qh facet_list, NULL, !qh_ALL, &numfacets, &numsimplicial,
00296 &totneighbors, &numridges, &numcoplanars);
00297
00298 qh_vertexneighbors();
00299 vertices= qh_facetvertices (qh facet_list, NULL, !qh_ALL);
00300 vertex_points= qh_settemp (numpoints);
00301 coplanar_points= qh_settemp (numpoints);
00302 qh_setzero (vertex_points, 0, numpoints);
00303 qh_setzero (coplanar_points, 0, numpoints);
00304 FOREACHvertex_(vertices)
00305 qh_point_add (vertex_points, vertex->point, vertex);
00306 FORALLfacet_(qh facet_list) {
00307 FOREACHpoint_(facet->coplanarset)
00308 qh_point_add (coplanar_points, point, facet);
00309 }
00310
00311 FOREACHvertex_i_(vertex_points) {
00312 if (vertex) {
00313 numneighbors= qh_setsize (vertex->neighbors);
00314
00315 numInLoop = numneighbors;
00316 qh_order_vertexneighbors (vertex);
00317 j=0;
00318 FOREACHneighbor_(vertex) {
00319 if (!neighbor->visitid) {
00320 fprintf(stderr,"Uh oh! neighbor->visitId==0, -neighbor->id: %d\n",-neighbor->id);
00321 numInLoop--;
00322 }
00323 else
00324 indices[j] = neighbor->visitid - 1;
00325
00326 if (j>0 && ((hullCoords[indices[j]]-hullCoords[indices[j-1]]).len() < IVTOL ||
00327 (hullCoords[indices[j]]-hullCoords[indices[0]]).len() < IVTOL))
00328 {
00329 numInLoop--;
00330 }
00331 else j++;
00332 }
00333 } else if ((facet= SETelemt_(coplanar_points, vertex_i, facetT))) {
00334 numInLoop=1;
00335 } else {
00336 numInLoop=0;
00337 continue;
00338 }
00339
00340 if (numInLoop<3) {
00341 DBGP("too few vertices to make a face. Ignoring ...");
00342 continue;
00343 }
00344
00345
00346 testNormal = (hullCoords[indices[1]] - hullCoords[indices[0]]) * (hullCoords[indices[j-1]] - hullCoords[indices[0]]);
00347 refNormal = vec3(planes[vertex_i][0],planes[vertex_i][1],planes[vertex_i][2]);
00348
00349 if ((dot = testNormal % refNormal) > 0.0) {
00350 for (j=0;j<numInLoop;j++)
00351 hullIndices.push_back(indices[j]);
00352 hullIndices.push_back(-1);
00353 } else {
00354
00355 for (j=numInLoop-1;j>=0;j--)
00356 hullIndices.push_back(indices[j]);
00357 hullIndices.push_back(-1);
00358 }
00359 }
00360
00361 qh_settempfree (&coplanar_points);
00362 qh_settempfree (&vertex_points);
00363 qh_settempfree (&vertices);
00364
00365 qh NOerrexit= True;
00366 qh_freeqhull(!qh_ALL);
00367 qh_memfreeshort (&curlong, &totlong);
00368 if (curlong || totlong)
00369 fprintf (stderr, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n",
00370 totlong, curlong);
00371
00372 for (i=0;i<validPlanes;i++)
00373 free(planes[i]);
00374 free(planes);
00375
00376 delete [] indices;
00377 delete [] array;
00378 DBGP("Succesfull completion of intersection task");
00379 return SUCCESS;
00380 }
00381
00382
00383 void
00384 GWS::setGravity(bool use, vec3 gd)
00385 {
00386 useGravity = use;
00387 if (!use) gravDirection = vec3(0,0,0);
00388 else gravDirection = gd;
00389 }
00390
00400 void
00401 GWS::computeHyperplaneMetrics()
00402 {
00403 if (!numHyperPlanes) {
00404 forceClosure = false;
00405 return;
00406 }
00407
00408 int posOffsets = 0;
00409 int minIndex = 0;
00410 double minOffset = -1.0;
00411
00412 for (int i=0; i<numHyperPlanes; i++) {
00413 if (hyperPlanes[i][6] > 0) posOffsets++;
00414 if (minOffset == -1.0 || -hyperPlanes[i][6]<minOffset) {
00415 minOffset = -hyperPlanes[i][6];
00416 minIndex = i;
00417 }
00418 }
00419
00420 grasp->setMinWrench(hyperPlanes[minIndex]);
00421
00422 if (posOffsets>0) {
00423 DBGP("QUALITY: NON FORCE CLOSURE GRASP, late exit");
00424 forceClosure = false;
00425 }
00426 else {
00427 DBGP("FORCE CLOSURE GRASP");
00428 forceClosure = true;
00429 }
00430 }
00431
00444 int
00445 GWS::buildHyperplanesFromWrenches(void *wr, int numWrenches,
00446 std::vector<int> useDimensions)
00447 {
00448 DBGP("Qhull init on " << numWrenches << " wrenches");
00449
00450 int dimensions = 0;
00451 for (int d=0; d<6; d++) {
00452 if (useDimensions[d]) dimensions++;
00453 }
00454
00455
00456 coordT *wrenches = (coordT*)wr;
00457 boolT ismalloc;
00458 int curlong, totlong, exitcode;
00459 char options[200];
00460 facetT *facet;
00461 int i;
00462
00463 ismalloc = False;
00464 FILE *qhfp = fopen("logfile-qhull","w");
00465 if (!qhfp) {
00466 fprintf(stderr,"Could not open qhull logfile!\n");
00467 qh_init_A(NULL, stdout, stderr, 0, NULL);
00468 }
00469 else
00470 qh_init_A(NULL, qhfp, qhfp, 0, NULL);
00471
00472
00473 if ((exitcode = setjmp(qh errexit))) {
00474 DBGP("QUALITY: 0 volume in " << dimensions <<"D, quick exit");
00475 qh NOerrexit= True;
00476 qh_freeqhull(!qh_ALL);
00477 qh_memfreeshort (&curlong, &totlong);
00478 if (curlong || totlong)
00479 fprintf (stderr, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n",
00480 totlong, curlong);
00481 if (qhfp) fclose(qhfp);
00482 return FAILURE;
00483 }
00484
00485 sprintf(options, "qhull Pp n Qx C-0.0001");
00486 qh_initflags(options);
00487 qh_init_B(&wrenches[0], numWrenches, dimensions, ismalloc);
00488 qh_qhull();
00489 qh_check_output();
00490 qh_getarea(qh facet_list);
00491 if (qhfp) fclose(qhfp);
00492
00493 hullArea = qh totarea;
00494 hullVolume = qh totvol;
00495 numHyperPlanes = qh num_facets;
00496
00497 hyperPlanes = new doublePtr[numHyperPlanes];
00498 if (!hyperPlanes) {
00499 DBGA("Out of memory allocating hyperPlanes array");
00500 return FAILURE;
00501 }
00502
00503 for (i=0;i<numHyperPlanes;i++) {
00504 hyperPlanes[i] = new double[7];
00505 if (!hyperPlanes[i]) {
00506 DBGA("Out of memory allocating hyperPlanes array");
00507 return FAILURE;
00508 }
00509 }
00510
00511 i=0;
00512
00513 mUsedDimensions = useDimensions;
00514 FORALLfacets {
00515 int hd = 0;
00516 for (int d=0; d<6; d++) {
00517 if (useDimensions[d]) {
00518 hyperPlanes[i][d] = facet->normal[hd];
00519 hd++;
00520 } else {
00521 hyperPlanes[i][d] = 0;
00522 }
00523 }
00524 hyperPlanes[i][6] = facet->offset;
00525 i++;
00526 }
00527
00528 qh NOerrexit= True;
00529 qh_freeqhull(!qh_ALL);
00530 qh_memfreeshort (&curlong, &totlong);
00531 if (curlong || totlong) {
00532 fprintf (stderr, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n",
00533 totlong, curlong);
00534 }
00535 DBGP("Qhull SUCCESS");
00536 return SUCCESS;
00537 }
00538
00561 int
00562 L1GWS::build(std::vector<int> useDimensions)
00563 {
00564 DBGP("in L1 gws build");
00565 if (useGravity) {
00566 DBGP("Gravity: " << gravDirection.x() << " " << gravDirection.y()
00567 << " " << gravDirection.z());
00568 } else {
00569 DBGP("No gravity");
00570 }
00571
00572 clearGWS();
00573
00574 if (!grasp->getNumContacts()) {
00575 forceClosure = false;
00576 DBGP(" No contacts, returning");
00577 return SUCCESS;
00578 }
00579
00580 int wrenchCount = 0;
00581 for (int i=0;i<grasp->getNumContacts();i++) {
00582 wrenchCount += grasp->getContact(i)->getMate()->numFrictionEdges;
00583 }
00584
00585
00586 int numDimensions = 0;
00587 for (int d=0; d<6; d++) {
00588 if (useDimensions[d]) {
00589 numDimensions++;
00590 }
00591 }
00592 DBGP("Building a " << numDimensions << "D L1 GWS");
00593
00594 if (numDimensions < 2) {
00595 DBGA("At least 2 used dimensions needed");
00596 return FAILURE;
00597 }
00598
00599 coordT *array = new coordT[wrenchCount*numDimensions];
00600 if (!array) {
00601 DBGA("Failed to allocate memory for wrenchCount" << wrenchCount);
00602 return FAILURE;
00603 }
00604
00605 coordT *p = &array[0];
00606 for (int i=0; i<grasp->getNumContacts(); i++) {
00607 for (int w=0; w<grasp->getContact(i)->getMate()->numFrictionEdges; w++) {
00608
00609 DBGP(" x: " << grasp->getContact(i)->getMate()->wrench[w].force.x() <<
00610 " y: " << grasp->getContact(i)->getMate()->wrench[w].force.y() <<
00611 " z: " << grasp->getContact(i)->getMate()->wrench[w].force.z() );
00612 DBGP("tx: " << grasp->getContact(i)->getMate()->wrench[w].torque.x() <<
00613 " ty: " << grasp->getContact(i)->getMate()->wrench[w].torque.y() <<
00614 " tz: " << grasp->getContact(i)->getMate()->wrench[w].torque.z() );
00615
00616 if (useDimensions[0]) *p++ = grasp->getContact(i)->getMate()->wrench[w].force.x();
00617 if (useGravity) *(p-1) = *(p-1) + gravDirection.x();
00618 if (useDimensions[1]) *p++ = grasp->getContact(i)->getMate()->wrench[w].force.y();
00619 if (useGravity) *(p-1) = *(p-1) + gravDirection.y();
00620 if (useDimensions[2]) *p++ = grasp->getContact(i)->getMate()->wrench[w].force.z();
00621 if (useGravity) *(p-1) = *(p-1) + gravDirection.z();
00622
00623 if (useDimensions[3]) *p++ = grasp->getContact(i)->getMate()->wrench[w].torque.x();
00624 if (useDimensions[4]) *p++ = grasp->getContact(i)->getMate()->wrench[w].torque.y();
00625 if (useDimensions[5]) *p++ = grasp->getContact(i)->getMate()->wrench[w].torque.z();
00626
00627 }
00628 }
00629
00630
00631 qhull_mutex.lock();
00632
00633 int result;
00634 try {
00635 result = buildHyperplanesFromWrenches(array, wrenchCount, useDimensions);
00636 } catch(...) {
00637 DBGA("Build QHull failed!!!");
00638 result = FAILURE;
00639 }
00640
00641
00642 qhull_mutex.unlock();
00643
00644 if (result == SUCCESS) {
00645 computeHyperplaneMetrics();
00646 } else{
00647 clearGWS();
00648 }
00649
00650 DBGP("HULL AREA: " << hullArea);
00651 DBGP("HULL VOLUME: " << hullVolume);
00652
00653 delete [] array;
00654 return result;
00655 }
00656
00662 void
00663 minkowskiSum(Grasp *g, int c, int &wrenchNum, coordT *wrenchArray, Wrench prevSum,
00664 std::vector<int> useDimensions)
00665 {
00666 static Wrench sum;
00667
00668 int nd = 0;
00669 for (int d=0; d<6; d++) {
00670 if (useDimensions[d]) nd++;
00671 }
00672 if (c == g->getNumContacts()) {
00673 if (useDimensions[0]) wrenchArray[ wrenchNum*nd + 0 ] = prevSum.force.x();
00674 if (useDimensions[1]) wrenchArray[ wrenchNum*nd + 1 ] = prevSum.force.y();
00675 if (useDimensions[2]) wrenchArray[ wrenchNum*nd + 2 ] = prevSum.force.z();
00676 if (useDimensions[3]) wrenchArray[ wrenchNum*nd + 3 ] = prevSum.torque.x();
00677 if (useDimensions[4]) wrenchArray[ wrenchNum*nd + 4 ] = prevSum.torque.y();
00678 if (useDimensions[5]) wrenchArray[ wrenchNum*nd + 5 ] = prevSum.torque.z();
00679 wrenchNum++;
00680 return;
00681 }
00682
00683
00684 minkowskiSum(g, c+1, wrenchNum, wrenchArray, prevSum, useDimensions);
00685
00686
00687 for (int w=0; w < g->getContact(c)->numFrictionEdges; w++) {
00688
00689 sum.force = prevSum.force + g->getContact(c)->getMate()->wrench[w].force;
00690 sum.torque = prevSum.torque + g->getContact(c)->getMate()->wrench[w].torque;
00691
00692 minkowskiSum(g, c+1, wrenchNum, wrenchArray, sum, useDimensions);
00693 }
00694 }
00695
00718 int
00719 LInfGWS::build(std::vector<int> useDimensions)
00720 {
00721 clearGWS();
00722 if (!grasp->getNumContacts()) {
00723 forceClosure = false;
00724 return SUCCESS;
00725 }
00726
00727
00728 int numDimensions = 0;
00729 for (int d=0; d<6; d++) {
00730 if (useDimensions[d]) {
00731 numDimensions++;
00732 }
00733 }
00734
00735 int wrenchCount = 1;
00736 for (int i=0; i<grasp->getNumContacts(); i++) {
00737 wrenchCount *= grasp->getContact(i)->getMate()->numFCWrenches + 1;
00738 if (wrenchCount > INT_MAX/6.0) {
00739 DBGA("Too many contacts to compute the Minkowski sum!");
00740 return FAILURE;
00741 }
00742 }
00743
00744 coordT *array = new coordT[wrenchCount*6];
00745 if (!array) {
00746 DBGA("Could not allocate wrench array in ComputeLInfHull. wrenchCount: " << wrenchCount);
00747 return FAILURE;
00748 }
00749
00750 Wrench initSum;
00751 initSum.force = vec3::ZERO;
00752 initSum.torque = vec3::ZERO;
00753
00754 int wrenchNum = 0;
00755 minkowskiSum(grasp, 0, wrenchNum, array, initSum, useDimensions);
00756
00757
00758 qhull_mutex.lock();
00759
00760 int result;
00761 try {
00762 result = buildHyperplanesFromWrenches(array, wrenchCount, useDimensions);
00763 } catch(...) {
00764 DBGA("Build QHull 3D failed!!!");
00765 result = FAILURE;
00766 }
00767
00768
00769 qhull_mutex.unlock();
00770
00771 if (result == SUCCESS) {
00772 computeHyperplaneMetrics();
00773 } else{
00774 clearGWS();
00775 }
00776
00777 DBGP("HULL VOLUME: " << hullVolume);
00778
00779 delete [] array;
00780 return result;
00781 }