多边形扫描转换-扫描线算法

#include <graphics.h>
#include <vector>
#include <algorithm>
#include<iostream>
using namespace std;

struct EdgeNode {
    int ymin;  // 边的最小y坐标
    double x;  // 当前x坐标
    double dx; // △x
    int ymax;  // 边的最大y坐标
};

void polygon_fill(vector<vector<int>>& polygon) {//i*2矩阵
    int y_min = INT_MAX;
    int y_max = INT_MIN;

    // 找到多边形的最小和最大y坐标
    for (const auto& point : polygon) {
        y_min = min(y_min, point[1]);
        y_max = max(y_max, point[1]);
    }

    vector<vector<EdgeNode>> NET(y_max + 1); 

    // 构造NET
    for (int i = 0; i < polygon.size(); i++) {
        int next_idx = (i + 1) % polygon.size();
        int x1 = polygon[i][0];
        int y1 = polygon[i][1];
        int x2 = polygon[next_idx][0];
        int y2 = polygon[next_idx][1];

        int ymin = min(y1, y2);
        int ymax = max(y1, y2);
        double dx = (double)(x2 - x1) / (y2 - y1);// △x

        if (ymax != ymin) {
            if (ymin == y1) {
                NET[ymin].push_back({ ymin, (double) (x1), dx, ymax });
            }
            else if (ymin == y2) {
                NET[ymin].push_back({ ymin, (double)(x2), dx, ymax });
            }
        }
    }

    vector<EdgeNode> AET; 
    //int ynow = y_min; // 当前扫描线号

    for (int i = y_min; i <= y_max; i++) { // 对每一条扫描线
        for (auto& edge : NET[i]) { // 把ymin=i的边放入AET
            if (edge.ymin == i) {
                AET.push_back(edge);
            }
        }
    }
    for (int i = y_min; i <= y_max; i++) { // 对每一条扫描线
        // 使用插入排序法对AET按x坐标递增顺序排序
        for (int j = 1; j < AET.size(); j++) {
            int k = j - 1;
            EdgeNode key = AET[j];
            while (k >= 0 && AET[k].x > key.x) {
                AET[k + 1] = AET[k];
                k--;
            }

            AET[k + 1] = key;
        }

        // 若允许多边形的边自交,用冒泡排序法对AET重新排序
        for (int j = 0; j < AET.size() - 1; j++) {
            for (int k = 0; k < AET.size() - j - 1; k++) {
                if (AET[k].x > AET[k + 1].x) {
                    swap(AET[k], AET[k + 1]);
                }
            }
        }
        // 遍历AET,找到配对的交点并填色
        for (int j = 0; j < AET.size(); j += 2) {
            int x_start = (int)(ceil(AET[j].x));
            int x_end = (int)(ceil(AET[j + 1].x));

            for (int x = x_start; x < x_end; x++) {
                putpixel(x, i, WHITE);
            }
        }

        // 遍历AET,更新x值,删除ymax=i的边
        vector<EdgeNode> new_AET;
        for (const auto& edge : AET) {
            if (edge.ymax > i) {
                EdgeNode new_edge = edge;
                new_edge.x += new_edge.dx;
                new_AET.push_back(new_edge);
            }
        }
        AET = new_AET;
    }
}

int main() {
    initgraph(800, 480);

    vector<vector<int>> polygon = { {100,200}, {200,200}, {150,150} };//三角形
    polygon_fill(polygon);

   polygon = { {300,150},{300,200}, {500,200 },{500,150}};//矩形
    polygon_fill(polygon);

    polygon = { {600,150}, {630,200 },{600,200},{630,150} };//漏斗形
    polygon_fill(polygon);
    system("pause");
    closegraph();
    return 0;
}

运行结果:

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值