conformalmesher.C

Go to the documentation of this file.
00001 
00006 #ifdef HAVE_CONFIG_H
00007 #include <tumble-conf.h>
00008 #endif /* HAVE_CONFIG_H */
00009 
00010 #include "conformalmesher.h"
00011 
00012 #include "beziermesh.h"
00013 #include "boundarymesh.h"
00014 #include "cell.h"
00015 #include "globals.h"
00016 #include "iterator_wrapper.h"
00017 #include "spline.h"
00018 
00019 #include <algorithm>
00020 #include <stack>
00021 
00022 
00023 /* Turn on verbose messages from the conformal mesher */
00024 //#define DEBUG_CONF_MESHER
00025 
00026 #ifdef DEBUG_CONF_MESHER
00027   #include "meshio.h"
00028 #endif
00029 
00030 using namespace std;
00031 using namespace hashers;
00032 
00033 class ConformalMesher::Subspline {
00034   public:
00035     Subspline(BoundaryEdge *bdrye, BezierVertex *v0, BezierVertex *v1) :
00036       bdrye_(bdrye) {
00037         v_[0] = v0;
00038         v_[1] = v1;
00039       }
00040 
00041     /* for O(1) destruction without leaking memory. */
00042     void set_delete_iterator(std::list<Subspline*>::iterator it) {
00043       delete_iterator = it;
00044     }
00045     list<Subspline*>::iterator get_delete_iterator() {
00046       return delete_iterator;
00047     }
00048 
00049     BezierVertex *get_vertex(int i) {
00050       assert(i >= 0); assert(i < 2);
00051       return v_[i];
00052     }
00053     const BezierVertex *get_vertex(int i) const {
00054       return const_cast<Subspline*>(this)->get_vertex(i);
00055     }
00056 
00057     const BezierVertex *get_other_vertex(BezierVertex *v) const {
00058       if(get_vertex(0) == v) {
00059         return get_vertex(1);
00060       } else {
00061         assert(get_vertex(1) == v);
00062         return get_vertex(0);
00063       }
00064     }
00065 
00066     const QBSpline *get_spline() const { return bdrye_->get_spline(); }
00067     QBSpline *get_spline() { return bdrye_->get_spline(); }
00068 
00069     const Point2D& get_deboor() const {
00070       int idx = get_segment_index();
00071       return *get_spline()->get_deboor(idx + 1); /* segment 0 has deboor 1 */
00072     }
00073 
00074     BezierVertex *split(BezierMesh *mesh, vector<Subspline*>& subs) {
00075       /* split the spline; return two new subsplines.
00076          the caller is responsible for deleting this subspline */
00077       int idx = get_segment_index();
00078       ControlPoint cp[3];
00079       ControlPoint newpt;
00080 
00081       get_spline()->split(idx, 0.5, cp[0], cp[1], cp[2]);
00082       newpt = cp[1]; /* we ignore cp[0] and cp[2] */
00083 
00084       BezierVertex *splitvertex = mesh->clean_insert_point(*newpt);
00085       splitvertex->set_bdry(bdrye_, idx + 1);
00086       mesh->replace_control_point(splitvertex, newpt);
00087 
00088       /* order of the vertices is important */
00089       subs.push_back(new Subspline(bdrye_, get_vertex(0), splitvertex));
00090       subs.push_back(new Subspline(bdrye_, splitvertex, get_vertex(1)));
00091 
00092       return splitvertex;
00093     }
00094 
00095     /* check if the vertex encroaches on us */
00096     bool is_encroached(BezierVertex *v) const {
00097       int idx = get_segment_index();
00098       /* '2' here is the degree of the curve: segment 0 starts
00099        * at b[0] and goes until b[2]. */
00100       Tumble::iterators::dereferencer<typeof(get_spline()->b.begin()), Point2D,
00101     const Point2D&>
00102        first(get_spline()->b.begin() + 2 * idx),
00103        last (get_spline()->b.begin() + 2 * (idx + 1));
00104       return BezierEdge::encroaches(v->get_cp(), first, ++last);
00105     }
00106 
00111     int get_segment_index() const {
00112       if(get_vertex(0)->containment_dimension() == 0) {
00113         /* our left vertex is a D0 vertex? then we're the first segment */
00114         return 0;
00115       }
00116       else {
00117         int idx = get_spline()->get_bezier_vertex_idx(get_vertex(0));
00118         assert(idx > 0); assert(idx < get_spline()->get_num_segments());
00119         return idx;
00120       }
00121     }
00122 
00123 
00124   private:
00125     BoundaryEdge *bdrye_;
00126     BezierVertex *v_[2];
00127     list<Subspline*>::iterator delete_iterator;
00128 };
00129 
00130 #ifdef DEBUG_CONF_MESHER
00131 static ostream& operator<<(ostream& os, ConformalMesher::Subspline *s) {
00132   return os << (void*)s << " [spline: " << (s->get_spline()) << " => "
00133     << s->get_vertex(0) << " to " << s->get_vertex(1)
00134     << " via " << s->get_deboor() << ']';
00135 }
00136 #endif
00137 
00138 /***************************************************************************
00139   ...
00140  ***************************************************************************/
00141 ConformalMesher::ConformalMesher(BezierMesh* _bezier_mesh,
00142                                  BoundaryMesh* _bdry_mesh)
00143 {
00144   bezier = _bezier_mesh;
00145   bdry = _bdry_mesh;
00146 }
00147 
00148 /***************************************************************************
00149   Delete all the subsplines.
00150  ***************************************************************************/
00151 ConformalMesher::~ConformalMesher()
00152 {
00153   for(list<Subspline*>::iterator it = subsplines.begin();
00154       it != subsplines.end(); ++it) {
00155     delete (*it);
00156   }
00157 }
00158 
00159 
00160 /***************************************************************************
00161   The main method to build a conformal mesh.  Simply passes off the work
00162   to others.
00163  ***************************************************************************/
00164 void ConformalMesher::mesh()
00165 {
00166 #ifdef DEBUG_CONF_MESHER
00167   cout << "ConformalMesher: starting.\n";
00168 #endif
00169   /* everything is linear at the start; allow the mesh to assume so */
00170   bezier->set_linear_flips(true);
00171 
00172   create_bbox();
00173   insert_d0_vertices();
00174   create_subsplines();
00175   conform();
00176   reticulate_splines();
00177 
00178   /* The mesh now is fully built; we're down to painting. */
00179 #ifdef DEBUG_CONF_MESHER
00180   cout << "ConformalMesher: done building; mesh size "
00181     << bezier->get_num_faces() << endl;
00182   cout<<"BezierMesh:"<<endl;
00183   bezier->print_statistics();
00184 #endif
00185   bezier->set_linear_flips(false);
00186 
00187   set_face_pointers();
00188   excavate_holes();
00189   cout << "ConformalMesher: done.\n";
00190   cout<<"************ Statistics (make sure these add up) ****************"<<endl;
00191   cout<<"BoundaryMesh:"<<endl;
00192   bdry->print_statistics();
00193   cout<<"BezierMesh:"<<endl;
00194   bezier->print_statistics();
00195 }
00196 
00197 /***************************************************************************
00198   Create a bounding box and triangulate it.
00199  ***************************************************************************/
00200 void ConformalMesher::create_bbox()
00201 {
00202 #ifdef DEBUG_CONF_MESHER
00203   cout << "ConformalMesher: building bbox" << flush;
00204 #endif
00205   /* [x][y] -- so [0][1] is the top-left, [1][0] bottom-right */
00206   Point2D p[2][2];
00207   BezierVertex *v[2][2];
00208   BezierEdge *e[5]; /* 4 outside, 1 cross edge */
00209   double diameter;
00210 
00211   bdry->bbox(p[1][1], p[0][0]);
00212   p[1][0] = Point2D(p[1][1].x(), p[0][0].y());
00213   p[0][1] = Point2D(p[0][0].x(), p[1][1].y());
00214 
00215   /* Grow the v such that there is no way that the exterior is
00216      introducing a small feature. */
00217   diameter = (p[0][0]-p[1][1]).mag();
00218   p[0][0] += Point2D(-diameter, -diameter);
00219   p[0][1] += Point2D(-diameter,  diameter);
00220   p[1][0] += Point2D( diameter, -diameter);
00221   p[1][1] += Point2D( diameter,  diameter);
00222   cout << " bottom-left: " << p[0][0] << " top-right " << p[1][1] << endl;
00223 
00224   /* Create the vertices. */
00225   for(int i = 0; i < 2; i++) {
00226     for(int j = 0; j < 2; j++) {
00227       v[i][j] = bezier->add_bezier_vertex(p[i][j]);
00228     }
00229   }
00230 
00231   /* Create the exterior and the one cross edge. */
00232   e[0] = bezier->add_straight_bezier_edge(v[0][0], v[0][1]);
00233   e[1] = bezier->add_straight_bezier_edge(v[0][0], v[1][0]);
00234   e[2] = bezier->add_straight_bezier_edge(v[1][1], v[0][1]);
00235   e[3] = bezier->add_straight_bezier_edge(v[1][1], v[1][0]);
00236   e[4] = bezier->add_straight_bezier_edge(v[0][0], v[1][1]);
00237 
00238   /* Create the two faces, in ccw order. */
00239   bezier->add_bezier_triangle(NULL, e[4], e[2], e[0]); //CCW: tp517 4/16/07
00240   bezier->add_bezier_triangle(NULL, e[4], e[1], e[3], true); // CCW: tp517 4/16/07
00241 
00242   /* The mesh is now Delaunay.  Remember the need to excavate the
00243    * exterior face when we're done. */
00244   remove_points.push_back(p[0][0]);
00245 
00246 #ifdef DEBUG_CONF_MESHER
00247   bezier->check_consistency();
00248 #endif
00249 }
00250 
00251 /***************************************************************************
00252   Insert the D0 vertices (input vertices).
00253   Just vanilla insertions; should be random but we the meshes are assumed
00254   to be small.
00255  ***************************************************************************/
00256 void ConformalMesher::insert_d0_vertices()
00257 {
00258 #ifdef DEBUG_CONF_MESHER
00259   cout << "ConformalMesher: inserting D0 vertices\n";
00260 #endif
00261   for(BoundaryMesh::Boundary_Vertex_Hash_T::iterator it = bdry->get_vertexs_begin();
00262       it != bdry->get_vertexs_end(); ++it) {
00263     BoundaryVertex *bdryv = (*it);
00264     BezierVertex *bezv = bezier->clean_insert_point(bdryv->get_cp());
00265     bezv->set_bdry(bdryv);
00266     bezier->replace_control_point(bezv, bdryv->get_control_point());
00267 
00268 #ifdef DEBUG_CONF_MESHER
00269     cout << "ConformalMesher:     - inserted " << (void*)bezv
00270       << " at " << bezv->get_cp() << endl;
00271 #endif
00272   }
00273 
00274 #ifdef DEBUG_CONF_MESHER
00275   bezier->check_consistency();
00276 #endif
00277 }
00278 
00279 /***************************************************************************
00280   Create the splines:
00281   - insert D1 vertices (the knots)
00282   - create Subsplines and put them on the stack
00283  ***************************************************************************/
00284 void ConformalMesher::create_subsplines()
00285 {
00286 #ifdef DEBUG_CONF_MESHER
00287   cout << "ConformalMesher: inserting D1 vertices, storing splines\n";
00288 #endif
00289   for(BoundaryMesh::Boundary_Edge_Hash_T::iterator it = bdry->get_edges_begin();
00290       it != bdry->get_edges_end(); ++it) {
00291     BoundaryEdge *bdrye = (*it);
00292     QBSpline *spline = bdrye->get_spline();
00293     vector<BezierVertex*> knots;
00294 
00295 #ifdef DEBUG_CONF_MESHER
00296     vector<BezierTriangle*> inverts;
00297 #endif
00298 
00299     /* Incrementally add every d1 vertex of the spline; store
00300      * all the d0 and d1 vertices, correctly indexed, in 'knots'.
00301      */
00302     knots.push_back(bdrye->get_vertex(0)->get_bezier());
00303     for (int i = 1; i <= spline->get_num_segments() - 1; i++) {
00304       ControlPoint cp = spline->get_control_point_at_idx(i);
00305       BezierVertex *bezv = bezier->clean_insert_point(*cp);
00306 
00307 #ifdef DEBUG_CONF_MESHER
00308       cout << "ConformalMesher:     - inserting " << cp << "... " << flush;
00309       bezier->find_inverted_triangles(inverts);
00310       if (!inverts.empty())
00311     {
00312       cout<< " INVERTED TRIANGLES FOUND IN CONF_MESHER "<<endl;
00313       cout<< " Just inserted : "<<cp<<endl;
00314       for (vector<BezierTriangle*>::iterator i = inverts.begin();
00315            i != inverts.end(); ++i)
00316         cout << "Inverted Triangle: "<<(**i)<<endl;
00317       MeshBinaryOutput mo(bezier,bdry);
00318       mo.write("created_inverted_during_create_subsplines.geo");
00319       assert(0);
00320     } else {
00321       cout << "Conformal mesher inversion check passed."<<endl;
00322     }
00323 #endif
00324 
00325       bezier->replace_control_point(bezv, cp);
00326       bezv->set_bdry(bdrye, i);
00327       knots.push_back(bezv);
00328 
00329       spline->set_bezier_vertex(i, knots.back());
00330 
00331     }
00332     knots.push_back(bdrye->get_vertex(1)->get_bezier());
00333     assert((unsigned)knots.size() == (unsigned)spline->get_num_segments() + 1);
00334 
00335     /* Create every subspline but don't put them in the mesh yet. */
00336     for (int i = 0; i < spline->get_num_segments(); i++) {
00337       Subspline *s = new Subspline(bdrye, knots[i], knots[i+1]);
00338       link_edge(s);
00339     }
00340   }
00341 #ifdef DEBUG_CONF_MESHER
00342   bezier->check_consistency();
00343 #endif
00344 }
00345 
00346 
00347 /***************************************************************************
00348   Enforce conformity:
00349   while there are subsplines that either don't appear or are encroached,
00350       split the subspline with a new vertex
00351  ***************************************************************************/
00352 void ConformalMesher::conform()
00353 {
00354 #ifdef DEBUG_CONF_MESHER
00355   cout << "ConformalMesher: enforcing conformity\n";
00356 #endif
00357   while(!spline_stack.empty()) {
00358     Subspline *s = spline_stack.back();
00359     spline_stack.pop_back();
00360     in_stack.erase(s);
00361 #ifdef DEBUG_CONF_MESHER
00362     cout << "ConformalMesher:   - considering " << s << endl;
00363     cout << "ConformalMesher:    ";
00364 #endif
00365     if ( (is_encroached.count(s) == 0) && segment_appears(s)) {
00366       #ifdef DEBUG_CONF_MESHER
00367       cout << "+ happy\n";
00368       #endif
00369       continue;
00370     }
00371 #ifdef DEBUG_CONF_MESHER
00372     cout << " => splitting!\n";
00373 #endif
00374 
00375     vector<Subspline*> newsegs;
00376     BezierVertex *splitvertex = split_destroy_segment(s, newsegs);
00377     assert(newsegs.size() == 2);
00378     s = (Subspline*)0x7; /* for debugging, make it crash */
00379 #ifdef DEBUG_CONF_MESHER
00380     cout << "ConformalMesher:      produced:\n"
00381          << "                      " << newsegs[0] << endl
00382          << "                      " << newsegs[1] << endl;
00383 #endif
00384 
00385     /* check neighbours of the new vertex for encroachment */
00386     deque<BezierEdge*> link_edges;
00387     bezier->enqueue_edges(splitvertex, link_edges);
00388     for(deque<BezierEdge*>::iterator link_it = link_edges.begin();
00389         link_it != link_edges.end(); ++link_it) {
00390       BezierEdge *link_e = (*link_it);
00391       BezierVertex *link_v = bezier->get_opposite_vertex(link_e, splitvertex);
00392 
00393       vector<Subspline*>::iterator seg_it = incident_edges[link_v].begin();
00394       vector<Subspline*>::iterator seg_end = incident_edges[link_v].end();
00395       for ( ; seg_it != seg_end ; ++seg_it) {
00396         Subspline *link_s = *seg_it;
00397         if (link_s == newsegs[0] || link_s == newsegs[1]) {
00398           /* splitvertex doesn't encroach on the segments of which it's
00399              a member */
00400           continue;
00401         }
00402         if (is_encroached.count(link_s) != 0) {
00403           /* Already both in the stack, and marked.
00404              Don't quit if !is_encroached but in_stack: when we pop the
00405              segment off, we must know about the encroachment */
00406           assert(in_stack.count(link_s) != 0);
00407           continue;
00408         }
00409 
00410         /* Check for encroachment; mark and ensure it's on the stack if it
00411          * is encroached. */
00412         if (link_s->is_encroached(splitvertex)) {
00413           is_encroached.insert(link_s);
00414           if (in_stack.count(link_s) == 0) {
00415             spline_stack.push_back(link_s);
00416             in_stack.insert(link_s);
00417           }
00418         }
00419       }
00420     }
00421   }
00422 
00423 #ifdef DEBUG_CONF_MESHER
00424   bezier->check_consistency();
00425 #endif
00426 }
00427 
00428 /***************************************************************************
00429   Seek out and 'fix' the BezierEdges that think they're straight but are
00430   actually conforming to a boundary.  Assumes that conform() has been called.
00431  ***************************************************************************/
00432 void ConformalMesher::reticulate_splines()
00433 {
00434 #ifdef DEBUG_CONF_MESHER
00435   cout << "ConformalMesher: adding splines to BezierMesh\n";
00436 #endif
00437 
00438   for (BoundaryMesh::Boundary_Edge_Hash_T::iterator it = bdry->get_edges_begin();
00439       it != bdry->get_edges_end(); ++it) {
00440     BoundaryEdge *bdrye = (*it);
00441     QBSpline *spline = bdrye->get_spline();
00442 
00443     int n = spline->get_num_segments();
00444     for (int i = 0 ; i < n; i++) {
00445       BezierVertex *v1 = (i == 0) ? bdrye->get_vertex(0)->get_bezier()
00446         : spline->get_bezier_vertex(i);
00447       assert(v1);
00448       BezierVertex *v2 = (i + 1 == n) ? bdrye->get_vertex(1)->get_bezier()
00449         : spline->get_bezier_vertex(i + 1);
00450       assert(v2);
00451       BezierEdge *edge = bezier->find_common_edge(v1, v2);
00452       assert(edge);
00453 
00454       edge->set_bdry(bdrye, spline->k[i], spline->k[i+1]);
00455       bezier->replace_control_point(edge, spline->get_deboor(i+1));
00456     }
00457   }
00458 #ifdef DEBUG_CONF_MESHER
00459   bezier->check_consistency();
00460 #endif
00461 }
00462 
00463 /***************************************************************************
00464   For every BezierTriangle corresponding to the BoundaryFace, set the
00465   BoundaryFace pointer.  This is where we use the face_points.
00466  ***************************************************************************/
00467 void ConformalMesher::set_face_pointers()
00468 {
00469 #ifdef DEBUG_CONF_MESHER
00470   cout << "ConformalMesher: setting face pointers\n";
00471 #endif
00472   for(vector<pair<BoundaryFace*,Point2D> >::iterator it = face_points.begin();
00473       it != face_points.end(); ++it) {
00474     BoundaryFace *face = (*it).first;
00475     Point2D p = (*it).second;
00476     hash_set<BezierTriangle*> triangles;
00477     int triangles_set = 0;
00478 
00479     collect_faces(p, triangles);
00480     for(hash_set<BezierTriangle*>::iterator it = triangles.begin();
00481         it != triangles.end(); ++it, triangles_set++) {
00482       BezierTriangle *t = *it;
00483       t->set_boundary_face(face);
00484     }
00485 #ifdef DEBUG_CONF_MESHER
00486     cout << "ConformalMesher:   - face " << (void*)face << " set "
00487       << triangles_set << " triangles\n";
00488 #endif
00489   }
00490 }
00491 
00492 /***************************************************************************
00493   Remove the elements in the holes.
00494  ***************************************************************************/
00495 void ConformalMesher::excavate_holes()
00496 {
00497 #ifdef DEBUG_CONF_MESHER
00498   cout << "ConformalMesher: excavating holes\n";
00499 #endif
00500   /* A list of things to kill; we must kill them in order.
00501      We may as well collect all holes together at once; there's
00502      no cost to doing otherwise.  */
00503   hash_set<BezierTriangle*> triangles;
00504   hash_set<BezierEdge*> edges;
00505   hash_set<BezierVertex*> vertices;
00506 
00507 #ifdef DEBUG_CONF_MESHER
00508   cout << "ConformalMesher:   - considering " << remove_points.size()
00509     << " holes\n";
00510 #endif
00511 
00512   for(vector<Point2D>::iterator it = remove_points.begin();
00513       it != remove_points.end(); ++it) {
00514     collect_faces(*it, triangles);
00515   }
00516 
00517   for(hash_set<BezierTriangle*>::iterator it = triangles.begin();
00518       it != triangles.end(); ++it) {
00519     BezierTriangle *t = (*it);
00520 
00521     /* Gather the three edges and vertices. */
00522     BezierTuple final_tup = bezier->get_tuple(t);
00523     BezierTuple tup = final_tup;
00524     do {
00525       /* Things that aren't boundaries get removed. */
00526       if (!tup.e->is_boundary()) {
00527         edges.insert(tup.e);
00528       }
00529       if (!tup.v->is_boundary()) {
00530         vertices.insert(tup.v);
00531       }
00532       tup = bezier->Switch(0, bezier->Switch(1, tup));
00533     } while (tup != final_tup);
00534   }
00535 
00536 
00537   /* remove all triangles */
00538 #ifdef DEBUG_CONF_MESHER
00539   cout << "ConformalMesher:   - removing " << triangles.size()
00540     << " triangles\n";
00541 #endif
00542   for(hash_set<BezierTriangle*>::iterator it = triangles.begin();
00543       it != triangles.end(); ++it) {
00544     bezier->delete_face(*it);
00545   }
00546 
00547 
00548   /* all edges */
00549 #ifdef DEBUG_CONF_MESHER
00550   cout << "ConformalMesher:   - removing " << edges.size() << " edges\n";
00551 #endif
00552   for(hash_set<BezierEdge*>::iterator it = edges.begin();
00553       it != edges.end(); ++it) {
00554     bezier->delete_edge(*it);
00555   }
00556 
00557 
00558   /* and all vertices */
00559 #ifdef DEBUG_CONF_MESHER
00560   cout << "ConformalMesher:   - removing " << vertices.size() << " vertices\n";
00561 #endif
00562   for(hash_set<BezierVertex*>::iterator
00563       it = vertices.begin(); it != vertices.end(); ++it) {
00564     bezier->delete_vertex(*it);
00565   }
00566 
00567 #ifdef DEBUG_CONF_MESHER
00568   bezier->check_consistency();
00569 #endif
00570 }
00571 
00572 /***************************************************************************
00573  * Return whether the given segment appears in the linear mesh.
00574  * To appear, two things must be true:
00575  * (1) it appears topologically
00576  * (2) the curve does not intersect the sides (except at endpoints)
00577  ***************************************************************************/
00578 bool ConformalMesher::segment_appears(Subspline *seg)
00579 {
00580   BezierEdge *edge = bezier->find_common_edge(seg->get_vertex(0),
00581                                               seg->get_vertex(1));
00582   if (!edge) {
00583     /* no such edge in the mesh? clearly it doesn't appear */
00584     cout << "(no such edge)" << flush;
00585     return false;
00586   }
00587 
00588   /* There are four tangent angles to check now: one for each
00589    * face/edge/vertex cell that correspond to our edge.
00590    * Due to input restrictions, two segments intersect with at least
00591    * 90 degrees between them, and the control angle is at least 90
00592    * degrees, so curved subsegments cannot intersect.  This means we
00593    * can conservatively assume the four other sides of the two
00594    * triangles are straight; only our edge is curved.
00595    */
00596   BezierTuple tuple;
00597   BezierEdge *e[4];
00598   BezierVertex *v[4];
00599 
00600   /* Get the two edges out of one vertex. */
00601   tuple = bezier->get_tuple(edge);
00602   v[0] = v[1] = tuple.v;
00603   assert(v[0] == seg->get_vertex(0) || v[0] == seg->get_vertex(1));
00604   e[0] = bezier->Switch(1, tuple).e;
00605   e[1] = bezier->Switch(1, bezier->Switch(2, tuple)).e;
00606 
00607   /* And out of the other. */
00608   tuple = bezier->Switch(0, tuple);
00609   v[2] = v[3] = tuple.v;
00610   assert(v[2] == seg->get_vertex(0) || v[2] == seg->get_vertex(1));
00611   assert(v[2] != v[0]);
00612   e[2] = bezier->Switch(1, tuple).e;
00613   e[3] = bezier->Switch(1, bezier->Switch(2, tuple)).e;
00614 
00615   for (int i = 0; i < 4; i++) {
00616     assert(e[i] != edge);
00617     if (!angle_is_positive(seg, v[i], e[i])) {
00618       #ifdef DEBUG_CONF_MESHER
00619       cout << "(angle " << i << " is negative)" << flush;
00620       #endif
00621       return false;
00622     }
00623   }
00624 
00625   /* all our tests came out good; the edge appears. */
00626   return true;
00627 }
00628 
00629 /***************************************************************************
00630  * Given a quadratic bezier segment and a straight segment that share a
00631  * vertex, return true if the curve is good (that is, does not
00632  * intersect the triangle except at endpoints).
00633  * This happens iff the angle at the vertex is positive.
00634  **************************************************************************/
00635 bool ConformalMesher::angle_is_positive(Subspline *s,
00636                                         BezierVertex *shared,
00637                                         BezierEdge *e)
00638 {
00639   Point2D pshared = shared->get_cp();
00640   Point2D pedge = bezier->get_opposite_vertex(e, shared)->get_cp();
00641   Point2D pdeboor = s->get_deboor();
00642   Point2D pspline = s->get_other_vertex(shared)->get_cp();
00643 
00644   /* if the spline is straight, the angle is good. */
00645   double sp_sh_d  = pdeboor.line_side_test(pspline, pshared);
00646   if (sp_sh_d == 0.0) {
00647     return true;
00648   }
00649 
00650   /* if the deboor point is on the opposite side of the spline edge
00651      from pedge, then the angle is good */
00652   double sp_sh_e = pedge.line_side_test(pspline, pshared);
00653   assert(sp_sh_e != 0.0); /* that would be a flat triangle */
00654   if (sp_sh_d * sp_sh_e < 0.0) {
00655     return true;
00656   }
00657 
00658   /* if the deboor point is on the same side of the straight edge
00659      as pspline, then the angle is good */
00660   double e_sh_d = pdeboor.line_side_test(pedge, pshared);
00661   double e_sh_sp = pspline.line_side_test(pedge, pshared);
00662   assert(e_sh_sp != 0.0); /* flat triangle */
00663   if (e_sh_d * e_sh_sp > 0.0) {
00664     return true;
00665   }
00666 
00667   /* anything else means the angle is bad */
00668   return false;
00669 }
00670 
00671 /***************************************************************************
00672   Link in a new subspline.
00673  ***************************************************************************/
00674 void ConformalMesher::link_edge(Subspline *s)
00675 {
00676   spline_stack.push_back(s);
00677   in_stack.insert(s);
00678   incident_edges[s->get_vertex(0)].push_back(s);
00679   incident_edges[s->get_vertex(1)].push_back(s);
00680   subsplines.push_front(s);
00681   s->set_delete_iterator(subsplines.begin());
00682 }
00683 
00684 /***************************************************************************
00685   Unlink and delete a subspline.  It must not be in the stack.
00686  ***************************************************************************/
00687 void ConformalMesher::unlink_edge(Subspline *s)
00688 {
00689   assert(in_stack.count(s) == 0);
00690   is_encroached.erase(s);
00691   for (int vi = 0; vi < 2; ++vi) {
00692     vector<Subspline*>& vect = incident_edges[s->get_vertex(vi)];
00693     bool did_find = false;
00694     for (unsigned i = 0; i < vect.size(); ++i) {
00695       if(vect[i] == s) {
00696         vect[i] = vect.back();
00697         vect.pop_back();
00698         did_find = true;
00699         break;
00700       }
00701     }
00702     assert(did_find);
00703   }
00704   subsplines.erase(s->get_delete_iterator());
00705   delete s;
00706 }
00707 
00708 /***************************************************************************
00709   Split s, destroying it but creating two new segments and
00710   a new vertex.
00711  ***************************************************************************/
00712 BezierVertex *ConformalMesher::split_destroy_segment(Subspline *s,
00713     vector<Subspline*>& newsegs)
00714 {
00715   /* do the split */
00716   BezierVertex *splitvertex = s->split(bezier, newsegs);
00717   assert(newsegs.size() == 2);
00718 
00719   /* remove s */
00720   unlink_edge(s);
00721 
00722   /* link in the new segments */
00723   link_edge(newsegs[0]);
00724   link_edge(newsegs[1]);
00725 
00726   return splitvertex;
00727 }
00728 
00729 /***************************************************************************
00730   Collect all triangles that are entirely inside the boundary face in which
00731   the point lies.
00732  ***************************************************************************/
00733 void ConformalMesher::collect_faces(Point2D start,
00734                                     hash_set<BezierTriangle*>& faces)
00735 {
00736   int cd;
00737   BezierTuple searchtup;
00738   double u, v;
00739 
00740   /* Find starting point for the DFS. */
00741   cd = bezier->blind_locate_point(start, searchtup, u, v);
00742 
00743   /* do a DFS over all neighboring triangles stopping at boundaries */
00744   deque<BezierTriangle*> todo;
00745 
00746   switch(cd) {
00747     case 0:
00748       /* All faces around this vertex should be included. */
00749       bezier->enqueue_faces(searchtup.v, todo);
00750       break;
00751 
00752     case 1:
00753       /* Both faces around this edge should be included. */
00754       todo.push_back(searchtup.f);
00755       todo.push_back(bezier->Switch(2, searchtup).f);
00756       break;
00757 
00758     case 2:
00759       todo.push_back(searchtup.f);
00760       break;
00761 
00762     default:
00763       assert(0);
00764       break;
00765   }
00766 
00767   while(!todo.empty()){
00768     BezierTriangle *tri = todo.back();
00769     todo.pop_back();
00770 
00771     faces.insert(tri);
00772 
00773     /* loop around the three edges; flip across it to get the other
00774        triangle if it's not a boundary */
00775     BezierTuple start = bezier->get_tuple(tri);
00776     BezierTuple tup = start;
00777     do {
00778       if(!tup.e->is_boundary()) {
00779         /* cross the edge and push that face on the stack */
00780         BezierTriangle *t = bezier->Switch(2, tup).f;
00781         if(faces.count(t) == 0) {
00782           todo.push_back(t);
00783         }
00784       }
00785       /* next edge along the triangle */
00786       tup = bezier->Switch(0, bezier->Switch(1, tup));
00787     } while(tup != start);
00788   }
00789 }

Generated on Mon May 24 09:53:30 2010 for TUMBLE by  doxygen 1.5.2