您的位置:首页 > 运维架构

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

2017-08-02 16:09 316 查看
前三篇内容的基础上,可以绘制出如下的图形:



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

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

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐