contrib/brl/bseg/bmdl/bmdl_mesh.cxx
Go to the documentation of this file.
00001 // This is brl/bseg/bmdl/bmdl_mesh.cxx
00002 #include "bmdl_mesh.h"
00003 //:
00004 // \file
00005 
00006 #include <vgl/vgl_intersection.h>
00007 #include <vgl/vgl_lineseg_test.h>
00008 #include <vgl/algo/vgl_fit_lines_2d.h>
00009 #include <vgl/vgl_area.h>
00010 #include <vgl/vgl_polygon.h>
00011 #include <vgl/vgl_line_2d.h>
00012 #include <vgl/vgl_distance.h>
00013 #include <vil/vil_bilin_interp.h>
00014 #include <vcl_cassert.h>
00015 #include <vcl_map.h>
00016 
00017 //: find the next trace point and direction
00018 bool bmdl_mesh::next_trace_point(unsigned int& i, unsigned int& j, int& dir,
00019                                  const unsigned int* &p, unsigned int value,
00020                                  unsigned int ni1, unsigned int nj1,
00021                                  vcl_ptrdiff_t istep, vcl_ptrdiff_t jstep)
00022 {
00023   bool moved = false;
00024   // else follow the straight edge
00025   switch (dir) {
00026     case 1:
00027       if (i<ni1 && p[istep]==value) { ++i; p+=istep; moved = true; }
00028       break;
00029     case 2:
00030       if (j<nj1 && p[jstep]==value) { ++j; p+=jstep; moved = true; }
00031       break;
00032     case 3:
00033       if (i>0 && p[-istep]==value) { --i; p-=istep; moved = true; }
00034       break;
00035     case 0:
00036       if (j>0 && p[-jstep]==value) { --j; p-=jstep; moved = true; }
00037       break;
00038     default:
00039       return false;
00040   }
00041 
00042   if (moved) {
00043     // if inside a concave corner, turn the corner
00044     switch (dir) {
00045       case 0:
00046         if (i<ni1 && p[istep]==value) { ++i; p+=istep; dir=1; }
00047         break;
00048       case 1:
00049         if (j<nj1 && p[jstep]==value) { ++j; p+=jstep; dir=2; }
00050         break;
00051       case 2:
00052         if (i>0 && p[-istep]==value) { --i; p-=istep; dir=3; }
00053         break;
00054       case 3:
00055         if (j>0 && p[-jstep]==value) { --j; p-=jstep; dir=0; }
00056         break;
00057       default:
00058         return false;
00059     }
00060   }
00061   else {
00062     // inside a convex corner, turn the corner
00063     dir = (dir+3)%4;
00064   }
00065   return true;
00066 }
00067 
00068 
00069 //: trace a single boundary starting and location (i,j)
00070 bool bmdl_mesh::trace_boundary(vcl_vector<vgl_point_2d<double> >& pts,
00071                                unsigned int value,
00072                                const vil_image_view<unsigned int>& labels,
00073                                vil_image_view<bool>& visited,
00074                                unsigned int i, unsigned int j)
00075 {
00076   unsigned int ni = labels.ni();
00077   unsigned int nj = labels.nj();
00078   vcl_ptrdiff_t istep = labels.istep(), jstep=labels.jstep();
00079   const unsigned* p = &labels(i,j);
00080   if (*p != value)
00081     return false;
00082 
00083   // first direction
00084   int dir = 2;
00085 
00086   unsigned int i0=i, j0=j;
00087   unsigned int ni1=ni-1, nj1=nj-1;
00088 
00089   do {
00090     if (dir == 2) {
00091       if (visited(i,j))
00092         return false;
00093       visited(i,j) = true;
00094     }
00095     unsigned int pi = i+((dir==0||dir==3)?1:0);
00096     unsigned int pj = j+((dir/2==0)?1:0);
00097     pts.push_back(vgl_point_2d<double>(pi-0.5, pj-0.5));
00098     next_trace_point(i,j,dir,p,value,ni1,nj1,istep,jstep);
00099   }
00100   while (i!=i0 || j!=j0 || dir!=2);
00101 
00102   return true;
00103 }
00104 
00105 
00106 //: trace the boundaries of the building labels into polygons
00107 // If \a dropped_clipped is true then buildings clipped by the image boundaries are not traced
00108 vcl_vector<vgl_polygon<double> >
00109 bmdl_mesh::trace_boundaries(const vil_image_view<unsigned int>& labels,
00110                             bool drop_clipped)
00111 {
00112   int ni = labels.ni();
00113   int nj = labels.nj();
00114   // find the largest label
00115   unsigned int num_labels = 0;
00116   for (int j=0; j<nj; ++j)
00117     for (int i=0; i<ni; ++i)
00118       if (labels(i,j) > num_labels)
00119         num_labels = labels(i,j);
00120 
00121   vcl_vector<vgl_polygon<double> > boundaries(num_labels,vgl_polygon<double>(0));
00122   for (unsigned i=0; i<num_labels; ++i)
00123     boundaries[i].clear();
00124   vil_image_view<bool> visited(ni,nj);
00125   visited.fill(false);
00126 
00127   for (int j=0; j<nj; ++j) {
00128     for (int i=0; i<ni; ++i) {
00129       unsigned int l = labels(i,j);
00130       if (l<2) continue;
00131       if (!visited(i,j) && (i==0 || labels(i-1,j)!=l)) {
00132         assert(l-2<boundaries.size());
00133         vgl_polygon<double>& poly = boundaries[l-2];
00134         vcl_vector<vgl_point_2d<double> > sheet;
00135 
00136         // trace the boundary and keep it only if it is not clipped
00137         // (or we don't care about clipping)
00138         if (trace_boundary(sheet,l,labels,visited,i,j) &&
00139             (!drop_clipped || !is_clipped(sheet,ni,nj)))
00140           poly.push_back(sheet);
00141       }
00142     }
00143   }
00144 
00145   return boundaries;
00146 }
00147 
00148 //: test if a boundary is clipped by the image of size \a ni by \a nj
00149 bool bmdl_mesh::is_clipped(const vcl_vector<vgl_point_2d<double> >& poly,
00150                            unsigned ni, unsigned nj)
00151 {
00152   // the maximum pixels are ni-1 and nj-1
00153   --ni;
00154   --nj;
00155   for (unsigned int i=0; i<poly.size(); ++i)
00156   {
00157     if (poly[i].x() < 0.0 || poly[i].y() < 0.0 ||
00158         poly[i].x() > ni || poly[i].y() > nj)
00159       return true;
00160   }
00161 
00162   return false;
00163 }
00164 
00165 
00166 namespace
00167 {
00168   // return a reference to the edge bin corresponding the edge between p1 and p2
00169   unsigned int& get_edge_bin(vil_image_view<unsigned int>& edge_bins,
00170                              const vgl_point_2d<double>& p1,
00171                              const vgl_point_2d<double>& p2)
00172   {
00173     unsigned int *binp = 0;
00174     if (vcl_abs(p2.x() - p1.x()) < 0.5)
00175     {
00176       binp = &edge_bins(static_cast<unsigned int>(p1.x()+1.0),
00177                         static_cast<unsigned int>((p1.y()+p2.y())/2.0+0.5), 0);
00178     }
00179     else
00180     {
00181       binp = &edge_bins(static_cast<unsigned int>((p1.x()+p2.x())/2.0+0.5),
00182                         static_cast<unsigned int>(p1.y()+1.0), 1);
00183     }
00184     return *binp;
00185   }
00186 }
00187 
00188 
00189 //: extract shared boundary edges from the polygon boundaries
00190 unsigned int bmdl_mesh::link_boundary_edges(const vil_image_view<unsigned int>& labels,
00191                                             const vcl_vector<vgl_polygon<double> >& polygons,
00192                                             vcl_vector<bmdl_edge>& edges,
00193                                             vcl_vector<bmdl_region>& regions)
00194 {
00195   unsigned int ni = labels.ni();
00196   unsigned int nj = labels.nj();
00197   vil_image_view<unsigned int> edge_labels(ni+1, nj+1, 2);
00198   edge_labels.fill(0);
00199 
00200   unsigned int joint_count = 0;
00201   unsigned int last_joint = static_cast<unsigned int>(-1);
00202 
00203   regions.resize(polygons.size());
00204   for (unsigned int i=0; i<polygons.size(); ++i)
00205   {
00206     const vgl_polygon<double>& poly = polygons[i];
00207     if (poly.num_sheets() < 1)
00208       continue;
00209     // determine which sheets are holes (CW vs CCW orientation)
00210     unsigned int num_cw=0, num_ccw=0;
00211     vcl_vector<bool> is_hole(poly.num_sheets(),false);
00212     for (unsigned int j=0; j<poly.num_sheets(); ++j)
00213     {
00214       double area = vgl_area_signed(vgl_polygon<double>(poly[j]));
00215       is_hole[j] = (area > 0.0);
00216       if (is_hole[j])
00217         ++num_ccw;
00218       else
00219         ++num_cw;
00220     }
00221     // expect to find exactly 1 CW sheet
00222     if (num_cw == 0)
00223       continue;
00224     else if (num_cw > 1)
00225     {
00226       vcl_cerr << "Ignoring polygon with multiple connected components "<< i << vcl_endl;
00227       for (unsigned int k=0; k<is_hole.size(); ++k)
00228         if (!is_hole[k])
00229         {
00230           vcl_cout << "  "<<poly[k][0].x()<<", "<<poly[k][0].y()<<vcl_endl;
00231         }
00232       continue;
00233     }
00234     bmdl_region& region = regions[i];
00235     if (num_ccw > 0)
00236       region.hole_edge_idxs.resize(num_ccw);
00237     unsigned int hole_count = 0;
00238     for (unsigned int j=0; j<poly.num_sheets(); ++j)
00239     {
00240       const vcl_vector<vgl_point_2d<double> >& pts = poly[j];
00241       vcl_vector<unsigned int>& edge_idxs = (!is_hole[j]) ?
00242                                             region.edge_idxs :
00243                                             region.hole_edge_idxs[hole_count++];
00244       for (unsigned int k1=pts.size()-1,k2=0; k2<pts.size(); k1=k2++)
00245       {
00246         vgl_vector_2d<double> v(pts[k2]-pts[k1]);
00247         vgl_point_2d<double> p = pts[k1] + 0.5*v;
00248         p += vgl_vector_2d<double>(-0.5*v.y(), 0.5*v.x());
00249         int x = static_cast<int>(p.x()+0.5);
00250         int y = static_cast<int>(p.y()+0.5);
00251         unsigned l = 0;
00252         if (x >= 0 && (unsigned)x < ni && y >=0 && (unsigned)y < nj)
00253         {
00254           l = labels(x,y);
00255           if (l > 0)
00256             l -= 1;
00257         }
00258 
00259         // find the bin for storing indices of edges already created
00260         unsigned int& bin = get_edge_bin(edge_labels,pts[k1],pts[k2]);
00261 
00262         if (bin > 0) // the label already exists
00263         {
00264           if (edge_idxs.empty() || edge_idxs.back() != bin-1)
00265           {
00266             // correct last joint if just created
00267             if (!edge_idxs.empty() && edges[edge_idxs.back()].building1 == i+1)
00268             {
00269               edges[edge_idxs.back()].joint2 = edges[bin-1].joint2;
00270               --joint_count;
00271             }
00272             edge_idxs.push_back(bin-1);
00273             assert(edges[edge_idxs.back()].building1 == l);
00274             assert(edges[edge_idxs.back()].building2 == i+1);
00275             last_joint = edges[edge_idxs.back()].joint1;
00276           }
00277         }
00278         else // create and build a new edge
00279         {
00280           if (edge_idxs.empty() || edges[edge_idxs.back()].building2 != l)
00281           {
00282             // start a new edge
00283             edge_idxs.push_back(edges.size());
00284             edges.push_back(bmdl_edge(i+1,l));
00285             edges.back().pts.push_back(pts[k1]);
00286             edges.back().joint1 = last_joint;
00287             edges.back().joint2 = joint_count++;
00288             last_joint = edges.back().joint2;
00289           }
00290           edges[edge_idxs.back()].pts.push_back(pts[k2]);
00291           bin = edge_idxs.back()+1;
00292         }
00293       }
00294       // handle special cases at the starting point
00295       if (edge_idxs.size() > 1)
00296       {
00297         // A region may touch the same previously created edge at beginning and end
00298         if (edge_idxs.front() == edge_idxs.back() &&
00299             edges[edge_idxs.front()].building2 == i+1)
00300         {
00301           edge_idxs.pop_back();
00302         }
00303         // Created edges at beginning and end may touch the same region (merge them)
00304         else if (edges[edge_idxs.front()].building2 == edges[edge_idxs.back()].building2 &&
00305                  edges[edge_idxs.front()].building2 != i+1)
00306         {
00307           vcl_vector<vgl_point_2d<double> >& pts1 = edges[edge_idxs.front()].pts;
00308           vcl_vector<vgl_point_2d<double> >& pts2 = edges[edge_idxs.back()].pts;
00309           // relabel bins
00310           for (unsigned int k=1; k<pts2.size(); ++k)
00311           {
00312             unsigned int& bin = get_edge_bin(edge_labels,pts2[k-1],pts2[k]);
00313             bin = edge_idxs.front()+1;
00314           }
00315           assert((pts1.front() - pts2.back()).length() < 1e-6);
00316           pts2.insert(pts2.end(),pts1.begin()+1,pts1.end());
00317           pts1.swap(pts2);
00318           assert(edge_idxs.back()+1 == edges.size());
00319           last_joint = edges[edge_idxs.back()].joint1;
00320           edge_idxs.pop_back();
00321           edges.pop_back();
00322           --joint_count;
00323         }
00324         // correct last joint if just created and the first edge was preexisting
00325         else if (edges[edge_idxs.back()].building1 == i+1 &&
00326                  edges[edge_idxs.front()].building2 == i+1 &&
00327                  edges[edge_idxs.back()].joint2 != edges[edge_idxs.front()].joint2 )
00328         {
00329           edges[edge_idxs.back()].joint2 = edges[edge_idxs.front()].joint2;
00330           --joint_count;
00331           --last_joint;
00332         }
00333       }
00334       // fix starting joint by completing the cycle
00335       if (edges[edge_idxs.front()].building1 == i+1)
00336       {
00337         edges[edge_idxs.front()].joint1 = last_joint;
00338       }
00339     }
00340   }
00341   return joint_count;
00342 }
00343 
00344 
00345 //: simplify a polygon by fitting lines
00346 // \a tol is the tolerance for line fitting
00347 void bmdl_mesh::simplify_polygon( vcl_vector<vgl_point_2d<double> >& pts, double tol )
00348 {
00349   vgl_fit_lines_2d<double> line_fitter(3,tol);
00350   // duplicate the last point to close the loop
00351   line_fitter.add_point(pts.back());
00352   line_fitter.add_curve(pts);
00353   line_fitter.fit();
00354   const vcl_vector<vgl_line_segment_2d<double> >& segs = line_fitter.get_line_segs();
00355   const vcl_vector<int>& indices = line_fitter.get_indices();
00356   vcl_vector<vgl_point_2d<double> > new_pts;
00357   vgl_point_2d<double> isect;
00358   for ( unsigned int i=0; i< indices.size(); )
00359   {
00360     if (indices[i] < 0)
00361     {
00362       new_pts.push_back(pts[i++]);
00363       continue;
00364     }
00365     const vgl_line_segment_2d<double>& seg = segs[indices[i]];
00366     // fix very short segments that trim corners
00367     if (new_pts.size() > 1 && vgl_distance(new_pts.back(),seg.point1())< 1.0 &&
00368         angle(vgl_vector_2d<double>(new_pts.back()-new_pts[new_pts.size()-2]),
00369               vgl_vector_2d<double>(seg.point1()-seg.point2())) > 0.5) {
00370       vgl_intersection(vgl_line_2d<double>(new_pts[new_pts.size()-2], new_pts.back()),
00371                        vgl_line_2d<double>(seg.point1(),seg.point2()),
00372                        isect);
00373       new_pts.back() = isect;
00374     }
00375     else
00376       new_pts.push_back(seg.point1());
00377     new_pts.push_back(seg.point2());
00378     // skip to the next point not part of this line
00379     for (int curr_seg_idx = indices[i];
00380          i<indices.size() && indices[i] == curr_seg_idx; ++i)
00381       ;
00382   }
00383   if (new_pts.size() > 3 && vgl_distance(new_pts.back(),new_pts.front())<1.0 &&
00384       angle(vgl_vector_2d<double>(new_pts.back()-new_pts[new_pts.size()-2]),
00385             vgl_vector_2d<double>(new_pts[0]-new_pts[1])) > 0.5) {
00386     vgl_intersection(vgl_line_2d<double>(new_pts[new_pts.size()-2], new_pts.back()),
00387                      vgl_line_2d<double>(new_pts[0],new_pts[1]),
00388                      isect);
00389     new_pts[0] = isect;
00390     new_pts.pop_back();
00391   }
00392   pts.swap(new_pts);
00393 }
00394 
00395 
00396 //: simplify the boundaries by fitting lines
00397 void bmdl_mesh::simplify_boundaries( vcl_vector<vgl_polygon<double> >& boundaries )
00398 {
00399   // fit lines to the data points
00400   for (unsigned int i=0; i<boundaries.size(); ++i)
00401   {
00402     vgl_polygon<double>& poly = boundaries[i];
00403     for (unsigned int j=0; j<poly.num_sheets(); ++j)
00404     {
00405       vcl_vector<vgl_point_2d<double> >& pts = poly[j];
00406       // shift point to the edge centers (diagonals line up better this way)
00407       vcl_vector<vgl_point_2d<double> > new_pts;
00408       for (unsigned p1=pts.size()-1, p2=0; p2<pts.size(); p1=p2, ++p2) {
00409         new_pts.push_back(vgl_point_2d<double>((pts[p1].x()+pts[p2].x())/2, (pts[p1].y()+pts[p2].y())/2));
00410       }
00411       pts.swap(new_pts);
00412 
00413       simplify_polygon(pts,0.01);
00414       simplify_polygon(pts,0.5);
00415     }
00416   }
00417 }
00418 
00419 
00420 //: simplify an edge by fitting lines
00421 // \a tol is the tolerance for line fitting
00422 void bmdl_mesh::simplify_edge( vcl_vector<vgl_point_2d<double> >& pts, double tol )
00423 {
00424   vgl_fit_lines_2d<double> line_fitter(3,tol);
00425   line_fitter.add_curve(pts);
00426   line_fitter.fit();
00427   const vcl_vector<vgl_line_segment_2d<double> >& segs = line_fitter.get_line_segs();
00428   const vcl_vector<int>& indices = line_fitter.get_indices();
00429   vcl_vector<vgl_point_2d<double> > new_pts;
00430   // the first point must be retained
00431   new_pts.push_back(pts.front());
00432   vgl_point_2d<double> isect;
00433   for ( unsigned int i=0; i< indices.size(); )
00434   {
00435     if (indices[i] < 0)
00436     {
00437       if (i==0 || i==indices.size()-1)
00438         ++i;
00439       else if (new_pts.empty() || new_pts.back() != pts[i])
00440         new_pts.push_back(pts[i++]);
00441 
00442       continue;
00443     }
00444     const vgl_line_segment_2d<double>& seg = segs[indices[i]];
00445     // fix very short segments that trim corners
00446     if (new_pts.size() > 1 && vgl_distance(new_pts.back(),seg.point1())< 1.0 &&
00447         angle(vgl_vector_2d<double>(new_pts.back()-new_pts[new_pts.size()-2]),
00448               vgl_vector_2d<double>(seg.point1()-seg.point2())) > 0.5) {
00449       vgl_intersection(vgl_line_2d<double>(new_pts[new_pts.size()-2], new_pts.back()),
00450                        vgl_line_2d<double>(seg.point1(),seg.point2()),
00451                        isect);
00452       new_pts.back() = isect;
00453     }
00454     // avoid duplicating the first point
00455     else if (i>0 || (seg.point1()-pts.front()).length()>0.5)
00456       new_pts.push_back(seg.point1());
00457 
00458     // remove duplicate points
00459     if (new_pts.size()>1 && new_pts.back() == new_pts[new_pts.size()-2])
00460       new_pts.pop_back();
00461 
00462     // skip to the next point not part of this line
00463     for (int curr_seg_idx = indices[i];
00464          i<indices.size() && indices[i] == curr_seg_idx; ++i)
00465       ;
00466 
00467     // avoid duplicating the last point
00468     if (i<indices.size() || (seg.point2()-pts.back()).length()>0.5)
00469       new_pts.push_back(seg.point2());
00470 
00471     if (new_pts.size()>1 && new_pts.back() == new_pts[new_pts.size()-2])
00472       new_pts.pop_back();
00473   }
00474   // the last point must be retained
00475   new_pts.push_back(pts.back());
00476   pts.swap(new_pts);
00477 }
00478 
00479 
00480 //: simplify the linked edges by fitting lines
00481 void bmdl_mesh::simplify_edges( vcl_vector<bmdl_edge>& edges )
00482 {
00483   for (unsigned int i=0; i<edges.size(); ++i)
00484   {
00485     vcl_vector<vgl_point_2d<double> >& pts = edges[i].pts;
00486 
00487     // shift point to the edge centers (diagonals line up better this way)
00488     vcl_vector<vgl_point_2d<double> > new_pts;
00489     new_pts.push_back(pts.front());
00490     for (unsigned j=1; j<pts.size(); ++j) {
00491       new_pts.push_back(vgl_point_2d<double>((pts[j-1].x()+pts[j].x())/2,
00492                                              (pts[j-1].y()+pts[j].y())/2));
00493     }
00494     new_pts.push_back(pts.back());
00495     pts.swap(new_pts);
00496 
00497     simplify_edge(pts, 0.01);
00498     simplify_edge(pts, 0.5);
00499   }
00500 }
00501 
00502 
00503 //: construct a mesh out of data and labels
00504 // The coordinate system is flipped over the x-axis to make it right handed
00505 // i.e. (x,y) -> (x,-y)
00506 void bmdl_mesh::mesh_lidar(const vcl_vector<vgl_polygon<double> >& boundaries,
00507                            const vil_image_view<unsigned int>& labels,
00508                            const vil_image_view<double>& heights,
00509                            const vil_image_view<double>& ground,
00510                            imesh_mesh& mesh)
00511 {
00512   unsigned ni = labels.ni();
00513   unsigned nj = labels.nj();
00514 
00515   // recover the vector of building heights
00516   vcl_vector<double> bld_heights(boundaries.size());
00517   for (unsigned int j=0; j<nj; ++j){
00518     for (unsigned int i=0; i<ni; ++i){
00519       if (labels(i,j) > 1){
00520         bld_heights[labels(i,j)-2] = heights(i,j);
00521       }
00522     }
00523   }
00524 
00525   imesh_vertex_array<3> *verts = new imesh_vertex_array<3>;
00526   imesh_face_array *faces = new imesh_face_array;
00527 
00528   // create the buildings
00529   for (unsigned int b=0; b<boundaries.size(); ++b) {
00530     if (boundaries[b].num_sheets() == 0)
00531       continue;
00532     const vcl_vector<vgl_point_2d<double> >& pts = boundaries[b][0];
00533     if (pts.size()<3)
00534       continue;
00535 
00536     unsigned int first_pt = verts->size();
00537     vcl_vector< unsigned int > roof;
00538     for (unsigned i=0; i<pts.size(); ++i) {
00539       const vgl_point_2d<double>& pt = pts[i];
00540       double g = vil_bilin_interp_safe_extend(ground, pt.x(), pt.y());
00541       verts->push_back(imesh_vertex<3>(pt.x(),-pt.y(), g));
00542       verts->push_back(imesh_vertex<3>(pt.x(),-pt.y(),bld_heights[b]));
00543       unsigned int bi = first_pt + 2*i;
00544       faces->push_back(imesh_quad(bi+1,bi,bi+2,bi+3));
00545       roof.push_back(bi+1);
00546     }
00547     // correct to loop back around to the start
00548     vcl_vector< unsigned int >& last_face = (*faces)[faces->size()-1];
00549     last_face[2] = first_pt;
00550     last_face[3] = first_pt+1;
00551 
00552     faces->push_back(roof);
00553   }
00554 
00555   vcl_auto_ptr<imesh_vertex_array_base> vb(verts);
00556   vcl_auto_ptr<imesh_face_array_base> fb(faces);
00557   mesh.set_vertices(vb);
00558   mesh.set_faces(fb);
00559 }
00560 
00561 
00562 namespace{
00563   unsigned int add_joint_vertex(imesh_vertex_array<3>& verts,
00564                                 vcl_vector<unsigned int>& vert_stack,
00565                                 const imesh_vertex<3>& v)
00566   {
00567     bool found = false;
00568     vcl_vector<unsigned int>::iterator i=vert_stack.begin();
00569     for (; i!=vert_stack.end() && verts[*i][2] <= v[2]; ++i)
00570     {
00571       if (verts[*i][2] == v[2])
00572       {
00573         found = true;
00574         break;
00575       }
00576     }
00577     if (found)
00578       return *i;
00579 
00580     unsigned int bi = verts.size();
00581     verts.push_back(v);
00582     vert_stack.insert(i,bi);
00583     return bi;
00584   }
00585 
00586 
00587   inline vcl_vector<unsigned int>::const_iterator
00588   find_by_height(const vcl_vector<unsigned int>& idxs,
00589                  const imesh_vertex_array<3>& verts,
00590                  double height)
00591   {
00592     for (vcl_vector<unsigned int>::const_iterator i=idxs.begin(); i!=idxs.end(); ++i)
00593       if (verts[*i][2] == height)
00594         return i;
00595     return idxs.end();
00596   }
00597 }
00598 
00599 //: construct a mesh out of data and labels using linked edges
00600 // The coordinate system is flipped over the x-axis to make it right handed
00601 // i.e. (x,y) -> (x,-y)
00602 void bmdl_mesh::mesh_lidar(const vcl_vector<bmdl_edge>& edges,
00603                            const vcl_vector<bmdl_region>& regions,
00604                            unsigned int num_joints,
00605                            const vil_image_view<unsigned int>& labels,
00606                            const vil_image_view<double>& heights,
00607                            const vil_image_view<double>& ground,
00608                            imesh_mesh& mesh)
00609 {
00610   unsigned ni = labels.ni();
00611   unsigned nj = labels.nj();
00612 
00613   // recover the vector of building heights
00614   vcl_vector<double> bld_heights(regions.size());
00615   for (unsigned int j=0; j<nj; ++j)
00616   {
00617     for (unsigned int i=0; i<ni; ++i)
00618     {
00619       if (labels(i,j) > 1){
00620         bld_heights[labels(i,j)-2] = heights(i,j);
00621       }
00622     }
00623   }
00624 
00625   vcl_vector<vcl_vector<unsigned int> > face_list(regions.size());
00626   for (unsigned int i = 0; i<regions.size(); ++i)
00627   {
00628     const vcl_vector<unsigned int>& edge_idxs = regions[i].edge_idxs;
00629     for (unsigned int j = 0; j<edge_idxs.size(); ++j)
00630     {
00631       if (edges[edge_idxs[j]].building1 == i+1)
00632       {
00633         face_list[i].push_back(edges[edge_idxs[j]].joint1);
00634         // insert two pseudo edge points for disambiguation
00635         face_list[i].push_back(num_joints + 2*edge_idxs[j]);
00636         face_list[i].push_back(num_joints + 2*edge_idxs[j] + 1);
00637       }
00638       else
00639       {
00640         face_list[i].push_back(edges[edge_idxs[j]].joint2);
00641         // insert two pseudo edge points for disambiguation
00642         face_list[i].push_back(num_joints + 2*edge_idxs[j] + 1);
00643         face_list[i].push_back(num_joints + 2*edge_idxs[j]);
00644       }
00645     }
00646   }
00647   imesh_half_edge_set he2d(face_list);
00648 
00649   // store the indices of vertices connected below each edge point
00650   vcl_vector<vcl_vector<unsigned int> > edge_to_mesh(edges.size());
00651   vcl_vector<vcl_vector<unsigned int> > joint_vert_stack(num_joints);
00652 
00653   imesh_vertex_array<3> *verts = new imesh_vertex_array<3>;
00654   imesh_face_array *faces = new imesh_face_array;
00655 
00656   // precompute a mesh vertices located at joints
00657   for (unsigned int e=0; e<edges.size(); ++e)
00658   {
00659     const bmdl_edge& edge = edges[e];
00660     const vgl_point_2d<double>& pt1 = edge.pts.front();
00661     const vgl_point_2d<double>& pt2 = edge.pts.back();
00662     vcl_vector<unsigned int>& jvs1 = joint_vert_stack[edge.joint1];
00663     vcl_vector<unsigned int>& jvs2 = joint_vert_stack[edge.joint2];
00664 
00665     bool b1_gnd = edge.building1 == 0 || regions[edge.building1-1].edge_idxs.empty();
00666     bool b2_gnd = edge.building2 == 0 || regions[edge.building2-1].edge_idxs.empty();
00667     // building 1 on ground
00668     if (b1_gnd || b2_gnd)
00669     {
00670       double g1 = vil_bilin_interp_safe_extend(ground, pt1.x(), pt1.y());
00671       add_joint_vertex(*verts, jvs1, imesh_vertex<3>(pt1.x(),-pt1.y(), g1));
00672       double g2 = vil_bilin_interp_safe_extend(ground, pt2.x(), pt2.y());
00673       add_joint_vertex(*verts, jvs2, imesh_vertex<3>(pt2.x(),-pt2.y(), g2));
00674     }
00675     if (!b1_gnd)
00676     {
00677       double h = bld_heights[edge.building1-1];
00678       add_joint_vertex(*verts, jvs1, imesh_vertex<3>(pt1.x(),-pt1.y(),h));
00679       add_joint_vertex(*verts, jvs2, imesh_vertex<3>(pt2.x(),-pt2.y(),h));
00680     }
00681     if (!b2_gnd)
00682     {
00683       double h = bld_heights[edge.building2-1];
00684       add_joint_vertex(*verts, jvs1, imesh_vertex<3>(pt1.x(),-pt1.y(),h));
00685       add_joint_vertex(*verts, jvs2, imesh_vertex<3>(pt2.x(),-pt2.y(),h));
00686     }
00687   }
00688 
00689   typedef vcl_pair<unsigned int, unsigned int> uint_pair;
00690   vcl_map<uint_pair, vcl_vector<unsigned int> > revised_stack;
00691   // find non-manifold corner junctions
00692   for (unsigned int i=0; i<joint_vert_stack.size(); ++i){
00693     // get the 4 adjacent faces (if there are 4)
00694     imesh_half_edge_set::v_const_iterator e1 = he2d.vertex_begin(i), ei = e1;
00695     imesh_half_edge_set::v_const_iterator invalid_e(imesh_invalid_idx,he2d);
00696     if (ei == invalid_e)
00697       continue;
00698     int f1 = static_cast<int>(ei->face_index());
00699     if (e1 == ++ei)
00700       continue;
00701     int f2 = static_cast<int>(ei->face_index());
00702     if (e1 == ++ei)
00703       continue;
00704     int f3 = static_cast<int>(ei->face_index());
00705     if (e1 == ++ei)
00706       continue;
00707     int f4 = static_cast<int>(ei->face_index());
00708     assert(e1 == ++ei);
00709 
00710     // look for double peaks
00711     if ((f1 > f2 && f1 > f4 && f3 > f2 && f3 > f4) ||
00712         (f2 > f1 && f2 > f3 && f4 > f1 && f4 > f3) )
00713     {
00714       if (f1 > f2) // shift
00715       {
00716         int tmp = f1;
00717         f1 = f2;
00718         f2 = f3;
00719         f3 = f4;
00720         f4 = tmp;
00721       }
00722 
00723       // split the old stack
00724       const vcl_vector<unsigned int>& jvs = joint_vert_stack[i];
00725 
00726       double h1 = (f1<0)?(*verts)[jvs.front()][2]:bld_heights[f1];
00727       double h2 = bld_heights[f2];
00728       double h3 = (f3<0)?(*verts)[jvs.front()][2]:bld_heights[f3];
00729       vcl_vector<unsigned int> new_stack1;
00730       for (unsigned int k=0; k<jvs.size(); ++k)
00731       {
00732         double z = (*verts)[jvs[k]][2];
00733         if (z == h1 || z == h2 || z == h3)
00734           new_stack1.push_back(jvs[k]);
00735       }
00736       revised_stack[uint_pair(f2,i)] = new_stack1;
00737 
00738       h1 = (f3<0)?(*verts)[jvs.front()][2]:bld_heights[f3];
00739       h2 = bld_heights[f4];
00740       h3 = (f1<0)?(*verts)[jvs.front()][2]:bld_heights[f1];
00741       vcl_vector<unsigned int> new_stack2;
00742       for (unsigned int k=0; k<jvs.size(); ++k)
00743       {
00744         double z = (*verts)[jvs[k]][2];
00745         if (z == h1 || z == h2 || z == h3)
00746           new_stack2.push_back(jvs[k]);
00747       }
00748       revised_stack[uint_pair(f4,i)] = new_stack2;
00749     }
00750   }
00751 
00752 
00753   // create the buildings
00754   for (unsigned int b=0; b<regions.size(); ++b) {
00755     if (regions[b].edge_idxs.empty())
00756       continue;
00757     unsigned int roof_face = 0;
00758     for (int h=-1; h<(int)regions[b].hole_edge_idxs.size(); ++h)
00759     {
00760       const vcl_vector<unsigned int>& edge_idxs = (h<0) ? regions[b].edge_idxs :
00761                                                           regions[b].hole_edge_idxs[h];
00762       vcl_vector< unsigned int > roof;
00763       for (unsigned int e=0; e<edge_idxs.size(); ++e)
00764       {
00765         const bmdl_edge& edge = edges[edge_idxs[e]];
00766         vcl_vector<unsigned int> e2m = edge_to_mesh[edge_idxs[e]];
00767         vcl_vector<vgl_point_2d<double> > pts = edge.pts;
00768         unsigned int other = 0;
00769         unsigned int j1 = edge.joint1;
00770         unsigned int j2 = edge.joint2;
00771         if (edge.building1 == b+1)
00772         {
00773           other = edge.building2;
00774         }
00775         else if (edge.building2 == b+1)
00776         {
00777           other = edge.building1;
00778           vcl_reverse(pts.begin(), pts.end());
00779           vcl_reverse(e2m.begin(), e2m.end());
00780           vcl_swap(j1,j2);
00781         }
00782         else
00783           vcl_cout << "mismatch "<<b+1<<", "<<edge.building1<<", "<<edge.building2<<vcl_endl;
00784 
00785         // if this has been marked as a non-manifold corner then a revised stack exists
00786         // otherwise use the original vertex stack
00787         vcl_map<uint_pair, vcl_vector<unsigned int> >::const_iterator rvs1 = revised_stack.find(uint_pair(b,j1));
00788         vcl_map<uint_pair, vcl_vector<unsigned int> >::const_iterator rvs2 = revised_stack.find(uint_pair(b,j2));
00789         const vcl_vector<unsigned int>& jvs1 = (rvs1==revised_stack.end())
00790                                                ? joint_vert_stack[j1]
00791                                                : rvs1->second;
00792         const vcl_vector<unsigned int>& jvs2 = (rvs2==revised_stack.end())
00793                                                 ? joint_vert_stack[j2]
00794                                                 : rvs2->second;
00795 
00796         // is this edge attached to the ground?
00797         bool on_ground = other == 0 || regions[other-1].edge_idxs.empty();
00798 
00799         typedef vcl_vector<unsigned int>::const_iterator vfitr;
00800         typedef vcl_vector<unsigned int>::const_reverse_iterator vritr;
00801 
00802         vfitr i1beg = jvs1.begin(); // first vertex is on ground
00803         vfitr i1end = find_by_height(jvs1, *verts, bld_heights[b]);
00804         vfitr i2beg = jvs2.begin(); // first vertex is on ground
00805         vfitr i2end = find_by_height(jvs2, *verts, bld_heights[b]);
00806         assert(i1end != jvs1.end());
00807         assert(i2end != jvs2.end());
00808         if (!on_ground)
00809         {
00810           i1beg = find_by_height(jvs1, *verts, bld_heights[other-1]);
00811           i2beg = find_by_height(jvs2, *verts, bld_heights[other-1]);
00812           assert(i1beg != jvs1.end());
00813           assert(i2beg != jvs2.end());
00814           if (bld_heights[other-1] > bld_heights[b])
00815           {
00816             vcl_swap(i1beg, i1end);
00817             vcl_swap(i2beg, i2end);
00818           }
00819         }
00820 
00821         if (!on_ground && edge.building1 == b+1) // don't create side faces yet
00822         {
00823           // create the base vertices for later faces and attach the current roof
00824           vcl_vector<unsigned int>& e2m_set = edge_to_mesh[edge_idxs[e]];
00825           roof.push_back(*i1beg);
00826           for (unsigned int i=1; i<pts.size()-1; ++i) {
00827             const vgl_point_2d<double>& pt = pts[i];
00828             unsigned int bi = verts->size();
00829             verts->push_back(imesh_vertex<3>(pt.x(),-pt.y(),bld_heights[b]));
00830             roof.push_back(bi);
00831             e2m_set.push_back(bi);
00832           }
00833           continue;
00834         }
00835 
00836         vcl_vector<unsigned int> face;
00837         // start the next face
00838         roof.push_back(*i1end);
00839         ++i1end;
00840         face.insert(face.end(), vritr(i1end), vritr(i1beg));
00841 
00842         if (on_ground) // attach to the ground
00843         {
00844           // add all faces in the middle
00845           for (unsigned int i=1; i<pts.size()-1; ++i) {
00846             const vgl_point_2d<double>& pt = pts[i];
00847             double g = vil_bilin_interp_safe_extend(ground, pt.x(), pt.y());
00848             unsigned int bi = verts->size();
00849             verts->push_back(imesh_vertex<3>(pt.x(),-pt.y(), g));
00850             verts->push_back(imesh_vertex<3>(pt.x(),-pt.y(),bld_heights[b]));
00851             roof.push_back(bi+1);
00852             // finish last face
00853             face.push_back(bi);
00854             face.push_back(bi+1);
00855             faces->push_back(face);
00856             // start the next face
00857             face.clear();
00858             face.push_back(bi+1);
00859             face.push_back(bi);
00860           }
00861         }
00862         else // attach to previous level
00863         {
00864           if (e2m.empty() && pts.size() > 2)
00865             continue;
00866           for (unsigned int i=1; i<pts.size()-1; ++i) {
00867             const vgl_point_2d<double>& pt = pts[i];
00868             unsigned int bi = verts->size();
00869             verts->push_back(imesh_vertex<3>(pt.x(),-pt.y(),bld_heights[b]));
00870             roof.push_back(bi);
00871             // finish last face
00872             face.push_back(e2m[i-1]);
00873             face.push_back(bi);
00874             faces->push_back(face);
00875             // start the next face
00876             face.clear();
00877             face.push_back(bi);
00878             face.push_back(e2m[i-1]);
00879           }
00880         }
00881         // finish the last face
00882         ++i2end;
00883         face.insert(face.end(), i2beg, i2end);
00884         faces->push_back(face);
00885         face.clear();
00886       }
00887       if (roof.size() > 2)
00888       {
00889         if (h<0){
00890           roof_face = faces->size();
00891           faces->push_back(roof);
00892         }
00893         else
00894           roof_subtract_hole(*verts,(*faces)[roof_face],roof);
00895       }
00896     }
00897   }
00898 
00899   vcl_auto_ptr<imesh_vertex_array_base> vb(verts);
00900   vcl_auto_ptr<imesh_face_array_base> fb(faces);
00901   mesh.set_vertices(vb);
00902   mesh.set_faces(fb);
00903 }
00904 
00905 
00906 //: Subtract a hole from an existing face in a mesh
00907 void bmdl_mesh::roof_subtract_hole(const imesh_vertex_array<3>& verts,
00908                                    vcl_vector<unsigned int>& face,
00909                                    const vcl_vector<unsigned int>& hole)
00910 {
00911   unsigned int i1, i2;
00912   bool valid = false;
00913   for (i1=0; i1<face.size(); ++i1)
00914   {
00915     vgl_point_2d<double> v1(verts[face[i1]][0],verts[face[i1]][1]);
00916     for (i2=0; i2<hole.size(); ++i2)
00917     {
00918       vgl_point_2d<double> v2(verts[hole[i2]][0],verts[hole[i2]][1]);
00919       // look for self intersections
00920       valid = true;
00921       for (unsigned int j1 = face.size()-1, j2=0; j2<face.size() && valid; j1=j2, ++j2)
00922       {
00923         if (j1 == i1 || j2 == i1)
00924           continue;
00925         vgl_point_2d<double> v3(verts[face[j1]][0],verts[face[j1]][1]);
00926         vgl_point_2d<double> v4(verts[face[j2]][0],verts[face[j2]][0]);
00927         valid = !vgl_lineseg_test_lineseg(v1.x(),v1.y(),v2.x(),v2.y(),
00928                                           v3.x(),v3.y(),v4.x(),v4.y());
00929       }
00930       for (unsigned int j1 = hole.size()-1, j2=0; j2<hole.size() && valid; j1=j2, ++j2)
00931       {
00932         if (j1 == i2 || j2 == i2)
00933           continue;
00934         vgl_point_2d<double> v3(verts[hole[j1]][0],verts[hole[j1]][1]);
00935         vgl_point_2d<double> v4(verts[hole[j2]][0],verts[hole[j2]][1]);
00936         valid = !vgl_lineseg_test_lineseg(v1.x(),v1.y(),v2.x(),v2.y(),
00937                                           v3.x(),v3.y(),v4.x(),v4.y());
00938       }
00939       if (valid)
00940         break;
00941     }
00942     if (valid)
00943       break;
00944   }
00945 
00946   if (!valid)
00947   {
00948     vcl_cout << "couldn't find connection for hole"<<vcl_endl;
00949     return;
00950   }
00951 
00952   vcl_vector<unsigned int> new_idxs;
00953   new_idxs.push_back(face[i1]);
00954   new_idxs.insert(new_idxs.end(), hole.begin()+i2, hole.end());
00955   new_idxs.insert(new_idxs.end(), hole.begin(), hole.begin()+i2);
00956   new_idxs.push_back(hole[i2]);
00957   face.insert(face.begin()+i1, new_idxs.begin(), new_idxs.end());
00958 }
00959