// 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); }
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); }
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; }
// 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()); } } }
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;*/ } }