예제 #1
0
//  generate recursively
void STGGeneric::constructTreeRecursive(SphereTree *st) const{
  CHECK_DEBUG0(st != NULL && st->degree > 1 && st->levels >= 1);
  CHECK_DEBUG0(reducer != NULL);
  CHECK_DEBUG0(eval != NULL);
  CHECK_DEBUG0(surfacePoints != NULL);

  //  make cells to have 10 pts each, most will have alot more
  int numCells = surfacePoints->getSize() / PTS_PER_CELL;
  int gridDim = ceil(pow(numCells, 1.0 / 3.0));
  OUTPUTINFO("numCells = %d, gridDim = %d\n", numCells, gridDim);

  //  create surface rep
  SurfaceRep surRep;
  surRep.setup(*surfacePoints, gridDim);

  //  bounding sphere for root
  SFWhite::makeSphere(&st->nodes.index(0), *surfacePoints);

  //  setup for the base level (should really do for 
  //  all levels - but doesn't fit in recursive form)
  reducer->setupForLevel(0, st->degree, &surRep);

  //  make children nodes - using recursive algorithm
  if (st->levels > 1)
    makeChildren(st, 0, 1, surRep);
}
예제 #2
0
void VFAdaptive::adaptiveSample(Voronoi3D *vor, float maxErr, int maxSam, int maxSph, int minSph, const SurfaceRep *coverRep, const Sphere *filterSphere, bool countOnlyCoverSpheres, int maxLoop){
  CHECK_DEBUG0(mt != NULL);
  const SurfaceRep *rep = coverRep;
  if (rep == NULL)
    rep = this->coverRep;

  VFAdaptive::adaptiveSample(vor, *mt, rep, maxErr, maxSam, maxSph, minSph, filterSphere, eval, countOnlyCoverSpheres, maxLoop);
}
예제 #3
0
bool RESelect::reduceSpheres(Array<int> *inds, int maxAllow, Array<int> *destCounts,
                           double maxMet, Array<double> *mets) const{
  CHECK_DEBUG0(srcSpheres != NULL);
  CHECK_DEBUG0(surRep != NULL);

  const Array<Surface::Point> *surPts = this->surRep->getSurPts();
  int numPts = surPts->getSize();
  int numSph = srcSpheres->getSize();

  //  counts of points covered by each sphere (count <= 0 means sphere is now invalid)
  Array<int> counts;
  counts.resize(numSph);
  for (int i = 0; i < numSph; i++)
    counts.index(i) = pointsPerSphere.index(i).getSize();

  //  flags for points covered by selected set
  Array<bool> coveredPts;
  coveredPts.resize(numPts);
  coveredPts.clear();
 
  //  do selection
  int numCov = 0;
  inds->setSize(0);
  if (mets)
    mets->setSize(0);
  while (numCov < numPts){
    if (maxAllow > 0 && inds->getSize() >= maxAllow)
      return false;   //  still surface covered and no more spheres allowed

    //  get the next sphere to add to the set
    double selMet = DBL_MAX;
    int maxI = selectSphere(counts, coveredPts, pointsPerSphere, &selMet, maxMet);
    if (maxI < 0)
      return false;   //  no more spheres to choose from

    //  store count
    if (destCounts)
      destCounts->addItem() = counts.index(maxI);

    //  add sphere to selected set
    inds->addItem() = maxI;
    counts.index(maxI) = -1;  //  make invalid
    if (mets)
      mets->addItem() = selMet;

    //  flag points as contained and update counts for points
    const Array<int> *bestPts = &pointsPerSphere.index(maxI);
    int numBest = bestPts->getSize();
    for (int i = 0; i < numBest; i++){
      int ptNum = bestPts->index(i);
      if (!coveredPts.index(ptNum)){
        coveredPts.index(ptNum) = true;
        numCov++;

        //  point wasn't covered - so now the spheres containing this point
        //  contain one less point
        const Array<int> *changed = &spheresPerPoint.index(ptNum);
        int numChanged = changed->getSize();
        for (int j = 0; j < numChanged; j++){
          int chSph = changed->index(j);
          counts.index(chSph)--;
          }
        }
      }
    }

  return true;
}
예제 #4
0
//  generate breadth first
void STGGeneric::constructTree(SphereTree *st) const{
  CHECK_DEBUG0(st != NULL && st->degree > 1 && st->levels >= 1);
  CHECK_DEBUG0(reducer != NULL);
  CHECK_DEBUG0(eval != NULL);
  CHECK_DEBUG0(surfacePoints != NULL);

  //  NULL out the entire tree
  st->initNode(0);

  //  make cells to have 10 pts each, most will have alot more
  int numCells = surfacePoints->getSize() / PTS_PER_CELL;
  int gridDim = ceil(pow(numCells, 1.0 / 3.0));
  OUTPUTINFO("numCells = %d, gridDim = %d\n", numCells, gridDim);

  SurfaceRep surRep;
  surRep.setup(*surfacePoints, gridDim);

  //  bounding sphere for root - should use vertices
  SFWhite::makeSphere(&st->nodes.index(0), *surfacePoints);

  //  list of points to be covered by each node
  unsigned long start, num;
  st->getRow(&start, &num, st->levels-1);
  Array<Array<int>/**/> pointsInSpheres;
  pointsInSpheres.resize(st->nodes.getSize() - num);

  //  initialise the list for the first node
  int numPts = surfacePoints->getSize();
  Array<int> *list0 = &pointsInSpheres.index(0);
  list0->resize(numPts);
  for (int i = 0; i < numPts; i++)
    list0->index(i) = i;

  //  process the remaining levels
  int numLeaves = 0;
  for (int level = 0; level < st->levels-1; level++){
    //  get the positions of the nodes
    unsigned long start, num;
    st->getRow(&start, &num, level);

    //  update samples etc. for this level
    reducer->setupForLevel(level, st->degree, &surRep);

    //  get the errors for all the spheres in that level
    int numActualSpheres = 0;
    double averageError = 0;
    Array<double> sphereErrors(num);
    for (int i = 0; i < num; i++){
      Sphere s = st->nodes.index(start+i);
      if (s.r >= 0){
        double err = eval->evalSphere(s);
        sphereErrors.index(i) = err;
        averageError += err;
        numActualSpheres++;
        }
      else 
        sphereErrors.index(i) = -1;
      }
    averageError /= numActualSpheres;
    if (level != 0 && numActualSpheres <= 1){
      numLeaves++;
      continue;     //  there is only one sphere here - will never improve
      }

    //  process each node's to make children
    int maxNode = -1;
    double maxR = -1;
    int levelChildren = 0;
    for (int nodeI = 0; nodeI < num; nodeI++){
      //OUTPUTINFO("Level = %d, node = %d\n", level, nodeI);
      printf("Level = %d, node = %d\n", level, nodeI);

      int node = nodeI + start;
      if (st->nodes.index(node).r <= 0){
          OUTPUTINFO("R = %f\n", st->nodes.index(node).r);
          st->initNode(node);
          continue;
          }

/*
      //  hack to do largest sphere at each run - gives guide to good params
      double r = st->nodes.index(node).r;
      if (r > maxR){
        maxR = r;
        maxNode = node;
        }
      }

      nodeI = maxNode - start;
      int node = maxNode;{
      //  end hack
*/

      //  make the set of surface poitns to be covered by this sphere
      Array<int> *selPtsI = &pointsInSpheres.index(node);
      int numSelPts = selPtsI->getSize();

      if (numSelPts <= 0)
        break;

      Array<Surface::Point> selPts(numSelPts);
      for (int i = 0; i < numSelPts; i++)
        selPts.index(i) = surfacePoints->index(selPtsI->index(i));

      //  get filter sphere
      Sphere s;
      SFWhite::makeSphere(&s, selPts);

      //  make cells to have 10 pts each, most will have alot more
      int numCells = numSelPts / PTS_PER_CELL;
      int gridDim = ceil(pow(numCells, 1.0 / 3.0));
      OUTPUTINFO("%d Points\n", numSelPts);
      OUTPUTINFO("numCells = %d, gridDim = %d\n", numCells, gridDim);

      //  make new SurfaceRepresentation
      SurfaceRep subRep;
      subRep.setup(selPts, gridDim);

      //  compute error for this sphere
      double err = sphereErrors.index(nodeI);
      if (err > averageError)
        err = averageError;  //  improve the bad ones a bit more

      //  generate the children nodes
      Array<Sphere> initChildren, children;
      reducer->getSpheres(&initChildren, st->degree, subRep, &s, err);

      //  apply optimiser if required
      if (optimiser && (maxOptLevel < 0 || level <= maxOptLevel)){
printf("RUNNING OPTIMISER...\n");
        optimiser->optimise(&initChildren, subRep, -1, &s, level);
printf("DONE OPTIMISING...\n");
        }

      //  do sphere refit - local optimisation
      if (useRefit){
        OUTPUTINFO("Refitting\n");
        SOPerSphere perSphere;
        perSphere.numIter = 3;
        perSphere.eval = eval;
        perSphere.optimise(&initChildren, subRep);
        }

      //  remove redundent spheres
      RELargest reLargest;
      if (!reLargest.reduceSpheres(&children, initChildren, subRep))
        children.clone(initChildren);

      //  setup the node's sub-division (make the regions to be covered by children)
      //subDivs.index(node).setup(children, &selPts);
      SurfaceDivision surDiv;
      surDiv.setup(children, &selPts);

      //  list of points that are covered
      Array<bool> covered(numSelPts);
      covered.clear();

      //  create the new nodes and their the points to cover
      int numChildren = children.getSize();
      int firstChild = st->getFirstChild(node);
      levelChildren += numChildren;
      for (int i = 0; i < numChildren; i++){
        int childNum = firstChild + i;

        //  get sphere
        const Sphere& s = children.index(i);

        //  add sphere to tree
        st->nodes.index(childNum).c = s.c;
        st->nodes.index(childNum).r = s.r;

        if (level < st->levels-2){
          //  get the points in this sphere
          Array<int> pointsInS;
          subRep.listContainedPoints(&pointsInS, NULL, s);
          int numInS = pointsInS.getSize();

          //  populate list of points in sphere
          Array<int> *pointsToCover = &pointsInSpheres.index(childNum);
          pointsToCover->resize(0);   //  just in case
          for (int j = 0; j < numInS; j++){
            int pI = pointsInS.index(j);
            if (surDiv.pointInRegion(selPts.index(pI).p, i)){
              pointsToCover->addItem() = selPtsI->index(pI);
              covered.index(pI) = true;
              }
            }
          }
        }

      //  assign uncovered points
      if (numChildren > 0 && level < st->levels-2){
        for (int i = 0; i < numSelPts; i++){
          if (!covered.index(i)){
            //  get point
            const Point3D& pt = selPts.index(i).p;

            //  find the sphere
            int minJ = -1;
            float minD = FLT_MAX;
            for (int j = 0; j < numChildren; j++){
              const Sphere& s = children.index(j);
              float d = pt.distance(s.c);// - s.r;
              if (d < minD){
                minD = d;
                minJ = j;
                }
              }

            //  add the point to the sphere's list
            pointsInSpheres.index(firstChild+minJ).addItem() = selPtsI->index(i);
            }
          }
        }

      //  save after each child set
      //st->saveSphereTree("saved.sph");
      }

    //  save after each level
    //st->saveSphereTree("saved.sph");

    //  see if we need to add another level
    if (level == st->levels - 2 && minLeaves > 0 && numLeaves + levelChildren < minLeaves){
      //  grow the tree
      OUTPUTINFO("Growing the tree : %d-->%d\n", st->levels, st->levels+1);
      OUTPUTINFO("New Nodes : %d-->", st->nodes.getSize());
      st->growTree(st->levels+1);
      OUTPUTINFO("%d\n", st->nodes.getSize());
      }
    }
}
예제 #5
0
bool insideSurfaceClosest(const Point3D &pTest, const Surface &s, const SpacialHash &faceHash, ClosestPointInfo *inf, float stopBelow, bool allowQuickTest){
  if (inf)
    inf->type = DIST_TYPE_INVALID;

  //  quick bounding box test
  if (allowQuickTest){
    if (pTest.x < s.pMin.x || pTest.x > s.pMax.x ||
        pTest.y < s.pMin.y || pTest.y > s.pMax.y ||
        pTest.z < s.pMin.z || pTest.z > s.pMax.z){
      return false;
      }
    }

  ClosestPointInfo localClosestInf;
  if (!inf)
    inf = &localClosestInf;
  float dist = getClosestPoint(inf, pTest, s, faceHash, stopBelow);

  if (dist < stopBelow){
    //  optimise for dodec
    return true;
    }

  //  vector to point on surface
  Vector3D v;
  v.difference(pTest, inf->pClose);
  v.norm();

  if (inf->type == FACE){
    //  face test 
    Vector3D n;
    s.getTriangleNormal(&n, inf->triangle);
    double dt = n.dot(v);
    return dt <= 0;
    }
  else if (inf->type == EDGE){
    //  edge test
    const Surface::Triangle *tri = &s.triangles.index(inf->triangle);

    //  edge will be between vertices v[num] and v[(num+1)%3]
    int e[2];
    e[0] = tri->v[inf->num];
    e[1] = tri->v[(inf->num+1)%3];

    int neigh = findNeighbour(s, *tri, e);
    if (neigh >= 0){
      //  make a plane for one of the triangles
      Vector3D n1;
      s.getTriangleNormal(&n1, inf->triangle);
      Point3D p1 = s.vertices.index(e[0]).p;
      Plane pl1;
      pl1.assign(n1, p1);

      //  get the point from the other triangle which is not part of edge
      const Surface::Triangle *tri2 = &s.triangles.index(neigh);
      for (int i = 0; i < 3; i++){
        if (tri2->v[i] != e[0] && tri2->v[i] != e[1])
          break;
        }
      CHECK_DEBUG0(i != 3);
      Point3D p2 = s.vertices.index(e[1]).p;
      
      //  get signed distance to plane
      float dist = pl1.dist(p2);

      //  need normal for second triangle
      Vector3D n2;
      s.getTriangleNormal(&n2, neigh);

      if (dist <= 0.0f){
        //  faces form convex spike, back facing to both
        return v.dot(n1) <= 0 && v.dot(n2) <= 0;
        }
      else{
        //  faces form concavity, back facing to either
        return v.dot(n1) <= 0 || v.dot(n2) <= 0;
        }
      }
    else{
      OUTPUTINFO("HHHHHMMMMMMM loose edge\n");
      return false;  //  only one triangle on edge - use face ??
      }
    }
  else{// if (minType == VERTEX)
    // chosen triangle
    const Surface::Triangle *tri = &s.triangles.index(inf->triangle);

    //  chosen vertex
    int vI = tri->v[inf->num];
    Vector3D n;
    s.getVertexNormal(&n, vI);
    return n.dot(v) <= 0;

/*
    //  get all faces
    Array<int> tris;
    s.findNeighbours(&tris, vI, inf->triangle);

    //  behind test for all faces
    int numTri = tris.getSize();
    for (int i = 0; i < numTri; i++){
      Vector3D n;
      s.getTriangleNormal(&n, tris.index(i));
      double dt = n.dot(v);
      if (dt > 0)
        return false;
      }

    //  must be behind all
    return true;*/
    }
}