// 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); }
double VFAdaptive::getErr(Voronoi3D::Vertex *vert, const SEBase *eval, const MedialTester *mt, const Voronoi3D *vor){ if (vert->err < 0){ if (!eval){ // no evaluator - use convex approx // get closest point Point3D pClose; mt->closestPoint(&pClose, vert); if (vert->flag == VOR_FLAG_UNKNOWN) OUTPUTINFO("GetErr : UNCATEGORISED POINT\n"); // evaluate fit float dSur = pClose.distance(vert->s.c); if (vert->flag == VOR_FLAG_COVER){ vert->err = vert->s.r + dSur; // sphere center is outside surface } else{ vert->err = vert->s.r - dSur; // sphere center is inside surface if (vert->err < 0) vert->err = 0; } } else{ vert->err = eval->evalSphere(vert->s); } } return vert->err; }
bool insideSurfaceCrossingIter(const Point3D &p, const Surface &s, const SpacialHash &faceHash, float mult){ // check against bounding box if (p.x < s.pMin.x || p.x > s.pMax.x || p.y < s.pMin.y || p.y > s.pMax.y || p.z < s.pMin.z || p.z > s.pMax.z){ return false; } // if we get 10 tests and they don't agree then we are ON the mesh // would it be better to use the distance to surface first ?? int inCount = 0, outCount = 0; while ((inCount+outCount < 1) || ((inCount < outCount*mult && outCount < inCount*mult) && inCount+outCount < 10)){ for (int i = 0; i < 2; i++){ bool in = insideSurfaceCrossing(p, s, faceHash); if (in) inCount++; else outCount++; } } if (inCount != 0 && outCount != 0) OUTPUTINFO("In = %d, out = %d\n", inCount, outCount); bool in = inCount > outCount; return in; }
void sampleDomain(Array<int> *counts, SamplerInfo infos[], int numVals, int numSamples){ // setup counts counts->reallocate(numVals); // initialise domain info & counts for (int i = 0; i < numVals; i++){ SamplerInfo *inf = &infos[i]; inf->sourceI = i; counts->index(i) = 0; } // order the infos in increasing order qsort(infos, numVals, sizeof(SamplerInfo), samplerInfoCompare); // get total of the domain values float total = 0.0f; for (int i = 0; i < numVals; i++){ total += infos[i].val; } // make cumulative and work out maxSamples float totalSofar = 0.0f; for (int i = 0; i < numVals; i++){ SamplerInfo *s = &infos[i]; s->maxSamples = numSamples*(s->val / total); totalSofar += s->val; s->val = totalSofar; } // generate samples for (int i = 0; i < numSamples; i++){ // pick a random triangle float r = rand()/(float)RAND_MAX; int j = findInfo(infos, r*total, numVals); if (j == -1){ OUTPUTINFO("Problem attributing sample"); i--; } else{ SamplerInfo *s = &infos[j]; if (counts->index(s->sourceI) <= s->maxSamples){ counts->index(s->sourceI)++; // do sample } else{ i--; // reject sample } } } }
//----------------------------------------------- CANPeakSysDongle::CANPeakSysDongle(int iBaudRate, std::string strDeviceName) { m_bInitialized = false; m_handle = LINUX_CAN_Open(strDeviceName.c_str(), O_RDWR | O_NONBLOCK); if (!m_handle) { // Fatal error LOGERROR("can not open CANPeakSysDongle device : "<<strDeviceName<< " " << strerror(errno)); Sleep(3000); exit(0); } OUTPUTINFO("baudrate: %i", iBaudRate); init(iBaudRate); }
// implementation of RE algorithm bool REDiscard::reduceSpheres(Array<int> *inds, int maxNum, Array<int> *destCounts, double maxMet, Array<double> *mets) const{ // get points const Array<Surface::Point> *surPts = surRep->getSurPts(); int numPts = surPts->getSize(); int numSph = srcSpheres->getSize(); // list of counts for number of spheres over each point Array<int> pointCounts(numPts), sphereCount(numSph); pointCounts.clear(); // fill list Array<bool> coveredPts(numPts); coveredPts.clear(); for (int i = 0; i < numSph; i++){ Array<int> list; surRep->listContainedPoints(&list, &coveredPts, srcSpheres->index(i)); int numList = list.getSize(); for (int j = 0; j < numList; j++){ int pI = list.index(j); pointCounts.index(pI)++; } sphereCount.index(i) = numList; } // no point continuing if the points aren't all covered to start for (int i = 0; i < numPts; i++) if (!coveredPts.index(i)) return false; // make list of spheres that are removable Array<bool> removable(numSph); for (int i = 0; i < numSph; i++) removable.index(i) = isSphereRemovable(pointCounts, i); // flags for which spheres have been dumped Array<bool> removed(numSph); removed.clear(); // do reduction while (true){ // find "smallest" removable sphere int minI = -1; int minCount = INT_MAX; for (int i = 0; i < numSph; i++){ if (removable.index(i)){ int count = sphereCount.index(i); if (count < minCount){ minCount = count; minI = i; } } } // did we find a removable sphere if (minI < 0) break; OUTPUTINFO("Discarding Sphere %d\n", minI); // remove sphere removed.index(minI) = true; removable.index(minI) = false; // decrement counts for number of spheres covering the points Array<int> list; surRep->listContainedPoints(&list, NULL, srcSpheres->index(minI)); int numList = list.getSize(); for (int i = 0; i < numList; i++){ int pI = list.index(i); pointCounts.index(pI)--; } // check the spheres for removability for (int i = 0; i < numSph; i++){ bool *flag = &removable.index(i); if ((*flag) == true){ (*flag) = isSphereRemovable(pointCounts, i); } } } // generate indices inds->setSize(0); for (int i = 0; i < numSph; i++){ if (!removed.index(i)) inds->addItem() = i; } OUTPUTINFO("%d Spheres left\n", inds->getSize()); return (maxNum < 0) || (inds->getSize() <= maxNum); }
void VFAdaptive::adaptiveSample(Voronoi3D *vor, const MedialTester &mt, const SurfaceRep *coverRep, float maxErr, int maxSam, int maxSph, int minSph, const Sphere *filterSphere, const SEBase *eval, bool countOnlyCoverSpheres, int maxLoops){ if (maxErr < 0.0f) return; // find the worst approximated point float errSofar; findWorstSphere(vor, mt, eval, filterSphere, &errSofar, NULL, false); OUTPUTINFO("Initial Error Sofar : %f\n", errSofar); // label the vertices int numCover = mt.processMedial(vor, coverRep, filterSphere, countOnlyCoverSpheres); // work out maximum loops alowed if (maxLoops <= 0){ if (maxSam > 0) maxLoops = maxSam*3; else if (maxSph) maxLoops = maxSph*3; } // find the starting error int loop = 0; while (true){ loop++; // find the worst approximated point int numInt = 0; float worstD = -1; int worstI = findWorstSphere(vor, mt, eval, filterSphere, &worstD, &numInt, true); if (countOnlyCoverSpheres) numInt = numCover; if (worstI < 0){ // clear the ban flags and try again int numVert = vor->vertices.getSize(); for (int i = 0; i < numVert; i++){ Voronoi3D::Vertex *vert = &vor->vertices.index(i); if (filterSphere && !vert->s.overlap(*filterSphere)) continue; vor->resetFlag(vert); } // update medial/coverage spheres numCover = mt.processMedial(vor, coverRep, filterSphere); worstI = findWorstSphere(vor, mt, eval, filterSphere, &worstD, &numInt, true); if (worstI < 0) break; // nothing more we can do } // enable this to output POV files //saveSpheres(vor, mt, worstI); if ((loop %25) ==0) OUTPUTINFO("NumSpheres : %4d \tErr : %10.6f \terrSofar : %10.6f\n", numInt, worstD, errSofar); if (errSofar < 0) // first iteration to have some spheres errSofar = worstD; // is it worth continuing ?? if (worstD < maxErr && numInt > minSph) break; else if ((maxSam > 0 && vor->formingPoints.getSize()-9 >= maxSam*2) || (maxSph > 0 && numInt >= maxSph*2) || (maxLoops > 0 && loop > maxLoops)){ // normally we would wait until we get back down to the correct error // but this CAN mean the algorithm will NEVER terminate // so guard against that happening // remove BAD cover spheres i.e. those with error > minError sofar // otherwise this will cause major problems for Merge/Burst int numVerts = vor->vertices.getSize(); for (int i = 0; i < numVerts; i++){ Voronoi3D::Vertex *v = &vor->vertices.index(i); if (v->flag == VOR_FLAG_COVER){ float err = getErr(v, eval, &mt, vor); if (err > errSofar) v->flag = VOR_FLAG_EXTERNAL; } } break; } else if (worstD <= errSofar || worstD <= EPSILON_LARGE){ if (worstD > EPSILON_LARGE) errSofar = worstD; else errSofar = EPSILON_LARGE; if ((maxSam > 0 && vor->formingPoints.getSize()-9 >= maxSam) || (maxSph > 0 && numInt >= maxSph) || (maxLoops > 0 && loop > maxLoops)) break; } // flag the vertex so that we cannot consider it in the future // just in case the vertex isn't removed Voronoi3D::Vertex *v = &vor->vertices.index(worstI); mt.blockMedial(v); // get the closest surface point to the vertex Vector3D n; Point3D pClose; mt.closestPointNormal(&pClose, &n, v); // check if the new point will improve the approximation if (pClose.distanceSQR(v->s.c) > v->s.r*v->s.r) OUTPUTINFO("WARNING : the closest point is further away than it should be\n"); // add the point to the Voronoi diagram vor->insertPoint(pClose, n, worstI); // save off the results of adding the new sphere // uncomment this to save POV files //saveSpheres(vor, mt, -1); // update medial/coverage spheres numCover = mt.processMedial(vor, coverRep, filterSphere); } }
void STGGeneric::makeChildren(SphereTree *st, int node, int level, const SurfaceRep &surRep) const{ // get the error of the parent Sphere parS = st->nodes.index(node); double parErr = eval->evalSphere(parS); // get minimum bounding sphere for points to give to reducer Sphere boundingSphere; SFWhite::makeSphere(&boundingSphere, *surRep.getSurPts()); // generate the set of child spheres Array<Sphere> initChildren, children; reducer->getSpheres(&initChildren, st->degree, surRep, &boundingSphere, parErr); // do sphere refit - local optimisation if (useRefit){ OUTPUTINFO("Refitting\n"); SOPerSphere perSphere; perSphere.numIter = 3; perSphere.eval = eval; perSphere.optimise(&initChildren, surRep); } // apply optimiser if required if (optimiser && (maxOptLevel < 0 || level <= maxOptLevel)) optimiser->optimise(&initChildren, surRep, -1, &parS, level-1); // remove redundent spheres RELargest reLargest; if (!reLargest.reduceSpheres(&children, initChildren, surRep)) children.clone(initChildren); int numChildren = children.getSize(); if (numChildren == 0) return; // get the points that this node covers const Array<Surface::Point> *surPts = surRep.getSurPts(); int numPts = surPts->getSize(); // info for areas to be covered by each sphere Array<Array<Surface::Point> > subPts(numChildren); Array<bool> covered(numPts); covered.clear(); // make the divisions between the children SurfaceDivision surDiv; surDiv.setup(children, surPts); // do the children int firstChild = st->getFirstChild(node); for (int i = 0; i < numChildren; i++){ // get sphere Sphere s = children.index(i); // list the points in the sphere Array<int> listPoints; surRep.listContainedPoints(&listPoints, NULL, s, NULL); int numList = listPoints.getSize(); // filter points Array<Surface::Point> *filterPts = &subPts.index(i); filterPts->resize(0); for (int j = 0; j < numList; j++){ // get point int pI = listPoints.index(j); Surface::Point p = surPts->index(pI); // check if it's in the region if (surDiv.pointInRegion(p.p, i)){ covered.index(j) = true; filterPts->addItem() = p; } } } // count/cover uncovered points for (int i = 0; i < numPts; i++){ if (!covered.index(i)){ // get the point Point3D p = surPts->index(i).p; // find the closest sphere int closestJ = -1; float closestD = 0; for (int j = 0; j < numChildren; j++){ Sphere s = children.index(j); float d = p.distance(s.c) - s.r; if (d < closestD){ closestJ = j; closestD = d; } } subPts.index(closestJ).addItem() = surPts->index(i); } } // store spheres & recurse to children int childNum = firstChild; for (int i = 0; i < numChildren; i++){ if (subPts.index(i).getSize() > 1){ // recreate the sphere 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-1 && numChildren > 1){ const Array<Surface::Point> *pts = &subPts.index(i); // make cells to have 10 pts each, most will have alot more int numCells = pts->getSize() / PTS_PER_CELL; int gridDim = ceil(pow(numCells, 1.0 / 3.0)); OUTPUTINFO("numCells = %d, gridDim = %d\n", numCells, gridDim); // make children by recursion SurfaceRep subRep; subRep.setup(*pts, gridDim); makeChildren(st, childNum, level+1, subRep); } childNum++; } } // NULL out the rest of the spheres for (int i = childNum; i < st->degree; i++) st->initNode(firstChild+i, level+1); }
// 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;*/ } }