contrib/gel/vtol/vtol_cycle_processor.cxx
Go to the documentation of this file.
00001 // This is gel/vtol/vtol_cycle_processor.cxx
00002 #include "vtol_cycle_processor.h"
00003 //:
00004 // \file
00005 
00006 #include <vcl_vector.h>
00007 #include <vcl_algorithm.h>
00008 #include <vcl_iostream.h>
00009 #include <vcl_cmath.h>
00010 
00011 #include <vsol/vsol_box_2d.h>
00012 #include <vsol/vsol_box_2d_sptr.h>
00013 #include <vdgl/vdgl_digital_curve.h>
00014 #include <vdgl/vdgl_interpolator.h>
00015 #include <vdgl/vdgl_edgel_chain.h>
00016 
00017 #include <vtol/vtol_vertex.h>
00018 #include <vtol/vtol_vertex_2d.h>
00019 #include <vtol/vtol_one_chain.h>
00020 #include <vtol/vtol_edge.h>
00021 #include <vtol/vtol_edge_2d.h>
00022 #include <vtol/vtol_edge_2d_sptr.h>
00023 
00024 //Constructors
00025 vtol_cycle_processor::vtol_cycle_processor(vcl_vector<vtol_edge_2d_sptr>& edges,
00026                                            bool debug1, bool debug2)
00027 {
00028   debug1_ = debug1;
00029   debug2_ = debug2;
00030   tolerance_ = 0;
00031   init(edges);
00032 }
00033 
00034 //: a more convenient interface
00035 //
00036 static void edge_2d_erase(vcl_vector<vtol_edge_2d_sptr>& edges,
00037                           vtol_edge_2d_sptr& e)
00038 {
00039   vcl_vector<vtol_edge_2d_sptr>::iterator eit =
00040     vcl_find(edges.begin(), edges.end(), e);
00041   if (eit == edges.end())
00042     return;
00043   edges.erase(eit);
00044   return;
00045 }
00046 
00047 //: print a vector of vertices
00048 //
00049 static void print_vertices(vcl_vector<vtol_vertex_sptr>& verts)
00050 {
00051   for (vcl_vector<vtol_vertex_sptr>::iterator vit = verts.begin();
00052        vit != verts.end(); ++vit)
00053     vcl_cout << *vit << '('
00054              << (*vit)->cast_to_vertex_2d()->x()<< ' '
00055              << (*vit)->cast_to_vertex_2d()->y()<< ")\n\n";
00056 }
00057 
00058 //: print a vector of edges_2d
00059 //
00060 static void print_edges(vcl_vector<vtol_edge_2d_sptr>& edges)
00061 {
00062   for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = edges.begin();
00063        eit != edges.end(); ++eit)
00064     vcl_cout << *eit << '('
00065              << (*eit)->v1()->cast_to_vertex_2d()->x()<< ' '
00066              << (*eit)->v1()->cast_to_vertex_2d()->y()<< " |"
00067              << (*eit)->v2()->cast_to_vertex_2d()->x()<< ' '
00068              << (*eit)->v2()->cast_to_vertex_2d()->y()<< ")\n\n";
00069 }
00070 
00071 //: print a vector of edges
00072 //
00073 static void print_edges(vcl_vector<vtol_edge_sptr>& edges)
00074 {
00075   for (vcl_vector<vtol_edge_sptr>::iterator eit = edges.begin();
00076        eit != edges.end(); ++eit)
00077     vcl_cout << *eit << '('
00078              << (*eit)->v1()->cast_to_vertex_2d()->x()<< ' '
00079              << (*eit)->v1()->cast_to_vertex_2d()->y()<< " |"
00080              << (*eit)->v2()->cast_to_vertex_2d()->x()<< ' '
00081              << (*eit)->v2()->cast_to_vertex_2d()->y()<< ")\n\n";
00082 }
00083 
00084 //---------------------------------------------------------------
00085 //
00086 static void pop_stacks(vertex_list& verts,
00087                        vcl_vector<vtol_edge_2d_sptr>& edges,
00088                        vtol_vertex_sptr& v,
00089                        vcl_vector<vtol_edge_2d_sptr>& cycle_edges)
00090 {
00091   bool found = false;
00092   while (verts.size()&&edges.size()&&!found)
00093   {
00094     found = verts.back()==v;
00095     cycle_edges.push_back(edges.back());
00096     verts.pop_back();
00097     edges.pop_back();
00098   }
00099   if (!edges.size()&&verts.size())
00100     verts.clear();
00101 }
00102 
00103 //: Access to flags
00104 //the user flags on SpatialObject are used to define the orientation
00105 //of vtol_edge(s) during the boundary tracing process.  In effect, FLAG1 and
00106 //FLAG2 define half edges. vtol_edges are used up when both half edges are used.
00107 static bool used(vtol_edge_2d_sptr& e)
00108 {
00109   return e->get_user_flag(VSOL_FLAG1)&&e->get_user_flag(VSOL_FLAG2);
00110 }
00111 
00112 static bool unused(vtol_edge_2d_sptr& e)
00113 {
00114   return !e->get_user_flag(VSOL_FLAG1)&&!e->get_user_flag(VSOL_FLAG2);
00115 }
00116 
00117 static bool plus_used(vtol_edge_2d_sptr& e)
00118 {
00119   return e->get_user_flag(VSOL_FLAG1) != 0;
00120 }
00121 
00122 static bool minus_used(vtol_edge_2d_sptr& e)
00123 {
00124   return e->get_user_flag(VSOL_FLAG2) != 0;
00125 }
00126 
00127 static bool half_used(vtol_edge_2d_sptr& e)
00128 {
00129   return e->get_user_flag(VSOL_FLAG1) ^ e->get_user_flag(VSOL_FLAG2);
00130   // exclusive OR; was: return (dir1&&!dir2)||(!dir1&&dir2);
00131 }
00132 
00133 // Assignment of flags
00134 static void use_plus(vtol_edge_2d_sptr& e)
00135 {
00136   e->set_user_flag(VSOL_FLAG1);
00137 }
00138 
00139 static void use_minus(vtol_edge_2d_sptr& e)
00140 {
00141   e->set_user_flag(VSOL_FLAG2);
00142 }
00143 
00144 // One Chain flags
00145 // predicates
00146 static bool ccw(vtol_one_chain_sptr& ch)
00147 {
00148   return ch && ch->get_user_flag(VSOL_FLAG1) != 0;
00149 }
00150 
00151 static bool cw(vtol_one_chain_sptr& ch)
00152 {
00153   return ch && ch->get_user_flag(VSOL_FLAG2) != 0;
00154 }
00155 
00156 // assignment
00157 static void set_ccw(vtol_one_chain_sptr& ch)
00158 {
00159   ch->set_user_flag(VSOL_FLAG1);
00160 }
00161 
00162 static void set_cw(vtol_one_chain_sptr& ch)
00163 {
00164   ch->set_user_flag(VSOL_FLAG2);
00165 }
00166 
00167 // other house keeping functions and predicates
00168 // vtol_edge functions
00169 static void clear(vtol_edge_2d_sptr& e)
00170 {
00171   e->unset_user_flag(VSOL_FLAG1);
00172   e->unset_user_flag(VSOL_FLAG2);
00173   e->unset_user_flag(VSOL_FLAG3);
00174 }
00175 
00176 #if 0 // only untouch(vtol_one_chain_sptr&) is used
00177 static void untouch(vtol_edge_2d_sptr& e)
00178 {
00179   e->unset_user_flag(VSOL_FLAG3);
00180 }
00181 #endif
00182 
00183 static void touch(vtol_edge_2d_sptr& e)
00184 {
00185   e->set_user_flag(VSOL_FLAG3);
00186 }
00187 
00188 static bool touched(vtol_edge_2d_sptr& e)
00189 {
00190   return e->get_user_flag(VSOL_FLAG3) != 0;
00191 }
00192 
00193 static bool self_loop(vtol_edge_2d_sptr& e)
00194 {
00195   vtol_vertex_sptr v1 = e->v1();
00196   vtol_vertex_sptr v2 = e->v2();
00197   bool loop = v1 == v2;
00198   return loop;
00199 }
00200 
00201 static bool bridge_traverse(double angle)
00202 {
00203   double tol = 1e-3;
00204   double delta = vcl_fabs(vcl_fabs(angle)-180);
00205   return delta<tol;
00206 }
00207 
00208 //vtol_one_chain functions
00209 static void untouch(vtol_one_chain_sptr& ch)
00210 {
00211   ch->unset_user_flag(VSOL_FLAG3);
00212 }
00213 
00214 #if 0 // only clear(vtol_edge_2d_sptr& ) is used
00215 static void clear(vtol_one_chain_sptr& ch)
00216 {
00217   ch->unset_user_flag(VSOL_FLAG1);
00218   ch->unset_user_flag(VSOL_FLAG2);
00219   ch->unset_user_flag(VSOL_FLAG3);
00220 }
00221 #endif
00222 
00223 static void touch(vtol_one_chain_sptr& ch)
00224 {
00225   ch->set_user_flag(VSOL_FLAG3);
00226 }
00227 
00228 static bool touched(vtol_one_chain_sptr& ch)
00229 {
00230   return ch->get_user_flag(VSOL_FLAG3) != 0;
00231 }
00232 
00233 //----------------------------------------------------------
00234 //:   Get an array of edges attached to a vertex.
00235 //    Only those edges
00236 //    present in the given edge array are considered attached. Previously
00237 //    un-traversed edges are returned unless force == true. Then edges
00238 //    which are half-used are allowed in the returned set.
00239 static void v_edges(vtol_vertex_sptr v, vcl_vector<vtol_edge_2d_sptr>& b_edges,
00240                     bool force, vcl_vector<vtol_edge_2d_sptr>& edges_at_vertex)
00241 {
00242   edges_at_vertex.clear();
00243   edge_list edges; v->edges(edges);
00244   for (edge_list::iterator eit = edges.begin(); eit != edges.end(); ++eit)
00245   {
00246     vtol_edge_2d_sptr e = (*eit)->cast_to_edge_2d();
00247     if (vcl_find(b_edges.begin(), b_edges.end(),e) != b_edges.end())
00248     {
00249       if (used(e))
00250         continue;
00251       if (unused(e))
00252         edges_at_vertex.push_back(e);
00253       if (half_used(e)&&force)
00254         edges_at_vertex.push_back(e);
00255     }
00256   }
00257 }
00258 
00259 inline static double flip_y(double ang)
00260 {
00261   // no need to use sin(), cos() and atan2() for this job! - PVr
00262   ang = vcl_fmod(ang,360.0);
00263   if (ang <= 0) ang += 360.0;
00264   return 360.0-ang;
00265 }
00266 
00267 static double tangent_angle_at_vertex(vtol_vertex_sptr v, vtol_edge_2d_sptr e)
00268 {
00269   double ang = 0;
00270   if (!e||!v||!(v==e->v1()||v==e->v2()))
00271   {
00272     vcl_cout << "vtol_vertex and vtol_edge not incident\n";
00273     return ang;
00274   }
00275   //Here we assume that the edgel_chain starts at v1 and ends at v2;
00276   if (v==e->v1())
00277   {
00278     ang = e->curve()->cast_to_vdgl_digital_curve()->
00279                         get_interpolator()->get_tangent_angle(0);
00280   }
00281   else
00282   {
00283     int N = e->curve()->cast_to_vdgl_digital_curve()->
00284                           get_interpolator()->get_edgel_chain()->size();
00285 
00286     ang = e->curve()->cast_to_vdgl_digital_curve()->
00287                         get_interpolator()->get_tangent_angle(N-1);
00288     //reverse the angle since we are at the end rather than the start of the edge?
00289     ang += 180.0;
00290   }
00291   //If we want cw and ccw to be correct senses, we flip y because the input
00292   //edges are in image coordinates that has a left-handed coordinate system.
00293   return flip_y(ang);
00294 }
00295 
00296 //----------------------------------------------------------------
00297 //:   Find the vtol_vertex, if any,  which is shared by two vtol_edge(s)
00298 static vtol_vertex_sptr common_vertex(vtol_edge_2d_sptr& e0, vtol_edge_2d_sptr& e1)
00299 {
00300   vtol_vertex_sptr v01 = e0->v1(), v02 = e0->v2();
00301   vtol_vertex_sptr v11 = e1->v1(), v12 = e1->v2();
00302   if ((vtol_vertex_sptr)v01==(vtol_vertex_sptr)v11)
00303     return v01;
00304   if ((vtol_vertex_sptr)v01==(vtol_vertex_sptr)v12)
00305     return v01;
00306   if ((vtol_vertex_sptr)v02==(vtol_vertex_sptr)v11)
00307     return v02;
00308   if ((vtol_vertex_sptr)v02==(vtol_vertex_sptr)v12)
00309     return v02;
00310   return NULL;
00311 }
00312 
00313 //----------------------------------------------------------------
00314 //:   Compute the angle between two edges at the specified vtol_vertex, v
00315 //    The angle is mapped to the interval [-180, 180].  The angle sense is
00316 //    defined so that the e0 orientation is towards v and the e1
00317 //    orientation is away from v.
00318 double vtol_cycle_processor::angle_between_edges(vtol_edge_2d_sptr e0,
00319                                                  vtol_edge_2d_sptr e1,
00320                                                  vtol_vertex_sptr v)
00321 {
00322   double theta0 = 180+tangent_angle_at_vertex(v, e0);
00323   if (theta0>360)
00324     theta0 -= 360;
00325   double theta1 = tangent_angle_at_vertex(v, e1);
00326   double angle = theta1-theta0;
00327   if (angle>180)
00328     angle-=360;
00329   if (angle<-180)
00330     angle+=360;
00331   return angle;
00332 }
00333 
00334 //------------------------------------------------------------
00335 //:   Find the most counter clockwise vtol_edge at the input vtol_vertex, from.
00336 //
00337 static vtol_edge_2d_sptr ccw_edge(vtol_edge_2d_sptr in_edg, vtol_vertex_sptr from,
00338                                   vcl_vector<vtol_edge_2d_sptr>& edges)
00339 {
00340   double most_ccw = -360;
00341   vtol_edge_2d_sptr ccw = NULL;
00342   for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = edges.begin();
00343        eit != edges.end(); ++eit)
00344   {
00345     if ((*eit)==in_edg)
00346       continue;
00347     double delta = vtol_cycle_processor::angle_between_edges(in_edg, *eit, from);
00348     if (delta>most_ccw)
00349     {
00350       most_ccw = delta;
00351       ccw = *eit;
00352     }
00353   }
00354   //There were no edges found except the incoming edge, so return it.
00355   if (!ccw && vcl_find(edges.begin(), edges.end(),in_edg) != edges.end())
00356     ccw = in_edg;
00357   return ccw;
00358 }
00359 
00360 //-----------------------------------------------------
00361 //:   Is an edge assignable to a path?
00362 //    "Assignable" is defined by
00363 //    the condition that an edge has not already been traversed in
00364 //    the required direction.  That is, if a traversal from s to e,
00365 //    (V1 to V2) has occurred then dir1 is true.  A second traversal
00366 //    is not allowed and the edge is considered un-assignable.
00367 //
00368 bool vtol_cycle_processor::assignable(vtol_edge_2d_sptr edg, vtol_vertex_sptr last)
00369 {
00370   if (debug2_)
00371   {
00372     vcl_cout << "In assignable(..)\n"
00373              << "edg " ; this->print_edge(edg);
00374     vcl_cout << "plus used(" << plus_used(edg) << ") minus used("
00375              << minus_used(edg) << ")\n"
00376              << "last " << *last << vcl_endl;
00377   }
00378   if (!edg||!last)
00379     return false;
00380   if (unused(edg))
00381     return true;
00382   if (used(edg))
00383     return false;
00384   vtol_vertex_sptr s = edg->v1();
00385   vtol_vertex_sptr e = edg->v2();
00386   if (last==s&&!plus_used(edg))
00387     return true;
00388   if (last==e&&!minus_used(edg))
00389     return true;
00390   return false;
00391 }
00392 
00393 //----------------------------------------------------------------------
00394 //:   Set up the first edge in a cycle (or bridge) traversal.
00395 //    A positive
00396 //    traversal (half edge) is in the direction from v1->v2.
00397 //    Self loops are a special case and use both directions on one traversal.
00398 //    There is no point in traversing the self loop twice.
00399 void vtol_cycle_processor::assign_initial_edge(vtol_edge_2d_sptr& e,
00400                                                vtol_vertex_sptr& first,
00401                                                vtol_vertex_sptr& last)
00402 {
00403   if (debug1_)
00404       vcl_cout << "==== entering assign_initial_edge =====\n"
00405                << "e " << *e << "plus used(" << plus_used(e) << ") minus used("
00406                << minus_used(e) << ")\n";
00407 
00408   if (used(e))
00409   {
00410     vcl_cout << "In vtol_cycle_processor::assign_intial_edge(..) "
00411              << "shouldn't happen - error\n";
00412     return;
00413   }
00414   vtol_vertex_sptr v1 = e->v1(), v2 = e->v2();
00415   if (v1==v2)
00416   {
00417     use_plus(e);
00418     use_minus(e);
00419     first = v1; last = v1;
00420   }
00421   if (plus_used(e))
00422   {
00423     use_minus(e);
00424     first = v2;
00425     last  = v1;
00426   }
00427   else
00428   {
00429     use_plus(e);
00430     first = v1;
00431     last  = v2;
00432   }
00433   if (debug1_)
00434     vcl_cout << "==== leaving assign_initial_edge =====\n"
00435              << "plus used(" << plus_used(e) << ") minus used("
00436              << minus_used(e) << ")\n\n";
00437 }
00438 
00439 //------------------------------------------------------------
00440 //:   Link the vtol_edge, "edg" to the vtol_vertex, "last".
00441 //    Set the appropriate direction flag
00442 
00443 void vtol_cycle_processor::assign_ends(vtol_edge_2d_sptr edg, vtol_vertex_sptr& last)
00444 {
00445   if (debug1_)
00446       vcl_cout << "==== entering assign_ends =====\n"
00447                << "edg " << *edg << "plus used(" << plus_used(edg) << ") minus used("
00448                << minus_used(edg) << ")\n";
00449   vtol_vertex_sptr s = edg->v1();
00450   vtol_vertex_sptr e = edg->v2();
00451   // compare to last point added
00452   // Here we need to be able to use the previous
00453   // edge if there is no other choice
00454   if (last == s)
00455   {
00456     last = e;
00457     use_plus(edg);//Forward direction
00458     if (s==e)
00459       use_minus(edg);//For a self-loop, any traversal uses it up
00460     return;
00461   }
00462   if (last == e)
00463   {
00464     last = s;
00465     use_minus(edg);//Reverse direction
00466     if (s==e)
00467       use_plus(edg);//For a self-loop, any traversal uses it up
00468     return;
00469   }
00470   vcl_cout << "In vtol_cycle_processor::assign ends(..) - shouldn't happen\n";
00471 }
00472 
00473 //------------------------------------------------------------
00474 //:
00475 //    Assign the next edge to the top of the edge stack when
00476 //    a cycle is popped off the stack. That is, start the new path
00477 //    with the edge at the top of the stack.  If the stack is
00478 //    empty, then the last assignment to l_ is used.
00479 static void assign_stack_edge(vcl_vector<vtol_edge_2d_sptr>& e_stack, vtol_edge_2d_sptr& next_edge)
00480 {
00481   if (!e_stack.size())
00482     return;
00483   next_edge = e_stack.back();
00484 }
00485 
00486 //------------------------------------------------------------------
00487 //:   The initial setup of the cycle process.
00488 //    Used by the vtol_cycle_processor
00489 //    constructors to establish the start conditions
00490 void vtol_cycle_processor::init(vcl_vector<vtol_edge_2d_sptr>& in_edges)
00491 {
00492   edges_.clear();
00493   chains_.clear();
00494   nested_one_cycles_.clear();
00495   for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = in_edges.begin();
00496        eit != in_edges.end(); ++eit)
00497   {
00498     clear(*eit);
00499     edges_.push_back(*eit);
00500   }
00501   this->set_bridge_vars();
00502   valid_ = false;
00503 }
00504 
00505 //---------------------------------------------------------------
00506 //:  Initializes the search for cycles starting with an unexplored vtol_edge.
00507 //   This initialization is called after a connected set of vtol_edge(s) is
00508 //   completely explored and removed from edges_.
00509 void vtol_cycle_processor::set_bridge_vars()
00510 {
00511   if (!edges_.size())
00512     return;
00513   v_stack_.clear();
00514   e_stack_.clear();
00515   l_ = edges_[0];
00516   e_stack_.push_back(l_);
00517   assign_initial_edge(l_, first_, last_);
00518   cycle_ = first_==last_;
00519   found_next_edge_ = true;
00520   v_stack_.push_back(last_);
00521   if (!cycle_)
00522     v_stack_.push_back(first_);//why do we put both first and last on the stack?
00523   else
00524     touch(l_);
00525   if (debug1_)
00526   {
00527     vcl_cout << "------init bridge vars-------\n"
00528              << "oooooooo Vertex Stack ooooooooo\n";
00529     print_vertices(v_stack_);
00530     vcl_cout << "oooooooo Edge Stack ooooooooo\n";
00531     print_edges(e_stack_);
00532   }
00533 }
00534 
00535 //------------------------------------------------------------------------
00536 //:   check for bridges and compute winding angle.
00537 //    (just convenient code packaging for use in classify_path)
00538 //
00539 static void classify_adjacent_edges(vtol_edge_2d_sptr& e0, vtol_edge_2d_sptr& e1,
00540                                     bool& all_bridge, double& angle)
00541 {
00542   vtol_vertex_sptr cv = common_vertex(e0, e1);
00543   if (cv)
00544   {
00545     angle = vtol_cycle_processor::angle_between_edges(e0, e1, cv);
00546     all_bridge = all_bridge && used(e1) && bridge_traverse(angle);
00547   }
00548 }
00549 
00550 //------------------------------------------------------------------------
00551 //:  Classify two edges, it is simpler to deal with this case exhaustively.
00552 //   Returns true if the path is cycle (not a bridge)
00553 //
00554 static bool classify_two_edge_path(vtol_edge_2d_sptr& e0, vtol_edge_2d_sptr& e1)
00555 {
00556   vtol_vertex_sptr v1 = e0->v1(), v2 = e0->v1();
00557   double angle1 = vtol_cycle_processor::angle_between_edges(e0, e1, v1);
00558   double angle2 = vtol_cycle_processor::angle_between_edges(e0, e1, v2);
00559   bool bridge = bridge_traverse(angle1)&&bridge_traverse(angle2);
00560   return !bridge;
00561 }
00562 
00563 //---------------------------------------------------------------------
00564 //:
00565 //   Search the set of vtol_edge(s) connected to the last path vertex for
00566 //   a suitable addition to the path
00567 //
00568 vtol_edge_2d_sptr vtol_cycle_processor::search_for_next_edge(vcl_vector<vtol_edge_2d_sptr>& edges_at_last)
00569 {
00570   while (edges_at_last.size())
00571   {
00572     vtol_edge_2d_sptr temp = ccw_edge(l_, last_, edges_at_last);
00573     if (debug2_)
00574     {
00575       vcl_cout << "next ccw_edge\n";
00576       this->print_edge(temp);
00577     }
00578     if (!temp || assignable(temp, last_))
00579       return temp;
00580     edge_2d_erase(edges_at_last, temp);
00581   }
00582   return NULL;
00583 }
00584 
00585 //---------------------------------------------------------------------
00586 //:   A suitable vtol_edge is added to the evolving path
00587 //
00588 void vtol_cycle_processor::add_edge_to_path()
00589 {
00590   vtol_vertex_sptr temp = last_;
00591   assign_ends(next_edge_, temp);
00592   if (debug2_)
00593     vcl_cout << "==== after assign_ends =====\n"
00594              << "next_edge_ "  << *next_edge_ << "plus used("
00595              << plus_used(next_edge_) << ") minus used("
00596              << minus_used(next_edge_) << ")\n\n";
00597   v_stack_.push_back(last_);
00598   last_ = temp;
00599   l_ = next_edge_;
00600   e_stack_.push_back(l_);
00601   touch(l_);
00602   if (debug1_)
00603   {
00604     vcl_cout << "------assign_edge_to_path-------\n"
00605              << "oooooooo Vertex Stack ooooooooo\n";
00606     print_vertices(v_stack_);
00607     vcl_cout << "oooooooo Edge Stack ooooooooo\n";
00608     print_edges(e_stack_);
00609   }
00610 }
00611 
00612 //------------------------------------------------------------------------
00613 //:   Classify a closed path as a cycle or bridge.
00614 //    The path traverse is reversed since the vtol_edge sequence was
00615 //    popped from the path stack.
00616 //    Thus, the winding angle is opposite in sign, which is
00617 //    accounted for in code.
00618 bool vtol_cycle_processor::classify_path(vcl_vector<vtol_edge_2d_sptr>& path_edges,
00619                                          vtol_one_chain_sptr& chain)
00620 {
00621   if (debug1_)
00622         vcl_cout << "======= In classify_path ========\n";
00623   if (!path_edges.size())
00624     return false;
00625   edge_list c_edges;
00626   vtol_edge_2d_sptr e0 = *path_edges.begin();
00627   //If the path is a self_loop then the treatment is special
00628   //A self loop is classified as both a cw and ccw cycle
00629   if (self_loop(e0))
00630   {
00631     c_edges.push_back(e0->cast_to_edge());
00632     chain = new vtol_one_chain(c_edges, true);
00633     set_ccw(chain); set_cw(chain);
00634     return true;
00635   }
00636   //scan the path and determine if it is a bridge.  Also compute
00637   //the cumulative angle between vtol_edge(s) along the path
00638   double winding_angle = 0, angle = 0;
00639   bool all_bridge = used(e0);
00640   //If the path has two edges it is simpler to deal with it as follows
00641   //JLM why don't we mark the edges as all used?
00642   if (path_edges.size()==2)
00643     if (classify_two_edge_path(e0, *(path_edges.begin()+1)))
00644     {
00645       c_edges.push_back(e0->cast_to_edge());
00646       chain = new vtol_one_chain(c_edges, true);
00647       set_ccw(chain); set_cw(chain);
00648       return true;
00649     }
00650   //the typical case, three or more edges
00651   for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = path_edges.begin()+1;
00652        eit != path_edges.end(); ++eit)
00653   {
00654     classify_adjacent_edges(e0, *eit, all_bridge, angle);
00655 
00656     if (debug1_)
00657       vcl_cout << "wind_ang " << winding_angle << " - " << angle << " = "
00658                << winding_angle - angle << vcl_endl;
00659 
00660     winding_angle -= angle;//because pop_stacks reverses the traverse order
00661 
00662     e0 = *eit;
00663   }
00664   vtol_edge_2d_sptr eN = *path_edges.begin();//The closure of the loop
00665   classify_adjacent_edges(e0, eN, all_bridge, angle);
00666   winding_angle -= angle;
00667   //If the path is completely a bridge then nothing more is done
00668   if (all_bridge)
00669     return false;
00670   //Form a cycle from the path
00671   for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = path_edges.begin();
00672        eit != path_edges.end(); ++eit)
00673     c_edges.push_back((*eit)->cast_to_edge());
00674 
00675   chain = new vtol_one_chain(c_edges, true);
00676   //classify the cycle
00677   if (winding_angle>0)
00678     set_ccw(chain); //ccw chain (outer boundary)
00679   else
00680     set_cw(chain);//cw chain (hole boundary)
00681   return true;
00682 }
00683 
00684 void vtol_cycle_processor::print_edge(vtol_edge_2d_sptr& e)
00685 {
00686   if (!e)
00687     return;
00688   vcl_cout << e << " :[(" << e->v1()->cast_to_vertex_2d()->x()
00689            << ' ' << e->v1()->cast_to_vertex_2d()->y()<< "), ("
00690            << e->v2()->cast_to_vertex_2d()->x() << ' '
00691            << e->v2()->cast_to_vertex_2d()->y() << ")]\n";
00692 }
00693 
00694 //------------------------------------------------------------------------
00695 //: The main cycle tracing algorithm.
00696 //  The input is edges_ and the output is chains_, a set of 1-cycles.
00697 //  The approach is to select a vtol_edge from edges_ and explore all the
00698 //  vtol_edge(s) connected to it.  The search proceeds by traversing connected
00699 //  vtol_edge(s), turning in a cw or ccw direction depending on the initial vtol_edge
00700 //  orientation.  If the search returns to a vertex already on the path,
00701 //  then a cycle is output.  The traversed vtol_edge(s) and vertices are pushed
00702 //  onto a stack so that cycles can be "popped" off and the search continued
00703 //  from a proper state.  Each vtol_edge can be traversed in a plus or minus
00704 //  direction (2 half_edges). Thus boundaries might be traced twice producing
00705 //  identical cycles but traversed in opposite senses.
00706 //
00707 //  Bridges are detected by the fact that all vtol_edge(s) in the bridge are
00708 //  used(plus and minus) and the traversal winding angle is 180 deg, i.e.,
00709 //  the path folds exactly back on itself.
00710 //
00711 //  Cycles are labeled according to the accumulated winding angle in
00712 //  traversing the cycle.  If the accumulated angle is + then the
00713 //  cycle is ccw, otherwise cw.  Here, the winding angle is defined as the
00714 //  exterior angle between two sequential vtol_edge(s) in the traversed path.
00715 //
00716 //  In the traversal, completely unused vtol_edge(s) are favored to continue in
00717 //  an unexplored path.  If none are available then the bool, force,
00718 //  is set and the remaining half_edge is used, retracing a previous path
00719 //  in the opposite direction.
00720 void vtol_cycle_processor::compute_cycles()
00721 {
00722   int limit = 10*edges_.size();//just to be guard against any infinite loop
00723   while (edges_.size()&&limit--)//should be removed when sure none can happen
00724     if (found_next_edge_&&!cycle_)
00725     {
00726       bool force = false;
00727 
00728       if (debug1_&&last_) {
00729         vcl_cout << "last_ ="; last_->print(); vcl_cout <<vcl_endl;
00730       }
00731 
00732       vcl_vector<vtol_edge_2d_sptr> edges_at_last;
00733       v_edges(last_, edges_, force, edges_at_last);
00734       next_edge_ = search_for_next_edge(edges_at_last);
00735 
00736       if (!next_edge_&&!force)
00737       {
00738         force = true;
00739         v_edges(last_, edges_, force, edges_at_last);
00740         next_edge_ = search_for_next_edge(edges_at_last);
00741       }
00742       if (debug1_&&next_edge_) {
00743         vcl_cout << "next_edge_("<< force <<") = "; this->print_edge(next_edge_);
00744       }
00745 
00746       if (!next_edge_)
00747         found_next_edge_ = false;
00748       else
00749         add_edge_to_path();
00750       if (debug1_)
00751           vcl_cout << "========checking for cycle ===========\n"
00752                    << " last_ " << last_ << '('
00753                    << last_->cast_to_vertex_2d()->x()<< ' '
00754                    << last_->cast_to_vertex_2d()->y()<< ")\n";
00755       cycle_ = vcl_find(v_stack_.begin(), v_stack_.end(), last_) != v_stack_.end();
00756       if (debug1_&&cycle_)
00757         vcl_cout << "...Found Cycle....\n\n";
00758     }
00759     else
00760     {
00761       if (cycle_)
00762       {
00763         cycle_ = false;
00764         vcl_vector<vtol_edge_2d_sptr> cycle_edges;
00765         pop_stacks(v_stack_, e_stack_, last_, cycle_edges);
00766         if (debug1_)
00767         {
00768           vcl_cout << "======== In Cycle Classifier =======\n"
00769                    << "cycle_edges\n";
00770           print_edges(cycle_edges);
00771         }
00772         assign_stack_edge(e_stack_, l_);
00773         vtol_one_chain_sptr cycle;
00774         bool is_cycle = classify_path(cycle_edges, cycle);
00775         if (debug1_)
00776         {
00777           vcl_cout << "is_cycle(" << is_cycle << ")\n";
00778           if (cycle)
00779           {
00780             vcl_cout << "cycle " << cycle << "[cw(" << cw(cycle)
00781                      << "), ccw(" << ccw(cycle) << ")]\n";
00782             vcl_vector<vtol_edge_sptr> c_edges; cycle->edges(c_edges);
00783             vcl_cout << "cycle edges\n";
00784             print_edges(c_edges);
00785           }
00786         }
00787         if (is_cycle)
00788           chains_.push_back(cycle);
00789         else//path was all bridge edges, so remove them from consideration
00790           for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = cycle_edges.begin();
00791                eit != cycle_edges.end(); ++eit)
00792             edge_2d_erase(edges_,*eit);
00793       }
00794       if (!found_next_edge_)
00795       {
00796         //Get rid of edges touched in the search
00797         vcl_vector<vtol_edge_2d_sptr> removed_edges;
00798         for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = edges_.begin();
00799              eit != edges_.end(); ++eit)
00800           if (touched(*eit)&&used(*eit))
00801             removed_edges.push_back(*eit);
00802         for (vcl_vector<vtol_edge_2d_sptr>::iterator
00803              eit = removed_edges.begin(); eit != removed_edges.end();
00804              ++eit)
00805           edge_2d_erase(edges_,*eit);
00806 
00807         this->set_bridge_vars();
00808       }
00809     }
00810   if (!limit)
00811     vcl_cout << "Limit Exhaused in vtol_cycle_processor::compute_cycles(..)\n";
00812 }
00813 
00814 //-----------------------------------------------------------------
00815 //:
00816 //    The input is a set of 1-cycles in chains_.  These cycles are
00817 //    sorted so that they form a proper containment relation.  That
00818 //    is, there is one outer cycle, with traversal in the ccw direction
00819 //    and zero or more interior hole boundaries with traversal in
00820 //    the cw direction. All other cycles are removed.  The output is
00821 //    nested_one_cycles_.
00822 void vtol_cycle_processor::sort_one_cycles()
00823 {
00824   if (!chains_.size())
00825   {
00826     vcl_cout << "In vtol_cycle_processor::sort_one_cycles(..) no cycles\n";
00827     return;
00828   }
00829   nested_one_cycles_.clear();
00830   //First, find the outer bounding vtol_one_chain. This outer boundary is
00831   //defined as a ccw cycle with the largest bounding box.
00832   //search for the largest ccw bounding box
00833   double area = 0;
00834   vtol_one_chain_sptr outer_chain = 0;
00835   for (one_chain_list::iterator cit=chains_.begin(); cit!=chains_.end(); ++cit)
00836   {
00837     untouch(*cit);
00838     if (!ccw(*cit))
00839       continue;
00840     vsol_box_2d_sptr box = (*cit)->get_bounding_box();
00841     double WxH = box->width()*box->height();
00842     if (WxH>area)
00843     {
00844       area = WxH;
00845       outer_chain = *cit;
00846     }
00847   }
00848 
00849   if (!outer_chain||!ccw(outer_chain))
00850   {
00851     vcl_cout << "In vtol_cycle_processor::sort_one_cycles(..)"
00852              << " Shouldn't happen that there is no outer chain\n"
00853              << "N cycles = " << chains_.size() << vcl_endl;
00854     for (one_chain_list::iterator cit = chains_.begin();
00855          cit != chains_.end(); ++cit)
00856     {
00857       vcl_cout << " chain is " << (ccw(*cit) ? "" : "not ") << "ccw, "
00858                << "chain is " << (cw(*cit) ? "" : "not ") << "cw\n";
00859     }
00860     vcl_cout << "Outer Chain " << outer_chain << vcl_endl;
00861     return;
00862   }
00863   nested_one_cycles_.push_back(outer_chain);
00864   touch(outer_chain);
00865   if (debug1_)
00866     vcl_cout << "Outer Cycle area = " << area << vcl_endl;
00867   //At this point, we have the outer bounding chain.
00868   //next we will include any cw cycles that lie inside the
00869   //outer_chain.  We exclude any cycle with the same bounding
00870   //box as the outer cycle.  This condition can occur since the outer
00871   //boundary is mostly traced twice, once ccw and once cw when there is
00872   //an included loop in the outer boundary.  The boundary vertices will
00873   //be identical and thus the bounding box will be the same.
00874   //
00875   // - one caveat is that the equality test below is exact.
00876   //   some situations may require a tolerance
00877   vsol_box_2d_sptr b = outer_chain->get_bounding_box();
00878   for (one_chain_list::iterator cit=chains_.begin(); cit!=chains_.end(); ++cit)
00879     if (cw(*cit)&&!touched(*cit))
00880     {
00881       if ((*cit)==outer_chain)
00882         continue;
00883       vsol_box_2d_sptr bc = (*cit)->get_bounding_box();
00884       if ((*bc<*b)&&!bc->near_equal(*b, tolerance_))
00885       {
00886         vsol_box_2d_sptr bc = (*cit)->get_bounding_box();
00887         if ((*bc<*b)&&!bc->near_equal(*b, tolerance_))
00888         {
00889           if (debug1_)
00890             vcl_cout << "Adding inner cycle with area = "
00891                      << bc->width()*bc->height() << vcl_endl;
00892 
00893           nested_one_cycles_.push_back(*cit);
00894           touch(*cit);
00895         }
00896       }
00897     }
00898 }
00899 
00900 void vtol_cycle_processor::process()
00901 {
00902   this->compute_cycles();
00903   this->sort_one_cycles();
00904   valid_ = true;
00905 }
00906 
00907 bool vtol_cycle_processor::nested_one_cycles(one_chain_list& one_chains,
00908                                              const float& tolerance)
00909 {
00910   if (!valid_||tolerance!=tolerance_)
00911   {
00912     tolerance_ = tolerance;
00913     process();
00914   }
00915   one_chains = nested_one_cycles_;
00916   return true; //later return error state
00917 }
00918 
00919 //: flag mutation functions
00920 static void clear_flags(vcl_vector<vtol_edge_sptr>& s, unsigned int flag)
00921 {
00922   for (vcl_vector<vtol_edge_sptr>::iterator eit = s.begin();
00923        eit != s.end(); ++eit)
00924     (*eit)->unset_user_flag(flag);
00925 }
00926 
00927 static void set_flags(vcl_vector<vtol_edge_sptr>& s, unsigned int flag)
00928 {
00929   for (vcl_vector<vtol_edge_sptr>::iterator eit = s.begin();
00930        eit != s.end(); ++eit)
00931     (*eit)->set_user_flag(flag);
00932 }
00933 
00934 //---------------------------------------------------------------------------
00935 //: This method scans the edge sets s1, s2 and computes their set intersection.
00936 // If the intersection is empty then the method returns false.
00937 // The method uses flags to mark edges appearing in both lists. Thus the
00938 // computation is O(n1+n2).
00939 //
00940 // This method might not be needed if stl algorithms worked ("old" vcl probs)
00941 // however with flags this might be faster than stl
00942 //
00943 bool vtol_cycle_processor::intersect_edges(vcl_vector<vtol_edge_sptr>& s1,
00944                                            vcl_vector<vtol_edge_sptr>& s2,
00945                                            vcl_vector<vtol_edge_sptr>& s1_and_s2)
00946 {
00947   s1_and_s2.clear();
00948   //If either set is empty then the result is empty
00949   if (!(s1.size()&&s2.size()))
00950     return false;
00951   //Get Flags
00952   unsigned int flag1 = VSOL_FLAG5, flag2 = VSOL_FLAG6;
00953   //Scan through s2 and clear the flags
00954   clear_flags(s2, flag1);
00955   clear_flags(s2, flag2);
00956 
00957   //Scan through s1 and set flag 1 which is used to indicate
00958   //that an edge is in s1.
00959   set_flags(s1, flag1);
00960 
00961   //Scan s2 again and push edges also in s1  onto the set intersection
00962   //mark the edge as in the output list with flag2.
00963   for (vcl_vector<vtol_edge_sptr>::iterator eit = s2.begin();
00964        eit != s2.end(); ++eit)
00965   {
00966     vtol_edge_sptr e = *eit;
00967     if (e->get_user_flag(flag1)&&!e->get_user_flag(flag2))
00968     {
00969       e->set_user_flag(flag2);//mark the edge as in the output
00970       s1_and_s2.push_back(e);
00971     }
00972   }
00973   //clean up the flags
00974   clear_flags(s1, flag1);
00975   clear_flags(s2, flag1);
00976   clear_flags(s1, flag2);
00977   clear_flags(s2, flag2);
00978   return s1_and_s2.size()>0;
00979 }
00980 
00981 //---------------------------------------------------------------------------
00982 //: This method scans the edge sets s1, s2 and computes their set difference.
00983 // i.e, s1 with any edges also in s2 removed. If the difference
00984 // is empty then the method returns false. The method uses flags to mark
00985 // edges appearing in both lists. Thus the computation is O(n1+n2).
00986 //
00987 // This method might not be needed if stl algorithms worked ("old" vcl probs)
00988 // however with flags this might be faster than stl
00989 //
00990 bool vtol_cycle_processor::difference_edges(vcl_vector<vtol_edge_sptr>& s1,
00991                                             vcl_vector<vtol_edge_sptr>& s2,
00992                                             vcl_vector<vtol_edge_sptr>& s1_minus_s2)
00993 {
00994   s1_minus_s2.clear();
00995   //If either set is empty then the result is empty
00996   if (!(s1.size()&&s2.size()))
00997     return false;
00998   //Get Flags
00999   unsigned int flag1 = VSOL_FLAG5, flag2 = VSOL_FLAG6;
01000   //Scan through s1 and clear the flags
01001   clear_flags(s1, flag1);
01002   clear_flags(s1, flag2);
01003 
01004   //Scan through s2 and set flag1 which marks that it is in s2.
01005   set_flags(s2, flag1);
01006 
01007   //Scan s1 again and push edges exclusively in s1 onto the output
01008   //mark the edge as in the output list with flag2.
01009   for (vcl_vector<vtol_edge_sptr>::iterator eit = s1.begin();
01010        eit != s1.end(); ++eit)
01011   {
01012     vtol_edge_sptr e = *eit;
01013     if (!e->get_user_flag(flag1)&&!e->get_user_flag(flag2))
01014     {
01015       e->set_user_flag(flag2);//mark the edge as in the output
01016       s1_minus_s2.push_back(e);
01017     }
01018   }
01019   //Clean up the flags
01020   clear_flags(s1, flag1);
01021   clear_flags(s2, flag1);
01022   clear_flags(s1, flag2);
01023   clear_flags(s2, flag2);
01024   return s1_minus_s2.size()>0;
01025 }
01026 
01027 //--------------------------------------------------------------------
01028 //: mark all vertices as used if they are incident on exactly two edges.
01029 // Vertices that are not incident two edges are output in the vector, bad_verts.
01030 bool vtol_cycle_processor::corrupt_boundary(vcl_vector<vtol_edge_2d_sptr>& edges,
01031                                             vcl_vector<vtol_vertex_sptr>& bad_verts)
01032 {
01033   bool bad = false;
01034   //Initialize Markers
01035   if (!edges.front())
01036   {
01037     vcl_cout << "In cycle_processor::corrupt_boundary - null edge\n";
01038     return false;
01039   }
01040   //setup vertex flags
01041   unsigned int f1=VSOL_FLAG4, f2=VSOL_FLAG5, f3=VSOL_FLAG6;
01042   //Initialize Flags
01043   for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = edges.begin();
01044        eit != edges.end(); ++eit)
01045   {
01046     vtol_vertex_sptr v1 = (*eit)->v1();
01047     vtol_vertex_sptr v2 = (*eit)->v2();
01048     v1->unset_user_flag(f1);
01049     v1->unset_user_flag(f2);
01050     v1->unset_user_flag(f3);
01051     v2->unset_user_flag(f1);
01052     v2->unset_user_flag(f2);
01053     v2->unset_user_flag(f3);
01054   }
01055   //Mark using flags that a vertex is incident on two edges
01056   //Flags f1 and f2 act as a counter
01057   for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = edges.begin();
01058        eit != edges.end(); ++eit)
01059   {
01060     vtol_vertex_sptr v1 = (*eit)->v1();
01061     vtol_vertex_sptr v2 = (*eit)->v2();
01062     if (!v1->get_user_flag(f1))
01063       v1->set_user_flag(f1);
01064     else
01065       v1->set_user_flag(f2);
01066     if (!v2->get_user_flag(f1))
01067       v2->set_user_flag(f1);
01068     else
01069       v2->set_user_flag(f2);
01070   }
01071   for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = edges.begin();
01072        eit != edges.end(); ++eit)
01073   {
01074     vtol_vertex_sptr v1 = (*eit)->v1();
01075     vtol_vertex_sptr v2 = (*eit)->v2();
01076     if ((v1!=v2)&&*v1==*v2)
01077       vcl_cout << "Improper Loop(\n" << *v1 << *v2 << ")\n\n";
01078     bool bad1 = !v1->get_user_flag(f2);
01079     bool bad2 = !v2->get_user_flag(f2);
01080     // flag f3 keeps track that we have already put the vertex onto the bad list
01081     if (bad1)
01082     {
01083       if (!v1->get_user_flag(f3))
01084       {
01085         bad_verts.push_back(v1);
01086         v1->set_user_flag(f3);
01087       }
01088       bad = true;
01089     }
01090     if (bad2)
01091     {
01092       if (!v2->get_user_flag(f3))
01093       {
01094         bad_verts.push_back(v2);
01095         v2->set_user_flag(f3);
01096       }
01097       bad = true;
01098     }
01099   }
01100   //release the flags
01101   for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = edges.begin();
01102        eit != edges.end(); ++eit)
01103   {
01104     vtol_vertex_sptr v1 = (*eit)->v1();
01105     vtol_vertex_sptr v2 = (*eit)->v2();
01106     v1->unset_user_flag(f1);
01107     v1->unset_user_flag(f2);
01108     v1->unset_user_flag(f3);
01109     v2->unset_user_flag(f1);
01110     v2->unset_user_flag(f2);
01111     v2->unset_user_flag(f3);
01112   }
01113   return bad;
01114 }
01115 
01116 //--------------------------------------------------------------------
01117 //:
01118 //    Input is a set of edges that do not form cycles. There is a
01119 //    set of vertices that represent the unconnected endpoints of a
01120 //    set of paths.  Two endpoints can be connected if there exists
01121 //    an edge between them that is not included in the input set of
01122 //    edges.
01123 bool vtol_cycle_processor::connect_paths(vcl_vector<vtol_edge_2d_sptr>& edges,
01124                                          vcl_vector<vtol_vertex_sptr>& bad_verts)
01125 {
01126   bool paths_connected = true;
01127   if (!bad_verts.size())
01128     return paths_connected;
01129 
01130 //   if (edges.size()==1)
01131 //     vcl_cout << "One Edge\n";
01132 
01133   //Clear the bad vertex flags
01134   vcl_vector<vtol_vertex_sptr> temp;//temporary bad_verts array
01135 
01136   //
01137   //Establish flags
01138   //flag1 defines the state of a vertex in the search for a connecting edge
01139   //flag2 defines the state of a vertex in forming the set edge_verts,
01140   //that is there should be no duplicate vertices
01141   unsigned int flag1 = VSOL_FLAG5, flag2=VSOL_FLAG6;
01142   //here we assume that all vertices are uniform in flag use.
01143   if (!bad_verts.front())
01144     return false;
01145   //make a copy of bad_verts
01146   for (vcl_vector<vtol_vertex_sptr>::iterator vit = bad_verts.begin();
01147        vit != bad_verts.end(); ++vit)
01148   {
01149     (*vit)->unset_user_flag(flag1);
01150     temp.push_back(*vit);
01151   }
01152   //Collect the vertices from edges
01153   //Initialize the flags.
01154   for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = edges.begin();
01155        eit != edges.end(); ++eit)
01156   {
01157     vtol_vertex_sptr v1 = (*eit)->v1(), v2 = (*eit)->v2();
01158     v1->unset_user_flag(flag1); v2->unset_user_flag(flag1);
01159     v1->unset_user_flag(flag2); v2->unset_user_flag(flag2);
01160   }
01161   //cache the verts for the edges already in the paths
01162   //flag1 keeps track of vertices added to edge_verts
01163   vcl_vector<vtol_vertex_sptr> edge_verts;
01164   for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = edges.begin();
01165        eit != edges.end(); ++eit)
01166   {
01167     vtol_vertex_sptr v1 = (*eit)->v1(), v2 = (*eit)->v2();
01168     if (!v1->get_user_flag(flag1))
01169       {edge_verts.push_back(v1); v1->set_user_flag(flag1);}
01170     if (!v2->get_user_flag(flag1))
01171       {edge_verts.push_back(v2); v2->set_user_flag(flag1);}
01172   }
01173 
01174   //search through the list of bad verts and attempt to connect them
01175   //repaired_verts allows the successfully connected vertices to be
01176   //removed from the bad_verts set.  flag2 marks vertices as used.
01177   vcl_vector<vtol_vertex_sptr> repaired_verts;
01178   for (vcl_vector<vtol_vertex_sptr>::iterator vit=bad_verts.begin();
01179        vit != bad_verts.end(); ++vit)
01180   {
01181     if ((*vit)->get_user_flag(flag2))//skip used vertices
01182       continue;
01183     bool found_edge = false;
01184     //find edges attached to each bad vert
01185     vcl_vector<vtol_edge_sptr> vedges; (*vit)->edges(vedges);
01186     //scan through vedges to find a connecting edge
01187     for (vcl_vector<vtol_edge_sptr>::iterator eit = vedges.begin();
01188          eit != vedges.end()&&!found_edge; ++eit)
01189     {
01190       vtol_edge_2d_sptr e = (*eit)->cast_to_edge_2d();
01191       vtol_vertex_sptr v = (*eit)->other_endpoint(*(*vit));
01192       //Continue if:
01193       //  0)the edge e is not a 2d edge
01194       //  1)the vertex v has been used;
01195       //  2)v can't be found in bad_verts;
01196       //  3)v can't be found in edge_verts;
01197       //  4)e is already in the input edge set.
01198       if (!e)
01199         continue; //condition 0)
01200       if (v->get_user_flag(flag2))
01201         continue; //condition 1)
01202       bool found_in_bad_verts = vcl_find(temp.begin(),temp.end(),v) != temp.end();
01203       bool found_in_edge_verts = false;
01204       if (!found_in_bad_verts) //condition 2)
01205         found_in_edge_verts = vcl_find(edge_verts.begin(),edge_verts.end(),v) != edge_verts.end();
01206       if (!found_in_bad_verts && !found_in_edge_verts) // condition 3)
01207         continue;
01208       if ( vcl_find(edges.begin(),edges.end(),e) != edges.end())
01209         continue; //condition 4)
01210 
01211       //Found a connecting edge, so add it to the input edges
01212       edges.push_back(e);
01213       found_edge = true;
01214       v->set_user_flag(flag2);
01215       (*vit)->set_user_flag(flag2);
01216       //record the successes
01217       repaired_verts.push_back(*vit);
01218       repaired_verts.push_back(v);//should also be in bad_verts
01219     }
01220     paths_connected =
01221       paths_connected&&(*vit)->get_user_flag(flag2);
01222   }
01223   //Clear the flags
01224   for (vcl_vector<vtol_vertex_sptr>::iterator vit = bad_verts.begin();
01225        vit!=bad_verts.end(); ++vit)
01226   {
01227     (*vit)->unset_user_flag(flag1);
01228     (*vit)->unset_user_flag(flag2);
01229   }
01230   for (vcl_vector<vtol_vertex_sptr>::iterator vit = edge_verts.begin();
01231        vit!=edge_verts.end(); ++vit)
01232   {
01233     (*vit)->unset_user_flag(flag1);
01234     (*vit)->unset_user_flag(flag2);
01235   }
01236   //Remove the successful vertex connections
01237   for (vcl_vector<vtol_vertex_sptr>::iterator vit = repaired_verts.begin();
01238        vit != repaired_verts.end(); ++vit)
01239   {
01240     vcl_vector<vtol_vertex_sptr>::iterator erit;
01241     erit = vcl_find(bad_verts.begin(), bad_verts.end(), *vit);
01242     if (erit != bad_verts.end())
01243       bad_verts.erase(erit);
01244   }
01245   return paths_connected;
01246 }