PLCRefiner.h

Go to the documentation of this file.
00001 #ifndef PLC_REFINER_HEADER
00002 #define PLC_REFINER_HEADER
00003 
00004 
00005 /***************************************************************************
00006  * Benoit Hudson (C) 2007.
00007  ***************************************************************************/
00008 
00009 #include "MeshConstructor.h"
00010 #include "MeshSet.h"
00011 #include "MeshTypes.h"
00012 #include "SplitData.h"
00013 #include "WorkItem.h"
00014 #include "WorkQueue.h"
00015 #include <boost/function_output_iterator.hpp>
00016 #include <delaunay/DelaunayHelpers.h>
00017 #include <io/PLC.h>
00018 #include <iterator>
00019 #include <refine-common/RefineConstants.h>
00020 #include <refine-common/Refiner.h>
00021 #include <topology/SimplicialHelpers.h>
00022 #include <utilities/OrderedHash.h>
00023 
00024 #if 0
00025 #define dprintf(...) printf(__VA_ARGS__);
00026 #else
00027 #define dprintf(...)
00028 #endif
00029 
00030 namespace SVR {
00031 
00032 /***************************************************************************
00033  * The refiner itself.
00034  *
00035  * Read <i>Hudson, Miller, Phillips 2006</i> to understand at a high level what
00036  * is going on here.
00037  *
00038  * The refiner has three main tasks:
00039  * -# initialization.  Create meshes for each dimension and link them up; then
00040  *    fill the work queue.  The creation work is mostly off-loaded to
00041  *    MeshConstructor, with the exception of encroachment fixing.
00042  * -# refinement.  While the work queue is non-empty, pop off the next element
00043  *    and process it.  The work queue is handled by the WorkQueue class.
00044  *    Much of the processing is handled by the ProtectedBall class.  There is
00045  *    some level of schizophrenia as to who handles what.
00046  * -# output.  Iterate over all the vertices ever created and output them;
00047  *    then, iterate over all the simplices in the top-level mesh and output
00048  *    them.  This is mostly handled in this very class.
00049  ***************************************************************************/
00050 template <size_t ambient>
00051 class PLCRefiner : public MeshRefiner {
00052 
00053   typedef Geometry::CenterRadius<ambient> CenterRadius;
00054   typedef Geometry::Point<ambient> Point;
00055   typedef ::MeshSet<ambient> MeshSet;
00056   typedef ::SplitData<ambient> SplitData;
00057   typedef ::WorkItem<ambient> WorkItem;
00058   typedef ::WorkQueue<ambient> WorkQueue;
00059   typedef typename MeshTypes<ambient>::Ball Ball;
00060   typedef typename MeshTypes<ambient>::Vertex Vertex;
00061   typedef typename MeshTypes<ambient>::GenericMesh GenericMesh;
00062   typedef typename Ball::BallSet BallSet;
00063   typedef typename Mesh<ambient, ambient>::Complex Complex;
00064   typedef typename Complex::Simplex Simplex;
00065   typedef typename Complex::OSimplex OSimplex;
00066   typedef typename Vertex::VertexUniqueList VertexUniqueList;
00067 
00068   const RefineConstants consts_;
00069 
00070   MeshSet meshes_; //<! A top-level mesh, and its lower-d submeshes.
00071   WorkQueue queue_; //<! Handle all the queues of protected balls.
00072   size_t nextID_; //<! Next ID to allocate for a vertex actually inserted into the mesh.
00073   unsigned nsimplices_; //<! Number of simplices in the top-dimensional mesh.  I keep this only because it saves me one pass over the mesh during output.
00074   std::vector<Vertex*> bbox_corners_;
00075 
00076   hudson::SmallList<Simplex> simplices_out_;
00077 
00078   unsigned niterations_; //<! Number of iterations of the main loop so far.
00079   unsigned message_niterations_; //<! Print a progress message at this iteration.
00080 
00081   private:
00082   Mesh<ambient,ambient> *getTopMesh() {
00083     return meshes_.getTopMesh();
00084   }
00085   const Mesh<ambient,ambient> *getTopMesh() const {
00086     return meshes_.getTopMesh();
00087   }
00088 
00089   public:
00091   size_t getID(const Vertex *v) const {
00092     return v->getID();
00093   }
00094   void setID(Vertex *v) {
00095     v->setID(nextID_++);
00096   }
00097 
00098 
00099   /***************************************************************************
00100    * Initialize a refiner.
00101    *
00102    * This is a static function instead of a constructor to allow munging the
00103    * constants a bit.  See the constructor for details.
00104    ***************************************************************************/
00105   public:
00106   static PLCRefiner *initialize(const SVR_IO::PLC *plc,
00107       RefineConstants consts) {
00108     consts.regularize(ambient, false);
00109     return new PLCRefiner(plc, consts);
00110   }
00111 
00112   /***************************************************************************
00113    * Initialize the set of meshes and the work queue, given the PLC.
00114    *
00115    * We use MeshConstructor to do most of the work of actual initialization.
00116    * We then use MC again to iterate over all the protected balls in the mesh,
00117    * and throw them into the queue.
00118    *
00119    * Finally, we initialize the variables we use during output.
00120    ***************************************************************************/
00121   private:
00122   PLCRefiner(const SVR_IO::PLC *plc, const RefineConstants& consts)
00123     : consts_(consts)
00124   {
00125     /* Build the meshes in each dimension, linking up their protective balls. */
00126     dprintf("Init from PLC\n");
00127     MeshConstructor<ambient>::construct(plc, consts_.rho, meshes_);
00128 
00129     /* Make an output iterator that calls addToQueues; then invoke it to run on
00130      * every ball in any dimension. */
00131     dprintf("Filling queues\n");
00132     meshes_.outputAllBalls(
00133         boost::make_function_output_iterator (
00134           std::bind1st(
00135             std::mem_fun( &PLCRefiner::checkBall )
00136             , this)
00137           )
00138         );
00139     Simplicial::collectVertices(
00140         getTopMesh()->getSimplicialComplex(),
00141         boost::make_function_output_iterator (
00142           std::bind1st(
00143             std::mem_fun( &PLCRefiner::checkVertex )
00144             , this)
00145           )
00146         );
00147     vector<Vertex*> verts;
00148     Simplicial::collectVertices(getTopMesh()->getSimplicialComplex(), verts);
00149     bbox_corners_.reserve(verts.size() - 1);
00150     BOOST_FOREACH(Vertex *v, verts) {
00151       if (v->getCD() == ambient) {
00152         bbox_corners_.push_back(v);
00153       }
00154     }
00155 
00156     /* Count the number of top-dimensional simplices. */
00157     dprintf("Counting top-dimensional balls\n");
00158     nsimplices_ = meshes_.template outputSomeBalls<ambient>(hudson::count_iterator<Ball*>(0));
00159     dprintf("  %u\n", nsimplices_);
00160 
00161     /* Find the next free ID to assign. */
00162     dprintf("Counting vertices\n");
00163     nextID_ = meshes_.getVertices().size() + plc->getFirstID(0);
00164 
00165     /* No iterations so far. */
00166     niterations_ = 0;
00167     message_niterations_ = 1;
00168   }
00169 
00172   private:
00173   struct EncroachmentChecker {
00174     WorkQueue *queue_;
00175     EncroachmentChecker(WorkQueue *q): queue_(q) {}
00176     void operator() (Ball *b) {
00177       BallSet uppers;
00178       b->gatherUppers(uppers);
00179       BOOST_FOREACH(Ball *up, uppers) {
00180         VertexUniqueList verts;
00181         up->gatherVertices(verts);
00182         BOOST_FOREACH(Vertex *v, verts) {
00183           if (b->encroachedBy(v)) {
00184             queue_->push( new typename WorkItem::Encroached(b) );
00185           }
00186         }
00187       }
00188     }
00189   };
00190 
00191   void fixInitialEncroachment() {
00192     WorkItem *item;
00193     EncroachmentChecker echeck(&queue_);
00194     meshes_.outputAllBalls(boost::make_function_output_iterator(echeck));
00195     dprintf("Start fixing initial encroachments.\n");
00196     while( (item = queue_.pop()) ) {
00197       if (item->getReason() > WorkItem::ENCROACHED) {
00198         /* Done dealing with initial encroachment. */
00199         queue_.push(item);
00200         break;
00201       } else {
00202         SplitData sdata(consts_);
00203         split(item, sdata);
00204         BOUNDED_FOREACH(Ball *b, sdata.begin_born(), sdata.end_born()) {
00205           echeck(b);
00206         }
00207       }
00208     }
00209     dprintf("Done fixing initial encroachments.\n");
00210   }
00211 
00212   friend class CheckFinal;
00213   struct CheckFinal {
00214     PLCRefiner *svr_;
00215     bool isGood;
00216     CheckFinal(PLCRefiner *svr): svr_(svr), isGood(true) { }
00217     void operator() (Ball *b) {
00218       WorkItem *w = svr_->classify(b);
00219       if (w) {
00220         fprintf(stderr, "Checking: bad simplex causes %s\n", w->toString().c_str());
00221         isGood = false;
00222       }
00223     }
00224   };
00225 
00226   void finalCheck() {
00227     CheckFinal final_mesh(this); // name chosen to make the assertion pretty
00228     meshes_.outputAllBalls(boost::make_function_output_iterator(final_mesh));
00229     assert(final_mesh.isGood);
00230   }
00231 
00232   /***************************************************************************
00233    * Run the SVR algorithm.
00234    *
00235    * First, we eliminate initial encroachment.  The published algorithm
00236    * requires that there be no initial encroachment, but we can easily fix them.
00237    * We lose runtime guarantees when we do this, but in practice it should be
00238    * fast on almost all inputs.
00239    *
00240    * Next, we iterate over the work queue until it is done.  This is the core of
00241    * SVR.
00242    *
00243    * At the end, we optionally remove all simplices that are outside the shape;
00244    * it had better be watertight if we try.
00245    *
00246    * Unless NDEBUG is on, we also iterate over all simplices and make sure we
00247    * didn't forget to do any work.
00248    ***************************************************************************/
00249   public:
00250   virtual void refine() {
00251     dprintf("Refining\n");
00252 
00253     fixInitialEncroachment();
00254 
00255     WorkItem *w;
00256     while( (w = queue_.pop()) ) {
00257       SplitData sdata(consts_);
00258       split(w, sdata);
00259     }
00260 
00261     if (consts_.cleanup) {
00262       cleanup();
00263     }
00264 
00265 #ifndef NDEBUG
00266     finalCheck();
00267 #endif
00268 
00269     printStats();
00270   }
00271 
00272   /***************************************************************************
00273    * Print some basic statistics.
00274    ***************************************************************************/
00275   public:
00276   void printStats() {
00277     printf("Output size %u simplices\n", nsimplices_);
00278   }
00279 
00280 
00281   /***************************************************************************
00282    * Basic SVR operation: process a work item.
00283    *
00284    * The work of this operation is divided.  The work item farms out the work
00285    * of finding a point to insert to the ball or vertex we must split, and
00286    * performs the Delaunay insertion, and updates the point location structures.
00287    *
00288    * This class does the work of finding new work to do based on the new
00289    * structures: we check for encroachment, skinnyness, etc.  Not published in
00290    * the 2006 IMR paper: we also deal with new vertices on the boundary and push
00291    * them up to higher dimensions immediately as the need arises.
00292    ***************************************************************************/
00293   public:
00294   void split(WorkItem *w, SplitData& sdata) {
00295     niterations_++;
00296     if (niterations_ >= message_niterations_) {
00297       printf("Iteration %u, we have %u simplices so far\n", niterations_,
00298           nsimplices_);
00299       message_niterations_ *= 2;;
00300     }
00301     dprintf("Iteration %u: %s (%s)\n", niterations_,
00302         w->isActive() ? "*splitting*" : "moot",
00303         w->toString().c_str());
00304 
00305     /* First, check if w is still active. */
00306     if (!w->isActive()) {
00307       delete w;
00308       return;
00309     }
00310 
00311     size_t topo = w->topological();
00312     bool didsplit = w->split(sdata);
00313 
00314     /* If we encroached, push the encroached items on the queue. */
00315     BOUNDED_FOREACH(Ball *encroached, sdata.begin_encroached(), sdata.end_encroached()) {
00316       queue_.push( new typename WorkItem::Encroached(encroached) );
00317     }
00318 
00319     /* If we actually did split, do all sorts of new work.  TODO factor this out. */
00320     if (didsplit) {
00321 
00322       /* If the vertex is new, set its ID and add to the list of vertices.  */
00323       Vertex *inserted = sdata.getVertex();
00324       bool isnew = inserted->getCD() == topo;
00325       if (isnew) {
00326         meshes_.add(inserted);
00327         setID(inserted);
00328         dprintf("  %s is a new vertex in dimension %u at %s\n",
00329             inserted->toString().c_str(), unsigned(inserted->getCD()),
00330             inserted->toPoint().toString().c_str());
00331       }
00332 
00333       /* If we inserted the vertex into the top-d mesh, check if it's crowded. */
00334       if (topo == ambient) {
00335         checkVertex(inserted);
00336       }
00337 
00338       /* Look at the top-d uppers, possibly push their vertices if they are
00339        * now crowded and weren't before (TODO: I just push if they're crowded
00340        * now, regardless whether they were before) */
00341       if (topo < ambient && isnew) {
00342         BallSet uppers;
00343         VertexUniqueList vset;
00344         BOUNDED_FOREACH(Ball *killed, sdata.begin_killed(), sdata.end_killed()) {
00345           killed->gatherUppers(uppers);
00346         }
00347         BOOST_FOREACH(Ball *upper, uppers) {
00348           if (upper->topological() != ambient) { continue; }
00349           upper->gatherVertices(vset);
00350         }
00351         BOOST_FOREACH(Vertex *upv, vset) {
00352           checkVertex(upv);
00353         }
00354       }
00355 
00356       /* Look at one of the simplices we split (any of them), call it s.
00357        * Look at the higher-d meshes that know about s.  For each upper
00358        * mesh m, if all of the vertices of s appear in m, add a new workqueue
00359        * item for an arbitrary s' in m telling it to split at v. */
00360       if (topo < ambient && isnew) {
00361         Ball *s = *sdata.begin_killed();
00362         // compute the uppers, split them up by mesh
00363         BallSet alluppers;
00364         hudson::OrderedHashSet<const GenericMesh*, hudson::HashPointer<GenericMesh> > meshes;
00365         hudson::FastHashMap<const GenericMesh*, BallSet, hudson::HashPointer<GenericMesh> > uppers;
00366         s->gatherUppers(alluppers);
00367         BOOST_FOREACH(Ball *upper, alluppers) {
00368           const GenericMesh *m = upper->getMesh();
00369           if (m->topological() == ambient) { continue; }
00370           uppers[m].insert(upper);
00371           meshes.insert(m);
00372         }
00373         VertexUniqueList verts;
00374         s->gatherVertices(verts);
00375         BOOST_FOREACH(const GenericMesh *m, meshes) {
00376           dprintf("  checking for immediate inclusion in %u-mesh[%p]...",
00377               m->topological(), m);
00378           VertexUniqueList mverts;
00379           BOOST_FOREACH(Ball *upper, uppers[m]) {
00380             upper->gatherVertices(mverts);
00381           }
00382           // check if s has all verts resolved
00383           bool allresolved = true;
00384           BOOST_FOREACH(Vertex *v, verts) {
00385             if (!mverts.has(v)) {
00386               dprintf("no\n");
00387               allresolved = false;
00388               break;
00389             }
00390           }
00391           if (allresolved) {
00392             // Find a simplex to blame.  The 'uppers' set is unrobust, but at
00393             // least one will be robustly good, so find it.
00394             Ball *topush = NULL;
00395             BOOST_FOREACH(Ball *upper, uppers[m]) {
00396               if (upper->inSphereExact(inserted)) {
00397                 topush = upper;
00398                 break;
00399               }
00400             }
00401             dprintf("split at %s\n", topush->toString().c_str());
00402             assert(topush);
00403             queue_.push( new typename WorkItem::NewBoundaryVertex(topush, inserted) );
00404           }
00405         }
00406       }
00407 
00408       /* Look at the new simplices, classify them, and possibly push them on the
00409          work queue skinny or sliver. */
00410       BOUNDED_FOREACH(Ball *newborn, sdata.begin_born(), sdata.end_born()) {
00411         checkBall(newborn);
00412       }
00413 
00414       /* Update the count of simplices. */
00415       if (topo == ambient) {
00416         nsimplices_ += sdata.nborn();
00417         nsimplices_ -= sdata.nkilled();
00418         dprintf("There are now %u simplices\n", unsigned(nsimplices_));
00419       }
00420 
00421       // TODO: put this somewhere useful
00422 #if 0
00423       /* Animation hack: print out every triangle that's all the same feature. */
00424       if (topo == ambient && inserted->getCD() < ambient) {
00425         animation_print();
00426       }
00427 #endif
00428     }
00429 
00430     /* Finally, if the work item is still active, push it back on.
00431        If not, delete it. */
00432     if (w->isActive()) {
00433       queue_.push(w);
00434     } else {
00435       delete w;
00436     }
00437   }
00438 
00439 
00440   /***************************************************************************
00441     * Printing, in my own special little format easy to perlify into other formats.
00442    ***************************************************************************/
00443   typedef std::pair<boost::array<unsigned, ambient>, unsigned> face_type;
00444   struct animator {
00445     hashers::hash_map<Vertex*, unsigned, hudson::hash_by_cast<Vertex*> > ids;
00446     hashers::hash_map<const GenericMesh*, unsigned, hudson::hash_by_cast<const GenericMesh*> > colours;
00447 
00448     std::vector<Vertex*> verts;
00449     std::vector<face_type> faces;
00450     const Complex& c;
00451 
00452     animator(const Complex& c) : c(c) { }
00453 
00454     static bool canEnter(const Simplex&) { return true; }
00455 
00456     bool choose(const Simplex& s) {
00457       OSimplex os = c.orientSimplex(s);
00458       for(unsigned i = 0; i <= ambient; ++i) { // for each of d+1 vertices of s
00459         processFace(c.getFace(i, os));
00460       }
00461       return false;
00462     }
00463 
00464     void processFace(const OSimplex& fi) {
00465       // Collect the intersection set of meshes that contain these points.
00466       // This uses the assumption that the meshes are stored in sorted order.
00467       std::vector<const GenericMesh*> meshes;
00468       std::copy(fi[0]->begin_uppers(ambient-1), fi[0]->end_uppers(ambient-1),
00469           std::back_inserter(meshes));
00470       for(unsigned j = 1; j < ambient; ++j) { // for each of d vertices of fi
00471         std::vector<const GenericMesh*> tmp;
00472         std::set_intersection(meshes.begin(), meshes.end(),
00473             fi[j]->begin_uppers(ambient - 1), fi[j]->end_uppers(ambient - 1),
00474             std::back_inserter(tmp));
00475         meshes.swap(tmp);
00476       }
00477       assert(meshes.size() == 0 || meshes.size() == 1);
00478       if (!meshes.empty()) {
00479         face_type face;
00480         for(unsigned j = 0; j < ambient; ++j) {
00481           face.first[j] = getVertexID(fi[j]);
00482         }
00483         face.second = getMeshColour(meshes[0]);
00484         faces.push_back(face);
00485       }
00486     }
00487     unsigned getVertexID(Vertex *v) {
00488       if(ids.find(v) == ids.end()) {
00489         unsigned id = ids.size();
00490         ids[v] = id;
00491         verts.push_back(v);
00492       }
00493       return ids[v];
00494     }
00495 
00496     unsigned getMeshColour(const GenericMesh *m) {
00497       if (colours.find(m) == colours.end()) {
00498         unsigned col = colours.size();
00499         colours[m] = col;
00500       }
00501       return colours[m];
00502     }
00503   };
00504 
00505 
00506   void animation_print() {
00507     /* Collect the faces. */
00508     const Complex& c = getTopMesh()->getSimplicialComplex();
00509     animator anim(c);
00510     c.dfsBySimplex(anim, c.getHandle());
00511     assert(ambient == 3);
00512 
00513     unsigned nvertices = anim.verts.size();
00514     unsigned nfaces = anim.faces.size();
00515     FILE *out;
00516 
00517     {
00518       char buffer[4096];
00519       snprintf(buffer, sizeof(buffer), "faces-%u.off", nvertices);
00520       out = fopen(buffer, "w");
00521     }
00522     assert(out);
00523 
00524     /* .off format */
00525     fprintf(out, "%u %u 0\n", nvertices, nfaces);
00526 
00527     BOOST_FOREACH(const Vertex *v, anim.verts) {
00528       Point p = v->toPoint();
00529       fprintf(out, "%g %g %g\n", p[0], p[1], p[2]);
00530     }
00531     BOOST_FOREACH(face_type face, anim.faces) {
00532       // three vertices, plus the colour.
00533       fprintf(out, "3 %u %u %u %u\n", face.first[0], face.first[1], face.first[2], face.second);
00534     }
00535     fclose(out);
00536   }
00537 
00538   /***************************************************************************
00539     * Cleanup after meshing: remove the exterior.
00540    ***************************************************************************/
00541   void cleanup() {
00542     bool watertight = MeshCleaner<ambient,ambient>::clean(
00543         getTopMesh()->getDelaunayDangerously(),
00544         bbox_corners_.begin(), bbox_corners_.end(),
00545         &simplices_out_);
00546 
00547     if (!watertight) {
00548       nsimplices_ = 0;
00549     } else {
00550       nsimplices_ = std::distance(simplices_out_.begin(), simplices_out_.end());
00551     }
00552 
00553     // In a perfect world, delete the excess vertices now.  Instead, I just
00554     // leak them.
00555   }
00556 
00557   /***************************************************************************
00558    ** Printing the top-dimensional mesh.
00559    ** TODO: print lower-dimensional ones (for debugging) also.
00560    ***************************************************************************/
00561   private:
00562   friend struct DoPrintSimplex;
00564   struct DoPrintSimplex {
00565     size_t n_;
00566     FILE *out_;
00567     const PLCRefiner *svr_;
00568     typedef typename Mesh<ambient, ambient>::Simplex Simplex;
00569 
00570     DoPrintSimplex(const PLCRefiner *svr, FILE *out): n_(0), out_(out), svr_(svr) { }
00571     static bool canEnter(const Simplex&) { return true; }
00572     bool choose(const Simplex& s) {
00573       boost::array<size_t, ambient + 1> arr;
00574       for (size_t i = 0; i <= ambient; ++i) {
00575         arr[i] = svr_->getID(s[i]);
00576       }
00577       Delaunay::printEle(n_++, arr, out_);
00578       return false;
00579     }
00580   };
00581 
00584   template <class v_iterator> void printVerts(FILE *node, v_iterator begin, v_iterator end) const {
00585     while (begin != end) {
00586       Vertex *v = *begin;
00587       ++begin;
00588       Delaunay::printPoint(getID(v), v->toPoint(), node);
00589     }
00590   }
00591 
00592   public:
00597   virtual void printToNodeEle(FILE *node, FILE *ele) const {
00598     /* print the .node file */
00599     fprintf(node, "%u %u 0 0\n", (unsigned)meshes_.getVertices().size(), unsigned(ambient));
00600     printVerts(node, meshes_.getVertices().begin(), meshes_.getVertices().end());
00601 
00602     /* print the .ele file */
00603     fprintf(ele, "%u %u 0\n", unsigned(nsimplices_), unsigned(ambient + 1));
00604     DoPrintSimplex dps(this, ele);
00605     if (consts_.cleanup) {
00606       BOOST_FOREACH(const Simplex& s, simplices_out_) {
00607         dps.choose(s);
00608       }
00609     } else {
00610       const Complex& c = getTopMesh()->getSimplicialComplex();
00611       c.dfsBySimplex(dps, c.getHandle());
00612     }
00613   }
00614 
00615 
00616   /***************************************************************************
00617     * Classify a ball's reason to be added to the work queue.
00618     * The reason may be NONE, in which case we won't add it.
00619    ***************************************************************************/
00620   private:
00621   WorkItem *classify(Ball *b) const {
00622     /* Assume unencroached; we check elsewhere. */
00623 
00624     double re2 = b->radiusEdge2();
00625     if (re2 > consts_.rhoprime * consts_.rhoprime) {
00626       return new typename WorkItem::VerySkinny(b);
00627     }
00628 
00629     if (consts_.sigma != 0.0 && b->topological() >= 3) {
00630       double sigma = b->computeSigma();
00631       if (sigma < consts_.sigma) {
00632         return new typename WorkItem::Sliver(b);
00633       }
00634     }
00635 
00636     if (re2 > consts_.rho * consts_.rho) {
00637       return new typename WorkItem::MediumSkinny(b);
00638     }
00639 
00640     /* Check if the simplex is supposed to be represented in the global mesh;
00641      * if so, and it's not, complain about that. */
00642     if (!b->isResolved()) {
00643       return new typename WorkItem::Unresolved(b);
00644     }
00645 
00646     return NULL;
00647   }
00648 
00649   /***************************************************************************
00650    * Check if a ball needs to be added to the work queue; if so, add it.
00651    ***************************************************************************/
00652   void checkBall (Ball *b) {
00653     WorkItem *w = classify(b);
00654     if (w) {
00655       queue_.push(w);
00656     }
00657   }
00658 
00660   void checkVertex (Vertex *v) {
00661     if (v->isCrowded(getTopMesh())) {
00662       if (v->getCD() == ambient) {
00663         queue_.push( new typename WorkItem::CrowdedSteiner(v, getTopMesh()) );
00664       } else {
00665         queue_.push( new typename WorkItem::CrowdedInput(v, getTopMesh()) );
00666       }
00667     }
00668   }
00669 
00670   bool isActive(const WorkItem *item) const {
00671     if (!item->isBall()) {
00672       return item->getVertex()->isCrowded(getTopMesh());
00673     } else {
00674       Ball *b = item.getBall();
00675       if (!b->isLive()) { return false; }
00676       if (item.getReason() == WorkQueue::UNRESOLVED) {
00677         return !isResolved(b);
00678       }
00679       return true;
00680     }
00681   }
00682 
00683 }; // class SVR::FeatureRefiner<d>
00684 } // namespace SVR
00685 
00686 #undef dprintf
00687 
00688 
00689 #endif

Generated on Thu Mar 27 19:04:14 2008 by  doxygen 1.4.6