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

多边形有两种重要的表示方式:顶点表示和点阵表示


顶点表示:用多边形的顶点序列来表示多边形。这种表示直观、几何意义强、占用内存少,易于进行几何变换。但未明确指出哪些像素在多边形内,不能直接用于面着色。

点阵表示:用位于多边形内的像素集合来刻画多边形。这种表示丢失了许多几何信息(如边界,顶点),但却是光栅显示系统显示时所需的表示形式。

光栅图像的一个基本问题时把多边形的顶点表示转换为点阵表示。这种转换称为多边形的扫描转换

多边形分为凸多边形,凹多边形,含内环的多边形等

1、凸多边形:任意两顶点间的连线均在多边形内


2、凹多边形:任意两顶点间的连线有不在多边形内


、3、含内环的多边形:多边形内包含多边形




X-扫描线算法

基本思想:按扫描线顺序,计算扫描线与多边形的相交区间,再用要求的颜色显示这些区间的像素,即完成填充工作

 区间的端点可以通过计算扫描线与多边形边界线的交点获得


扫描线y=3与多边形边界的交点为(2,3),(4,3),(7,3),(9,3)。则落在多边形内的区间为[2,4]和[7,9]。将区间内的像素取填充色

步骤:

1、确定多边形顶点的最大和最小值(ymin,ymax)

2、从y=ymin到y=ymax,每次用一条扫描线进行填充

3、对一条扫描线填充过程可分为4步:

a、求交:计算扫描线与多边形各边的交点

b、排序:将所有交点按递增顺序进行排序

c、交点配对:第一个于第二个,第三个和第四个等

d、区间填色:把区间内像素置为不同于背景色的填充色

但有可能出现特殊情况:多边形顶点和扫描线得交点怎么算。如图


解决方案:

1、若共享顶点的两条边分别落在扫描线的两边,交点只算一个

2、若共享顶点的两条边在扫描线的同一边,这时交点作为零个或两个。检查共享顶点的两条边的另外两个端点的y值,按这两个y值中大于交点y值得个数来决定交点数。若另外两个端点y值大于交点y值即两条边在扫描线上方交点为2个,若另外两个端点y值小于交点y值即在扫描线下方交点为0个。


  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
多边形扫描转换扫描线算法是一种常用于计算机图形学中的多边形填充算法。其基本思想是将多边形沿着 y 轴方向分割成若干条线段,然后从上往下逐条扫描,使用扫描线多边形边界的交点来确定多边形内部的区域,并进行填充。 以下是多边形扫描转换扫描线算法的伪代码: ``` // 输入多边形的顶点列表 vertices,以及多边形边界的最大和最小 y 坐标值 ymax 和 ymin ScanLineFill(vertices, ymax, ymin) { // 定义边表结构体,用于存储多边形边界的信息 struct Edge { float x; // 边界与扫描线的交点的 x 坐标 float dx; // 边界的斜率的倒数 int ymax; // 边界的最大 y 坐标 }; // 定义活动边表和等待边表 vector<Edge> AET, NET; // 从最小 y 坐标开始,逐条扫描每条扫描线 for (int y = ymin; y <= ymax; y++) { // 将所有与当前扫描线有交点的边界添加到等待边表中 for (int i = 0; i < vertices.size(); i++) { if (vertices[i].y == y) { // 如果多边形的顶点与当前扫描线重合,则将该顶点作为交点添加到等待边表中 Edge e; e.x = vertices[i].x; e.dx = 0; e.ymax = vertices[i].y; NET.push_back(e); } else if (vertices[i].y == y-1) { // 如果多边形的边界与当前扫描线相交,则计算交点并添加到等待边表中 Edge e; if (vertices[i].y < vertices[(i+1)%vertices.size()].y) { e.x = vertices[i].x + (vertices[(i+1)%vertices.size()].x - vertices[i].x) * (y - vertices[i].y) / (vertices[(i+1)%vertices.size()].y - vertices[i].y); } else { e.x = vertices[i].x + (vertices[(i+1)%vertices.size()].x - vertices[i].x) * (y - vertices[(i+1)%vertices.size()].y) / (vertices[i].y - vertices[(i+1)%vertices.size()].y); } e.dx = (vertices[(i+1)%vertices.size()].x - vertices[i].x) / (vertices[(i+1)%vertices.size()].y - vertices[i].y); e.ymax = max(vertices[i].y, vertices[(i+1)%vertices.size()].y) - 1; NET.push_back(e); } } // 根据交点的 x 坐标对等待边表进行排序 sort(NET.begin(), NET.end(), [](const Edge& a, const Edge& b) { return a.x < b.x; }); // 将等待边表中的边界添加到活动边表中 for (int i = 0; i < NET.size(); i++) { AET.push_back(NET[i]); } NET.clear(); // 根据交点的 x 坐标对活动边表进行排序 sort(AET.begin(), AET.end(), [](const Edge& a, const Edge& b) { return a.x < b.x; }); // 遍历活动边表,将两两相邻的边界之间的区域进行填充 for (int i = 0; i < AET.size(); i += 2) { int x1 = ceil(AET[i].x); int x2 = floor(AET[i+1].x); for (int x = x1; x <= x2; x++) { drawPixel(x, y); } } // 更新活动边表中每条边界的交点 x 坐标 for (int i = 0; i < AET.size(); i++) { AET[i].x += AET[i].dx; } // 删除活动边表中 ymax 达到当前扫描线的边界 for (int i = 0; i < AET.size(); i++) { if (AET[i].ymax == y) { AET.erase(AET.begin() + i); i--; } } } } ``` 其中,`drawPixel(x, y)` 是用来填充像素点的函数,可以根据具体的实现方式来定义。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值