四连通的整形类型的多边形,处理合并,栅格化,抽稀等问题。
上图和下图都是经过栅格化的处理。
此类,可以处理这类复杂多边形的合并(去掉内部区域)。
#pragma once
#include <vector>
#include "StdStrFile.h"
//#include "arearect.h"
//坐标为整数的点
class IntPt
{
public:
int x;
int y;
IntPt(int _x = 0, int _y = 0)
{
x = _x;
y = _y;
}
public:
bool operator==(const IntPt& T)const
{
return x == T.x && y == T.y;
}
bool operator<(const IntPt& T)const
{
return x < T.x ? true : x == T.x ? y < T.y : false;
}
};
//保留关键点,只在四连通方向抽稀
int KeepSegmentPts(int** pX, int** pY, int* pVertexNum);
//栅格化,必须是四连通的数据
int RasterSegment(int** pX, int** pY, int* pVertexNum);
class CIntPoly
{
public:
int* pX;
int* pY;
int nVertexNum;
CIntPoly()
{
pX = nullptr;
pY = nullptr;
nVertexNum = 0;
}
public:
//CAreaRect BoundRect();
int FindIntPt(int x, int y);
int Offset(int x_offset, int y_offset);
//只保留多边形的关键点,四连通方向
int KeeyPolyKeyPts(){return KeepSegmentPts(&pX, &pY, &nVertexNum);}
//栅格化,使得成为连续的点
int RasterPoly(){return RasterSegment(&pX, &pY, &nVertexNum);}
//释放内存
int ReleaseBuffer(bool bDelBuffer = true);
//从rrlx读取
int ReadFromRrlx(const _tstring stRrlxPath);
//保存为rrlx
int SaveAsRrlx(const _tstring stRrlxPath);
int TransData(CIntPoly* pDstPoly);
//内部会释放p1,p2,因为pOut可能为p1或者p2
static int MergePoly(CIntPoly* p1, CIntPoly* p2, CIntPoly* pOut);
private:
//从自身的某个非公共点,合并另外一个区域
bool TryMergePoly(CIntPoly* pInput, int index);
};
下面是实现文件:
#include "IntPoly.h"
//保留关键点,只在四连通方向抽稀
int KeepSegmentPts(int** pX, int** pY, int* pVertexNum)
{
int nVertexNum = *pVertexNum;
if (nVertexNum < 3)
{
return -1;
}
std::vector<IntPt> vPts;
vPts.reserve(nVertexNum); //最多nVertexNum个点
//第一个点必须添加
vPts.push_back(IntPt((*pX)[0], (*pY)[0]));
for (int i = 1; i < nVertexNum - 1; ++i)
{
int x_p = vPts[vPts.size() - 1].x;
int y_p = vPts[vPts.size() - 1].y;
int x = (*pX)[i];
int y = (*pY)[i];
int x_n = (*pX)[i + 1];
int y_n = (*pY)[i + 1];
if (x_p == x && x == x_n)
{
continue;
}
else if (y_p == y && y == y_n)
{
continue;
}
vPts.push_back(IntPt(x, y));
}
//加上最后一个点
vPts.push_back(IntPt((*pX)[nVertexNum - 1], (*pY)[nVertexNum - 1]));
delete[] *pX;
delete[] *pY;
*pVertexNum = vPts.size();
(*pX) = new int[*pVertexNum]();
(*pY) = new int[*pVertexNum]();
for (int i = 0; i < *pVertexNum; ++i)
{
(*pX)[i] = vPts[i].x;
(*pY)[i] = vPts[i].y;
}
return *pVertexNum;
}
//栅格化,必须是四连通的数据
int RasterSegment(int** pX, int** pY, int* pVertexNum)
{
//栅格化,保证点是连续的
int nVertexNum = *pVertexNum;
std::vector<IntPt> vPts;
for (int i = 0; i < nVertexNum - 1; ++i)
{
int x = (*pX)[i];
int y = (*pY)[i];
int x_n = (*pX)[i + 1];
int y_n = (*pY)[i + 1];
if (x == x_n)
{
int g = abs(y - y_n);
int d = y < y_n ? 1 : -1;
for (int j = 0; j < g; ++j)
{
vPts.push_back(IntPt(x, y + j * d));
}
}
else if (y == y_n)
{
int g = abs(x - x_n);
int d = x < x_n ? 1: -1;
for (int j = 0; j < g; ++j)
{
vPts.push_back(IntPt(x + j * d, y));
}
}
}
//加上最后一个点
vPts.push_back(IntPt((*pX)[nVertexNum - 1], (*pY)[nVertexNum - 1]));
delete[] *pX;
delete[] *pY;
*pVertexNum = vPts.size();
(*pX) = new int[*pVertexNum]();
(*pY) = new int[*pVertexNum]();
for (int i = 0; i < *pVertexNum; ++i)
{
(*pX)[i] = vPts[i].x;
(*pY)[i] = vPts[i].y;
}
return *pVertexNum;
}
#if 0
CAreaRect CIntPoly::BoundRect()
{
CAreaRect rc;
for (int i = 0; i < nVertexNum; ++i)
{
if (i != 0)
{
rc.left = min(rc.left, pX[i]);
rc.down = min(rc.down, pY[i]);
rc.right = max(rc.right, pX[i]);
rc.up = max(rc.up, pY[i]);
}
else
{
rc.left = rc.right = pX[i];
rc.down = rc.up = pY[i];
}
}
return rc;
}
#endif //0
int CIntPoly::FindIntPt(int x, int y)
{
for (int i = 0; i < nVertexNum; ++i)
{
if (pX[i] == x && pY[i] == y)
{
return i;
}
}
return -1;
}
int CIntPoly::Offset(int x_offset, int y_offset)
{
for (int i = 0; i < nVertexNum; ++i)
{
pX[i] += x_offset;
pY[i] += y_offset;
}
return 0;
}
int CIntPoly::ReleaseBuffer(bool bDelBuffer /*= true*/)
{
if (pX && bDelBuffer)
{
delete[] pX;
}
pX = nullptr;
if (pY && bDelBuffer)
{
delete[] pY;
}
pY = nullptr;
nVertexNum = 0;
return 0;
}
int CIntPoly::ReadFromRrlx(const _tstring stRrlxPath)
{
std::list<_tstring> lContentInFile;
CStdFile::ParseTXTFile(stRrlxPath, lContentInFile);
if (lContentInFile.size() == 0)
{
return -1;
}
std::vector<IntPt> vPtsRes;
std::list<_tstring>::iterator it_c = lContentInFile.begin();
int nSize = 0;
CStdTpl::ConvertFromString(nSize, *it_c);
++it_c;
int nIndex = 0;
for (; it_c != lContentInFile.end() && nIndex < nSize; ++it_c)
{
std::string coor = CStdStr::ws2s(*it_c);
int x = 0, y = 0, z = 0;
sscanf_s(coor.c_str(), "%d%d%d", &x, &y, &z);
vPtsRes.push_back(IntPt(x, y));
++nIndex;
}
//如果存在相邻的点重合,则去掉其中一个点,注意首尾也可能重合
//for (size_t i = 0; i < vPtsRes.size() - 1; ++i)
//{
// if (vPtsRes[i] == vPtsRes[i + 1])
// {
// vPtsRes.erase(vPtsRes.begin() + i--);
// }
//}
ReleaseBuffer();
nVertexNum = nIndex;
pX = new int[nVertexNum]();
pY = new int[nVertexNum]();
for (int i = 0; i < nVertexNum; ++i)
{
pX[i] = vPtsRes[i].x;
pY[i] = vPtsRes[i].y;
}
return nIndex;
}
int CIntPoly::SaveAsRrlx(const _tstring stRrlxPath)
{
std::vector<_tstring> vContent;
vContent.push_back(ToString(nVertexNum));
for (int i = 0; i < nVertexNum; ++i)
{
vContent.push_back(ToString(pX[i]) + _T("\t") + ToString(pY[i]) + _T("\t 0"));
}
return CStdFile::SaveTXTFile(vContent, stRrlxPath, false);
}
int CIntPoly::TransData(CIntPoly* pDstPoly)
{
pDstPoly->pX = pX;
pDstPoly->pY = pY;
pDstPoly->nVertexNum = nVertexNum;
return ReleaseBuffer(false);
}
int CIntPoly::MergePoly(CIntPoly* p1, CIntPoly* p2, CIntPoly* pOut)
{
int nVertexNum = p1->nVertexNum;
int nVertexNumAdj = p2->nVertexNum;
//如果有一个不存在,则输出存在的区域
if (nVertexNum == 0 || nVertexNumAdj == 0)
{
if (nVertexNum)
{
//输出p1
if (pOut != p1)
{
p1->TransData(pOut);
}
}
if (nVertexNumAdj)
{
//输出p2
if (pOut != p2)
{
p2->TransData(pOut);
}
}
return 0;
}
//开始合并
std::vector<IntPt> vPtRes;
vPtRes.reserve(nVertexNum + nVertexNumAdj);
std::list<IntPt> lAllPt;
for (int i = 0; i < nVertexNum; ++i)
{
lAllPt.push_back(IntPt(p1->pX[i], p1->pY[i]));
}
for (int i = 0; i < nVertexNumAdj; ++i)
{
lAllPt.push_back(IntPt(p2->pX[i], p2->pY[i]));
}
lAllPt.sort();
IntPt ptLD = *lAllPt.begin();
int offset = p1->FindIntPt(ptLD.x, ptLD.y);
if (offset != -1)
{
p1->TryMergePoly(p2, offset);
if (pOut != p1)
{
p1->TransData(pOut);
}
return pOut->nVertexNum;
}
offset = p2->FindIntPt(ptLD.x, ptLD.y);
if (offset != -1)
{
p2->TryMergePoly(p1, offset);
//输出p2
if (pOut != p2)
{
p2->TransData(pOut);
}
return pOut->nVertexNum;
}
return 0;
}
bool CIntPoly::TryMergePoly(CIntPoly* pInput, int index)
{
int nVertexNumAdj = pInput->nVertexNum;
std::vector<IntPt> vPtRes;
for (int i = 0; i < nVertexNum; ++i)
{
if (vPtRes.size() > nVertexNum + nVertexNumAdj)
{
return false;
}
int x = pX[(i + index) % nVertexNum];
int y = pY[(i + index) % nVertexNum];
int x_n = pX[(i + index + 1) % nVertexNum];
int y_n = pY[(i + index + 1) % nVertexNum];
int nFindCur = pInput->FindIntPt(x, y);
int nFindNext = pInput->FindIntPt(x_n, y_n);
bool bFindCur = nFindCur != -1;
bool bFindNext = nFindNext != -1;
if (!bFindCur && !bFindNext)
{
vPtRes.push_back(IntPt(x, y));
if (vPtRes.size() > 1 && vPtRes[0] == IntPt(x, y))break;
}
else if (!bFindCur && bFindNext)
{
vPtRes.push_back(IntPt(x, y));
if (vPtRes.size() > 1 && vPtRes[0] == IntPt(x, y))break;
//开始添加相邻区域的边
for (int j = 0; j < nVertexNumAdj; ++j)
{
int iss = j + nFindNext;
if (iss >= nVertexNumAdj * 2)
{
//出现错误
return false;
}
int x_s = pInput->pX[iss % nVertexNumAdj];
int y_s = pInput->pY[iss % nVertexNumAdj];
int x_sn = pInput->pX[(iss + 1) % nVertexNumAdj];
int y_sn = pInput->pY[(iss + 1) % nVertexNumAdj];
int nFindCurSub = FindIntPt(x_s, y_s);
int nFindNextSub = FindIntPt(x_sn, y_sn);
bool bFindCurSub = nFindCurSub != -1;
bool bFindNextSub = nFindNextSub != -1;
if (bFindCurSub && !bFindNextSub)
{
vPtRes.push_back(IntPt(x_s, y_s));
if (vPtRes.size() > 1 && vPtRes[0] == IntPt(x_s, y_s))break;
}
else if (!bFindCurSub && !bFindNextSub)
{
vPtRes.push_back(IntPt(x_s, y_s));
}
else if (!bFindCurSub && bFindNextSub)
{
vPtRes.push_back(IntPt(x_s, y_s));
if (vPtRes[0] == IntPt(x_sn, y_sn))
{
//结束外层循环
vPtRes.push_back(IntPt(x_sn, y_sn));
i = nVertexNum;
}
else
{
i = --nFindNextSub - index;
}
break;
}
}
}
else if (bFindCur && !bFindNext)
{
vPtRes.push_back(IntPt(x, y));
if (vPtRes.size() > 1 && vPtRes[0] == IntPt(x, y))break;
}
}
//将结果输出给this
ReleaseBuffer();
pInput->ReleaseBuffer();
int nDstPtCount = static_cast<int>(vPtRes.size());
nVertexNum = nDstPtCount;
pX = new int[nDstPtCount]();
pY = new int[nDstPtCount]();
for (int i = 0; i < nDstPtCount; ++i)
{
pX[i] = vPtRes[i].x;
pY[i] = vPtRes[i].y;
}
return true;
}