/* * Copyright (C) =USTC= Fu Li * * Author : Fu Li * Create : 2003-4-8 * Home : http://www.crazy-bit.com/ * Mail : crazybit@263.net * History : */ #ifndef __FOO_OBJECT_SELECTION__2003_04_08__H__ #define __FOO_OBJECT_SELECTION__2003_04_08__H__ #include "ObjImage.h" #include "PCL_interface_zoom.h" //============================================================================= /** * Selection object (bitmap mask). * it's a 8-bit gray image, 0xFF means pixel selected, otherwise unselected. */ class FCObjSelect : public FCObjImage { public: /** handle type. */ enum RGN_TYPE { RGN_CREATE=0, /**< create a new selection */ RGN_ADD=1, /**< add selection into current selection */ RGN_SUB=2, /**< sub selection from current selection */ }; public: /** * @name Constructor. */ //@{ /// Create an empty selection. FCObjSelect () { m_nZoom = ZOOM_UNSCAN ; m_nCurAnt = 0 ; } /// Copy constructor. FCObjSelect (const FCObjSelect& sel) { m_nZoom = ZOOM_UNSCAN ; m_nCurAnt = 0 ; *this = sel ; } //@} FCObjSelect& operator= (const FCObjSelect& sel) { if (&sel == this) { assert(false); return *this; } __SetSelectionEmpty(); // enable empty copy if (sel.HasSelected()) { m_nZoom = sel.m_nZoom; m_nCurAnt = sel.m_nCurAnt; m_ptEdge = sel.m_ptEdge; // copy the edge point FCObjImage::operator=(sel); } return *this; } /// Is selection object valid. bool HasSelected() const {return IsValidImage();} /** * Optimize selection. * erase un-selected point around. the position of selection will be adjusted automatically. */ void SelectionOptimize() { if (!HasSelected()) return ; RECT rcBound = {Width(), Height(), 0, 0} ; for (int y=0 ; y < Height() ; y++) for (int x=0 ; x < Width() ; x++) if (*GetBits(x,y) == 0xFF) { if (x < rcBound.left) rcBound.left = x ; if (x > rcBound.right) rcBound.right = x ; if (y < rcBound.top) rcBound.top = y ; if (y > rcBound.bottom) rcBound.bottom = y ; } // the selection is open, so we ++ rcBound.right++ ; rcBound.bottom++ ; // the whole selection is empty if (IsRectEmpty(&rcBound)) { __SetSelectionEmpty() ; return ; } // the selection can't be optimized const RECT rcSel = {0, 0, Width(), Height()} ; if (memcmp (&rcSel, &rcBound, sizeof(RECT)) == 0) // rect is equal return ; // erase == get a sub block const POINT ptOldPos = GetGraphObjPos() ; FCObjImage imgSub ; GetSubBlock (&imgSub, rcBound) ; *static_cast(this) = imgSub ; SetGraphObjPos (ptOldPos.x+rcBound.left, ptOldPos.y+rcBound.top) ; m_ptEdge.clear() ; m_nCurAnt = 0 ; m_nZoom = ZOOM_UNSCAN ; // force to re-calculate edge } /** * Calculate edge point by nZoom. * edge point's coordinate relative to top-left of selection object. */ void RecalculateEdge (int nZoom, bool bForceRecalculate) { if (!HasSelected()) { m_ptEdge.clear() ; m_nCurAnt = 0 ; m_nZoom = ZOOM_UNSCAN ; return ; } if (!bForceRecalculate) if (m_nZoom == nZoom) return ; m_ptEdge.clear() ; m_nCurAnt = 0 ; m_nZoom = nZoom ; if ((m_nZoom == ZOOM_UNSCAN) || (m_nZoom == 0)) return ; // search edge point FCObjImage EdgeImg (Width(), Height(), 8) ; int nEdgeNum = 0 ; // is edge point : current is selected around is non-selected // brim point must be edge point for (int y=0 ; y < Height() ; y++) for (int x=0 ; x < Width() ; x++) if (*GetBits(x,y) == 0xFF) if ((y == 0) || (*GetBits(x,y-1) == 0) || // up (y == Height()-1) || (*GetBits(x,y+1) == 0) || // down (x == 0) || (*GetBits(x-1,y) == 0) || // left (x == Width()-1) || (*GetBits(x+1,y) == 0) || // right (*GetBits(x+1,y-1) == 0) || // right-up (*GetBits(x+1,y+1) == 0) || // right-down (*GetBits(x-1,y+1) == 0) || // left-down (*GetBits(x-1,y-1) == 0)) // left-up { *EdgeImg.GetBits(x,y) = 0xFF ; nEdgeNum++ ; } // no edge point if (nEdgeNum == 0) return ; if (m_nZoom <= -1) { // deflate, only div FCObjImage imgHash (Width()/-m_nZoom+2, Height()/-m_nZoom+2, 8) ; for (int y=0 ; y < Height() ; y++) for (int x=0 ; x < Width() ; x++) if (*EdgeImg.GetBits(x,y) == 0xFF) { POINT pt = {x/-m_nZoom, y/-m_nZoom} ; BYTE * pHash = imgHash.GetBits (pt.x, pt.y) ; if (*pHash == 0) // some point --> one point { *pHash = 0xFF ; m_ptEdge.push_back (pt) ; } } } else { // inflate, we should insert some point const int nNewW = Width() * m_nZoom, nNewH = Height() * m_nZoom ; // calculate x/y table PCL_array pX (nNewW), pY (nNewH) ; int x, y ; for (y=0 ; y < nNewH ; y++) {pY[y] = y / m_nZoom; assert (pY[y] < Height());} for (x=0 ; x < nNewW ; x++) {pX[x] = x / m_nZoom; assert (pX[x] < Width());} // search edge for (y=0 ; y < nNewH ; y++) for (x=0 ; x < nNewW ; x++) if (*EdgeImg.GetBits (pX[x],pY[y]) == 0xFF) { // still edge point after inflate int cr = *GetBits (pX[x],pY[y]) ; if ((y == 0) || (*GetBits(pX[x],pY[y-1]) != cr) || // up (y == nNewH-1) || (*GetBits(pX[x],pY[y+1]) != cr) || // down (x == 0) || (*GetBits(pX[x-1],pY[y]) != cr) || // left (x == nNewW-1) || (*GetBits(pX[x+1],pY[y]) != cr)) // right // (*(pPixel + 1 + dwPitch) == 0) || // right-up // (*(pPixel + 1 - dwPitch) == 0) || // right-down // (*(pPixel - 1 - dwPitch) == 0) || // left-down // (*(pPixel - 1 + dwPitch) == 0)) // left_up { POINT pt = {x,y} ; m_ptEdge.push_back (pt) ; } } } } private: enum { ZOOM_UNSCAN = 0x7FFF, }; // internal. set selection empty void __SetSelectionEmpty() { FCObjImage::Destroy() ; m_ptEdge.clear() ; m_nZoom = ZOOM_UNSCAN ; m_nCurAnt = 0 ; } private: int m_nZoom ; int m_nCurAnt ; // [0..7] std::deque m_ptEdge ; // scaled edge point friend class FCWin32 ; }; //=================================================================== // inline implement //=================================================================== #endif