矩形裁剪算法_python3最终版
程序员文章站
2023-08-26 10:30:22
环境准备:
Python版本是3.5.1。使用pip命令:pip install pyopengl 安装pyopengl模块
另外注意需要将opengl文件(打开文件链接,...
环境准备:
Python版本是3.5.1。使用pip命令:pip install pyopengl 安装pyopengl模块
另外注意需要将opengl文件(打开文件链接,也可自行百度)复制到系统盘System32(32位系统)或SysWOW64(64位系统)目录下,不然可能或报错。我今天在学校实验室碰到了此问题,错误信息好像是glutInit函数不能使用之类的。
说明:
老师的要求是实现键盘输入和鼠标点击两种交互方式,没法子,只好封装一下函数,方便调用了。
代码:
#encoding='utf-8' #python3.5.1 #author by 张政伟 2016/6/21 #矩形裁剪算法 from OpenGL.GLUT import * from OpenGL.GL import * import sys blue=(0.0,0.0,1.0) green=(0.0,1.0,0.0) red=(1.0,0.0,0.0) color=blue winx=400 #窗口宽度 winy=400 #窗口高度 l1=[];#存储坐标 class point: x=0 #x坐标 y=0 #y坐标 pl=0 #相对于矩形裁剪区域左边,此点的位置,0为内,1为外 pt=0 #相对于矩形裁剪区域上边,此点的位置,0为内,1为外 pr=0 #相对于矩形裁剪区域右边,此点的位置,0为内,1为外 pb=0 #相对于矩形裁剪区域下边,此点的位置,0为内,1为外 def __init__(self,x,y,pl,pt,pr,pb): self.x=x self.y=y self.pl=pl self.pt=pt self.pr=pr self.pb=pb i=point(0,0,0,0,0,0) #函数:得到被裁剪区域顶点坐标相对于裁剪区域四条边的位置 def judgePositon(i,prt,plb): #判断左边 if(i.x<plb.x): i.pl=1 else: i.pl=0 #判断上边 if(i.y<prt.y): i.pt=0 else: i.pt=1 #判断右边 if(i.x<prt.x): i.pr=0 else: i.pr=1 #判断下边 if(i.y<plb.y): i.pb=1 else: i.pb=0 def leftClip(prt,plb,*l): l=l[0] l2=[] #左边裁剪 print(l[0].x) for i in range(0,len(l)): if(i==len(l)-1): if(l[i].pl==0): #都在内部,保留第二个顶点 if(l[0].pl==0): l2.append(l[0]) #一内一外,保留交点 else: k=(l[i].y-l[0].y)/(l[i].x-l[0].x) b=l[i].y-k*l[i].x x=plb.x y=x*k+b temp=point(x,y,0,0,0,0) l2.append(temp) else: #一外一内,保留交点与内 if(l[0].pl==0): k=(l[i].y-l[0].y)/(l[i].x-l[0].x) b=l[i].y-k*l[i].x x=plb.x y=x*k+b temp=point(x,y,0,0,0,0) l2.append(temp) l2.append(l[0]) #都在外部,全部舍弃 else: pass else: if(l[i].pl==0): #都在内部,保留第二个顶点 if(l[i+1].pl==0): l2.append(l[i+1]) #一内一外,保留交点 else: k=(l[i].y-l[i+1].y)/(l[i].x-l[i+1].x) b=l[i].y-k*l[i].x x=plb.x y=x*k+b temp=point(x,y,0,0,0,0) l2.append(temp) else: #一外一内,保留交点与内 if(l[i+1].pl==0): k=(l[i].y-l[i+1].y)/(l[i].x-l[i+1].x) b=l[i].y-k*l[i].x x=plb.x y=x*k+b temp=point(x,y,0,0,0,0) l2.append(temp) l2.append(l[i+1]) #都在外部,全部舍弃 else: pass return l2 def topClip(prt,plb,*l): l2=l[0] l=[] for i in range(0,len(l2)): if(i==len(l2)-1): if(l2[i].pt==0): #都在内部,保留第二个顶点 if(l2[0].pt==0): l.append(l2[0]) #一内一外,保留交点 else: if(l2[i].x==l2[0].x): x=l2[i].x y=prt.y temp=point(x,y,0,0,0,0) l.append(temp) else: k=(l2[i].y-l2[0].y)/(l2[i].x-l2[0].x) b=l2[i].y-k*l2[i].x y=prt.y if k!=0: x=(y-b)/k temp=point(x,y,0,0,0,0) l.append(temp) else: #一外一内,保留交点与内 if(l2[0].pt==0): if(l2[i].x==l2[0].x): x=l2[i].x y=prt.y temp=point(x,y,0,0,0,0) l.append(temp) l.append(l2[0]) else: k=(l2[i].y-l2[0].y)/(l2[i].x-l2[0].x) b=l2[i].y-k*l2[i].x y=prt.y if k!=0: x=(y-b)/k temp=point(x,y,0,0,0,0) l.append(temp) l.append(l2[0]) #都在外部,全部舍弃 else: pass else: if(l2[i].pt==0): #都在内部,保留第二个顶点 if(l2[i+1].pt==0): l.append(l2[i+1]) #一内一外,保留交点 else: if(l2[i].x==l2[i+1].x): x=l2[i].x y=prt.y temp=point(x,y,0,0,0,0) l.append(temp) else: k=(l2[i].y-l2[i+1].y)/(l2[i].x-l2[i+1].x) b=l2[i].y-k*l2[i].x y=prt.y if k!=0: x=(y-b)/k temp=point(x,y,0,0,0,0) l.append(temp) else: #一外一内,保留交点与内 if(l2[i+1].pt==0): if(l2[i].x==l2[i+1].x): x=l2[i].x y=prt.y temp=point(x,y,0,0,0,0) l.append(temp) l.append(l2[i+1]) else: k=(l2[i].y-l2[i+1].y)/(l2[i].x-l2[i+1].x) b=l2[i].y-k*l2[i].x y=prt.y if k!=0: x=(y-b)/k temp=point(x,y,0,0,0,0) l.append(temp) l.append(l2[i+1]) #都在外部,全部舍弃 else: pass return l def rightClip(prt,plb,*l): l=l[0] l2=[] for i in range(0,len(l)): if(i==len(l)-1): if(l[i].pr==0): #都在内部,保留第二顶点 if(l[0].pr==0): l2.append(l[0]) #一内一外,保留交点 else: k=(l[i].y-l[0].y)/(l[i].x-l[0].x) b=l[i].y-k*l[i].x x=prt.x y=x*k+b temp=point(x,y,0,0,0,0) l2.append(temp) else: #一外一内,保留交点与内 if(l[0].pr==0): k=(l[i].y-l[0].y)/(l[i].x-l[0].x) b=l[i].y-k*l[i].x x=prt.x y=x*k+b temp=point(x,y,0,0,0,0) l2.append(temp) l2.append(l[0]) #都在外部,全部舍弃 else: pass else: if(l[i].pr==0): #都在内部,保留第二顶点 if(l[i+1].pr==0): l2.append(l[i+1]) #一内一外,保留交点 else: k=(l[i].y-l[i+1].y)/(l[i].x-l[i+1].x) b=l[i].y-k*l[i].x x=prt.x y=x*k+b temp=point(x,y,0,0,0,0) l2.append(temp) else: #一外一内,保留交点与内 if(l[i+1].pr==0): k=(l[i].y-l[i+1].y)/(l[i].x-l[i+1].x) b=l[i].y-k*l[i].x x=prt.x y=x*k+b temp=point(x,y,0,0,0,0) l2.append(temp) l2.append(l[i+1]) #都在外部,全部舍弃 else: pass return l2 def bottomClip(prt,plb,*l): l2=l[0] l=[] for i in range(0,len(l2)): if(i==len(l2)-1): if(l2[i].pb==0): #都在内部,保留第二顶点 if(l2[0].pb==0): l.append(l2[0]) #一内一外,保留交点 else: if(l2[i].x==l2[0].x): x=l2[i].x y=plb.y temp=point(x,y,0,0,0,0) l.append(temp) else: k=(l2[i].y-l2[0].y)/(l2[i].x-l2[0].x) b=l2[i].y-k*l2[i].x y=plb.y if k!=0: x=(y-b)/k temp=point(x,y,0,0,0,0) l.append(temp) else: #一外一内,保留交点内 if(l2[0].pb==0): if(l2[i].x==l2[0].x): x=l2[i].x y=plb.y temp=point(x,y,0,0,0,0) l.append(temp) l.append(l2[0]) else: k=(l2[i].y-l2[0].y)/(l2[i].x-l2[0].x) b=l2[i].y-k*l2[i].x y=plb.y if k!=0: x=(y-b)/k temp=point(x,y,0,0,0,0) l.append(temp) l.append(l2[0]) #都在外部,全部舍弃 else: pass else: if(l2[i].pb==0): #都在内部,保留第二顶点 if(l2[i+1].pb==0): l.append(l2[i+1]) #一内一外,保留交点 else: if(l2[i].x==l2[i+1].x): x=l2[i].x y=plb.y temp=point(x,y,0,0,0,0) l.append(temp) else: k=(l2[i].y-l2[i+1].y)/(l2[i].x-l2[i+1].x) b=l2[i].y-k*l2[i].x y=plb.y if k!=0: x=(y-b)/k temp=point(x,y,0,0,0,0) l.append(temp) else: #一外一内,保留交点与内 if(l2[i+1].pb==0): if(l2[i].x==l2[i+1].x): x=l2[i].x y=plb.y temp=point(x,y,0,0,0,0) l.append(temp) l.append(l2[i+1]) else: k=(l2[i].y-l2[i+1].y)/(l2[i].x-l2[i+1].x) b=l2[i].y-k*l2[i].x y=plb.y if k!=0: x=(y-b)/k temp=point(x,y,0,0,0,0) l.append(temp) l.append(l2[i+1]) #都在外部,全部舍弃 else: pass return l #窗口左上角为(0,0),而PyOpengl画图以窗口中心为(0,0)且最大x坐标与y坐标都是100。 #因此需要将鼠标获取的坐标转换成PyOpengl画图坐标。 def translate(point): a=winx/2 b=winy/2 if point.x < a and point.y < b: point.x=(point.x/a)*100-100 point.y=100-(point.y/b)*100 elif point.x > a and point.y < b: point.x=((point.x-a)/a)*100 point.y=100-(point.y/b)*100 elif point.x < a and point.y > b: point.x=(point.x/a)*100-100 point.y=((point.y-b)/b)*100*(-1) else: point.x=((point.x-a)/a)*100 point.y=((point.y-b)/b)*100*(-1) def display(): glClearColor(0.0,0.0,0.0,0.0) #背景色=黑色,RGBA全为0 glClear(GL_COLOR_BUFFER_BIT) #清除颜色缓冲区 glColor3fv(color) #设置下面绘制物体的颜色 #f表示参数类型为浮点类型,v表示接受的参数为数组形式 #glRectf(-10.0,-20.0,20.0,10.0) #画填充矩形 #绘制坐标系 glColor3f(1.0, 1.0, 1.0) glBegin(GL_LINES) glVertex2f(0.0, 0.0) glVertex2f(0.0, 95.0) glVertex2f(0.0, 95.0) glVertex2f(4.0, 92.0) glVertex2f(0.0, 95.0) glVertex2f(-4.0, 92.0) glVertex2f(0.0, 0.0) glVertex2f(0.0, -95.0) glVertex2f(0.0, 0.0) glVertex2f(95.0,0.0) glVertex2f(95.0,0.0) glVertex2f(92.0,4.0) glVertex2f(95.0,0.0) glVertex2f(92.0,-4.0) glVertex2f(0.0, 0.0) glVertex2f(-95.0,0.0) glEnd() glColor3f(0.0,0.0,1.0) glBegin(GL_POINTS); glVertex2i(0,0); glEnd(); glFlush() def reshape(winx,winy): glViewport(0,0,winx,winy) #定义相对视窗大小(像素范围) glMatrixMode(GL_PROJECTION) #选择投影矩阵 glLoadIdentity() #读取规范化的单位矩阵 glOrtho(-100.0,100.0, -100.0,100.0, 0.0,100.0) #定义空间坐标系范围 glMatrixMode(GL_MODELVIEW) #选择模型视图矩阵 glLoadIdentity() def key(key,mousex,mousey): global color if(key==b'q'): #按下q按键时 print('退出') glutDestroyWindow(winid) #根据ID结束窗口 sys.exit() elif(key==b'e'): l1.clear() print('初始化界面') glutPostRedisplay() #重绘,将调用display elif(key==b'g'): #以绿线画裁剪后图形并输出裁剪后坐标 if l1[0].x<l1[1].x: #矩形裁剪区域:左下点的坐标 plb=point(l1[0].x,l1[0].y,0,0,0,0) #矩形裁剪区域:右上点的坐标 prt=point(l1[1].x,l1[1].y,0,0,0,0) else: #矩形裁剪区域:左下点的坐标 plb=point(l1[1].x,l1[1].y,0,0,0,0) #矩形裁剪区域:右上点的坐标 prt=point(l1[0].x,l1[0].y,0,0,0,0) #输出 print('裁剪区域左下点坐标:') print(plb.x,plb.y) print('裁剪区域右上点坐标:') print(prt.x,prt.y) #被裁剪区域顶点坐标 l=l1[2:] #调用函数,完全初始化被裁减区域顶点坐标 for i in l1: judgePositon(i,prt,plb) #测试输出被裁剪区域顶点坐标 print("init:") for i in l: print(i.x,i.y,i.pl,i.pt,i.pr,i.pb) #左边裁剪 #调用左边裁减函数 l=leftClip(prt,plb,l) #初始化左裁剪后顶点坐标相对裁剪区域的位置 for i in l: judgePositon(i,prt,plb) #输出左裁剪后顶点坐标 print("leftClip:") for i in l: print(i.x,i.y,i.pl,i.pt,i.pr,i.pb) #上边裁剪 #调用上边裁剪函数 l=topClip(prt,plb,l) #初始化上裁剪后顶点坐标相对裁剪区域的位置 for i in l: judgePositon(i,prt,plb) #输出上裁剪后顶点坐标 print("topClip:") for i in l: print(i.x,i.y,i.pl,i.pt,i.pr,i.pb) #右边裁剪 #调用右边裁剪函数 l=rightClip(prt,plb,l) #初始化右裁剪后顶点坐标相对裁剪区域的位置 for i in l: judgePositon(i,prt,plb) #输出右裁剪后顶点坐标 print("rightClip:") for i in l: print(i.x,i.y,i.pl,i.pt,i.pr,i.pb) #下边裁剪 #调用下边裁剪函数 l=bottomClip(prt,plb,l) #初始化下裁剪后顶点坐标相对裁剪区域的位置 for i in l: judgePositon(i,prt,plb) #输出下裁剪后顶点坐标 print("bottomClip:") for i in l: print(i.x,i.y,i.pl,i.pt,i.pr,i.pb) #以绿线画裁剪后区域 color=green glColor3fv(color) print('以绿线画被裁剪多边形') for i in range(0,len(l)): if(i==len(l)-1): glBegin(GL_LINES) #画线 glVertex2f(l[i].x,l[i].y) glVertex2f(l[0].x,l[0].y) glEnd() glFlush() else: glBegin(GL_LINES) #画线 glVertex2f(l[i].x,l[i].y) glVertex2f(l[i+1].x,l[i+1].y) glEnd() glFlush() elif(key==b'r'):#以红色画矩形裁剪窗口 color=red glColor3fv(color) print('以红线画矩形裁剪窗口') glBegin(GL_LINES) #画线 glVertex2f(l1[0].x,l1[0].y) glVertex2f(l1[0].x,l1[1].y) glVertex2f(l1[0].x,l1[1].y) glVertex2f(l1[1].x,l1[1].y) glVertex2f(l1[1].x,l1[1].y) glVertex2f(l1[1].x,l1[0].y) glVertex2f(l1[1].x,l1[0].y) glVertex2f(l1[0].x,l1[0].y) glEnd() glFlush() elif(key==b'b'): color=blue glColor3fv(color) print('以蓝线画被裁剪多边形') for i in range(2,len(l1)): if(i==len(l1)-1): glBegin(GL_LINES) #画线 glVertex2f(l1[i].x,l1[i].y) glVertex2f(l1[2].x,l1[2].y) glEnd() glFlush() else: glBegin(GL_LINES) #画线 glVertex2f(l1[i].x,l1[i].y) glVertex2f(l1[i+1].x,l1[i+1].y) glEnd() glFlush() elif(key==b'k'): print('请输入左下点x坐标:') lx=float(input()) print('请输入左下点y坐标:') ly=float(input()) print('请输入右下点x坐标:') rx=float(input()) print('请输入右下点y坐标:') ry=float(input()) l1.clear() plb=point(lx,ly,0,0,0,0) prt=point(rx,ry,0,0,0,0) l1.append(plb) l1.append(prt) #矩形顶点坐标 for i in l1: print(i.x,i.y) print("输入被裁剪多边形顶点个数:") n=int(input()) for i in range(0,n): print('请输入第%d个顶点x坐标' %(i+1)) tempX=float(input()) print('请输入第%d点y坐标' %(i+1)) tempY=float(input()) temp=point(tempX,tempY,0,0,0,0) l1.append(temp) print('按\'r\'键绘制裁剪区域。') print('按\'b\'键绘制被裁剪区域') print('按\'g\'键绘制被裁剪后区域') def mouse(button,state,x,y): #鼠标左键按下 if button == GLUT_LEFT_BUTTON and state == GLUT_DOWN: glColor3fv(color) temp=point(x,y,0,0,0,0) translate(temp) l1.append(temp) print('使用说明:') print('1.鼠标点击:') print('请用鼠标点击确定矩形裁剪区域左下点与右下点坐标,按\'r\'键绘制裁剪区域') print('请用鼠标点击确定被裁剪区域坐标,按\'b\'键绘制被裁剪区域') print('按\'g\'键绘制被裁剪后区域') print('按\'e\'键初始化界面') print('按\'q\'键退出程序') print('按\'k\'键从命令行输入坐标绘图裁剪') glutInit(sys.argv) glutInitDisplayMode(GLUT_SINGLE|GLUT_RGBA) glutInitWindowSize(winx,winy) glutInitWindowPosition(100,100) winid=glutCreateWindow(b"main") #建立窗口的ID返回到winid glutDisplayFunc(display) glutReshapeFunc(reshape) glutKeyboardFunc(key) glutMouseFunc(mouse) glutMainLoop()
上一篇: 猪腰子汤的做法你会了吗?