ComputeApproxMVBB.hpp
Go to the documentation of this file.
1 // ========================================================================================
2 // ApproxMVBB
3 // Copyright (C) 2014 by Gabriel Nützi <nuetzig (at) imes (d0t) mavt (d0t) ethz (døt) ch>
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 // ========================================================================================
9 
10 #ifndef ApproxMVBB_ComputeApproxMVBB_hpp
11 #define ApproxMVBB_ComputeApproxMVBB_hpp
12 
15 
16 #include ApproxMVBB_TypeDefs_INCLUDE_FILE
18 
19 
20 #include ApproxMVBB_OOBB_INCLUDE_FILE
24 
25 
26 namespace ApproxMVBB {
27 
30 
39 template<typename Derived>
41  const MatrixBase<Derived> & points,
42  const unsigned int nPoints,
43  OOBB & oobb,
45  )
46 {
47  using IndexType = typename Derived::Index;
48 
49  if(nPoints > points.cols() || nPoints < 2) {
50  ApproxMVBB_ERRORMSG("Wrong arguments!" << "sample nPoints: (>2) " << nPoints << " of points: " << points.cols() << std::endl )
51  }
52 
53  newPoints.resize(3,nPoints);
54 
55  //total points = bottomPoints=gridSize^2 + topPoints=gridSize^2
56  unsigned int gridSize = std::max( static_cast<unsigned int>( std::sqrt( static_cast<double>(nPoints) / 2.0 )) , 1U );
57 
58  // Set z-Axis to longest dimension
59  //std::cout << oobb.m_minPoint.transpose() << std::endl;
60  oobb.setZAxisLongest();
61 
62  IndexType halfSampleSize = gridSize*gridSize;
63 
64  struct BottomTopPoints{
65  IndexType bottomIdx = 0;
66  PREC bottomZ;
67 
68  IndexType topIdx = 0;
69  PREC topZ;
70  };
71 
72  // grid of the bottom/top points in Z direction (indexed from 1 )
73  std::vector< BottomTopPoints > boundaryPoints(halfSampleSize);
74 
75  using LongInt = long long int;
76  MyMatrix::Array2<LongInt> idx; // Normalized P
77  //std::cout << oobb.extent() << std::endl;
78  //std::cout << oobb.m_minPoint.transpose() << std::endl;
79  Array2 dxdyInv = Array2(gridSize,gridSize) / oobb.extent().head<2>(); // in K Frame;
80  Vector3 K_p;
81 
82  Matrix33 A_KI(oobb.m_q_KI.matrix().transpose());
83 
84  // Register points in grid
85  IndexType size = points.cols();
86  for(IndexType i=0; i<size; ++i) {
87 
88  K_p = A_KI * points.col(i);
89  // get x index in grid
90  idx = ( (K_p - oobb.m_minPoint).head<2>().array() * dxdyInv ).template cast<LongInt>();
91  // map to grid
92  idx(0) = std::max( std::min( LongInt(gridSize-1), idx(0)), 0LL );
93  idx(1) = std::max( std::min( LongInt(gridSize-1), idx(1)), 0LL );
94  //std::cout << idx.transpose() << std::endl;
95 
96  // Register points in grid
97  // if z component of p is > pB.topZ -> set new top point at pos
98  // if z component of p is < pB.bottomZ -> set new bottom point at pos
99  auto & pB = boundaryPoints[idx(0) + idx(1)*gridSize];
100 
101  if( pB.bottomIdx == 0) {
102  pB.bottomIdx = pB.topIdx = i+1;
103  pB.bottomZ = pB.topZ = K_p(2);
104  } else {
105  if( pB.topZ < K_p(2) ) {
106  pB.topIdx = i+1;
107  pB.topZ = K_p(2);
108  }else{
109  if( pB.bottomZ > K_p(2) ) {
110  pB.bottomIdx = i+1;
111  pB.bottomZ = K_p(2);
112  }
113  }
114  }
115  }
116 
117  // Copy top and bottom points
118  IndexType k=0;
119  ApproxMVBB_MSGLOG_L2("Sampled Points incides: [ ")
120  // k does not overflow -> 2* halfSampleSize = 2*gridSize*gridSize <= nPoints;
121  for(IndexType i=0; i<halfSampleSize; ++i) {
122  if( boundaryPoints[i].bottomIdx != 0 ) {
123  // comment in if you want the top/bottom points of the grid
124  //Array3 a(i % gridSize,i/gridSize,oobb.m_maxPoint(2)-oobb.m_minPoint(2));
125  //a.head<2>()*=dxdyInv.inverse();
126  ApproxMVBB_MSGLOG_L2( boundaryPoints[i].topIdx-1 << ", " << ((k%30==0)? "\n" : "") )
127  newPoints.col(k++) = points.col(boundaryPoints[i].topIdx-1); // A_KI.transpose()*(oobb.m_minPoint + a.matrix()).eval() ;
128  if(boundaryPoints[i].topIdx != boundaryPoints[i].bottomIdx) {
129  // comment in if you want the bottom points of the grid
130  //Array3 a(i % gridSize,i/gridSize,0);
131  //a.head<2>()*=dxdyInv.inverse();
132  ApproxMVBB_MSGLOG_L2( boundaryPoints[i].bottomIdx-1 << ", " )
133  newPoints.col(k++) = points.col(boundaryPoints[i].bottomIdx-1); // A_KI.transpose()*(oobb.m_minPoint + a.matrix()).eval() ;
134  }
135  }
136  }
137 
138  // Add random points!
139  // Random indices if too little points
140  if( k < nPoints ){
143  typename std::make_unsigned<IndexType>::type
144  > dis(0, points.cols()-1);
145  IndexType s;
146  while( k < nPoints) {
147  s = dis(gen);
148  ApproxMVBB_MSGLOG_L2( s << ", " )
149  newPoints.col(k++) = points.col( s ); //= Vector3(0,0,0);//
150  }
151  }
152  ApproxMVBB_MSGLOG_L2( "]" << std::endl )
153 }
154 
163 template<typename Derived>
164 APPROXMVBB_EXPORT OOBB optimizeMVBB( const MatrixBase<Derived> & points,
165  OOBB oobb,
166  unsigned int nLoops = 10,
167  PREC volumeAcceptFactor = 1e-6,
168  PREC minBoxExtent = 1e-12
169  )
170 {
171 
172  EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Derived,3,Eigen::Dynamic)
173 
174  if( oobb.volume() == 0.0 || nLoops == 0) {
175  return oobb;
176  }
177 
178  // Define the volume lower bound above we accept a new volume as
179  PREC volumeAcceptTol = oobb.volume() * volumeAcceptFactor;
180 
181 
182  unsigned int cacheIdx = 0; // current write Idx into the cache
183  Vector3 dirCache[3]; // save the last three directions (avoiding cycling in choosen axis)
184 
185  Vector3 dir;
186  ProjectedPointSet proj;
187  for(unsigned int loop = 0; loop < nLoops; ++loop ) {
188 
189  // Determine Direction (choose x or y axis)
190  //std::cout << oobb.m_q_KI.matrix() << std::endl;
191  dir = oobb.getDirection(0);
192 
193  // check against all chache values
194  for(unsigned char i=0; i<3 && i<loop; ++i) {
195  PREC dotp = std::abs(dir.dot(dirCache[i])); //
196  if( std::abs(dotp - 1.0) <= 1e-3 ) {
197  //std::cout << "Change Dir" << std::endl;
198  // direction are almost the same as in the cache, choose another one
199  dir = oobb.getDirection(1);
200  break;
201  }
202  }
203  // Write to cache and shift write idx
204  dirCache[cacheIdx] = dir;
205  cacheIdx = (cacheIdx + 1) % 3;
206 
207  //std::cout << "Optimizing dir: " << dir << std::endl;
208  OOBB o = proj.computeMVBB( dir, points);
209 
210  // Expand box such the volume is not zero for points in a plane
211  o.expandToMinExtentAbsolute(minBoxExtent);
212 
213  if( o.volume() < oobb.volume() && o.volume()>volumeAcceptTol) {
214  oobb = o;
215  }
216  }
217 
218  return oobb;
219 }
220 
221 
233 template<typename Derived>
234 APPROXMVBB_EXPORT OOBB approximateMVBBGridSearch(const MatrixBase<Derived> & points,
235  OOBB oobb,
236  PREC epsilon,
237  const unsigned int gridSize = 5,
238  const unsigned int optLoops = 6,
239  PREC volumeAcceptFactor = 1e-6,
240  PREC minBoxExtent = 1e-12
241  )
242 {
243  EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Derived,3,Eigen::Dynamic)
244 
245  // Extent input oobb
246  oobb.expandToMinExtentAbsolute(minBoxExtent);
247 
248  // Define the volume lower bound above we accept a new volume as
249  /*PREC volumeAcceptTol = oobb.volume() * volumeAcceptFactor;*/
250 
251  //Get the direction of the input OOBB in I frame:
252  Vector3 dir1 = oobb.getDirection(0);
253  Vector3 dir2 = oobb.getDirection(1);
254  Vector3 dir3 = oobb.getDirection(2);
255 
256  Vector3 dir;
257 
258  ProjectedPointSet proj;
259 
260  for(int x = -int(gridSize); x <= (int)gridSize; ++x ) {
261  for(int y = -int(gridSize); y <= (int)gridSize; ++y ) {
262  for(int z = 0; z <= (int)gridSize; ++z ) {
263 
264  if( MathFunctions::gcd3(x,y,z)> 1 || ((x==0) && (y==0) && (z==0)) ) {
265  continue;
266  }
267 
268  // Make direction
269  dir = x*dir1 + y*dir2 + z*dir3;
270  ApproxMVBB_MSGLOG_L3( "gridSearch: dir: " << dir.transpose() << std::endl; )
271 
272  // Compute MVBB in dirZ
273  auto res = proj.computeMVBB(dir,points);
274 
275  // Expand to minimal extent for points in a surface or line
276  res.expandToMinExtentAbsolute(minBoxExtent);
277 
278  if(optLoops){
279  res = optimizeMVBB(points,res,optLoops,volumeAcceptFactor,minBoxExtent);
280  }
281  ApproxMVBB_MSGLOG_L3( "gridSearch: volume: " << res.volume() << std::endl;)
282  if(res.volume() < oobb.volume() /*&& res.volume()>volumeAcceptTol */) {
283 
284  ApproxMVBB_MSGLOG_L2( "gridSearch: new volume: " << res.volume() << std::endl << "for dir: " << dir.transpose() << std::endl; )
285  oobb = res;
286  }
287 
288  }
289  }
290  }
291  return oobb;
292 }
293 
300 template<typename Derived>
301 APPROXMVBB_EXPORT OOBB approximateMVBBDiam(const MatrixBase<Derived> & points,
302  const PREC epsilon,
303  const unsigned int optLoops = 10,
305  )
306 {
307  EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Derived,3,Eigen::Dynamic)
308 
309  using namespace PointFunctions;
310  auto pp = estimateDiameter<3>(points, epsilon, seed );
311 
313 
314  // TODO: Is this direction inversion needed? not really ?
315  if( ( dirZ.array() <= 0.0).all() ) {
316  dirZ *= -1;
317  }
318 
319  // If direction zero, use (1,0)
320  if( (dirZ.array() == 0.0).all() ) {
321  dirZ.setZero();
322  dirZ(0)= 1;
323  }
324  ApproxMVBB_MSGLOG_L1("estimated 3d diameter: " << dirZ.transpose() << " eps: " << epsilon << std::endl;)
325 
326  // Compute MVBB in dirZ
327  ProjectedPointSet proj;
328  //OOBB oobb = proj.computeMVBB();
329  // or faster estimate diameter in projected plane and build coordinate system
330  OOBB oobb = proj.computeMVBBApprox(dirZ,points,epsilon);
331 
332  if(optLoops) {
333  oobb = optimizeMVBB(points,oobb,optLoops);
334  }
335  return oobb;
336 }
337 
338 template<typename Derived >
339 APPROXMVBB_EXPORT OOBB approximateMVBB(const MatrixBase<Derived> & points,
340  const PREC epsilon,
341  const unsigned int pointSamples = 400,
342  const unsigned int gridSize = 5,
343  const unsigned int mvbbDiamOptLoops = 0,
344  const unsigned int mvbbGridSearchOptLoops = 6,
346  )
347 {
348  EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Derived,3,Eigen::Dynamic)
349 
350  // Get get MVBB from estimated diameter direction
351  // take care forwarding means not using gen anymore !
352  auto oobb = approximateMVBBDiam(points,epsilon,mvbbDiamOptLoops, seed );
353 
354  // Check if we sample the point cloud
355  if(pointSamples<points.cols()) {
356 
357  // sample points
358  Matrix3Dyn sampled;
359  samplePointsGrid(sampled,points,pointSamples,oobb, seed);
360 
361  // Exhaustive grid search with sampled points
362  oobb = approximateMVBBGridSearch(sampled,oobb,epsilon,gridSize,mvbbGridSearchOptLoops);
363 
364  } else {
365  // Exhaustive grid search with sampled points
366  oobb = approximateMVBBGridSearch(points,oobb,epsilon,gridSize,mvbbGridSearchOptLoops);
367  }
368 
369  return oobb;
370 }
371 
372 }
373 
374 
375 
376 #endif // ApproxMVBB_hpp
377 
Eigen::Array< Scalar, 2, 1 > Array2
std::enable_if< std::is_integral< T >::value, T >::type gcd3(T a, T b, T c)
PREC volume() const
Definition: OOBB.hpp:133
OOBB computeMVBB(const Vector3 &zDir, const MatrixBase< Derived > &points)
These are some container definitions.
#define ApproxMVBB_MSGLOG_L3(message)
Definition: LogDefines.hpp:36
APPROXMVBB_EXPORT OOBB approximateMVBB(const MatrixBase< Derived > &points, const PREC epsilon, const unsigned int pointSamples=400, const unsigned int gridSize=5, const unsigned int mvbbDiamOptLoops=0, const unsigned int mvbbGridSearchOptLoops=6, std::size_t seed=ApproxMVBB::RandomGenerators::defaultSeed)
#define ApproxMVBB_ERRORMSG(message)
Vector3 getDirection(unsigned int i) const
Definition: OOBB.hpp:139
Array3 extent() const
Definition: OOBB.hpp:81
#define APPROXMVBB_EXPORT
Definition: Platform.hpp:60
ApproxMVBB_DEFINE_MATRIX_TYPES ApproxMVBB_DEFINE_POINTS_CONFIG_TYPES APPROXMVBB_EXPORT void samplePointsGrid(Matrix3Dyn &newPoints, const MatrixBase< Derived > &points, const unsigned int nPoints, OOBB &oobb, std::size_t seed=ApproxMVBB::RandomGenerators::defaultSeed)
APPROXMVBB_EXPORT OOBB optimizeMVBB(const MatrixBase< Derived > &points, OOBB oobb, unsigned int nLoops=10, PREC volumeAcceptFactor=1e-6, PREC minBoxExtent=1e-12)
static const uint64_t defaultSeed
MatrixStatDyn< 3 > Matrix3Dyn
void expandToMinExtentAbsolute(PREC minExtent)
Definition: OOBB.cpp:75
Eigen::Matrix< Scalar, 3, 3 > Matrix33
Quaternion m_q_KI
Rotation of frame I to frame K, corresponds to a transformation A_IK;.
Definition: OOBB.hpp:175
Vector3 m_minPoint
in K Frame
Definition: OOBB.hpp:176
#define ApproxMVBB_DEFINE_POINTS_CONFIG_TYPES
#define ApproxMVBB_MSGLOG_L2(message)
Definition: LogDefines.hpp:35
std::uniform_int_distribution< T > DefaultUniformUIntDistribution
APPROXMVBB_EXPORT OOBB approximateMVBBDiam(const MatrixBase< Derived > &points, const PREC epsilon, const unsigned int optLoops=10, std::size_t seed=ApproxMVBB::RandomGenerators::defaultSeed)
APPROXMVBB_EXPORT OOBB approximateMVBBGridSearch(const MatrixBase< Derived > &points, OOBB oobb, PREC epsilon, const unsigned int gridSize=5, const unsigned int optLoops=6, PREC volumeAcceptFactor=1e-6, PREC minBoxExtent=1e-12)
Eigen::Matrix< Scalar, 3, 1 > Vector3
void setZAxisLongest()
Definition: OOBB.hpp:54
#define ApproxMVBB_DEFINE_MATRIX_TYPES
Definition: TypeDefs.hpp:26
#define ApproxMVBB_MSGLOG_L1(message)
Definition: LogDefines.hpp:34


asr_approx_mvbb
Author(s): Gassner Nikolai
autogenerated on Mon Jun 10 2019 12:38:08