计算机图形学:多边形扫描转换算法的python实现
由于OpenGL库还是没有安装好,所以还是选择使用python模拟实现
下面是代码及其思路:
导入库包
import numpy as np
import matplotlib.pyplot as plt
使用两个列表分别储存所有点和线段。
Y_max和Y_min分别用于记录需要扫描的上下限。
point_list=[] #点组成的列表
line_list=[] #线段组成的列表
Y_max=0 #扫描的两个上下界
Y_min=0
定义点
#定义点
class point:
def __init__(self,x,y):
self.x=x
self.y=y
定义线段,这里线段是由两个点初始化,线段的一些属性如下,分别记录线段上方点的y值,最低点的y值(这里为了确定总体扫描上下限),最低点的x值和线段的斜率的倒数,便于计算线段和扫描线的交点。
#定义线段
class line:
def __init__(self,point1,point2): #由两个端点输出化直线段
if point1.y > point2.y:
self.Y_max=point1.y #最大的y值
self.Y_min=point2.y #新增Y_min属性储存直线中最小的y值,便于后面奇异点的判断
self.X=point2.x #线段下端顶点的x值
if point2.y == point1.y: # 处理常数直线情况
self.k = 0
else:
self.k = (point2.x - point1.x) / (point2.y - point1.y) #斜率的倒数
else:
self.Y_max = point2.y
self.Y_min= point1.y
self.X = point1.x
if point2.y == point1.y:
self.k = 0
else:
self.k = (point2.x - point1.x) / (point2.y - point1.y)
#由顺序给出的点绘制直线并且加入直线列表中存储
def get_linelist():
for i in range(len(point_list)-1):
temp_line=line(point_list[i],point_list[i+1])
line_list.append(temp_line)
temp_line=line(point_list[len(point_list)-1],point_list[0])
line_list.append(temp_line)
获取所要描绘的点
#获取用户输入
def get_pointlist():
i=1
while True:
str=input('请输入第%d个点的坐标,用空格隔开,输入0结束\n' % i)
if str == '0':
break
else:
str=str.split(' ')
temp_point=point(int(str[0]),int(str[1]))
point_list.append(temp_point)
i+=1
由坐标轴模拟像素点
def draw_axis(cs):
# 画出坐标轴
plt.xlim(-cs, cs+1)
plt.ylim(-cs, cs+1)
ax = plt.gca() # 获取整个框架
ax.spines['right'].set_color('none') # 可以隐藏两条边
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data', 0))
ax.spines['bottom'].set_position(('data', 0))
x_ticks=np.arange(-cs,cs,5)
y_ticks=np.arange(-cs,cs,5)
plt.xticks(x_ticks,fontsize=8)
plt.yticks(y_ticks,fontsize=8)
plt.grid() #生成网格
由点画出多边形
def draw_polygon(point_list): #由线段列表生成多边形并画出显示
for i in range(len(point_list)-1):
plt.plot([point_list[i].x,point_list[i+1].x],[point_list[i].y,point_list[i+1].y])
plt.plot([point_list[len(point_list)-1].x,point_list[0].x],[point_list[len(point_list)-1].y,point_list[0].y])
#取得扫描的上下界
def get_y_area():
global Y_max,Y_min
Y_max=point_list[0].y
Y_min=point_list[0].y
for i in range(1,len(point_list)):
if Y_max<point_list[i].y:
Y_max = point_list[i].y
if Y_min>point_list[i].y:
Y_min=point_list[i].y
# print(Y_max,Y_min)
算法核心思想:不采用活化链表,而是直接计算扫描线(y扫描)和所有线段的交点,遇到奇异点时候,处理成两个一样的交点,再把所有和扫描线的交点按照顺序排列,两两之间的点便是填充区域。
#画每一条扫描线
def draw_cropoint_x(scan_y):
x_list=[]
for lines in line_list:
if scan_y == lines.Y_min: #处理奇异点,因为奇异点一定出线在Y_min处,所以干脆直接在扫描的时候判断增加两个x坐标值
x_list.append(lines.X)
if scan_y>=lines.Y_min and scan_y<=lines.Y_max:
x=round(lines.X+(scan_y-lines.Y_min)*lines.k)
x_list.append(x)
x_list.sort() #按照顺序排列
for i in range(0,len(x_list)-1,2):
plt.scatter(np.arange(x_list[i]+1,x_list[i+1]),np.array([scan_y]*(x_list[i+1]-x_list[i]-1)),marker="*")
def area_filling():
get_y_area() #获取扫描区域
for scan_y in range(Y_min-1,Y_max+1):
draw_cropoint_x(scan_y)
plt.pause(0.05)
结果实现
if __name__=='__main__':
plt.figure(figsize=(6, 6))
draw_axis(int(input('请输入坐标轴大小\n')))
get_pointlist()
get_linelist()
draw_polygon(point_list)
area_filling()
plt.show()
跑出来是这样的:
主要是为了在Python上完成作业,只考虑了实现,并没有考虑算法的效率。