跨平台二维绘图程序(四)——多边形绘制

前三篇内容的基础上,可以绘制出如下的图形:


这一篇介绍如何绘制多边形。

(1)GDI通过API函数Polygon或者PolyPolygon就能够绘制不规则的多边形,包括自交带内洞,而GLES只能绘制三角形;

(2)多边形三角化有个开源的triangle.h,这里推荐下:http://compgeom.com/~piyush/scripts/triangle/triangle_8h-source.html

(3)三角化的时候要注意几个问题。多边形点中不可以有重复坐标点,否则会出错;多边形坐标点数不可过少,否则出错。

以下是多边形三角化的一个类:

struct Triangle
{
	std::vector<Coor> cos;
	void set(const std::vector<Coor>& polygon)
	{
		cos.clear();
		cos.insert(cos.end(), polygon.begin(), polygon.end());
	}

	void set(const Coor& A, const Coor& B, const Coor& C)
	{
		cos.clear();
		cos.push_back(A);
		cos.push_back(B);
		cos.push_back(C);
	}
};

class WithInnerTriangulation
{// 2D Coor
public:
	Coor getCenter(const std::vector<Coor>& cos)
	{
		Coor center;

		if (cos.size() == 3)
		{
			for (size_t j = 0; j < 3; ++j)
			{
				center.x += cos[j].x;
				center.y += cos[j].y;
			}
		}
		else
		{
			struct triangulateio in, out;
			triangulateioinit(&in);
			triangulateioinit(&out);

			int numPoints = cos.size();
			int numSeg = cos.size();

			in.numberofpoints = numPoints;
			in.numberofpointattributes = 0;
			in.pointlist = (REAL*)malloc(sizeof(REAL) * in.numberofpoints * 2);

			for (size_t i = 0; i < cos.size(); i++)
			{
				in.pointlist[i * 2 + 0] = cos[i].x;
				in.pointlist[i * 2 + 1] = cos[i].y;
			}

			in.numberofsegments = numSeg;
			in.segmentlist = (int*)malloc(sizeof(int) * in.numberofsegments * 2);

			size_t i = 0;
			for (i = 0; i < cos.size() - 1; i++)
			{
				in.segmentlist[i * 2 + 0] = i;
				in.segmentlist[i * 2 + 1] = i + 1;
			}
			in.segmentlist[i * 2 + 0] = i;
			in.segmentlist[i * 2 + 1] = 0;

			triangulate("pzFQ", &in, &out, NULL);

			int count = out.numberoftriangles * 3;
			if (count > 3)
				count = 3;

			for (int i = 0; i < count; i++)
			{
				int coor_index = out.trianglelist[i];
				center.x += out.pointlist[coor_index * 2];
				center.y += out.pointlist[coor_index * 2 + 1];
			}

			triangulateiofree(&out, 0);
			triangulateiofree(&in, 1);
		}

		center.x /= 3;
		center.y /= 3;

		return center;
	}

	bool transform(const std::vector< std::vector<Coor> >& polys2,
		std::vector<Triangle>& triangles)
	{
		struct triangulateio in, out;
		triangulateioinit(&in);
		triangulateioinit(&out);

		std::vector< std::vector<Coor> > polys;
		for (size_t i = 0; i < polys2.size(); ++i)
		{
			std::vector<Coor> temp;
			GeoAlgorithm::kick_overlay_dot(polys2[i],
				temp,
				false);

			if (temp.size() >= 3)
			{
				// 点数过少会导致后面的triangulate函数崩溃
				polys.push_back(temp);
			}
		}

		if (polys.size() == 0)
		{
			return false;
		}

		int numPoints = 0;
		int numSeg = 0;
		std::vector<Coor> centers;
		for (size_t i = 0; i < polys.size(); i++)
		{
			numSeg += polys[i].size();
			Coor center = getCenter(polys[i]);
			centers.push_back(center);
		}
		numPoints = numSeg;

		in.numberofpoints = numPoints;
		in.numberofpointattributes = 0;
		in.pointlist = (REAL*)malloc(sizeof(REAL) * in.numberofpoints * 2);

		int pointc = 0;
		for (size_t i = 0; i < polys.size(); i++)
		{
			for (size_t j = 0; j < polys[i].size(); j++, pointc++)
			{
				in.pointlist[pointc * 2 + 0] = polys[i][j].x;
				in.pointlist[pointc * 2 + 1] = polys[i][j].y;
			}
		}

		in.numberofsegments = numSeg;
		in.segmentlist = (int*)malloc(sizeof(int) * in.numberofsegments * 2);
		pointc = 0;
		for (size_t i = 0; i < polys.size(); i++, pointc++)
		{
			int first = pointc;
			for (size_t j = 0; j < polys[i].size() - 1; j++, pointc++)
			{
				in.segmentlist[pointc * 2 + 0] = pointc;
				in.segmentlist[pointc * 2 + 1] = pointc + 1;
			}
			in.segmentlist[pointc * 2 + 0] = pointc;
			in.segmentlist[pointc * 2 + 1] = first;
		}

		in.numberofregions = 0;
		in.numberofholes = centers.size() - 1;
		in.holelist = (REAL*)malloc(sizeof(REAL) * in.numberofholes * 2);

		for (size_t i = 1; i < centers.size(); i++)
		{
			in.holelist[(i - 1) * 2 + 0] = centers[i].x;
			in.holelist[(i - 1) * 2 + 1] = centers[i].y;
		}

		triangulate("pzFQ", &in, &out, NULL);
		// verify the mesh a bit
		if (out.numberofpoints - out.numberofedges + out.numberoftriangles !=
			2 - centers.size())
		{
			cout << endl << "epc wrong" << endl;
		}
		std::vector<Coor> cos;
		int numberofvertex, coor_index;
		numberofvertex = out.numberoftriangles * 3;
		for (int i = 0; i < numberofvertex; i++)
		{
			coor_index = out.trianglelist[i];
			Coor co;
			co.x = out.pointlist[coor_index * 2];
			co.y = out.pointlist[coor_index * 2 + 1];

			cos.push_back(co);
		}

		for (int i = 0; i < out.numberoftriangles; ++i)
		{
			Triangle tri;
			tri.set(cos[3 * i], cos[3 * i + 1], cos[3 * i + 2]);
			triangles.push_back(tri);
		}

		triangulateiofree(&out, 0);
		triangulateiofree(&in, 1);

		return true;
	}
};


有了这样的三角化类,就可以将不规则多边形(如凹多边形,带内洞多边形)转换为三角形,然后将三角形传递到VBO中。

std::vector< std::vector<Coor> > polys;
			int32_t idx = 0;
			for (int32_t i = 0; i < pc; ++i)
			{
				std::vector<Coor> pts;
				for (int32_t j = 0; j < ptsc[i]; ++j)
				{
					Coor cc;
					cc.x = pco[idx].x - m_vo.s_left;
					cc.y = pco[idx].y - m_vo.s_bottom;
					cc.z = 0.f;

					pts.push_back(cc);
					idx++;
				}
				polys.push_back(pts);
			}

			{
				WithInnerTriangulation wit;
				std::vector<Triangle> triangles;
				wit.transform(polys, triangles);
				size_t tc = triangles.size();
				if (tc)
				{
					auto tri = triangles.begin();
					while (tri != triangles.end())
					{
						PointF cc;
						cc.z = m_vo.s_zIndex;
						cc.x = tri->cos[0].x; cc.y = tri->cos[0].y;
						m_vo.polyBuffer.cos.push_back(cc);

						cc.x = tri->cos[1].x; cc.y = tri->cos[1].y;
						m_vo.polyBuffer.cos.push_back(cc);

						cc.x = tri->cos[2].x; cc.y = tri->cos[2].y;
						m_vo.polyBuffer.cos.push_back(cc);

						m_vo.polyBuffer.cols.push_back(colF);
						m_vo.polyBuffer.cols.push_back(colF);
						m_vo.polyBuffer.cols.push_back(colF);

						++tri;
					}
				}
			}

这样多边形就能够渲染出来了!


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wayright

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值