#include "stdafx.h" #include "otsdataconst.h" #include "FieldMgr.h" #include "../OTSLog/COTSUtilityDllFunExport.h" namespace OTSIMGPROC { namespace { // fill the matrics with the spiral sequence number ,n*n is the largest fill number. // the row and col number should be odd number. void getSpiralMatrics(std::vector >& arrays,int row,int col) { int n = max(col, row); arrays.resize(n, std::vector(n)); int c = 0, i, j; int z = n * n; int ou = z; while (ou >= 1) { i = 0; j = 0; for (i += c, j += c; j < n - c; j++)//从左到右 { if (ou > z) break; arrays[i][j] = ou--; } for (j--, i++; i < n - c; i++) // 从上到下 { if (ou > z) break; arrays[i][j] = ou--; } for (i--, j--; j >= c; j--)//从右到左 { if (ou > z) break; arrays[i][j] = ou--; } for (j++, i--; i >= c + 1; i--)//从下到上 { if (ou > z) break; arrays[i][j] = ou--; } c++; } // if col<>row then shift the matrics so that the smallest number is in the center of the row*col's matrics. if (row > col) { int offset = (row - col) / 2; for (int k = 0; k < col; k++)//move mat to left (row-col)/2 cols. { for (int m = 0; m < row; m++) { arrays[m][k] = arrays[m][k + offset]; } } } else if (col > row) { int offset = (col - row) / 2; for (int k = 0; k < row; k++)//move mat to up (col-row)/2 cols. { for (int m = 0; m < col; m++) { arrays[k][m] = arrays[k+offset][m]; } } } } void getZShapeMatrics(std::vector >& arrays, int row, int col) { arrays.resize(row, std::vector(col)); for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { /*if (i % 2 == 0) {*/ arrays[i][j] = col *(row- i) + j+1; /*} else { arrays[i][j] = col * i+(col- j); }*/ } } } void getUpDownMeanderMatrics(std::vector >& arrays, int row, int col) { arrays.resize(row, std::vector(col)); for (int i = 0; i CFieldMgr::GetUnmeasuredFieldCentrePoints(std::vector a_listMeasuredFieldCentrePoints) { std::vector allPoints = CalculateFieldCentrePoints1(); std::vector unmeasuredPoints; for(auto p:allPoints) if (!IsInMeasuredFieldList(p,a_listMeasuredFieldCentrePoints)) { // add the field centre into the unmeasured field centre points list unmeasuredPoints.push_back(p); } return unmeasuredPoints; } // reset BOOL CFieldMgr::Reset(CDomainPtr a_pMeasureArea, CSize a_ResolutionSize, int a_FieldStartMode, int a_scanFieldSzie, std::vector& a_listMeasuredFieldCentrePoints) { // input check ASSERT(a_pMeasureArea); if (!a_pMeasureArea || a_pMeasureArea->IsInvalid()) { LogErrorTrace(__FILE__, __LINE__, _T("Reset: invalid measure area poiter.")); return FALSE; } // check member parameters //ASSERT(m_pMeasureArea && m_poImageScanParam && m_poSEMDataMsr); if (!m_pMeasureArea || m_ScanFieldSize==0) { // shouldn't happen LogErrorTrace(__FILE__, __LINE__, _T("Reset: invalid member parameter(s).")); return FALSE; } // check if need to re-do field centres calculation if (!(*(a_pMeasureArea.get()) == *(m_pMeasureArea.get())) || // measure domain has been changed a_FieldStartMode != m_fieldStartMode ) { // need to re-do field centres calculation return Init(a_pMeasureArea, m_ResolutionSize, a_scanFieldSzie,m_fieldStartMode); } return TRUE; } // calculate total fields long CFieldMgr::CalculateTotalFields(CDomainPtr a_poMeasureArea, double a_dScanFieldSizeX, CSize a_sizePixelImage) { // total fields long nTotalFields = -1; // input check ASSERT(a_poMeasureArea); if (!a_poMeasureArea || a_poMeasureArea->IsInvalid()) { LogErrorTrace(__FILE__, __LINE__, _T("CalculateTotalFields: invalid mesure area point.")); return nTotalFields; } // calculate scan field size--Y double dScanFieldSizeY = a_dScanFieldSizeX * (double)a_sizePixelImage.cy / (double)a_sizePixelImage.cx; // calculate total columns long nTotalCols = (long)ceil((double)a_poMeasureArea->GetDomainRect().Width() / a_dScanFieldSizeX); // calculate total rows long nTotalRows = (long)ceil((double)a_poMeasureArea->GetDomainRect().Height() / dScanFieldSizeY); // calculate column on the right of the center column long nRightColumns = nTotalCols / 2; // calculate rows above the center row long nTopRows = nTotalRows / 2; // re-calculate total columns, total rows make sure they are odd numbers nTotalCols = nRightColumns * 2 + 1; nTotalRows = nTopRows * 2 + 1; // measure are is a rectangle? if (a_poMeasureArea->IsRect() || nTotalCols == 1 || nTopRows == 1) { // easy nTotalFields = nTotalCols * nTopRows; } else { // we need to do more calculation // centre row, centre column and centre field nTotalFields = nRightColumns * 2 + nTotalRows * 2 + 1; // calculate top right part int nTopRightPartFileds = 0; CPoint poi; // row by row for (int i = 1; i <= nTopRows; ++i) { // calculate row y position (field bottom) poi.y = a_poMeasureArea->GetDomainCenter().y + (int)dScanFieldSizeY * i - (int)dScanFieldSizeY / 2; // column by column for (int j = 1; j <= nRightColumns; ++j) { // calculate column x position (field left) poi.x = a_poMeasureArea->GetDomainCenter().x + (int)a_dScanFieldSizeX * i - (int)a_dScanFieldSizeX / 2; // test if this field is in the measure domain if (a_poMeasureArea->PtInDomain(poi)) { // in the measure domain, count it. ++nTopRightPartFileds; } else { // not in the measure domain, get out row test break; } } } // add other fields (top right part fields times 4) nTotalFields += nTopRightPartFileds * 4; } // return total fields return nTotalFields; } // field centre points list BOOL CFieldMgr::GetFieldRectByIndex(int a_nIndex, CRect& a_rectField) { auto m_listFieldCentrePoints = CalculateFieldCentrePoints1(); // check input if (a_nIndex < 0 || a_nIndex >(int)m_listFieldCentrePoints.size()) { LogErrorTrace(__FILE__, __LINE__, _T("GetFieldRectByIndex: invalid intex value.")); return FALSE; } // get image size CSize sizePixelImage = m_ResolutionSize; // scan field size (x, y) CSize sizeImage; sizeImage.cx = m_ScanFieldSize; sizeImage.cy = sizeImage.cx * sizePixelImage.cy / sizePixelImage.cx; // get left top CPoint ptLeftTop = m_listFieldCentrePoints[a_nIndex] - CPoint(sizeImage.cx / 2, sizeImage.cy / 2); // get field rectangle a_rectField = CRect(ptLeftTop, sizeImage); return TRUE; } // measure area void CFieldMgr::SetMeasureArea(CDomainPtr a_pMeasureArea) { // input check ASSERT(a_pMeasureArea); if (!a_pMeasureArea) { LogErrorTrace(__FILE__, __LINE__, _T("SetMeasureArea: invalid measure area poiter.")); return; } m_pMeasureArea = CDomainPtr(new CDomain(a_pMeasureArea.get())); } COTSFieldDataPtr CFieldMgr::FindNeighborField(const COTSFieldDataList a_flds, COTSFieldDataPtr a_centerField, SORTING_DIRECTION a_direction) { COTSFieldDataPtr fld; double pixelsize; double mScanfieldsize_y = m_ScanFieldSize * m_ResolutionSize.cy / m_ResolutionSize.cx; for (auto f : a_flds) { SORTING_DIRECTION di; IsNeighborFieldCentre(f->GetPosition(), a_centerField->GetPosition(), m_ScanFieldSize, mScanfieldsize_y, di); if (di == a_direction) { return f; } } return fld; } // protected // calculate field centre points list std::vector CFieldMgr::CalculateFieldCentrePoints1() { // field centre points list std::vector m_listFieldCentrePoints; // clean up m_listFieldCentrePoints.clear(); CSize ImageSizeByPixel = m_ResolutionSize; // scan field size (x, y) double pixelx = ImageSizeByPixel.cx ; double pixely = ImageSizeByPixel.cy; double dScanFiledSizeX = m_ScanFieldSize ; double dScanFiledSizeY = dScanFiledSizeX * pixely / pixelx; CSize sizeImage; sizeImage.cx = dScanFiledSizeX; sizeImage.cy = dScanFiledSizeY; double dOverLapSizeX = m_Overlap * dScanFiledSizeX / pixelx; double dOverLapSizeY = m_Overlap * dScanFiledSizeY / pixely; // the measure domain rectangle CRect rectMeasureDomain = m_pMeasureArea->GetDomainRect(); // the measure domain centre CPoint poiDomainCentre = rectMeasureDomain.CenterPoint(); // start mode OTS_GET_IMAGE_MODE nStartMode = (OTS_GET_IMAGE_MODE)m_fieldStartMode; // calculate total columns, rows and make sure the domain area be covered int nTotalCols = (int)(ceil((double)rectMeasureDomain.Width() / (dScanFiledSizeX - 2 * dOverLapSizeX))); int nTotalRows = (int)(ceil((double)rectMeasureDomain.Height() / (dScanFiledSizeY - 2 * dOverLapSizeY))); // calculate column on the left of the centre point int nLeftCols = nTotalCols / 2; int nRightCols = nLeftCols; // fields on top int nRowsOnTop = nTotalRows / 2; // sure total columns, rows are odd numbers nTotalCols = nLeftCols * 2 + 1; //nTotalRows = nTotalRows * 2 + 1; nTotalRows = nRowsOnTop * 2 + 1; // calculate left, right field column position (x only int nLeftMostColX = poiDomainCentre.x - nLeftCols * ((int)dScanFiledSizeX - 2 * (int)dOverLapSizeX); int nUpMostRowY = poiDomainCentre.y - nRowsOnTop * ((int)dScanFiledSizeY - 2* (int)dOverLapSizeY); std::vector > pointMatrics(nTotalRows, std::vector(nTotalCols)); for (int i = 0; i < nTotalRows; i++) { for (int j = 0; j < nTotalCols; j++) { pointMatrics[i][j].x = nLeftMostColX + j * ((int)dScanFiledSizeX - 2 * (int)dOverLapSizeX); pointMatrics[i][j].y = nUpMostRowY + i * ((int)dScanFiledSizeY - 2 * (int)dOverLapSizeY); } } std::vector > sequenceMat; //construct an matrics map to the pointMatrics,but the content is the sequence number. switch (nStartMode) { case OTS_GET_IMAGE_MODE::SpiralSequnce: getSpiralMatrics(sequenceMat, nTotalRows,nTotalCols); break; case OTS_GET_IMAGE_MODE::SnakeSequnce : getUpDownMeanderMatrics(sequenceMat, nTotalRows, nTotalCols); break; case OTS_GET_IMAGE_MODE::ZShapeSequnce : getZShapeMatrics(sequenceMat, nTotalRows, nTotalCols); case OTS_GET_IMAGE_MODE::RANDOM : break; } std::map mapCenterPoint; for (int i = 0; i < nTotalRows; i++) { for (int j = 0; j < nTotalCols; j++) { int sequenceNum = sequenceMat[i][j]; CPoint p = pointMatrics[i][j]; mapCenterPoint[sequenceNum] = p;// sorting all the field center point by the sequence number. } } // 判断当前样品获取帧图信息的测量区域为多边形 if ((int)m_pMeasureArea->GetShape() > 1) { std::vector ptPolygon = m_pMeasureArea->GetPolygonPoint(); for (auto itr : mapCenterPoint) { CPoint itrPoint = itr.second; if (IsInPolygonMeasureArea(itrPoint, sizeImage, ptPolygon)) { m_listFieldCentrePoints.push_back(itr.second); } } } else { for (auto itr : mapCenterPoint) { if (IsInMeasureArea(itr.second, sizeImage)) { m_listFieldCentrePoints.push_back(itr.second); } } } return m_listFieldCentrePoints; } // test if field is in or partly in the measure domain area BOOL CFieldMgr::IsInPolygonMeasureArea(CPoint a_poiField, CSize a_sizeImageSize, std::vector ptPolygon) { // check measure area parameter ASSERT(m_pMeasureArea); if (!m_pMeasureArea) { // shouldn't happen LogErrorTrace(__FILE__, __LINE__, _T("IsInDomainArea: invalid measure area parameter.")); return FALSE; } // test field centre point first if (PtInPolygon(a_poiField, ptPolygon)) { // centre in the measure domain area, return TRUE return TRUE; } // get measure field centre CPoint poiMsrAreaCentre = m_pMeasureArea->GetDomainCenter(); // move to left top postion. a_poiField -= CPoint(a_sizeImageSize.cx / 2, a_sizeImageSize.cy / 2); // rectangle of the field CRect rectFiled(a_poiField, a_sizeImageSize); // // on the top left side, need to test the bottom right corner if (PtInPolygon(CPoint(rectFiled.right, rectFiled.top), ptPolygon)) { return TRUE; } // // on the bottom left side, need to test the top right corner if (PtInPolygon(rectFiled.BottomRight(), ptPolygon)) { return TRUE; } // // on the top left side, need to test the bottom right corner if (PtInPolygon(rectFiled.TopLeft(), ptPolygon)) { return TRUE; } // // on the bottom left side, need to test the top right corner if (PtInPolygon(CPoint(rectFiled.left, rectFiled.bottom), ptPolygon)) { return TRUE; } // this field is not in the area at all, return FALSE. return FALSE; } //作用:判断点是否在多边形内 //p指目标点, ptPolygon指多边形的点集合, nCount指多边形的边数 BOOL CFieldMgr::PtInPolygon(CPoint p, std::vector ptPolygon) { int nCount = ptPolygon.size(); // 交点个数 int nCross = 0; for (int i = 0; i < nCount; i++) { CPoint p1 = ptPolygon[i]; CPoint p2 = ptPolygon[(i + 1) % nCount];// 点P1与P2形成连线 if (p1.y == p2.y) continue; if (p.y < min(p1.y, p2.y)) continue; if (p.y >= max(p1.y, p2.y)) continue; // 求交点的x坐标(由直线两点式方程转化而来) double x = (double)(p.y - p1.y) * (double)(p2.x - p1.x) / (double)(p2.y - p1.y) + p1.x; // 只统计p1p2与p向右射线的交点 if (x > p.x) { nCross++; } } // 交点为偶数,点在多边形之外 // 交点为奇数,点在多边形之内 if ((nCross % 2) == 1) { //true; return TRUE; } else { //false; return FALSE; } } // test if field is in or partly in the measure domain area BOOL CFieldMgr::IsInMeasureArea(CPoint a_poiField, CSize a_sizeImageSize) { // check measure area parameter ASSERT(m_pMeasureArea); if (!m_pMeasureArea) { // shouldn't happen LogErrorTrace(__FILE__, __LINE__, _T("IsInDomainArea: invalid measure area parameter.")); return FALSE; } // test field centre point first if (m_pMeasureArea->PtInDomain(a_poiField)) { // centre in the measure domain area, return TRUE return TRUE; } // get measure field centre CPoint poiMsrAreaCentre = m_pMeasureArea->GetDomainCenter(); // move to left top postion. a_poiField -= CPoint(a_sizeImageSize.cx / 2, a_sizeImageSize.cy / 2); // rectangle of the field CRect rectFiled(a_poiField, a_sizeImageSize); // check field position if (rectFiled.left <= poiMsrAreaCentre.x && rectFiled.right >= poiMsrAreaCentre.x) { // centre column field or centre field return TRUE; } else if (rectFiled.top <= poiMsrAreaCentre.y && rectFiled.bottom >= poiMsrAreaCentre.y) { // centre row field? return TRUE; } else if ( rectFiled.right <= poiMsrAreaCentre.x) { // on the left side //up if (rectFiled.top >= poiMsrAreaCentre.y) { // on the top left side, need to test the bottom right corner if (m_pMeasureArea->PtInDomain(CPoint(rectFiled.right, rectFiled.top))) { return TRUE; } } else if(rectFiled.bottom <= poiMsrAreaCentre.y) //down// { // on the bottom left side, need to test the top right corner if (m_pMeasureArea->PtInDomain(rectFiled.BottomRight())) { return TRUE; } } } else if(rectFiled.left >= poiMsrAreaCentre.x) { // on the right side //up if (rectFiled.top >= poiMsrAreaCentre.y) { // on the top left side, need to test the bottom right corner if (m_pMeasureArea->PtInDomain(rectFiled.TopLeft())) { return TRUE; } } else if (rectFiled.bottom <= poiMsrAreaCentre.y) //down// { // on the bottom left side, need to test the top right corner if (m_pMeasureArea->PtInDomain(CPoint(rectFiled.left, rectFiled.bottom))) { return TRUE; } } } // this field is not in the area at all, return FALSE. return FALSE; } // test if field is in the measured field centre points list BOOL CFieldMgr::IsInMeasuredFieldList(CPoint a_poiField, std::vector m_listHaveMeasuredFieldCentrePoints) { // has to not be in the measured field centre points list //auto itr = std::find(m_listHaveMeasuredFieldCentrePoints.begin(), m_listHaveMeasuredFieldCentrePoints.end(), a_poiField); //if (itr != m_listHaveMeasuredFieldCentrePoints.end()) //{ // // in the measured field centre points list, this is a measured field, return TRUE // return TRUE; //} for (CPoint pnt : m_listHaveMeasuredFieldCentrePoints) { double scanHeight = (double)m_ScanFieldSize * ((double)m_ResolutionSize.cy / (double)m_ResolutionSize.cx); CPoint leftTop = CPoint(pnt.x - m_ScanFieldSize / 2, pnt.y + scanHeight / 2); CPoint rightBottom = CPoint(pnt.x + m_ScanFieldSize / 2, pnt.y - scanHeight / 2); COTSRect rec = COTSRect(leftTop, rightBottom); if (rec.PointInRect(a_poiField)) { return true; } } // ok, return FALSE return FALSE; } // find the next field centre BOOL CFieldMgr::FindNeighborFieldCentre(const std::vector& a_listFieldCentres, double a_dScanFieldSizeX, double a_dScanFieldSizeY, CPoint a_poiCurrent, SORTING_DIRECTION& a_nDirection, CPoint& a_poiNeighbor) { // assume no neighbor BOOL bFind = FALSE; // go through the field centres list for (const CPoint& poiFieldCentre : a_listFieldCentres) { // test if this is a neighbor field centre SORTING_DIRECTION nDirection; if (IsNeighborFieldCentre(poiFieldCentre, a_poiCurrent, a_dScanFieldSizeX, a_dScanFieldSizeY, nDirection)) { // we find a neighbor field centre // let see if this is neighbor we are looking for switch (a_nDirection) { // last move is left case SORTING_DIRECTION::LEFT: { // we are looking for DOWN neighbor if (nDirection == SORTING_DIRECTION::DOWN) { // we find a neighbor below, get out a_poiNeighbor = poiFieldCentre; a_nDirection = SORTING_DIRECTION::DOWN; return TRUE; } } break; // last move is down case SORTING_DIRECTION::DOWN: { // we are looking for RIGHT neighbor if (nDirection == SORTING_DIRECTION::RIGHT) { // we find a neighbor on the right, get out a_poiNeighbor = poiFieldCentre; a_nDirection = SORTING_DIRECTION::RIGHT; return TRUE; } } break; // last move is right case SORTING_DIRECTION::RIGHT: { // we are looking for UP neighbor if (nDirection == SORTING_DIRECTION::UP) { // we find a neighbor above a_poiNeighbor = poiFieldCentre; a_nDirection = SORTING_DIRECTION::UP; return TRUE; } } break; // last move is up case SORTING_DIRECTION::UP: { // we are looking for LEFT neighbor if (nDirection == SORTING_DIRECTION::LEFT) { // we find a neighbor on the left, get out a_poiNeighbor = poiFieldCentre; a_nDirection = SORTING_DIRECTION::LEFT; return TRUE; } } break; } } } for (const CPoint& poiFieldCentre : a_listFieldCentres) { // test if this is a neighbor field centre SORTING_DIRECTION nDirection; if (IsNeighborFieldCentre(poiFieldCentre, a_poiCurrent, a_dScanFieldSizeX, a_dScanFieldSizeY, nDirection)) { // we find a neighbor field centre // let see if this is neighbor we are looking for switch (a_nDirection) { // last move is left case SORTING_DIRECTION::LEFT: { // we are looking for DOWN neighbor , but not found // or LEFT neighbor otherwise if (nDirection == SORTING_DIRECTION::LEFT) { // we find a neighbor on the left, continue looking a_poiNeighbor = poiFieldCentre; return TRUE; } } break; // last move is down case SORTING_DIRECTION::DOWN: { // we are looking for RIGHT neighbor, but not found // or DOWN neighbor otherwise if (nDirection == SORTING_DIRECTION::DOWN) { // we find a neighbor below, continue looking a_poiNeighbor = poiFieldCentre; return TRUE; } } break; // last move is right case SORTING_DIRECTION::RIGHT: { // we are looking for UP neighbor, but not found // or RIGHT neighbor, otherwise if (nDirection == SORTING_DIRECTION::RIGHT) { // we find a neighbor on the right, continue looking a_poiNeighbor = poiFieldCentre; return TRUE; } } break; // last move is up case SORTING_DIRECTION::UP: { // we are looking for LEFT neighbor, but not found // or UP neighbor, otherwise if (nDirection == SORTING_DIRECTION::UP) { // we find a neighbor above, continue looking a_poiNeighbor = poiFieldCentre; return TRUE; } } break; } } } // return find result return bFind; } // find field centre closest to measure domain point BOOL CFieldMgr::FindFieldCentreClosestMeasureDomainCentre(const std::vector& a_listFieldCentres, CPoint a_poiMeasureDomain, CPoint& a_poi) { // distance ratio int nDisRadio = -1; for (const CPoint& poiFieldCentre : a_listFieldCentres) { // calculate current field centre distance ratio int nCurFiledDisRadio = (poiFieldCentre.x - a_poiMeasureDomain.x)*(poiFieldCentre.x - a_poiMeasureDomain.x) + (poiFieldCentre.y - a_poiMeasureDomain.y)*(poiFieldCentre.y - a_poiMeasureDomain.y); // pick one which more closer to centre if (nDisRadio > nCurFiledDisRadio || nDisRadio == -1) { a_poi = poiFieldCentre; nDisRadio = nCurFiledDisRadio; } } // nDisRadio != -1 means there still field centre in the a_listFieldCentres return nDisRadio != -1; } // find right far side field centre void CFieldMgr::FindRightMostFieldCentre(const std::vector& a_listFieldCentres, CPoint& a_poi) { for (auto& poi : a_listFieldCentres) { if (poi.y == a_poi.y && poi.x > a_poi.x) { a_poi = poi; } } } // find left far side field centre void CFieldMgr::FindLeftMostFieldCentre(const std::vector& a_listFieldCentres, CPoint& a_poi) { for (auto& poi : a_listFieldCentres) { if (poi.y == a_poi.y && poi.x < a_poi.x) { a_poi = poi; } } } // find top far side field centre void CFieldMgr::FindHeighestFieldCentre(const std::vector& a_listFieldCentres, CPoint& a_poi) { for (auto& poi : a_listFieldCentres) { if (poi.x == a_poi.x && poi.y > a_poi.y) { a_poi = poi; } } } // find bottom far side field centre void CFieldMgr::FindLowestFieldCentre(const std::vector& a_listFieldCentres, CPoint& a_poi) { for (auto& poi : a_listFieldCentres) { if (poi.x == a_poi.x && poi.y < a_poi.y) { a_poi = poi; } } } // check if this is a neighbor field centre BOOL CFieldMgr::IsNeighborFieldCentre(CPoint a_poiFieldCentre, CPoint a_poiCurrent, double a_dScanFieldSizeX, double a_dScanFieldSizeY, SORTING_DIRECTION& a_nDirection) { // x position of the tow field centres are the same, y positions have one field difference if (a_poiFieldCentre.x == a_poiCurrent.x && abs(a_poiFieldCentre.y - a_poiCurrent.y) == long(a_dScanFieldSizeY)) { // test is above or below if (a_poiCurrent.y > a_poiFieldCentre.y) { // below a_nDirection = SORTING_DIRECTION::DOWN; } else { // above a_nDirection = SORTING_DIRECTION::UP; } // this is a neighbor field centre, return TRUE return TRUE; } // y position of the tow field centres are the same, x positions have one field difference else if (a_poiFieldCentre.y == a_poiCurrent.y && abs(a_poiFieldCentre.x - a_poiCurrent.x) == long(a_dScanFieldSizeX)) { // test is on left or right if (a_poiCurrent.x > a_poiFieldCentre.x) { // on the left a_nDirection = SORTING_DIRECTION::LEFT; } else { // on the right a_nDirection = SORTING_DIRECTION::RIGHT; } // this is a neighbor field centre, return TRUE return TRUE; } // this is not a neighbor field centre, return FALSE return FALSE; } // get a random number in a given range int CFieldMgr::GetRangedRandNumber(int a_nRange_min, int a_nRange_max) { // return a random number int nRet; // get a random number in the given range nRet = long((double)rand() / (RAND_MAX + 1) * (a_nRange_max - a_nRange_min) + a_nRange_min); // return the random number return nRet; } }