整型四連通多邊形的處理類

四連通的整形類型的多邊形,處理合並,柵格化,抽稀等問題。

上圖和下圖都是經過柵格化的處理。

此類,可以處理這類複雜多邊形的合併(去掉內部區域)。

#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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章