/*! Uses the \a projCoords and \a fixedCoordSet (which identifies the indices
	of the fixed coordinates) to project the 6D hyperplanes of the Grasp Wrench 
	Space into 3D. The \a projCoords is an array of 6 values, but only 3 are used.  
	It then calls qhull to perform a halfspace intersection to get the vertices 
	of the 3D volume.  These vertices are stored in \a hullCoords, and indices 
	of the individual faces that make up the volume are stored in \a hullIndices 
	(an Indexed Face Set).
*/
int
GWS::projectTo3D(double *projCoords, std::set<int> fixedCoordSet,
				 std::vector<position> &hullCoords, std::vector<int> &hullIndices)
{
  int i,j,k,validPlanes,numCoords,numInLoop;
  double **planes;
  int freeCoord[3],fixedCoord[3];

  // qhull variables
  boolT ismalloc;
  int curlong,totlong,exitcode;
  char options[200];  
  facetT *facet;

  if (numHyperPlanes == 0) {
	  DBGP("No hyperplanes");
	  return SUCCESS;
  }

  planes = (double **) malloc(numHyperPlanes * sizeof(double *));
  if (!planes) {
#ifdef GRASPITDBG
    pr_error("GWS::ProjectTo3D,Out of memory allocating planes array");
    printf("NumHyperplanes: %d\n",numHyperPlanes);
#endif
    return FAILURE;
  }

  validPlanes = 0;

  // determine which dimensions are free and which are fixed
  // the set keeps things ordered
  for (i=0,j=0,k=0;i<6;i++) {
    if (fixedCoordSet.find(i) == fixedCoordSet.end()) {
      freeCoord[k++] = i;
	} else {
      fixedCoord[j++] = i;
	}
  }

  // project the hyperplanes to three dimensional planes
  for (i=0;i<numHyperPlanes;i++) {
    double len = sqrt(hyperPlanes[i][freeCoord[0]]*hyperPlanes[i][freeCoord[0]] +
                      hyperPlanes[i][freeCoord[1]]*hyperPlanes[i][freeCoord[1]] +
                      hyperPlanes[i][freeCoord[2]]*hyperPlanes[i][freeCoord[2]]);

    if (len>1e-11) {
      planes[validPlanes] = (double *) malloc(4 * sizeof(double));
      if (!planes[validPlanes]) {
		pr_error("Out of memory allocating planes array");
	    DBGP("Out of memory allocating planes array");
		return FAILURE;
	  }
      planes[validPlanes][0] = hyperPlanes[i][freeCoord[0]]/len;
      planes[validPlanes][1] = hyperPlanes[i][freeCoord[1]]/len;
      planes[validPlanes][2] = hyperPlanes[i][freeCoord[2]]/len;
      planes[validPlanes][3] = (hyperPlanes[i][6] + 
	                            hyperPlanes[i][fixedCoord[0]]*projCoords[fixedCoord[0]] +
		                        hyperPlanes[i][fixedCoord[1]]*projCoords[fixedCoord[1]] +
		                        hyperPlanes[i][fixedCoord[2]]*projCoords[fixedCoord[2]])/len;
      
      validPlanes++;
	}
  }

  if (validPlanes<numHyperPlanes) {
	  DBGP("Ignored " << numHyperPlanes-validPlanes << 
		   " hyperplanes which did not intersect this 3-space");
  }
  if (!validPlanes) {
	  DBGA("No valid planes in 3D projection!");
	  return FAILURE;
  }
	   

  //
  // call qhull to do the halfspace intersection
  //
  coordT *array = new coordT[validPlanes*3];
  coordT *p = &array[0];
  
  boolT zerodiv;
  coordT *point, *normp, *coordp, **pointp, *feasiblep;
  vertexT *vertex, **vertexp;

#ifdef GRASPITDBG
  printf("Calling qhull to perform a 3D halfspace intersection of %d planes...\n",validPlanes);
#endif

  ismalloc = False; 	// True if qh_freeqhull should 'free(array)'

  // I want to get rid of this but qh_init needs some sort of file pointer
  // for stdout and stderr
  FILE *qhfp = fopen("logfile","w");

  if (!qhfp) {
	fprintf(stderr,"Could not open qhull logfile!\n");
	qh_init_A(NULL, stdout, stderr, 0, NULL);
  }
  else
   qh_init_A(NULL, qhfp, qhfp, 0, NULL);

  if ((exitcode = setjmp(qh errexit))) {
    delete [] array;
	qh NOerrexit= True;
	qh_freeqhull(!qh_ALL);
	qh_memfreeshort (&curlong, &totlong);
	if (curlong || totlong)  	/* optional */
	   fprintf (stderr, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n",
		 totlong, curlong);
    for (i=0;i<validPlanes;i++)
      free(planes[i]);
    free(planes);
	if (qhfp) fclose(qhfp);
	DBGP("Qhull forces the exit; probably no valid intersection");
    return FAILURE; //exit(exitcode);
  }
  sprintf(options, "qhull -H0,0,0 Pp");
  qh_initflags(options);
  qh_setfeasible(3);
  if (!(qh feasible_point)) printf("why is qh_qh NULL?\n");
  for(i=0;i<validPlanes;i++) {
    qh_sethalfspace (3, p, &p, planes[i],&(planes[i][3]), qh feasible_point);
  }

  qh_init_B(&array[0], validPlanes, 3, ismalloc);
  qh_qhull();
  qh_check_output();
  if (qhfp) fclose(qhfp);

  //
  // Collect the vertices of the volume
  //
  hullCoords.clear();
  numCoords = qh num_facets;
  hullCoords.reserve(numCoords);
  int *indices = new int[numCoords];

  double scale = grasp->getMaxRadius(); // Hmm, is this right?

  point= (pointT*)qh_memalloc (qh normal_size);

  FORALLfacets {
    coordp = point;
	if (facet->offset > 0)
      goto LABELprintinfinite;
	
    normp= facet->normal;
    feasiblep= qh feasible_point;
    if (facet->offset < -qh MINdenom) {
      for (k= qh hull_dim; k--; )
        *(coordp++)= (*(normp++) / - facet->offset) + *(feasiblep++);
    }else {
      for (k= qh hull_dim; k--; ) {
        *(coordp++)= qh_divzero (*(normp++), facet->offset, qh MINdenom_1,&zerodiv) + *(feasiblep++);
        if (zerodiv) {
          goto LABELprintinfinite;
        }
      }
    }    
    hullCoords.push_back(position(point[0]*scale,point[1]*scale,
				  point[2]*scale));
    continue;
    LABELprintinfinite:
    hullCoords.push_back(position(qh_INFINITE,qh_INFINITE,qh_INFINITE));
    fprintf(stderr,"intersection at infinity!\n");
  }
  qh_memfree (point, qh normal_size);


  //
  // use adjacency information to build faces of the volume
  //
  double dot;
  vec3 testNormal, refNormal;

  int numfacets, numsimplicial, numridges, totneighbors, numneighbors, numcoplanars;
  setT *vertices, *vertex_points, *coplanar_points;
  int numpoints= qh num_points + qh_setsize (qh other_points);
  int vertex_i, vertex_n;
  facetT *neighbor, **neighborp;
  int unused_numnumtricoplanarsp; //added because countfacets takes more arguments in qhull 2012
								  //FIXME - understand what this argument does. 
  qh_countfacets (qh facet_list, NULL, !qh_ALL, &numfacets, &numsimplicial, 
      &totneighbors, &numridges, &numcoplanars, &unused_numnumtricoplanarsp);  /* sets facet->visitid */

  qh_vertexneighbors();
  vertices= qh_facetvertices (qh facet_list, NULL, !qh_ALL);
  vertex_points= qh_settemp (numpoints);
  coplanar_points= qh_settemp (numpoints);
  qh_setzero (vertex_points, 0, numpoints);
  qh_setzero (coplanar_points, 0, numpoints);
  FOREACHvertex_(vertices)
    qh_point_add (vertex_points, vertex->point, vertex);
  FORALLfacet_(qh facet_list) {
    FOREACHpoint_(facet->coplanarset)
      qh_point_add (coplanar_points, point, facet);
  }
Exemplo n.º 2
0
SEXP C_halfspacen(const SEXP p, const SEXP options, const SEXP tmpdir)
{
  /* Return value*/
  SEXP retval;

  /* Run Qhull */
  qhT *qh= (qhT*)malloc(sizeof(qhT));
  char errstr1[100], errstr2[100];
  unsigned int dim, n;
  char cmd[50] = "qhull H";
  int exitcode = qhullNewQhull(qh, p, cmd,  options, tmpdir, &dim, &n, errstr1, errstr2);

  /* If error */
  if (exitcode) {
    freeQhull(qh);
    error("Received error code %d from qhull. Qhull error:\n    %s    %s", exitcode, errstr1, errstr2);
  }

  if (!qh->feasible_point) {
    freeQhull(qh);
    error("qhull input error (qh_printafacet): option 'Fp' needs qh->feasible_point");
  }
  
  /* Extract information from output */
  int i;
  facetT *facet;
  boolT zerodiv;
  coordT *point, *normp, *coordp, *feasiblep;
    
  /* Count facets. Perhaps a better way of doing this is: 
     int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
     int num;
     qh_countfacets(qh, NULL, facets, printall, &numfacets, &numsimplicial,
     &totneighbors, &numridges, &numcoplanars, &numtricoplanars); */
  int nf = 0;
  FORALLfacets {
    nf++;
  }

  /* Output of intersections based on case qh_PRINTpointintersect:
     qh_printafacet() in io_r.c . This corresponds to the "Fp"
     option to the qhull program */
  retval = PROTECT(allocMatrix(REALSXP, nf, dim-1));
  int k;
  i=0; /* Facet counter */
  FORALLfacets {
    point = coordp = (coordT*)qh_memalloc(qh, qh->normal_size);
    if (facet->offset > 0) {
      for (k=qh->hull_dim; k--; ) {
        point[k] = R_PosInf;
      }
    } else {
      normp = facet->normal;
      feasiblep = qh->feasible_point;
      if (facet->offset < -qh->MINdenom) {
        for (k=qh->hull_dim; k--; )
          *(coordp++) = (*(normp++) / - facet->offset) + *(feasiblep++);
      } else {
        for (k=qh->hull_dim; k--; ) {
          *(coordp++) = qh_divzero(*(normp++), facet->offset, qh->MINdenom_1,
                                   &zerodiv) + *(feasiblep++);
          if (zerodiv) {
            for (k=qh->hull_dim; k--; ) {
              point[k] = R_PosInf;
            }
          }
        }
      }
    }
    /* qh_printpoint(qh, fp, NULL, point); */
    for (k=0; k<qh->hull_dim; k++) {
      REAL(retval)[i + k*nf] = point[k];
    }
    qh_memfree(qh, point, qh->normal_size);
    i++; /* Increment facet counter */
  }

  freeQhull(qh);
  UNPROTECT(1);

  return retval;
}