MFC三角形三个顶点为红、绿、蓝,使用有效边表算法进行填充
时间: 2023-07-10 21:03:02 浏览: 59
以下是使用有效边表算法进行三角形填充的代码示例:
```C++
// 定义一个结构体表示边表中的每一项
struct Edge {
float ymax; // 边的最大y坐标
float x; // 边与扫描线的交点x坐标的初始值
float dx; // 斜率倒数
Edge* next; // 下一条边
Edge(float y, float x1, float y1, float x2, float y2) {
ymax = y2;
next = nullptr;
if (y1 == y2) {
dx = 0;
x = x1;
}
else {
dx = (x2 - x1) / (y2 - y1);
x = x1 + dx * (y - y1);
}
}
};
// 画三角形的函数
void DrawTriangle(CDC* pDC, CPoint p1, CPoint p2, CPoint p3) {
// 按y值从小到大排序三个顶点
if (p1.y > p2.y) std::swap(p1, p2);
if (p1.y > p3.y) std::swap(p1, p3);
if (p2.y > p3.y) std::swap(p2, p3);
// 初始化活性边表
Edge* AET = nullptr;
Edge* ET[1000]; // 边表
memset(ET, 0, sizeof(Edge*) * 1000);
// 扫描线逐行扫描
for (int y = p1.y; y <= p3.y; y++) {
// 将新的边加入边表
if (y == p2.y) {
ET[p2.y] = new Edge(p2.y, p2.x, p2.y, p3.x, p3.y);
if (p2.x < p1.x) ET[p2.y]->x = p2.x;
AET = ET[p2.y];
}
if (y == p1.y) {
ET[p1.y] = new Edge(p1.y, p1.x, p1.y, p2.x, p2.y);
AET = ET[p1.y];
}
if (y > p1.y && y < p2.y) {
float x = (y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x;
ET[y] = new Edge(y, x, y, p2.x, p2.y);
}
if (y > p2.y && y < p3.y) {
float x = (y - p2.y) * (p3.x - p2.x) / (p3.y - p2.y) + p2.x;
if (!ET[y]) ET[y] = new Edge(y, x, y, p3.x, p3.y);
else ET[y]->next = new Edge(y, x, y, p3.x, p3.y), ET[y] = ET[y]->next;
}
// 处理活性边表
Edge* e = AET;
Edge* prev = nullptr;
while (e) {
// 删除ymax等于当前扫描线y值的边
if (e->ymax == y) {
if (e == AET) AET = e->next;
else prev->next = e->next;
}
else {
// 更新交点x坐标
e->x += e->dx;
prev = e;
}
e = e->next;
}
// 根据活性边表填充像素
e = AET;
while (e && e->next) {
for (int x = (int)std::ceil(e->x); x < (int)std::floor(e->next->x); x++) {
pDC->SetPixel(x, y, RGB(255, 0, 0));
}
e = e->next->next;
}
}
// 释放边表内存
for (int i = 0; i < 1000; i++) {
Edge* e = ET[i];
while (e) {
Edge* next = e->next;
delete e;
e = next;
}
}
}
```
在上面的代码中,我们首先将三个顶点按照y坐标从小到大排序,然后初始化边表和活性边表。接着,我们逐行扫描扫描线,并将新的边加入边表。在处理活性边表时,我们首先删除ymax等于当前扫描线y值的边,然后更新交点x坐标。最后,我们根据活性边表填充像素。
需要注意的是,有效边表算法在处理三角形边缘共线的情况时可能会有问题,需要针对特殊情况进行处理。此外,为了简化代码,上面的示例中并没有进行边界检查等错误处理,实际应用时需要进行相应的处理。