ccInnerRect2DFinder.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. //##########################################################################
  2. //# #
  3. //# CLOUDCOMPARE #
  4. //# #
  5. //# This program is free software; you can redistribute it and/or modify #
  6. //# it under the terms of the GNU General Public License as published by #
  7. //# the Free Software Foundation; version 2 or later of the License. #
  8. //# #
  9. //# This program is distributed in the hope that it will be useful, #
  10. //# but WITHOUT ANY WARRANTY; without even the implied warranty of #
  11. //# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
  12. //# GNU General Public License for more details. #
  13. //# #
  14. //# COPYRIGHT: EDF R&D / TELECOM ParisTech (ENST-TSI) #
  15. //# #
  16. //##########################################################################
  17. #include "ccInnerRect2DFinder.h"
  18. //qCC_db
  19. #include <ccLog.h>
  20. //system
  21. #include <assert.h>
  22. ccInnerRect2DFinder::ccInnerRect2DFinder()
  23. : m_maxArea(0)
  24. , m_cloud(nullptr)
  25. , m_X(0)
  26. , m_Y(1)
  27. {}
  28. ccBox* ccInnerRect2DFinder::process( ccGenericPointCloud* cloud, unsigned char zDim/*=2*/ )
  29. {
  30. if (!init(cloud,zDim))
  31. return nullptr;
  32. //Find the 'biggest' rectangle
  33. m_maxRect = Rect();
  34. m_maxArea = 0;
  35. findBiggestRect(m_boundingRect,0);
  36. ccBox* resultBox = nullptr;
  37. if (m_maxArea > 0)
  38. {
  39. ccBBox bbox = cloud->getOwnBB();
  40. assert(bbox.isValid());
  41. //box size
  42. CCVector3 boxDim = bbox.getDiagVec();
  43. boxDim.u[m_X] = static_cast<PointCoordinateType>(m_maxRect.width());
  44. boxDim.u[m_Y] = static_cast<PointCoordinateType>(m_maxRect.height());
  45. CCVector3 boxCenter = bbox.getCenter();
  46. boxCenter.u[m_X] = static_cast<PointCoordinateType>((m_maxRect.x0 + m_maxRect.x1)/2);
  47. boxCenter.u[m_Y] = static_cast<PointCoordinateType>((m_maxRect.y0 + m_maxRect.y1)/2);
  48. ccGLMatrix shiftMat;
  49. shiftMat.setTranslation(boxCenter);
  50. resultBox = new ccBox(boxDim,&shiftMat,"Biggest rect");
  51. }
  52. return resultBox;
  53. }
  54. bool ccInnerRect2DFinder::init(ccGenericPointCloud* cloud, unsigned char zDim)
  55. {
  56. if (!cloud || cloud->size() == 0)
  57. {
  58. ccLog::Error("[ccInnerRect2DFinder] Invalid input cloud");
  59. return false;
  60. }
  61. ccBBox bbox = cloud->getOwnBB();
  62. if (!bbox.isValid())
  63. {
  64. ccLog::Error("[ccInnerRect2DFinder] Invalid input cloud");
  65. return false;
  66. }
  67. if (zDim > 2)
  68. {
  69. ccLog::Error("[ccInnerRect2DFinder] Invalid input parameter (zDim)");
  70. return false;
  71. }
  72. unsigned char Z = zDim;
  73. unsigned char X = ((Z+1) % 3);
  74. unsigned char Y = ((X+1) % 3);
  75. m_cloud = cloud;
  76. m_X = X;
  77. m_Y = Y;
  78. //init bounding rectangle
  79. {
  80. const CCVector3* P0 = m_cloud->getPoint(0);
  81. m_boundingRect = Rect(P0->u[m_X],P0->u[m_Y],P0->u[m_X],P0->u[m_Y]);
  82. unsigned pointCloud = m_cloud->size();
  83. for (unsigned i=1; i<pointCloud; ++i)
  84. {
  85. const CCVector3* P = m_cloud->getPoint(i);
  86. if (P->u[m_X] < m_boundingRect.x0)
  87. m_boundingRect.x0 = P->u[m_X];
  88. else if (P->u[m_X] > m_boundingRect.x1)
  89. m_boundingRect.x1 = P->u[m_X];
  90. if (P->u[m_Y] < m_boundingRect.y0)
  91. m_boundingRect.y0 = P->u[m_Y];
  92. else if (P->u[m_Y] > m_boundingRect.y1)
  93. m_boundingRect.y1 = P->u[m_Y];
  94. }
  95. }
  96. return true;
  97. }
  98. void ccInnerRect2DFinder::findBiggestRect(const Rect& rect, unsigned startIndex)
  99. {
  100. assert(m_cloud);
  101. //test if at least one point falls inside the input rectangle
  102. const CCVector3* Pinside = nullptr;
  103. {
  104. unsigned pointCount = m_cloud->size();
  105. double minSquareDistToCenter = -1.0;
  106. double xc = (rect.x0+rect.x1)/2;
  107. double yc = (rect.y0+rect.y1)/2;
  108. for (unsigned i=startIndex; i<pointCount; ++i)
  109. {
  110. const CCVector3* P = m_cloud->getPoint(i);
  111. if ( P->u[m_X] > rect.x0 && P->u[m_X] < rect.x1 //strict inequalities!
  112. && P->u[m_Y] > rect.y0 && P->u[m_Y] < rect.y1 )
  113. {
  114. double dist2 = (xc - P->u[m_X])*(xc - P->u[m_X]) + (yc - P->u[m_Y])*(yc - P->u[m_Y]);
  115. if (minSquareDistToCenter < 0)
  116. {
  117. Pinside = P;
  118. minSquareDistToCenter = dist2;
  119. startIndex = i;
  120. }
  121. else if (dist2 < minSquareDistToCenter)
  122. {
  123. Pinside = P;
  124. minSquareDistToCenter = dist2;
  125. }
  126. //break;
  127. }
  128. }
  129. }
  130. //do we have an empty rectangle?
  131. if (!Pinside)
  132. {
  133. //we remember it only if its size is bigger
  134. double surf = rect.area();
  135. if (surf > m_maxArea)
  136. {
  137. m_maxArea = surf;
  138. m_maxRect = rect;
  139. }
  140. }
  141. else //otherwise we test the 4 sub-rectangles
  142. {
  143. //left sub-rectangle
  144. Rect r(rect.x0,rect.y0,Pinside->u[m_X],rect.y1);
  145. if (r.area() > m_maxArea)
  146. findBiggestRect(r,startIndex);
  147. //right sub-rectangle
  148. r = Rect(Pinside->u[m_X],rect.y0,rect.x1,rect.y1);
  149. if (r.area() > m_maxArea)
  150. findBiggestRect(r,startIndex);
  151. //upper sub-rectangle
  152. r = Rect(rect.x0,rect.y0,rect.x1,Pinside->u[m_Y]);
  153. if (r.area() > m_maxArea)
  154. findBiggestRect(r,startIndex);
  155. //lower sub-rectangle
  156. r = Rect(rect.x0,Pinside->u[m_Y],rect.x1,rect.y1);
  157. if (r.area() > m_maxArea)
  158. findBiggestRect(r,startIndex);
  159. }
  160. }