ObjSelect.h 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. /*
  2. * Copyright (C) =USTC= Fu Li
  3. *
  4. * Author : Fu Li
  5. * Create : 2003-4-8
  6. * Home : http://www.crazy-bit.com/
  7. * Mail : crazybit@263.net
  8. * History :
  9. */
  10. #ifndef __FOO_OBJECT_SELECTION__2003_04_08__H__
  11. #define __FOO_OBJECT_SELECTION__2003_04_08__H__
  12. #include "ObjImage.h"
  13. #include "PCL_interface_zoom.h"
  14. //=============================================================================
  15. /**
  16. * Selection object (bitmap mask).
  17. * it's a 8-bit gray image, 0xFF means pixel selected, otherwise unselected.
  18. */
  19. class FCObjSelect : public FCObjImage
  20. {
  21. public:
  22. /** handle type. */
  23. enum RGN_TYPE
  24. {
  25. RGN_CREATE=0, /**< create a new selection */
  26. RGN_ADD=1, /**< add selection into current selection */
  27. RGN_SUB=2, /**< sub selection from current selection */
  28. };
  29. public:
  30. /**
  31. * @name Constructor.
  32. */
  33. //@{
  34. /// Create an empty selection.
  35. FCObjSelect ()
  36. {
  37. m_nZoom = ZOOM_UNSCAN ;
  38. m_nCurAnt = 0 ;
  39. }
  40. /// Copy constructor.
  41. FCObjSelect (const FCObjSelect& sel)
  42. {
  43. m_nZoom = ZOOM_UNSCAN ;
  44. m_nCurAnt = 0 ;
  45. *this = sel ;
  46. }
  47. //@}
  48. FCObjSelect& operator= (const FCObjSelect& sel)
  49. {
  50. if (&sel == this)
  51. {
  52. assert(false); return *this;
  53. }
  54. __SetSelectionEmpty(); // enable empty copy
  55. if (sel.HasSelected())
  56. {
  57. m_nZoom = sel.m_nZoom;
  58. m_nCurAnt = sel.m_nCurAnt;
  59. m_ptEdge = sel.m_ptEdge; // copy the edge point
  60. FCObjImage::operator=(sel);
  61. }
  62. return *this;
  63. }
  64. /// Is selection object valid.
  65. bool HasSelected() const {return IsValidImage();}
  66. /**
  67. * Optimize selection.
  68. * erase un-selected point around. the position of selection will be adjusted automatically.
  69. */
  70. void SelectionOptimize()
  71. {
  72. if (!HasSelected())
  73. return ;
  74. RECT rcBound = {Width(), Height(), 0, 0} ;
  75. for (int y=0 ; y < Height() ; y++)
  76. for (int x=0 ; x < Width() ; x++)
  77. if (*GetBits(x,y) == 0xFF)
  78. {
  79. if (x < rcBound.left) rcBound.left = x ;
  80. if (x > rcBound.right) rcBound.right = x ;
  81. if (y < rcBound.top) rcBound.top = y ;
  82. if (y > rcBound.bottom) rcBound.bottom = y ;
  83. }
  84. // the selection is open, so we ++
  85. rcBound.right++ ; rcBound.bottom++ ;
  86. // the whole selection is empty
  87. if (IsRectEmpty(&rcBound))
  88. {
  89. __SetSelectionEmpty() ;
  90. return ;
  91. }
  92. // the selection can't be optimized
  93. const RECT rcSel = {0, 0, Width(), Height()} ;
  94. if (memcmp (&rcSel, &rcBound, sizeof(RECT)) == 0) // rect is equal
  95. return ;
  96. // erase == get a sub block
  97. const POINT ptOldPos = GetGraphObjPos() ;
  98. FCObjImage imgSub ;
  99. GetSubBlock (&imgSub, rcBound) ;
  100. *static_cast<FCObjImage*>(this) = imgSub ;
  101. SetGraphObjPos (ptOldPos.x+rcBound.left, ptOldPos.y+rcBound.top) ;
  102. m_ptEdge.clear() ;
  103. m_nCurAnt = 0 ;
  104. m_nZoom = ZOOM_UNSCAN ; // force to re-calculate edge
  105. }
  106. /**
  107. * Calculate edge point by nZoom.
  108. * edge point's coordinate relative to top-left of selection object.
  109. */
  110. void RecalculateEdge (int nZoom, bool bForceRecalculate)
  111. {
  112. if (!HasSelected())
  113. {
  114. m_ptEdge.clear() ;
  115. m_nCurAnt = 0 ;
  116. m_nZoom = ZOOM_UNSCAN ;
  117. return ;
  118. }
  119. if (!bForceRecalculate)
  120. if (m_nZoom == nZoom)
  121. return ;
  122. m_ptEdge.clear() ;
  123. m_nCurAnt = 0 ;
  124. m_nZoom = nZoom ;
  125. if ((m_nZoom == ZOOM_UNSCAN) || (m_nZoom == 0))
  126. return ;
  127. // search edge point
  128. FCObjImage EdgeImg (Width(), Height(), 8) ;
  129. int nEdgeNum = 0 ;
  130. // is edge point : current is selected around is non-selected
  131. // brim point must be edge point
  132. for (int y=0 ; y < Height() ; y++)
  133. for (int x=0 ; x < Width() ; x++)
  134. if (*GetBits(x,y) == 0xFF)
  135. if ((y == 0) || (*GetBits(x,y-1) == 0) || // up
  136. (y == Height()-1) || (*GetBits(x,y+1) == 0) || // down
  137. (x == 0) || (*GetBits(x-1,y) == 0) || // left
  138. (x == Width()-1) || (*GetBits(x+1,y) == 0) || // right
  139. (*GetBits(x+1,y-1) == 0) || // right-up
  140. (*GetBits(x+1,y+1) == 0) || // right-down
  141. (*GetBits(x-1,y+1) == 0) || // left-down
  142. (*GetBits(x-1,y-1) == 0)) // left-up
  143. {
  144. *EdgeImg.GetBits(x,y) = 0xFF ;
  145. nEdgeNum++ ;
  146. }
  147. // no edge point
  148. if (nEdgeNum == 0)
  149. return ;
  150. if (m_nZoom <= -1)
  151. {
  152. // deflate, only div
  153. FCObjImage imgHash (Width()/-m_nZoom+2, Height()/-m_nZoom+2, 8) ;
  154. for (int y=0 ; y < Height() ; y++)
  155. for (int x=0 ; x < Width() ; x++)
  156. if (*EdgeImg.GetBits(x,y) == 0xFF)
  157. {
  158. POINT pt = {x/-m_nZoom, y/-m_nZoom} ;
  159. BYTE * pHash = imgHash.GetBits (pt.x, pt.y) ;
  160. if (*pHash == 0) // some point --> one point
  161. {
  162. *pHash = 0xFF ;
  163. m_ptEdge.push_back (pt) ;
  164. }
  165. }
  166. }
  167. else
  168. {
  169. // inflate, we should insert some point
  170. const int nNewW = Width() * m_nZoom,
  171. nNewH = Height() * m_nZoom ;
  172. // calculate x/y table
  173. PCL_array<int> pX (nNewW),
  174. pY (nNewH) ;
  175. int x, y ;
  176. for (y=0 ; y < nNewH ; y++)
  177. {pY[y] = y / m_nZoom; assert (pY[y] < Height());}
  178. for (x=0 ; x < nNewW ; x++)
  179. {pX[x] = x / m_nZoom; assert (pX[x] < Width());}
  180. // search edge
  181. for (y=0 ; y < nNewH ; y++)
  182. for (x=0 ; x < nNewW ; x++)
  183. if (*EdgeImg.GetBits (pX[x],pY[y]) == 0xFF)
  184. {
  185. // still edge point after inflate
  186. int cr = *GetBits (pX[x],pY[y]) ;
  187. if ((y == 0) || (*GetBits(pX[x],pY[y-1]) != cr) || // up
  188. (y == nNewH-1) || (*GetBits(pX[x],pY[y+1]) != cr) || // down
  189. (x == 0) || (*GetBits(pX[x-1],pY[y]) != cr) || // left
  190. (x == nNewW-1) || (*GetBits(pX[x+1],pY[y]) != cr)) // right
  191. // (*(pPixel + 1 + dwPitch) == 0) || // right-up
  192. // (*(pPixel + 1 - dwPitch) == 0) || // right-down
  193. // (*(pPixel - 1 - dwPitch) == 0) || // left-down
  194. // (*(pPixel - 1 + dwPitch) == 0)) // left_up
  195. {
  196. POINT pt = {x,y} ;
  197. m_ptEdge.push_back (pt) ;
  198. }
  199. }
  200. }
  201. }
  202. private:
  203. enum
  204. {
  205. ZOOM_UNSCAN = 0x7FFF,
  206. };
  207. // internal. set selection empty
  208. void __SetSelectionEmpty()
  209. {
  210. FCObjImage::Destroy() ;
  211. m_ptEdge.clear() ;
  212. m_nZoom = ZOOM_UNSCAN ;
  213. m_nCurAnt = 0 ;
  214. }
  215. private:
  216. int m_nZoom ;
  217. int m_nCurAnt ; // [0..7]
  218. std::deque<POINT> m_ptEdge ; // scaled edge point
  219. friend class FCWin32 ;
  220. };
  221. //===================================================================
  222. // inline implement
  223. //===================================================================
  224. #endif