AABB包围盒

前情回顾

在上一节的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的时候有一行没删干净

 改了以后,好像正常了.同一簇相交的图形都是同一个颜色。

 然后,按簇求包围盒。。

先从简单的开始,如何绘制包围盒?

绘制矩形glrected

如何绘制空心矩形框

        #相互配合,实现矩形框的绘制
        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包围盒,确实能按散点求。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值