python/计算机图形学

计算机图形学:多边形扫描转换算法的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上完成作业,只考虑了实现,并没有考虑算法的效率。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值