shape_doc 0.1
/Users/mourrain/Devel/mmx/shape/include/shape/find_minimal_edges.hpp
Go to the documentation of this file.
00001 #ifndef FIND_MINIMAL_EDGES_HPP
00002 #define FIND_MINIMAL_EDGES_HPP
00003 
00004 /*****************************************************************************
00005  * M a t h e m a g i x
00006  *****************************************************************************
00007  * Find Minimal Edges
00008  * 2009-04-29
00009  * Johan Seland & Bernard Mourrain
00010  *****************************************************************************
00011  *               Copyright (C) 2009 INRIA Sophia-Antipolis
00012  *****************************************************************************
00013  * Comments :
00014  * find_minimal_edges implement a recursive algorithm to find the
00015  * minimal edges of an kd-tree. Minimal edges are edges of leaf cubes that do not
00016  * properly contain an edge of a neighboring leaf.
00017  *
00018  *
00019  ****************************************************************************/
00020 
00021 #include <tr1/array>
00022 #include <vector>
00023 #include <algorithm>
00024 #include <cassert>
00025 #include <iostream>
00026 
00027 #include "shape/node.hpp"
00028 #include "shape/bounding_box.hpp"
00029 
00030 //#define ELB_DEBUG
00031 //#define ELB_RUNTIME_CHECK
00032 
00033 namespace mmx { namespace shape {
00034                 template<class node_t> class EdgeListBuilder {
00035                 public:
00036                         typedef std::tr1::array<const node_t*, 2> faceTuple_t;
00037                         typedef std::vector<faceTuple_t>                                  faceList_t;
00038 
00039                         typedef std::tr1::array<const node_t*, 3> edgeTuple_t;
00040                         typedef std::vector<edgeTuple_t>                                  edgeList_t;
00041 
00042                         typedef mmx::shape::bounding_box<double>  boundingBox_t;
00043 
00044                         EdgeListBuilder() : m_os( std::cerr ) {}
00045 
00046                         void cellProc( const node_t* n );
00047                         bool faceProc( const node_t* n0, const node_t* n1, int split_dir );
00048                         void edgeProc( const node_t* n0, const node_t* n1, const node_t* n2, int split_dir );
00049 
00051                         int dist( const node_t* n0, const node_t* n1 ) const {
00052                                 return std::abs( n0->depth() - n1->depth() );
00053                         }
00054 
00056                         const node_t* getChild( const node_t* n, typename node_t::NODE_TYPE nt ) const {
00057 
00058                                 assert( !n->is_leaf() && "Trying to take children of leaf node." );
00059 
00060                                 switch ( nt ) {
00061                                 case node_t::LEFT : return n->left();  break;
00062                                 case node_t::RIGHT: return n->right(); break;
00063                                 default: return 0;
00064                                 }
00065                         }
00066 
00068                         bool commonFace( const faceTuple_t& f ) const;
00069 
00070                         boundingBox_t computeCommonFace( const faceTuple_t& t ) const;
00071 
00074                         bool overlapAlongAxis( const node_t* n0, const node_t* n1, int axis, bool strict ) const;
00075 
00077                         void verifyFaceList() const;
00078 
00080                         typename node_t::NODE_TYPE getSplitDirParentType( const node_t* n, const int split_dir ) const {
00081                                 while ( n->parent() != 0 && n->parent()->split_dir() != split_dir ) {
00082                                         n = n->parent();
00083                                 }
00084                                 if ( n->parent() == 0 )
00085                                         std::cerr << "Could not find a parent that was split in "
00086                                                         <<      split_dir << " direction.\n";
00087 
00088                                 return n->type();
00089                         }
00090 
00092                         const edgeList_t& edgeList() const { return m_edgelist; }
00093 
00095                         edgeList_t& edgeList() { return m_edgelist; }
00096 
00098                         const faceList_t& faceList() const { return m_facelist; }
00099 
00101                         faceList_t& faceList() { return m_facelist; }
00102 
00103                 protected:
00104                         void edgeProc_helper( const node_t* n0, const node_t* n1, const node_t* n2, int split_dir );
00105                         edgeList_t m_edgelist;
00106                         faceList_t m_facelist;
00107                         std::vector<int> m_facesplitdir;
00108 
00109                         std::ostream& m_os;
00110                 };
00111 
00112                 template<class node_t> void EdgeListBuilder<node_t>::verifyFaceList() const {
00113                         size_t errs = 0;
00114                         for ( size_t i = 0; i < m_facelist.size(); ++i ) {
00115 
00116                                 if ( !commonFace( m_facelist[i] ) ) {
00117                                         errs++;
00118                                         m_os << "Invalid facetuple found: \n";
00119                                         m_os << m_facelist[i][0]->get_cell()->boundingBox() << std::endl;
00120                                         m_os << m_facelist[i][1]->get_cell()->boundingBox() << std::endl;
00121                                         m_os << m_facelist[i][0]->split_dir() << ", "
00122                                                         << m_facelist[i][1]->split_dir() << "\n";
00123                                         m_os << "Split dir: " << m_facesplitdir[i] << std::endl;
00124                                         const node_t* n0 = m_facelist[i][0];
00125                                         const node_t* n1 = m_facelist[i][1];
00126 
00127                                         while ( n0->parent() != 0 ) {
00128                                                 m_os << n0->get_cell()->boundingBox() << std::endl;
00129                                                 n0 = n0->parent();
00130                                         }
00131                                         m_os << std::endl;
00132                                         while ( n1->parent() != 0 ) {
00133                                                 m_os << n1->get_cell()->boundingBox() << std::endl;
00134                                                 n1 = n1->parent();
00135                                         }
00136                                         exit ( 0 );
00137                                 } else {
00138                                         m_os << m_facelist[i][0]->get_cell()->boundingBox() << std::endl;
00139                                         m_os << m_facelist[i][1]->get_cell()->boundingBox() << std::endl;
00140                                         boundingBox_t c = computeCommonFace( m_facelist[i] );
00141                                         m_os << "[" << c.xmin() << ", " << c.xmax() << "] x [" << c.ymin() << ", " << c.ymax() << "] x [" << c.zmin() << ", " << c.zmax() << "]\n\n" ;
00142                                 }
00143 
00144 
00145                         }
00146 
00147                         m_os << "Errors found: " << errs << " (total " << m_facelist.size() << ")\n";
00148 
00149                 }
00150 
00151                 template<class node_t> bool EdgeListBuilder<node_t>::commonFace
00152                                 ( const faceTuple_t& f ) const {
00153 
00154 
00155                         int strict = 0;
00156                         int nonstrict = 0;
00157 
00158                         for ( int i = 0; i < 3; ++i ) {
00159                                 if ( overlapAlongAxis( f[0], f[1], i, true ) )
00160                                         strict++;
00161                                 if ( overlapAlongAxis( f[0], f[1], i, false ) )
00162                                         nonstrict++;
00163                         }
00164 
00165                         return  ( strict >= 2 && nonstrict >= 3 ) ? true : false;
00166                 }
00167 
00168                 template<class node_t>  typename EdgeListBuilder<node_t>::boundingBox_t EdgeListBuilder<node_t>::computeCommonFace ( const faceTuple_t& f ) const {
00169 
00170                         using std::min; using std::max;
00171 
00172                         boundingBox_t b0 = f[0]->get_cell()->boundingBox();
00173                         boundingBox_t b1 = f[1]->get_cell()->boundingBox();
00174 
00175                         boundingBox_t b( max( b0.xmin(), b1.xmin() ),
00176                                                                                          min( b0.xmax(), b1.xmax() ),
00177                                                                                          max( b0.ymin(), b1.ymin() ),
00178                                                                                          min( b0.ymax(), b1.ymax() ),
00179                                                                                          max( b0.zmin(), b1.zmin() ),
00180                                                                                          min( b0.zmax(), b1.zmax() ) );
00181 
00182                         return b;
00183                 }
00184 
00185 
00186 
00187                 template<class node_t> bool EdgeListBuilder<node_t>::overlapAlongAxis
00188                                 ( const node_t* n0, const node_t* n1, const int axis, bool strict ) const {
00189 
00190                         // Intervals for the boundingbox
00191 
00192                         std::tr1::array<double, 2> a, b;
00193 
00194                         switch( axis ) {
00195                         case 0:
00196                                 a[0] = n0->get_cell()->boundingBox().xmin();
00197                                 b[0] = n1->get_cell()->boundingBox().xmin();
00198                                 a[1] = n0->get_cell()->boundingBox().xmax();
00199                                 b[1] = n1->get_cell()->boundingBox().xmax();
00200                                 break;
00201                         case 1:
00202                                 a[0] = n0->get_cell()->boundingBox().ymin();
00203                                 b[0] = n1->get_cell()->boundingBox().ymin();
00204                                 a[1] = n0->get_cell()->boundingBox().ymax();
00205                                 b[1] = n1->get_cell()->boundingBox().ymax();
00206                                 break;
00207                         case 2:
00208                                 a[0] = n0->get_cell()->boundingBox().zmin();
00209                                 b[0] = n1->get_cell()->boundingBox().zmin();
00210                                 a[1] = n0->get_cell()->boundingBox().zmax();
00211                                 b[1] = n1->get_cell()->boundingBox().zmax();
00212                                 break;
00213                         default:
00214                                 std::cerr << "Trying to take boudningbox along unknown axis!\n";
00215                                 return false;
00216                         }
00217 
00218                         // Now check the overlap of these intervals
00219                         // Test taken from overlap method of boost::interval.
00220 
00221                         if ( strict )
00222                                 return ( a[0] <= b[0] && b[0] < a[1] ) ||
00223                                                          ( b[0] <= a[0] && a[0] < b[1] );
00224                         else
00225                                 return ( a[0] <= b[0] && b[0] <= a[1] ) ||
00226                                                          ( b[0] <= a[0] && a[0] <= b[1] );
00227 
00228                 }
00229 
00230                 template<class node_t> void EdgeListBuilder<node_t>::cellProc( const node_t* n ) {
00231 #ifdef ELB_DEBUG
00232                         m_os << __FUNCTION__ << n->get_cell()->boundingBox() << std::endl;
00233 #endif
00234 
00235                         if ( n->is_leaf() )
00236                                 return;
00237 
00238                         // Obvious, left and right share a face
00239                         faceProc( n->left(), n->right(), n->split_dir() );
00240 
00241                         // Obvious
00242                         cellProc( n->left() );
00243                         cellProc( n->right() );
00244                 }
00245 
00249                 template<class node_t> bool EdgeListBuilder<node_t>::faceProc
00250                                 ( const node_t* left, const node_t* right, const int split_dir ) {
00251 
00252 #ifdef ELB_DEBUG
00253                         m_os << __FUNCTION__ << std::endl;
00254                         //                      m_os << left->get_cell()->boundingBox() << std::endl;
00255                         //                      m_os << right->get_cell()->boundingBox() << std::endl;
00256 #endif
00257 
00258                         // Check that boxes overlap
00259                         //if ( !overlapAlongAxis( left, right, split_dir ) )
00260                         //      return false;
00261                         faceTuple_t f = {{left, right}};
00262                         if ( !commonFace( f ) )
00263                                 return false;
00264 
00265                         if ( left->is_leaf() && right->is_leaf() ) {
00266                                 faceTuple_t f = {{ left, right }};
00267 #ifdef ELB_DEBUG
00268                                 m_os << "Inserted\n";
00269                                 m_os << left->get_cell()->boundingBox() << std::endl;
00270                                 m_os << right->get_cell()->boundingBox() << std::endl;
00271 #endif
00272 
00273 #ifdef ELB_RUNTIME_CHECK
00274                                 if ( std::find( m_facelist.begin(), m_facelist.end(), f )
00275                                         != m_facelist.end() ) {
00276                                         m_os << "Face already inserted!\n";
00277 
00278                                         exit(0);
00279                                 }
00280 #endif
00281                                 m_facelist.push_back( f );
00282                                 m_facesplitdir.push_back( split_dir );
00283 
00284                                 return true;
00285                         }
00286 
00287                         // We naively split into both children cells and test for
00288                         // overlap at the start of the recursive step.
00289                         if ( !left->is_leaf() ) {
00290                                 if ( left->split_dir() != split_dir ) {
00291                                         //edgeProc( left->left(), left->right(), right, split_dir );
00292                                         faceProc( left->left(), right, split_dir );
00293                                         faceProc( left->right(), right, split_dir );
00294                                 } else { // left->split_dir() == split_dir
00295                                         faceProc( left->right(), right, split_dir );
00296                                 }
00297                         } else if ( !right->is_leaf() ) {
00298                                 if ( right->split_dir() != split_dir ) {
00299                                         //edgeProc( left, right->left(), right->right(), split_dir );
00300                                         faceProc( left, right->left(), split_dir );
00301                                         faceProc( left, right->right(), split_dir );
00302                                 } else { // right->split_dir() == split_dir
00303                                         faceProc( left, right->left(), split_dir );
00304                                 }
00305                         }
00306 
00307                         return false;
00308                 }
00309 
00310                 template<class node_t> void EdgeListBuilder<node_t>::edgeProc_helper
00311                                 ( const node_t* n0, const node_t* n1, const node_t* n2, const int split_dir ) {
00312 
00313                         if ( !n0->is_leaf() ) {
00314                                 if ( n0->split_dir() != split_dir ) {
00315                                         edgeProc( n0->left(),  n1, n2, split_dir );
00316                                         edgeProc( n0->right(), n1, n2, split_dir );
00317                                 } else { // n0->split_dir() == split_dir
00318                                         //edgeProc( getChild( n0, getSplitDirParentType( n0, split_dir ) ),
00319                                         //                                      n1, n2, split_dir );
00320                                 }
00321                         }
00322                 }
00323 
00324                 template<class node_t> void EdgeListBuilder<node_t>::edgeProc
00325                                 ( const node_t* n0, const node_t* n1, const node_t* n2, const int split_dir ) {
00326 
00327 #ifdef ELB_DEBUG
00328                         m_os << __FUNCTION__ << std::endl;
00329 #endif
00330 
00331                         if ( n0->is_leaf() && n1->is_leaf() && n2->is_leaf() ) {
00332                                 edgeTuple_t n = {{ n0, n1, n2 }};
00333                                 m_edgelist.push_back( n );
00334 
00335 #ifdef ELB_DEBUG
00336                                 m_os << "Found nodeTuple.\n";
00337                                 for ( int i = 0; i < 3; ++i ) {
00338                                         m_os << n[i]->get_cell()->boundingBox() << std::endl;
00339                                 }
00340                                 m_os << std::endl;
00341 #endif
00342                         } else {
00343                                 edgeProc_helper( n0, n1, n2, split_dir );
00344                                 edgeProc_helper( n1, n2, n0, split_dir );
00345                                 edgeProc_helper( n2, n0, n1, split_dir );
00346                         }
00347                 }
00348 
00349         }} // namespace mmx::shape
00350 
00351 #endif // FIND_MINIMAL_EDGES_HPP