contrib/brl/bbas/btol/btol_face_algs.cxx
Go to the documentation of this file.
00001 #include "btol_face_algs.h"
00002 //:
00003 // \file
00004 
00005 #include <vgl/vgl_point_2d.h>
00006 #include <vdgl/vdgl_digital_curve.h>
00007 #include <vdgl/vdgl_interpolator.h>
00008 #include <vdgl/vdgl_edgel_chain.h>
00009 #include <vtol/vtol_vertex_sptr.h>
00010 #include <vtol/vtol_vertex_2d.h>
00011 #include <vtol/vtol_edge_2d.h>
00012 #include <vtol/vtol_face_2d.h>
00013 #include <vsol/vsol_point_2d.h>
00014 #include <vsol/vsol_polygon_2d.h>
00015 #include <bsol/bsol_algs.h>
00016 #include "btol_vertex_algs.h"
00017 
00018 //:
00019 //If the edge direction is minus then the vertices are flipped using
00020 //the ::vertices() method. Thus they are out of order for eventual
00021 //re-linking.  This method avoids the flip problem.
00022 static bool properly_ordered_verts(vtol_one_chain_sptr const& cycle,
00023                                    vcl_vector<vtol_vertex_sptr>& verts)
00024 {
00025   if (!cycle||!cycle->is_cycle())
00026     return false;
00027   int n = cycle->num_edges();
00028   for (int i = 0; i<n; i++)
00029   {
00030     vtol_edge_sptr e = cycle->edge(i);
00031     verts.push_back(e->v1());
00032   }
00033   return true;
00034 }
00035 
00036 //: convert a face to a vgl_polygon
00037 bool btol_face_algs::vtol_to_vgl(vtol_face_2d_sptr const & face,
00038                                  vgl_polygon<double>& poly)
00039 {
00040   if (!face)
00041     return false;
00042 #if 0
00043   poly.clear();
00044   poly.new_sheet();
00045   vcl_vector<vtol_one_chain_sptr> one_chains;
00046   face->one_chains(one_chains);
00047   if (one_chains.size()!=1)
00048     return false;
00049   vcl_vector<vtol_vertex_sptr> verts;
00050   face->vertices(verts);
00051   if (!verts.size())
00052     return false;
00053   for (vcl_vector<vtol_vertex_sptr>::iterator vit = verts.begin();
00054        vit != verts.end(); vit++)
00055   {
00056     vtol_vertex_2d* v = (*vit)->cast_to_vertex_2d();
00057     if (v)
00058       poly.push_back(v->x(), v->y());
00059   }
00060 #endif
00061   poly.clear();
00062   poly.new_sheet();
00063   vcl_vector<vtol_vertex_sptr>* outside_verts =
00064     face->outside_boundary_vertices();
00065   for (vcl_vector<vtol_vertex_sptr>::iterator vit = outside_verts->begin();
00066        vit != outside_verts->end(); ++vit)
00067     {
00068       vtol_vertex_2d* v = (*vit)->cast_to_vertex_2d();
00069       if (v)
00070         poly.push_back(v->x(), v->y());
00071     }
00072   delete outside_verts;
00073   //add the holes, if any
00074   vcl_vector<vtol_one_chain_sptr>* hole_chains = face->get_hole_cycles();
00075   vcl_vector<vcl_vector<vtol_vertex_sptr> > all_hole_verts;
00076   for (vcl_vector<vtol_one_chain_sptr>::iterator cit = hole_chains->begin();
00077        cit != hole_chains->end(); cit++)
00078     {
00079       vcl_vector<vtol_vertex_sptr> hole_verts;
00080       if (!properly_ordered_verts(*cit, hole_verts))
00081        return false;
00082       poly.new_sheet();
00083       for (vcl_vector<vtol_vertex_sptr>::iterator vit = hole_verts.begin();
00084            vit != hole_verts.end(); ++vit)
00085         {
00086           vtol_vertex_2d_sptr v = (*vit)->cast_to_vertex_2d();
00087           if (v)
00088             poly.push_back(v->x(), v->y());
00089         }
00090     }
00091   delete hole_chains;
00092   return true;
00093 }
00094 
00095 //: convert a vgl_polygon to a vtol_face_2d.  Works for multiply-connected polys
00096 bool btol_face_algs::vgl_to_vtol(vgl_polygon<double>const & poly,
00097                                  vtol_face_2d_sptr& face)
00098 {
00099   //convert the polygon sheets to one_chains
00100   vcl_vector<vtol_one_chain_sptr> chains;
00101   int n_sheets = poly.num_sheets();
00102   for (int i = 0; i<n_sheets; i++)
00103   {
00104     vtol_one_chain_sptr chain = new vtol_one_chain();
00105     vcl_vector<vgl_point_2d<double> > s = poly[i];
00106     vgl_point_2d<double> p0 = s[0];
00107     vtol_vertex_2d_sptr vs = new vtol_vertex_2d(p0.x(), p0.y()), v0 = vs, vi;
00108     vtol_edge_2d_sptr e;
00109     for (vcl_vector<vgl_point_2d<double> >::iterator pit = s.begin()+1;
00110          pit != s.end(); ++pit)
00111       {
00112         vgl_point_2d<double> pi = *pit;
00113         vi = new vtol_vertex_2d(pi.x(), pi.y());
00114         e  = new vtol_edge_2d(v0, vi);
00115         chain->add_edge(e, i==0);//outer cycle is positive
00116         v0 = vi;
00117       }
00118     //last edge closes the cycle
00119     e = new vtol_edge_2d(vi, vs);
00120     chain->add_edge(e, i==0);//outer cycle is positive
00121     chain->set_cycle(true);
00122     chains.push_back(chain);
00123   }
00124   //so now we have a set of nested one chains
00125   //and can construct the face
00126   face  = new vtol_face_2d(chains);
00127   return true;
00128 }
00129 
00130 //: currently only works for a digital edge (not a line segment)
00131 bool btol_face_algs::edge_intersects(vtol_face_2d_sptr const & face,
00132                                      vtol_edge_2d_sptr const & edge)
00133 {
00134   if (!face||!edge)
00135     return false;
00136   //quick check
00137   vsol_box_2d_sptr face_bounds = face->get_bounding_box();
00138   vsol_box_2d_sptr edge_bounds = edge->get_bounding_box();
00139   if (!bsol_algs::meet(face_bounds, edge_bounds))
00140     return false;
00141   vsol_curve_2d_sptr c = edge->curve();
00142   vdgl_digital_curve_sptr dc = c->cast_to_vdgl_digital_curve();
00143   if (!dc)
00144   {
00145     vcl_cout << "In btol_face_algs::edge_intersects(.) -"
00146              << " only digital curve geometry implemented\n";
00147     return false;
00148   }
00149   //convert the face to a polygon
00150   vgl_polygon<double> poly;
00151   btol_face_algs::vtol_to_vgl(face, poly);
00152   //iterate through the digital curve points
00153   vdgl_interpolator_sptr intp = dc->get_interpolator();
00154   vdgl_edgel_chain_sptr ec = intp->get_edgel_chain();
00155   int nedgl = ec->size();
00156   for (int i=0; i<nedgl; i++)
00157     if (poly.contains((*ec)[i].x(), (*ec)[i].y()))
00158       return true;
00159   return false;
00160 }
00161 
00162 //: takes an input set of edges and constructs the intersecting set.
00163 //  Returns false if the intersecting set is empty.
00164 bool btol_face_algs::
00165 intersecting_edges(vtol_face_2d_sptr const & face,
00166                    vcl_vector<vtol_edge_2d_sptr> const & edges,
00167                    vcl_vector<vtol_edge_2d_sptr>& inter_edges)
00168 {
00169   if (!face||!edges.size())
00170     return false;
00171   inter_edges.clear();
00172   bool empty = true;
00173   for (vcl_vector<vtol_edge_2d_sptr>::const_iterator eit = edges.begin();
00174        eit != edges.end(); eit++)
00175     if (btol_face_algs::edge_intersects(face, *eit))
00176     {
00177       inter_edges.push_back(*eit);
00178       empty = false;
00179     }
00180   return !empty;
00181 }
00182 
00183 //: only works if the edges are straight lines
00184 vsol_point_2d_sptr btol_face_algs::centroid(vtol_face_2d_sptr const & face)
00185 {
00186   if (!face)
00187     return (vsol_point_2d*)0;
00188   vcl_vector<vtol_vertex_sptr> verts;
00189   face->vertices(verts);
00190   int n = 0;
00191   double x0=0, y0=0;
00192   for (vcl_vector<vtol_vertex_sptr>::iterator vit = verts.begin();
00193        vit != verts.end(); vit++, n++)
00194   {
00195     vtol_vertex_2d_sptr v = (*vit)->cast_to_vertex_2d();
00196     x0 += v->x();
00197     y0 += v->y();
00198   }
00199   if (!n)
00200     return (vsol_point_2d*)0;
00201   x0 /=n;
00202   y0 /=n;
00203   return new vsol_point_2d(x0, y0);
00204 }
00205 
00206 vtol_face_2d_sptr btol_face_algs::box(const double x0, const double y0,
00207                                       const double width, const double height)
00208 {
00209   double w = width/2, h = height/2;
00210   vcl_vector<vtol_vertex_sptr> verts;
00211   vtol_vertex_2d* v0 = new vtol_vertex_2d(x0-w, y0-h);
00212   vtol_vertex_2d* v1 = new vtol_vertex_2d(x0+w, y0-h);
00213   vtol_vertex_2d* v2 = new vtol_vertex_2d(x0+w, y0+h);
00214   vtol_vertex_2d* v3 = new vtol_vertex_2d(x0-w, y0+h);
00215   verts.push_back(v0); verts.push_back(v1);
00216   verts.push_back(v2); verts.push_back(v3);
00217   vtol_face_2d_sptr f = new vtol_face_2d(verts);
00218   return f;
00219 }
00220 
00221 //: create a simply-connected one_chain from a set of vertices.
00222 // dir=true corresponds to +.
00223 vtol_one_chain_sptr btol_face_algs::
00224 one_chain(vcl_vector<vtol_vertex_sptr> const& verts)
00225 {
00226   vtol_one_chain_sptr out;
00227   int n = verts.size();
00228   if (n<3)
00229     return out;
00230   vtol_vertex_2d_sptr v0 = verts[0]->cast_to_vertex_2d(), vs = v0, vi;
00231   vtol_edge_2d_sptr e;
00232   out = new vtol_one_chain();
00233   for (int i = 1; i<n; i++)
00234   {
00235     vi = verts[i]->cast_to_vertex_2d();
00236     e = new vtol_edge_2d(v0, vi);
00237     out->add_edge(e, true);
00238     v0=vi;
00239   }
00240   //add final edge
00241   e = new vtol_edge_2d(vi, vs);
00242   out->add_edge(e, true);
00243   out->set_cycle(true);
00244   return out;
00245 }
00246 
00247 //: create a new face by transforming the input face.
00248 // Only valid for faces with linear (straight line) geometry
00249 vtol_face_2d_sptr btol_face_algs::
00250 transform(vtol_face_2d_sptr const& face,
00251           vnl_matrix_fixed<double, 3, 3> const& T)
00252 {
00253   vtol_face_2d_sptr out;
00254   if (!face)
00255     return out;
00256   // transform the vertices of the outside boundary
00257   vcl_vector<vtol_vertex_sptr>* outside_verts =
00258     face->outside_boundary_vertices();
00259 
00260   vcl_vector<vtol_vertex_sptr> trans_outside_verts;
00261   for (vcl_vector<vtol_vertex_sptr>::iterator vit = outside_verts->begin();
00262        vit != outside_verts->end(); ++vit)
00263     {
00264       vtol_vertex_2d_sptr new_v =
00265         btol_vertex_algs::transform((*vit)->cast_to_vertex_2d(), T);
00266       if (!new_v)
00267         return out;
00268       trans_outside_verts.push_back(new_v->cast_to_vertex());
00269     }
00270   delete outside_verts;
00271   // transform the vertices of the interior holes
00272   vcl_vector<vtol_one_chain_sptr>* hole_chains = face->get_hole_cycles();
00273   vcl_vector<vcl_vector<vtol_vertex_sptr> > trans_hole_verts;
00274   for (vcl_vector<vtol_one_chain_sptr>::iterator cit = hole_chains->begin();
00275        cit != hole_chains->end(); cit++)
00276   {
00277     vcl_vector<vtol_vertex_sptr> hole_verts, t_hole_verts;
00278     if (!properly_ordered_verts(*cit, hole_verts))
00279       return out;
00280     for (vcl_vector<vtol_vertex_sptr>::iterator vit = hole_verts.begin();
00281          vit != hole_verts.end(); ++vit)
00282     {
00283       vtol_vertex_2d_sptr v = (*vit)->cast_to_vertex_2d();
00284       vtol_vertex_2d_sptr new_v =
00285         btol_vertex_algs::transform(v, T);
00286       if (!new_v)
00287         return out;
00288       t_hole_verts.push_back(new_v->cast_to_vertex());
00289     }
00290     trans_hole_verts.push_back(t_hole_verts);
00291   }
00292   delete hole_chains;
00293   //now reassemble the face
00294   //form the chains
00295   vcl_vector<vtol_one_chain_sptr> new_chains;
00296   new_chains.push_back(btol_face_algs::one_chain(trans_outside_verts));
00297   for (vcl_vector<vcl_vector<vtol_vertex_sptr> >::iterator vts =
00298        trans_hole_verts.begin(); vts != trans_hole_verts.end(); ++vts)
00299     new_chains.push_back(btol_face_algs::one_chain(*vts));
00300 
00301   //construct the face
00302   return new vtol_face_2d(new_chains);
00303 }
00304 
00305 //=========================================================
00306 // Convert a vsol polygon to a vtol face.  No interior holes
00307 //
00308 bool btol_face_algs::vsol_to_vtol(vsol_polygon_2d_sptr const & poly,
00309                                   vtol_face_2d_sptr& face)
00310 {
00311   if (!poly)
00312     return false;
00313   int n_verts = poly->size();
00314   if (!n_verts)
00315     return false;
00316   vcl_vector<vtol_vertex_sptr> verts;
00317   for (int i = 0; i<n_verts; i++)
00318   {
00319     vsol_point_2d_sptr p = poly->vertex(i);
00320     vtol_vertex_sptr v = (new vtol_vertex_2d(p->x(), p->y()))->cast_to_vertex();
00321     verts.push_back(v);
00322   }
00323   face = new vtol_face_2d(verts);
00324   return true;
00325 }