前情回顾
在上一节的CSDN中:
实现了鼠标拖动,和大小缩放
还实现了一个数据结构,根据相交关系,组织了一下图元。
如下所示
from asyncio.windows_events import NULL
from os import stat
import dxfgrabber
import math
import numpy as np
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
inputFilePath='e:/test3-11/Drawing4.dxf' #输入文件的路径
#供读取的数据结构
class Line:
def __init__(self,id,start,end):
self.id=id
self.start=start
self.end=end
LINELIST=[]
class Arc:
def __init__(self,id,center,radius,startAngle,endAngle) -> None:
self.id=id
self.center=center
self.radius=radius
self.start_angle=startAngle
self.end_angle=endAngle
pass
ARCLIST=[]
VIRTUALLIST=[]
SCALE=1.0#用于缩放
DX,DY=0,0#用于移动
#读取
dxf = dxfgrabber.readfile(inputFilePath)
lineNum=0
arcNum=0
for e in dxf.entities:
if e.dxftype == 'LINE':
LINELIST.append(Line(lineNum,e.start,e.end))
lineNum+=1
elif e.dxftype=='ARC':
ARCLIST.append(Arc(arcNum,e.center,e.radius,e.start_angle,e.end_angle))
arcNum+=1
#图元重组
def intersectionTestLineAndArc(line,arc)->bool:
#python怎么解方程——先从简处理吧
x=arc.center[0]+arc.radius*math.cos(arc.start_angle/180*math.pi)
y=arc.center[1]+arc.radius*math.sin(arc.start_angle/180*math.pi)
p0=np.array([x,y])
x=arc.center[0]+arc.radius*math.cos(arc.end_angle/180*math.pi)
y=arc.center[1]+arc.radius*math.sin(arc.end_angle/180*math.pi)
p1=np.array([x,y])
p2=np.array(line.start[0:2])
p3=np.array(line.end[0:2])
d=list(range(4))
d[0]=np.sum(np.square(p0-p2))
d[1]=np.sum(np.square(p0-p3))
d[2]=np.sum(np.square(p1-p2))
d[3]=np.sum(np.square(p1-p3))
if min(d)<=1:
return True
return False
def intersectionTest()->set:#加入新图元后,与之前加入的图元进行相交测试,返回与之相交的图元集合
global VIRTUALLIST
result=set()#空集合
if len(VIRTUALLIST)==1:
return result
entity=VIRTUALLIST[-1]#列表的最后一个就是新加入的图元
for virtualEntity in VIRTUALLIST[0:-1]:#目前,只能处理直线和弧的关系,排列组合……2*2
if type(entity)==Line and type(virtualEntity)==Line:
pass
elif type(entity)==Line and type(virtualEntity)==Arc:
pass
elif type(entity)==Arc and type(virtualEntity)==Arc:
pass
elif type(entity)==Arc and type(virtualEntity)==Line:#本例中,只会用到这个分支
if intersectionTestLineAndArc(virtualEntity,entity):
result.add(virtualEntity)
result.add(entity)
pass
else:
pass
pass
else:
pass
return result
INTERSECTIONLIST=[]
for line in LINELIST:
VIRTUALLIST.append(line)
result=intersectionTest()
for arc in ARCLIST:
VIRTUALLIST.append(arc)
result=intersectionTest()
if len(result)!=0:
newCluster=True#是否是新的一簇图形
if len(INTERSECTIONLIST)==0:
INTERSECTIONLIST.append(result)
newCluster=False
else:
for iL in INTERSECTIONLIST:
if not iL.isdisjoint(result):#双重否定,等于肯定
temp=iL.union(result)
#获取下标
index=INTERSECTIONLIST.index(iL)
#修改list中的指定set:
INTERSECTIONLIST[index]=temp
newCluster=False
if newCluster:
INTERSECTIONLIST.append(result)
else:
continue
#按照相交关系,重组完成
print(INTERSECTIONLIST)
#显示——OpenGL
def init():
glClearColor(0.3, 0.3, 0.3, 1.0)
gluOrtho2D(0, 400.0, 0, 400)#窗口坐标系的大小,左下角是原点
def drawFunc():
glClear(GL_COLOR_BUFFER_BIT)
glPushMatrix()
glScale(SCALE,SCALE,1.0)#缩放——OpenGL里没有鼠标滚轮.pyQT里有吗?
glTranslatef(DX,DY,0)
#绘制所有直线
glBegin(GL_LINES)
for line in LINELIST:
glVertex2f(line.start[0],line.start[1])
glVertex2f(line.end[0],line.end[1])
glEnd()
#用描点的形式绘制所有弧线
glBegin(GL_POINTS)
for arc in ARCLIST:
start_angle=arc.start_angle/180.0*math.pi
end_angle=arc.end_angle/180*math.pi
#CAD里,圆弧都是从起点到终点,顺时针转的;所以,这里只取正值
dAngle=abs(end_angle-start_angle)
pointNum=500#一个弧500个点
for i in range(0,pointNum):
x=arc.center[0]+arc.radius*math.cos(start_angle+dAngle*i/pointNum)
y=arc.center[1]+arc.radius*math.sin(start_angle+dAngle*i/pointNum)
glVertex2f(x,y)
glEnd()
glPopMatrix()
glFlush()
#方向键进行缩放——为什么是方向键?因为鼠标滚轮不知道怎么调用
def specialKey(key=0,x=0,y=0):
global SCALE
if (key==GLUT_KEY_UP):
SCALE+=0.1
elif(key==GLUT_KEY_DOWN):
SCALE-=0.1
glutPostRedisplay()
mouseX,mouseY=0,0
def mouseClick(button=0,state=0,x=0,y=0):
glutPostRedisplay()
def mouseDownAndMove(x=0,y=0):
global DX,DY
global mouseX,mouseY
DX+=x-mouseX
DY+=-(y-mouseY)#因为原点在左上角,Y轴与图形的Y轴颠倒,故取反
mouseX=x
mouseY=y
glutPostRedisplay()
def mouseMove(x=0,y=0):
global mouseX,mouseY
mouseX=x
mouseY=y
glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
glutInitWindowSize(400, 400)
glutCreateWindow("test")
glutDisplayFunc(drawFunc)#回调函数
glutMouseFunc(mouseClick)#鼠标点击时调用
glutMotionFunc(mouseDownAndMove)#鼠标按下并移动时调用——原点在左上角
glutPassiveMotionFunc(mouseMove)
glutSpecialFunc(specialKey)#键盘交互
init()
glutMainLoop()
正文
然后干什么?
软件测试
from asyncio.windows_events import NULL
from os import stat
import dxfgrabber
import math
import numpy as np
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
inputFilePath='e:/test3-11/Drawing4.dxf' #输入文件的路径
#供读取的数据结构
class Line:
def __init__(self,id,start,end):
self.id=id
self.start=start
self.end=end
LINELIST=[]
class Arc:
def __init__(self,id,center,radius,startAngle,endAngle) -> None:
self.id=id
self.center=center
self.radius=radius
self.start_angle=startAngle
self.end_angle=endAngle
pass
ARCLIST=[]
VIRTUALLIST=[]
SCALE=1.0#用于缩放
DX,DY=0,0#用于移动
#读取
dxf = dxfgrabber.readfile(inputFilePath)
lineNum=0
arcNum=0
for e in dxf.entities:
if e.dxftype == 'LINE':
LINELIST.append(Line(lineNum,e.start,e.end))
lineNum+=1
elif e.dxftype=='ARC':
ARCLIST.append(Arc(arcNum,e.center,e.radius,e.start_angle,e.end_angle))
arcNum+=1
#图元重组
def intersectionTestLineAndArc(line,arc)->bool:
#python怎么解方程——先从简处理吧
x=arc.center[0]+arc.radius*math.cos(arc.start_angle/180*math.pi)
y=arc.center[1]+arc.radius*math.sin(arc.start_angle/180*math.pi)
p0=np.array([x,y])
x=arc.center[0]+arc.radius*math.cos(arc.end_angle/180*math.pi)
y=arc.center[1]+arc.radius*math.sin(arc.end_angle/180*math.pi)
p1=np.array([x,y])
p2=np.array(line.start[0:2])
p3=np.array(line.end[0:2])
d=list(range(4))
d[0]=np.sum(np.square(p0-p2))
d[1]=np.sum(np.square(p0-p3))
d[2]=np.sum(np.square(p1-p2))
d[3]=np.sum(np.square(p1-p3))
if min(d)<=1:
return True
return False
def intersectionTest()->set:#加入新图元后,与之前加入的图元进行相交测试,返回与之相交的图元集合
global VIRTUALLIST
result=set()#空集合
if len(VIRTUALLIST)==1:
return result
entity=VIRTUALLIST[-1]#列表的最后一个就是新加入的图元
for virtualEntity in VIRTUALLIST[0:-1]:#目前,只能处理直线和弧的关系,排列组合……2*2
if type(entity)==Line and type(virtualEntity)==Line:
pass
elif type(entity)==Line and type(virtualEntity)==Arc:
pass
elif type(entity)==Arc and type(virtualEntity)==Arc:
pass
elif type(entity)==Arc and type(virtualEntity)==Line:#本例中,只会用到这个分支
if intersectionTestLineAndArc(virtualEntity,entity):
result.add(virtualEntity)
result.add(entity)
pass
else:
pass
pass
else:
pass
return result
INTERSECTIONLIST=[]
for line in LINELIST:
VIRTUALLIST.append(line)
result=intersectionTest()
for arc in ARCLIST:
VIRTUALLIST.append(arc)
result=intersectionTest()
if len(result)!=0:
newCluster=True#是否是新的一簇图形
if len(INTERSECTIONLIST)==0:
INTERSECTIONLIST.append(result)
newCluster=False
else:
for iL in INTERSECTIONLIST:
if not iL.isdisjoint(result):#双重否定,等于肯定
temp=iL.union(result)
#获取下标
index=INTERSECTIONLIST.index(iL)
#修改list中的指定set:
INTERSECTIONLIST[index]=temp
newCluster=False
if newCluster:
INTERSECTIONLIST.append(result)
else:
continue
#按照相交关系,重组完成
#print(INTERSECTIONLIST)
#显示——OpenGL
def init():
glClearColor(0.3, 0.3, 0.3, 1.0)
gluOrtho2D(0, 400.0, 0, 400)#窗口坐标系的大小,左下角是原点
def drawLine(line):
glVertex2f(line.start[0],line.start[1])
glVertex2f(line.end[0],line.end[1])
def drawArc(arc):
#用描点的形式绘制所有弧线
for arc in ARCLIST:
start_angle=arc.start_angle/180.0*math.pi
end_angle=arc.end_angle/180*math.pi
#CAD里,圆弧都是从起点到终点,顺时针转的;所以,这里只取正值
dAngle=abs(end_angle-start_angle)
pointNum=500#一个弧500个点
for i in range(0,pointNum):
x=arc.center[0]+arc.radius*math.cos(start_angle+dAngle*i/pointNum)
y=arc.center[1]+arc.radius*math.sin(start_angle+dAngle*i/pointNum)
glVertex2f(x,y)
def drawFunc():
glClear(GL_COLOR_BUFFER_BIT)
glPushMatrix()
glScale(SCALE,SCALE,1.0)#缩放——OpenGL里没有鼠标滚轮.pyQT里有吗?
glTranslatef(DX,DY,0)
#从相交列表里取数据渲染
global INTERSECTIONLIST
for iL in INTERSECTIONLIST:
# if INTERSECTIONLIST.index(iL)%2==0:
# glColor3f(1.0,0.0,0.0)
# else:
# glColor3f(0.0,1.0,0.0)
#依次显示
if INTERSECTIONLIST.index(iL)==0:
pass
else:
break
for entity in iL:
if type(entity)==Line:
glBegin(GL_LINES)
drawLine(entity)
glEnd()
elif type(entity)==Arc:
glBegin(GL_POINTS)
drawArc(entity)
glEnd()
glPopMatrix()
glFlush()
#方向键控制缩放
def specialKey(key=0,x=0,y=0):
global SCALE
if (key==GLUT_KEY_UP):
SCALE+=0.1
elif(key==GLUT_KEY_DOWN):
SCALE-=0.1
glutPostRedisplay()
mouseX,mouseY=0,0
def mouseClick(button=0,state=0,x=0,y=0):
glutPostRedisplay()
def mouseDownAndMove(x=0,y=0):
global DX,DY
global mouseX,mouseY
DX+=x-mouseX
DY+=-(y-mouseY)#因为原点在左上角,Y轴与图形的Y轴颠倒,故取反
mouseX=x
mouseY=y
glutPostRedisplay()
def mouseMove(x=0,y=0):
global mouseX,mouseY
mouseX=x
mouseY=y
glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
glutInitWindowSize(400, 400)
glutCreateWindow("test")
glutDisplayFunc(drawFunc)#回调函数
glutMouseFunc(mouseClick)#鼠标点击时调用
glutMotionFunc(mouseDownAndMove)#鼠标按下并移动时调用——原点在左上角
glutPassiveMotionFunc(mouseMove)
glutSpecialFunc(specialKey)#键盘交互
init()
glutMainLoop()
然后新问题就出现了
这个是相交列表里的第一个集合……
再往后就都出错了
哪错了?也许是CV的时候有一行没删干净
改了以后,好像正常了.同一簇相交的图形都是同一个颜色。
然后,按簇求包围盒。。
先从简单的开始,如何绘制包围盒?
#相互配合,实现矩形框的绘制
glPolygonMode(GL_FRONT, GL_LINE)
glRectd(100,100,200,200)
包围盒大概就是这么画的。这个问题解决了,下一个问题就出现了,矛盾具有普遍性,没有矛盾就没有世界——怎么求包围盒?
把一簇图形都打成散点吧,按散点求……这又需要一个配套的数据结构
from asyncio.windows_events import NULL
from os import stat
import dxfgrabber
import math
import numpy as np
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
inputFilePath='e:/test3-11/Drawing4.dxf' #输入文件的路径
#供读取的数据结构
class Line:
def __init__(self,id,start,end):
self.id=id
self.start=start
self.end=end
LINELIST=[]
class Arc:
def __init__(self,id,center,radius,startAngle,endAngle) -> None:
self.id=id
self.center=center
self.radius=radius
self.start_angle=startAngle
self.end_angle=endAngle
pass
ARCLIST=[]
VIRTUALLIST=[]
SCALE=1.0#用于缩放
DX,DY=0,0#用于移动
#读取
dxf = dxfgrabber.readfile(inputFilePath)
lineNum=0
arcNum=0
for e in dxf.entities:
if e.dxftype == 'LINE':
LINELIST.append(Line(lineNum,e.start,e.end))
lineNum+=1
elif e.dxftype=='ARC':
ARCLIST.append(Arc(arcNum,e.center,e.radius,e.start_angle,e.end_angle))
arcNum+=1
#图元重组
def intersectionTestLineAndArc(line,arc)->bool:
#python怎么解方程——先从简处理吧
x=arc.center[0]+arc.radius*math.cos(arc.start_angle/180*math.pi)
y=arc.center[1]+arc.radius*math.sin(arc.start_angle/180*math.pi)
p0=np.array([x,y])
x=arc.center[0]+arc.radius*math.cos(arc.end_angle/180*math.pi)
y=arc.center[1]+arc.radius*math.sin(arc.end_angle/180*math.pi)
p1=np.array([x,y])
p2=np.array(line.start[0:2])
p3=np.array(line.end[0:2])
d=list(range(4))
d[0]=np.sum(np.square(p0-p2))
d[1]=np.sum(np.square(p0-p3))
d[2]=np.sum(np.square(p1-p2))
d[3]=np.sum(np.square(p1-p3))
if min(d)<=1:
return True
return False
def intersectionTest()->set:#加入新图元后,与之前加入的图元进行相交测试,返回与之相交的图元集合
global VIRTUALLIST
result=set()#空集合
if len(VIRTUALLIST)==1:
return result
entity=VIRTUALLIST[-1]#列表的最后一个就是新加入的图元
for virtualEntity in VIRTUALLIST[0:-1]:#目前,只能处理直线和弧的关系,排列组合……2*2
if type(entity)==Line and type(virtualEntity)==Line:
pass
elif type(entity)==Line and type(virtualEntity)==Arc:
pass
elif type(entity)==Arc and type(virtualEntity)==Arc:
pass
elif type(entity)==Arc and type(virtualEntity)==Line:#本例中,只会用到这个分支
if intersectionTestLineAndArc(virtualEntity,entity):
result.add(virtualEntity)
result.add(entity)
pass
else:
pass
pass
else:
pass
return result
INTERSECTIONLIST=[]
for line in LINELIST:
VIRTUALLIST.append(line)
result=intersectionTest()
for arc in ARCLIST:
VIRTUALLIST.append(arc)
result=intersectionTest()
if len(result)!=0:
newCluster=True#是否是新的一簇图形
if len(INTERSECTIONLIST)==0:
INTERSECTIONLIST.append(result)
newCluster=False
else:
for iL in INTERSECTIONLIST:
if not iL.isdisjoint(result):#双重否定,等于肯定
temp=iL.union(result)
#获取下标
index=INTERSECTIONLIST.index(iL)
#修改list中的指定set:
INTERSECTIONLIST[index]=temp
newCluster=False
if newCluster:
INTERSECTIONLIST.append(result)
else:
continue
BOUNDINGBOXLIST=[]
for iL in INTERSECTIONLIST:
#如何用一个通用的方法计算一簇图形的包围盒呢?
result=list(range(4))#xmin,ymin,xmax,ymax
#把这簇图形,都简化成散点,散点的包围盒好求呐,这里只考虑包围盒,不考虑轴向的问题
pointsX=[]
pointsY=[]
for entity in iL:
if type(entity)==Line:
pointsX.append(entity.start[0])
pointsY.append(entity.start[1])
pointsX.append(entity.end[0])
pointsY.append(entity.end[1])
elif type(entity)==Arc:
#严格的说,这里应该求个弧的包围盒……但是暴力带值法也行……
start_angle=entity.start_angle/180.0*math.pi
end_angle=entity.end_angle/180*math.pi
#CAD里,圆弧都是从起点到终点,顺时针转的;所以,这里只取正值
dAngle=abs(end_angle-start_angle)
pointNum=100#一个弧500个点
for i in range(0,pointNum):
x=entity.center[0]+entity.radius*math.cos(start_angle+dAngle*i/pointNum)
y=entity.center[1]+entity.radius*math.sin(start_angle+dAngle*i/pointNum)
pointsX.append(x)
pointsY.append(y)
result[0]=min(pointsX)
result[1]=min(pointsY)
result[2]=max(pointsX)
result[3]=max(pointsY)
BOUNDINGBOXLIST.append(result)
#print(BOUNDINGBOXLIST)
#显示——OpenGL
def init():
glClearColor(0.3, 0.3, 0.3, 1.0)
gluOrtho2D(0, 400.0, 0, 400)#窗口坐标系的大小,左下角是原点
def drawLine(line):
glVertex2f(line.start[0],line.start[1])
glVertex2f(line.end[0],line.end[1])
def drawArc(arc):
#用描点的形式绘制所有弧线
start_angle=arc.start_angle/180.0*math.pi
end_angle=arc.end_angle/180*math.pi
#CAD里,圆弧都是从起点到终点,顺时针转的;所以,这里只取正值
dAngle=abs(end_angle-start_angle)
pointNum=500#一个弧500个点
for i in range(0,pointNum):
x=arc.center[0]+arc.radius*math.cos(start_angle+dAngle*i/pointNum)
y=arc.center[1]+arc.radius*math.sin(start_angle+dAngle*i/pointNum)
glVertex2f(x,y)
def drawFunc():
glClear(GL_COLOR_BUFFER_BIT)
glPushMatrix()
glScale(SCALE,SCALE,1.0)#缩放——OpenGL里没有鼠标滚轮.pyQT里有吗?
glTranslatef(DX,DY,0)
#从相交列表里取数据绘制图形
global INTERSECTIONLIST
for iL in INTERSECTIONLIST:
#一种颜色是一家
if INTERSECTIONLIST.index(iL)%2==0:
glColor3f(1.0,0.0,0.0)
else:
glColor3f(0.0,1.0,0.0)
for entity in iL:
if type(entity)==Line:
glBegin(GL_LINES)
drawLine(entity)
glEnd()
elif type(entity)==Arc:
glBegin(GL_POINTS)
drawArc(entity)
glEnd()
#从包围盒列表里取数据绘制包围盒
for bb in BOUNDINGBOXLIST:
#相互配合,实现矩形框的绘制
glColor3f(1,1,1)
glPolygonMode(GL_FRONT, GL_LINE)
glRectd(bb[0],bb[1],bb[2],bb[3])
glPopMatrix()
glFlush()
#方向键控制缩放
def specialKey(key=0,x=0,y=0):
global SCALE
if (key==GLUT_KEY_UP):
SCALE+=0.1
elif(key==GLUT_KEY_DOWN):
SCALE-=0.1
glutPostRedisplay()
mouseX,mouseY=0,0
def mouseClick(button=0,state=0,x=0,y=0):
glutPostRedisplay()
def mouseDownAndMove(x=0,y=0):
global DX,DY
global mouseX,mouseY
DX+=x-mouseX
DY+=-(y-mouseY)#因为原点在左上角,Y轴与图形的Y轴颠倒,故取反
mouseX=x
mouseY=y
glutPostRedisplay()
def mouseMove(x=0,y=0):
global mouseX,mouseY
mouseX=x
mouseY=y
glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
glutInitWindowSize(400, 400)
glutCreateWindow("test")
glutDisplayFunc(drawFunc)#回调函数
glutMouseFunc(mouseClick)#鼠标点击时调用
glutMotionFunc(mouseDownAndMove)#鼠标按下并移动时调用——原点在左上角
glutPassiveMotionFunc(mouseMove)
glutSpecialFunc(specialKey)#键盘交互
init()
glutMainLoop()
不考虑轴向的包围盒,AABB包围盒,确实能按散点求。