多边形组成的网格的边界提取方法

来源:互联网 发布:python 量化 开发环境 编辑:程序博客网 时间:2024/06/05 05:37

最近一个项目,需要提取多边形组成的网格的边界点(关键点),如图所示:

希望得到如下图所示的多边形:

已知条件:

1.每个多边形上的点坐标

2.多边形都是顺时针或者逆时针(相同)

3.多边形都是接壤的,没有独立的多边形(降低难度)

4.大多边形的外边界上一定存在一个边界点只属于一个多边形,(降低难度)


多方探索,最终找到了解决办法,算是自己想出来的一个小办法吧,其实条件3,4 都可以去掉,代码难度会高一点,但是沿用编程的思想还是可以解决,那么现在问题既然简单化,就开始吧。


条件4相当于告诉我们一个边界点,所以就从这个点出发,然后开始寻找其他边界点。

为了方便处理,我们对每一个多边形编号(顺序无所谓),然后分别记录每个点在哪几个多边形中,具体细节就赘述了,这里给出核心代码。

int GiveBoundPtFlag(std::vector<CRrlxContent>& vRrlxs, const std::vector<OneKey>& vKeyPts){size_t nKeyPtNum = vKeyPts.size();std::vector<geodetic> vPtsAll, vPt1D;//第一遍保证基础的边界点被检测出来for (int i = 0; i < nKeyPtNum; ++i){geodetic& gKeyPt = vRrlxs[vKeyPts[i].nRrlxIndex].m_vKeyPoints[vKeyPts[i].nKeyIndex];if (gKeyPt.vIndexs.size() < 3 && !(gKeyPt.nFlag & RND_G)){//第一步,标记所有的边界点,不仅仅是带KEY_G标志的关键点geodetic& gKeyPoint = gKeyPt;for (int m = 0; m < gKeyPoint.vIndexs.size(); ++m){for (int n = 0; n < vRrlxs[gKeyPoint.vIndexs[m]].m_vKeyPoints.size(); ++n){if (vRrlxs[gKeyPoint.vIndexs[m]].m_vKeyPoints[n] == gKeyPoint){vRrlxs[gKeyPoint.vIndexs[m]].m_vKeyPoints[n].nFlag |= NMV_G;}}}//提取所有的关键点,带KEY_G标志vPtsAll.push_back(gKeyPt);//提取1维的关键点,带KEY_G标志if (gKeyPt.vIndexs.size() == 1){vPt1D.push_back(gKeyPt);}}}//第二类特殊的边界点可能会漏掉,需要特殊处理//考虑到影像可能出现独立和分块的现象,所以需要分多块进行考虑std::vector<geodetic> vPts1DBlock = vPt1D;const size_t n1DNum = vPt1D.size();for (int i = 0; i < n1DNum; ++i){//去掉拷贝一维点中的所有标志位//因为可能被分成几大块(后续每个一维点都必须被标记)vPts1DBlock[i].nFlag &= ~NMV_G;}for (int i = 0; i < n1DNum; ++i){if (vPts1DBlock[i].nFlag & NMV_G){continue;}//第一个点一定是一维的点geodetic& gBoundPt1st = vPts1DBlock[i];int nPreRrlxIndex = -1;bool bFindNextBound = false;geodetic gCurBound(gBoundPt1st);do {//内部会改变gCurBound和nPreRrlxIndexbFindNextBound = FindNextBoudPt(vRrlxs, vKeyPts, gBoundPt1st, gCurBound, nPreRrlxIndex);//找到当前的bound点在rrlx中的位置,并给予标记NMW_Gint nBoundPos = GetIndexInOneKeys(vRrlxs, vKeyPts, gCurBound);if (nBoundPos != -1 && !(gCurBound.nFlag & NMV_G)){//标记所有的边界点,不仅仅是带KEY_G标志的关键点geodetic& gKeyPoint = gCurBound;for (int m = 0; m < gKeyPoint.vIndexs.size(); ++m){for (int n = 0; n < vRrlxs[gKeyPoint.vIndexs[m]].m_vKeyPoints.size(); ++n){if (vRrlxs[gKeyPoint.vIndexs[m]].m_vKeyPoints[n] == gKeyPoint){vRrlxs[gKeyPoint.vIndexs[m]].m_vKeyPoints[n].nFlag |= NMV_G;}}}}//减少循环次数int nBlockPos = CStdTpl::VectorFind(vPts1DBlock, gCurBound);if (nBlockPos != -1 && !(vPts1DBlock[nBlockPos].nFlag & NMV_G)){vPts1DBlock[nBlockPos].nFlag |= NMV_G;}} while (bFindNextBound);}return 0;}

其中CRrlxContent是多边形的类,包含每个顶点坐标,项目原因我就不贴出来了。

下面继续核心代码:

bool FindNextBoudPt(std::vector<CRrlxContent>& vRrlxs, const std::vector<OneKey>& vKeyPts, const geodetic& gPtBound1st, geodetic& gPtBoundCur, int& nRrlxIndexPre){//根据当前的边界点,以及其所属的ploygon以及其相邻的ploygon寻找下一个边界点std::vector<int> vIndexs = gPtBoundCur.vIndexs;const size_t nDim = vIndexs.size();if (1 == nDim){//如果是一维点,则可以直接找到下一个点geodetic gForward, gBackward;FindForwardBackKeyPts(vRrlxs[vIndexs[0]], gPtBoundCur, gForward, gBackward);gPtBoundCur = gBackward;nRrlxIndexPre = vIndexs[0];}else if (2 == nDim){//如果是二维点,则需要判断下一个边界点int nPos = CStdTpl::VectorFind(vIndexs, nRrlxIndexPre);if (-1 == nPos){return false;}vIndexs.erase(vIndexs.begin() + nPos);geodetic gForward, gBackward;FindForwardBackKeyPts(vRrlxs[vIndexs[0]], gPtBoundCur, gForward, gBackward);gPtBoundCur = gBackward;nRrlxIndexPre = vIndexs[0];}else{//如果是三维以及以上的点int nPos = CStdTpl::VectorFind(vIndexs, nRrlxIndexPre);if (-1 == nPos){return false;}vIndexs.erase(vIndexs.begin() + nPos);geodetic gForward, gBackward;do {FindForwardBackKeyPts(vRrlxs[nRrlxIndexPre], gPtBoundCur, gForward, gBackward);std::vector<int> vCurIndexs = vIndexs;std::vector<int> vBackIndexs = gBackward.vIndexs;std::vector<int> vBCInter(MIN(vCurIndexs.size(), vBackIndexs.size()), -1);//取交集的时候必须要先排序std::sort(vCurIndexs.begin(), vCurIndexs.end());std::sort(vBackIndexs.begin(), vBackIndexs.end());std::set_intersection(vCurIndexs.begin(), vCurIndexs.end(),vBackIndexs.begin(), vBackIndexs.end(), vBCInter.begin());//排除错误情形for (int k = 0; k < vBCInter.size(); ++k){if (vBCInter[k] == -1){vBCInter.erase(vBCInter.begin() + k);--k;}}if (vBCInter.size() != 1){return false;}//vIndex中需要去掉这个值nPos = CStdTpl::VectorFind(vIndexs, vBCInter[0]);if (-1 == nPos && vIndexs.size() > 1){return false;}else{vIndexs.erase(vIndexs.begin() + nPos);}if (1 == vIndexs.size()){break;}nRrlxIndexPre = vBCInter[0];} while (vIndexs.size() > 1);FindForwardBackKeyPts(vRrlxs[vIndexs[0]], gPtBoundCur, gForward, gBackward);gPtBoundCur = gBackward;nRrlxIndexPre = vIndexs[0];}//如果循环一圈了,则返回falsereturn gPtBoundCur != gPtBound1st;}

以上就可以把所有的边界点提取出来了,即便没有条件3也没问题,如果没有条件4的话,则需要先找到一个边界点,以及相连的边界点即可,具体就不展开了。

原创粉丝点击