ComputeApproxMVBB.hpp
Go to the documentation of this file.
00001 // ========================================================================================
00002 //  ApproxMVBB
00003 //  Copyright (C) 2014 by Gabriel Nützi <nuetzig (at) imes (d0t) mavt (d0t) ethz (døt) ch>
00004 //
00005 //  This Source Code Form is subject to the terms of the Mozilla Public
00006 //  License, v. 2.0. If a copy of the MPL was not distributed with this
00007 //  file, You can obtain one at http://mozilla.org/MPL/2.0/.
00008 // ========================================================================================
00009 
00010 #ifndef ApproxMVBB_ComputeApproxMVBB_hpp
00011 #define ApproxMVBB_ComputeApproxMVBB_hpp
00012 
00013 #include "ApproxMVBB/Config/Config.hpp"
00014 #include "ApproxMVBB/Common/LogDefines.hpp"
00015 
00016 #include ApproxMVBB_TypeDefs_INCLUDE_FILE
00017 #include "ApproxMVBB/TypeDefsPoints.hpp"
00018 
00019 
00020 #include ApproxMVBB_OOBB_INCLUDE_FILE
00021 #include "ApproxMVBB/GreatestCommonDivisor.hpp"
00022 #include "ApproxMVBB/RandomGenerators.hpp"
00023 #include "ApproxMVBB/ProjectedPointSet.hpp"
00024 
00025 
00026 namespace ApproxMVBB {
00027 
00028     ApproxMVBB_DEFINE_MATRIX_TYPES
00029     ApproxMVBB_DEFINE_POINTS_CONFIG_TYPES
00030 
00039 template<typename Derived>
00040 APPROXMVBB_EXPORT void samplePointsGrid(Matrix3Dyn & newPoints,
00041                       const MatrixBase<Derived> & points,
00042                       const unsigned int nPoints,
00043                       OOBB & oobb,
00044                       std::size_t seed = ApproxMVBB::RandomGenerators::defaultSeed
00045                       )
00046 {
00047     using IndexType = typename Derived::Index;
00048     
00049     if(nPoints > points.cols() || nPoints < 2) {
00050         ApproxMVBB_ERRORMSG("Wrong arguments!" << "sample nPoints: (>2) " << nPoints << " of points: " << points.cols() << std::endl )
00051     }
00052 
00053     newPoints.resize(3,nPoints);
00054 
00055     //total points = bottomPoints=gridSize^2  + topPoints=gridSize^2
00056     unsigned int gridSize = std::max( static_cast<unsigned int>( std::sqrt( static_cast<double>(nPoints) / 2.0 )) , 1U );
00057 
00058     // Set z-Axis to longest dimension
00059     //std::cout << oobb.m_minPoint.transpose() << std::endl;
00060     oobb.setZAxisLongest();
00061 
00062     IndexType halfSampleSize = gridSize*gridSize;
00063     
00064     struct BottomTopPoints{
00065         IndexType bottomIdx = 0;
00066         PREC bottomZ;
00067     
00068         IndexType topIdx = 0;
00069         PREC topZ; 
00070     };
00071     
00072     // grid of the bottom/top points in Z direction (indexed from 1 )
00073     std::vector< BottomTopPoints > boundaryPoints(halfSampleSize); 
00074        
00075     using LongInt = long long int;
00076     MyMatrix::Array2<LongInt> idx; // Normalized P
00077     //std::cout << oobb.extent() << std::endl;
00078     //std::cout << oobb.m_minPoint.transpose() << std::endl;
00079     Array2 dxdyInv =  Array2(gridSize,gridSize) / oobb.extent().head<2>(); // in K Frame;
00080     Vector3 K_p;
00081 
00082     Matrix33 A_KI(oobb.m_q_KI.matrix().transpose());
00083 
00084     // Register points in grid
00085     IndexType size = points.cols();
00086     for(IndexType i=0; i<size; ++i) {
00087 
00088         K_p = A_KI * points.col(i);
00089         // get x index in grid
00090         idx = (  (K_p - oobb.m_minPoint).head<2>().array() * dxdyInv ).template cast<LongInt>();
00091         // map to grid
00092         idx(0) = std::max(   std::min( LongInt(gridSize-1), idx(0)),  0LL   );
00093         idx(1) = std::max(   std::min( LongInt(gridSize-1), idx(1)),  0LL   );
00094         //std::cout << idx.transpose() << std::endl;
00095         
00096         // Register points in grid
00097         // if z component of p is > pB.topZ  -> set new top point at pos
00098         // if z component of p is < pB.bottomZ    -> set new bottom point at pos
00099         auto & pB = boundaryPoints[idx(0) + idx(1)*gridSize];
00100         
00101         if( pB.bottomIdx == 0) {
00102             pB.bottomIdx  = pB.topIdx  = i+1;
00103             pB.bottomZ = pB.topZ       = K_p(2);
00104         } else {
00105             if( pB.topZ < K_p(2) ) {
00106                 pB.topIdx = i+1;
00107                 pB.topZ = K_p(2);
00108             }else{
00109                 if( pB.bottomZ > K_p(2) ) {
00110                     pB.bottomIdx = i+1;
00111                     pB.bottomZ = K_p(2);
00112                 }
00113             }
00114         }
00115     }
00116 
00117     // Copy top and bottom points
00118     IndexType k=0;
00119     ApproxMVBB_MSGLOG_L2("Sampled Points incides: [ ")
00120     // k does not overflow -> 2* halfSampleSize = 2*gridSize*gridSize <= nPoints;
00121     for(IndexType i=0; i<halfSampleSize; ++i) {
00122         if( boundaryPoints[i].bottomIdx != 0 ) {
00123             // comment in if you want the top/bottom points of the grid
00124             //Array3 a(i % gridSize,i/gridSize,oobb.m_maxPoint(2)-oobb.m_minPoint(2));
00125             //a.head<2>()*=dxdyInv.inverse();
00126             ApproxMVBB_MSGLOG_L2( boundaryPoints[i].topIdx-1 << ", " << ((k%30==0)? "\n" : "") )
00127             newPoints.col(k++) =  points.col(boundaryPoints[i].topIdx-1);  //  A_KI.transpose()*(oobb.m_minPoint + a.matrix()).eval() ;
00128             if(boundaryPoints[i].topIdx != boundaryPoints[i].bottomIdx) {
00129                 // comment in if you want the bottom points of the grid
00130                 //Array3 a(i % gridSize,i/gridSize,0);
00131                 //a.head<2>()*=dxdyInv.inverse();
00132                 ApproxMVBB_MSGLOG_L2( boundaryPoints[i].bottomIdx-1 << ", " )
00133                 newPoints.col(k++) = points.col(boundaryPoints[i].bottomIdx-1); //  A_KI.transpose()*(oobb.m_minPoint + a.matrix()).eval() ;
00134             }
00135         }
00136     }
00137     
00138     // Add random points!
00139     // Random indices if too little points
00140     if( k < nPoints ){
00141         RandomGenerators::DefaultRandomGen gen(seed);
00142         RandomGenerators::DefaultUniformUIntDistribution< 
00143                                 typename std::make_unsigned<IndexType>::type 
00144                            > dis(0, points.cols()-1);
00145         IndexType s;
00146         while( k < nPoints) {
00147             s = dis(gen);
00148             ApproxMVBB_MSGLOG_L2( s << ", " )
00149             newPoints.col(k++) = points.col( s ); //= Vector3(0,0,0);//
00150         }
00151     }
00152     ApproxMVBB_MSGLOG_L2( "]" << std::endl )
00153 }
00154 
00163 template<typename Derived>
00164 APPROXMVBB_EXPORT OOBB optimizeMVBB( const MatrixBase<Derived> & points,
00165                                      OOBB oobb,
00166                                      unsigned int nLoops = 10,
00167                                      PREC volumeAcceptFactor = 1e-6,
00168                                      PREC minBoxExtent = 1e-12
00169                                      )
00170 {
00171 
00172     EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Derived,3,Eigen::Dynamic)
00173 
00174     if( oobb.volume() == 0.0 || nLoops == 0) {
00175         return oobb;
00176     }
00177 
00178     // Define the volume lower bound above we accept a new volume as
00179     PREC volumeAcceptTol = oobb.volume() * volumeAcceptFactor;
00180 
00181 
00182     unsigned int cacheIdx = 0; // current write Idx into the cache
00183     Vector3 dirCache[3]; // save the last three directions (avoiding cycling in choosen axis)
00184 
00185     Vector3 dir;
00186     ProjectedPointSet proj;
00187     for(unsigned int loop = 0; loop < nLoops; ++loop ) {
00188 
00189         // Determine Direction (choose x or y axis)
00190         //std::cout << oobb.m_q_KI.matrix() << std::endl;
00191         dir = oobb.getDirection(0);
00192 
00193         // check against all chache values
00194         for(unsigned char i=0; i<3 && i<loop; ++i) {
00195             PREC dotp = std::abs(dir.dot(dirCache[i])); //
00196             if( std::abs(dotp - 1.0) <= 1e-3 ) {
00197                 //std::cout << "Change Dir" << std::endl;
00198                 // direction are almost the same as in the cache, choose another one
00199                 dir = oobb.getDirection(1);
00200                 break;
00201             }
00202         }
00203         // Write to cache and shift write idx
00204         dirCache[cacheIdx] = dir;
00205         cacheIdx = (cacheIdx + 1) % 3;
00206 
00207         //std::cout << "Optimizing dir: " << dir << std::endl;
00208         OOBB o = proj.computeMVBB( dir, points);
00209 
00210         // Expand box such the volume is not zero for points in a plane
00211         o.expandToMinExtentAbsolute(minBoxExtent);
00212 
00213         if( o.volume() < oobb.volume() && o.volume()>volumeAcceptTol) {
00214             oobb = o;
00215         }
00216     }
00217 
00218     return  oobb;
00219 }
00220 
00221 
00233 template<typename Derived>
00234 APPROXMVBB_EXPORT OOBB approximateMVBBGridSearch(const MatrixBase<Derived> & points,
00235                                OOBB oobb,
00236                                PREC epsilon,
00237                                const unsigned int gridSize = 5,
00238                                const unsigned int optLoops = 6,
00239                                PREC volumeAcceptFactor = 1e-6,
00240                                PREC minBoxExtent = 1e-12
00241                                )
00242 {
00243     EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Derived,3,Eigen::Dynamic)
00244 
00245     // Extent input oobb
00246     oobb.expandToMinExtentAbsolute(minBoxExtent);
00247 
00248     // Define the volume lower bound above we accept a new volume as
00249     /*PREC volumeAcceptTol = oobb.volume() * volumeAcceptFactor;*/
00250 
00251     //Get the direction of the input OOBB in I frame:
00252     Vector3 dir1 = oobb.getDirection(0);
00253     Vector3 dir2 = oobb.getDirection(1);
00254     Vector3 dir3 = oobb.getDirection(2);
00255 
00256     Vector3 dir;
00257 
00258     ProjectedPointSet proj;
00259 
00260     for(int x = -int(gridSize); x <= (int)gridSize; ++x ) {
00261         for(int  y = -int(gridSize); y <= (int)gridSize; ++y ) {
00262             for(int z = 0; z <= (int)gridSize; ++z ) {
00263 
00264                 if( MathFunctions::gcd3(x,y,z)> 1 ||  ((x==0) && (y==0) &&  (z==0))  ) {
00265                     continue;
00266                 }
00267 
00268                 // Make direction
00269                 dir = x*dir1 + y*dir2 + z*dir3;
00270                 ApproxMVBB_MSGLOG_L3( "gridSearch: dir: " << dir.transpose() << std::endl; )
00271 
00272                 // Compute MVBB in dirZ
00273                 auto res = proj.computeMVBB(dir,points);
00274 
00275                 // Expand to minimal extent for points in a surface or line
00276                 res.expandToMinExtentAbsolute(minBoxExtent);
00277 
00278                 if(optLoops){
00279                     res = optimizeMVBB(points,res,optLoops,volumeAcceptFactor,minBoxExtent);
00280                 }
00281                 ApproxMVBB_MSGLOG_L3( "gridSearch: volume: " << res.volume() << std::endl;)
00282                 if(res.volume() < oobb.volume() /*&& res.volume()>volumeAcceptTol */) {
00283 
00284                     ApproxMVBB_MSGLOG_L2( "gridSearch: new volume: " << res.volume() << std::endl <<  "for dir: " << dir.transpose() << std::endl; )
00285                     oobb = res;
00286                 }
00287 
00288             }
00289         }
00290     }
00291     return oobb;
00292 }
00293 
00300 template<typename Derived>
00301 APPROXMVBB_EXPORT OOBB approximateMVBBDiam(const MatrixBase<Derived> & points,
00302                          const PREC epsilon,
00303                          const unsigned int optLoops = 10,
00304                          std::size_t seed = ApproxMVBB::RandomGenerators::defaultSeed
00305                         )
00306 {
00307     EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Derived,3,Eigen::Dynamic)
00308 
00309     using namespace PointFunctions;
00310         auto pp = estimateDiameter<3>(points, epsilon, seed );
00311 
00312         ApproxMVBB::MyMatrix::Vector3<ApproxMVBB::TypeDefsPoints::PREC> dirZ = pp.first - pp.second;
00313 
00314     // TODO: Is this direction inversion needed? not really ?
00315     if( ( dirZ.array() <= 0.0).all() ) {
00316         dirZ *= -1;
00317     }
00318 
00319     // If direction zero, use (1,0)
00320     if( (dirZ.array() == 0.0).all() ) {
00321         dirZ.setZero();
00322         dirZ(0)= 1;
00323     }
00324     ApproxMVBB_MSGLOG_L1("estimated 3d diameter: " << dirZ.transpose() << " eps: " << epsilon << std::endl;)
00325 
00326     // Compute MVBB in dirZ
00327     ProjectedPointSet proj;
00328     //OOBB oobb = proj.computeMVBB();
00329     // or faster estimate diameter in projected plane and build coordinate system
00330     OOBB oobb = proj.computeMVBBApprox(dirZ,points,epsilon);
00331 
00332     if(optLoops) {
00333         oobb = optimizeMVBB(points,oobb,optLoops);
00334     }
00335     return oobb;
00336 }
00337 
00338 template<typename Derived >
00339 APPROXMVBB_EXPORT OOBB approximateMVBB(const MatrixBase<Derived> & points,
00340                      const PREC epsilon,
00341                      const unsigned int pointSamples = 400,
00342                      const unsigned int gridSize = 5,
00343                      const unsigned int mvbbDiamOptLoops = 0,
00344                      const unsigned int mvbbGridSearchOptLoops = 6,
00345                      std::size_t seed = ApproxMVBB::RandomGenerators::defaultSeed
00346                      )
00347 {
00348     EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Derived,3,Eigen::Dynamic)
00349 
00350     // Get get MVBB from estimated diameter direction
00351     // take care forwarding means not using gen anymore !
00352     auto oobb = approximateMVBBDiam(points,epsilon,mvbbDiamOptLoops, seed );
00353 
00354     // Check if we sample the point cloud
00355     if(pointSamples<points.cols()) {
00356 
00357         // sample points
00358         Matrix3Dyn sampled;
00359         samplePointsGrid(sampled,points,pointSamples,oobb, seed);
00360 
00361         // Exhaustive grid search with sampled points
00362         oobb = approximateMVBBGridSearch(sampled,oobb,epsilon,gridSize,mvbbGridSearchOptLoops);
00363 
00364     } else {
00365         // Exhaustive grid search with sampled points
00366         oobb = approximateMVBBGridSearch(points,oobb,epsilon,gridSize,mvbbGridSearchOptLoops);
00367     }
00368 
00369     return oobb;
00370 }
00371 
00372 }
00373 
00374 
00375 
00376 #endif // ApproxMVBB_hpp
00377 


asr_approx_mvbb
Author(s): Gassner Nikolai
autogenerated on Sat Jun 8 2019 20:21:49