#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++) { arrays[i][j] = col *(row- i) + j+1; } } } 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 = CalculateFieldCentrePoints(); 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; } std::vector CFieldMgr::GetFieldCentrePoints() { auto m_listFieldCentrePoints = CalculateFieldCentrePoints(); return m_listFieldCentrePoints; } int CFieldMgr::GetTotalFields() { auto m_listFieldCentrePoints = CalculateFieldCentrePoints(); return (int)m_listFieldCentrePoints.size(); } // 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())); } int CFieldMgr::GetEffectiveFieldWidth() { auto width= m_ScanFieldSize - 2*m_overlap; return width; } int CFieldMgr::GetEffectiveFieldHeight() { 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; auto height= dScanFiledSizeY - 2*m_overlap; return height; } COTSFieldDataPtr CFieldMgr::FindNeighborField(const COTSFieldDataList a_flds, COTSFieldDataPtr a_centerField, SORTING_DIRECTION a_direction) { COTSFieldDataPtr fld; double pixelsize; for (auto f : a_flds) { SORTING_DIRECTION di; IsNeighborFieldCentre(f->GetPosition(), a_centerField->GetPosition(), GetEffectiveFieldWidth(), GetEffectiveFieldHeight(), di); if (di == a_direction) { return f; } } return fld; } bool CFieldMgr::FindNeighborField(const std::vector a_flds, CPoint a_centerField,CPoint& neighbor, SORTING_DIRECTION a_direction) { for (auto f : a_flds) { SORTING_DIRECTION di; IsNeighborFieldCentre(f, a_centerField, GetEffectiveFieldWidth(), GetEffectiveFieldHeight(), di); if (di == a_direction) { neighbor=f; return true; } } return false; } // protected // calculate field centre points list std::vector CFieldMgr::CalculateFieldCentrePoints() { // field centre points list std::vector m_listFieldCentrePoints; // clean up m_listFieldCentrePoints.clear(); // the measure domain rectangle CRect rectMeasureDomain = m_pMeasureArea->GetDomainRect(); // the measure domain centre CPoint poiDomainCentre = rectMeasureDomain.CenterPoint(); double effectiveWidth = GetEffectiveFieldWidth(); double effectiveHeight = GetEffectiveFieldHeight(); CSize sizeImage; sizeImage.cx = effectiveWidth; sizeImage.cy = effectiveHeight; // 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() / effectiveWidth)); int nTotalRows = (int)(ceil((double)rectMeasureDomain.Height() / effectiveHeight)); // 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 * (effectiveWidth); int nUpMostRowY = poiDomainCentre.y - nRowsOnTop * (effectiveHeight); 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 * (effectiveWidth); pointMatrics[i][j].y = nUpMostRowY + i * (effectiveHeight); } } 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 (m_pMeasureArea->GetShape() == DOMAIN_SHAPE::POLYGON) { 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; } BOOL CFieldMgr::IsThisPointInMeasureArea(CPoint a_position) { // 判断当前样品获取帧图信息的测量区域为多边形 if (m_pMeasureArea->GetShape() == DOMAIN_SHAPE::POLYGON) { std::vector ptPolygon = m_pMeasureArea->GetPolygonPoint(); if (PtInPolygon(a_position, ptPolygon)) { // centre in the measure domain area, return TRUE return TRUE; } else { return FALSE; } } else { if (m_pMeasureArea->PtInDomain(a_position)) { // centre in the measure domain area, return TRUE return TRUE; } else { return FALSE; } } } // 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) { 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; } }