跳转至

display显示

约 612 个字 356 行代码 9 张图片 预计阅读时间 6 分钟

背景颜色

from OCC.Display.SimpleGui import init_display
from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox
from OCC.Core.Quantity import (
    Quantity_Color,
    Quantity_NOC_ALICEBLUE,
    Quantity_NOC_ANTIQUEWHITE,
)

display, start_display, add_menu, add_function_to_menu = init_display()
my_box = BRepPrimAPI_MakeBox(10.0, 20.0, 30.0).Shape()

# 设置显示窗口的背景为 渐变色
display.View.SetBgGradientColors(
    Quantity_Color(Quantity_NOC_ALICEBLUE),
    Quantity_Color(Quantity_NOC_ANTIQUEWHITE),
    2, # 渐变类型: 垂直
    True, # 是否立即更新视图
)
display.Repaint() # 确保背景颜色更新
display.DisplayShape(my_box, update=True)
start_display()

callback

用户可以添加鼠标回调事件,官网的案例中,当点击几何体时会打印一些几何体的信息:

from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox, BRepPrimAPI_MakeTorus
from OCC.Core.Bnd import Bnd_Box
from OCC.Core.BRepBndLib import brepbndlib
from OCC.Display.SimpleGui import init_display

def print_xy_click(shp, *kwargs):
    # 当用户点击 3D 对象时,打印选中对象的 Python 对象信息
    for shape in shp:
        print("Shape selected: ", shape)
    print(kwargs)

def compute_bbox(shp, *kwargs):
    # 计算选中对象的边界框(尺寸和中心坐标)
    print("Compute bbox for %s " % shp)
    for shape in shp:
        # 创建一个 Bnd_Box 对象,用于存储边界框(Bounding Box)数据的类
        bbox = Bnd_Box()
        # 将几何体的边界信息填充到 Bnd_Box
        brepbndlib.Add(shape, bbox)
        # 获取边界框的最小/最大坐标
        xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get()
        dx = xmax - xmin
        dy = ymax - ymin
        dz = zmax - zmin
        print("Selected shape bounding box : dx=%f, dy=%f, dz=%f." % (dx, dy, dz))
        print(
            "               bounding box center: x=%f, y=%f, z=%f"
            % (xmin + dx / 2.0, ymin + dy / 2.0, zmin + dz / 2.0)
        )

display, start_display, add_menu, add_function_to_menu = init_display()

# 将两个函数绑定到鼠标选择事件
display.register_select_callback(print_xy_click)
display.register_select_callback(compute_bbox)

# 创建几何体
my_box = BRepPrimAPI_MakeBox(10.0, 20.0, 30.0).Shape()
my_torus = BRepPrimAPI_MakeTorus(30.0, 5.0).Shape()

display.DisplayShape(my_torus)
display.DisplayShape(my_box, update=True)

start_display()

AddClipPlane

from OCC.Display.SimpleGui import init_display
from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox
from OCC.Core.Graphic3d import Graphic3d_ClipPlane
from OCC.Core.Quantity import Quantity_Color, Quantity_TOC_RGB
from OCC.Core.gp import gp_Pln, gp_Pnt, gp_Dir
from OCC.Core.Bnd import Bnd_Box
from OCC.Core.BRepBndLib import brepbndlib  


def shape_center(shape):
    """返回形状包围盒中心点 (cx, cy, cz)。"""
    bbox = Bnd_Box()
    brepbndlib.Add(shape, bbox)  
    xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get()
    return (0.5 * (xmin + xmax), 0.5 * (ymin + ymax), 0.5 * (zmin + zmax))


def make_clip_plane(point, normal, rgb=(0.75, 0.78, 0.85)):
    """
    创建一个启用 capping 的裁切平面:
    - point: 平面上一点 (x, y, z)
    - normal: 法向量 (nx, ny, nz)
    - rgb: 截面填充颜色 (0~1)
    """
    clip = Graphic3d_ClipPlane()
    clip.SetOn(True)            # 启用
    clip.SetCapping(True)       # 开启截面填充
    clip.SetCappingHatch(True)  # 带阴影线

    mat = clip.CappingMaterial()
    col = Quantity_Color(*rgb, Quantity_TOC_RGB)
    mat.SetAmbientColor(col)
    mat.SetDiffuseColor(col)
    clip.SetCappingMaterial(mat)

    pln = gp_Pln(gp_Pnt(*point), gp_Dir(*normal))
    clip.SetEquation(pln)
    return clip


def main():
    display, start_display, *_ = init_display()

    my_box = BRepPrimAPI_MakeBox(10.0, 20.0, 30.0).Shape()
    ais = display.DisplayShape(my_box, update=True)[0]

    # 计算中心点
    cx, cy, cz = shape_center(my_box)

    # 三个正交裁切平面(均过中心)
    plane_x = make_clip_plane((cx, cy, cz), (1, 0, 0), rgb=(0.80, 0.70, 0.70))  # X 向
    plane_y = make_clip_plane((cx, cy, cz), (0, 1, 0), rgb=(0.70, 0.80, 0.70))  # Y 向
    plane_z = make_clip_plane((cx, cy, cz), (0, 0, 1), rgb=(0.70, 0.75, 0.90))  # Z 向

    # 添加到可交互对象
    ais.AddClipPlane(plane_x)
    ais.AddClipPlane(plane_y)
    ais.AddClipPlane(plane_z)

    # 可视化
    display.FitAll()
    start_display()

if __name__ == "__main__":
    main()
  • 想保留另一半(翻面裁切)的话,可以把对应法向量取反,比如 (1, 0, 0) → (-1, 0, 0)
  • 想把裁切位置从中心改为任意截面(例如 x = 6):把 point 改成 (6, cy, cz) 且法向仍为 (1, 0, 0)

AIS_Shape

from OCC.Core.AIS import AIS_Shape
from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox
from OCC.Display.SimpleGui import init_display
from OCC.Core.Quantity import (
    Quantity_Color, Quantity_TOC_RGB,
    Quantity_NOC_BLUE1
)
display, start_display, add_menu, add_function_to_menu = init_display()

s = BRepPrimAPI_MakeBox(200, 100, 50).Shape()

ais_shp = AIS_Shape(s)

ais_shp.SetWidth(4) # 设置线宽
ais_shp.SetTransparency(0.50) # 设置透明度
ais_shp.SetColor(Quantity_Color(Quantity_NOC_BLUE1)) # 设置颜色

# Get Context
ais_context = display.GetContext()
ais_context.SetAutoActivateSelection(False) # 鼠标选中时不影响线颜色的变化
ais_context.Display(ais_shp, True)

display.View_Iso()
display.FitAll()
start_display()

通过AIS_Shape(s),可以获得该形状的特征。后处理显示时更加灵活。上面代码可创建一个透明度为10%,边缘线宽为4的box:

HLR 模式

SetModeHLR():设置为 HLR 模式(Hidden Line Removal,隐藏线消除模式),在这个模式下,物体只显示轮廓线和可见边。

from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeCylinder
from OCC.Display.SimpleGui import init_display

display, start_display, add_menu, add_function_to_menu = init_display()

# HLR模式
display.SetModeHLR()

# 管理交互式对象
ais_context = display.GetContext()

# 控制绘制参数
drawer = ais_context.DefaultDrawer()
drawer.SetIsoOnPlane(True) # 启用等参线(在曲面上画的辅助线)

la = drawer.LineAspect()
la.SetWidth(4)

line_aspect = drawer.SeenLineAspect()   # 获取可见线样式
drawer.EnableDrawHiddenLine()           # 启用隐藏线显示
line_aspect.SetWidth(4)                 

# 把这个线样式应用到线框显示模式
drawer.SetWireAspect(line_aspect)

s = BRepPrimAPI_MakeCylinder(50.0, 50.0).Shape()
display.DisplayShape(s)

display.View_Iso()
display.FitAll()
start_display()

隐藏边界线

SetFaceBoundaryDraw(False):不绘制面边界线

from OCC.Display.SimpleGui import init_display
from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox

display, start_display, add_menu, add_function_to_menu = init_display()
my_box = BRepPrimAPI_MakeBox(10.0, 20.0, 30.0).Shape()

display.default_drawer.SetFaceBoundaryDraw(False)
display.DisplayShape(my_box, update=True)
start_display()

隐藏/删除/重新显示

from OCC.Core.BRepPrimAPI import (
    BRepPrimAPI_MakeBox,
    BRepPrimAPI_MakeCylinder,
    BRepPrimAPI_MakeSphere,
)
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_Transform
from OCC.Core.gp import gp_Trsf, gp_Vec
from OCC.Display.SimpleGui import init_display

display, start_display, add_menu, add_function_to_menu = init_display()

a_box = BRepPrimAPI_MakeBox(10.0, 20.0, 30.0).Shape()

tr1 = gp_Trsf(); tr1.SetTranslation(gp_Vec(50, 0, 0))
a_sphere = BRepBuilderAPI_Transform(BRepPrimAPI_MakeSphere(10.0).Shape(), tr1, False).Shape()

tr2 = gp_Trsf(); tr2.SetTranslation(gp_Vec(-50, 0, 0))
a_cylinder = BRepBuilderAPI_Transform(BRepPrimAPI_MakeCylinder(10.0, 40.0).Shape(), tr2, False).Shape()

ais_box = display.DisplayShape(a_box)[0]
ais_sphere = display.DisplayShape(a_sphere)[0]
ais_cylinder = display.DisplayShape(a_cylinder)[0]

display.FitAll()

# 隐藏(从视图中擦除,但仍在上下文里,可再次显示)
# display.Context.Erase(ais_box, True)
# display.Context.Erase(ais_sphere, True)
# display.Context.Erase(ais_cylinder, True)

# 重新显示
# display.Context.Display(ais_box, True)
# display.Context.Display(ais_sphere, True)
# display.Context.Display(ais_cylinder, True)

# 永久移除
# display.Context.Remove(ais_box, True)
# display.Context.Remove(ais_sphere, True)
# display.Context.Remove(ais_cylinder, True)

# 全部隐藏/清除
# display.EraseAll()                         # 视图层面的全部擦除
# display.Context.EraseAll(True)             # 上下文层面的全部擦除
# display.Context.RemoveAll(True)            # 上下文层面的全部移除

# 进入交互
start_display()
  • display.DisplayShape(a_box)这里返回的是列表,如果是display.DisplayShape(a_box)[0]则返回的是AIS_Shape对象,可进行下一步的操作,当然也可以将Shape列表传入display.DisplayShape然后进行索引

视图层面

  • 只和 当前窗口里的绘图缓冲区 打交道
  • 比如 display.EraseAll():清空屏幕,把所有图形从画布上移除
  • 但是对象本身依旧保存在 AIS_InteractiveContext(上下文)里,下次 FitAll() 或者 Redisplay() 又能让它们重新出现

上下文层面

  • 管理的是 AIS 对象本身的生命周期和显示状态
  • 这里有三种常用操作:
    1. Erase(ais_shape, True)
      • 隐藏对象(从上下文里标记为不显示),但还在上下文里保存着,可以再 Display()
    2. Remove(ais_shape, True)
      • 彻底移除上下文,不再管理这个对象。以后要看必须重新 DisplayShape() 创建新的 AIS
    3. EraseAll() / RemoveAll()
      • 同理,只是对所有对象操作

线段样式

from OCC.Display.SimpleGui import init_display
from OCC.Core.gp import gp_Pnt, gp_Dir
from OCC.Core.Geom import Geom_Line
from OCC.Core.AIS import AIS_Line
from OCC.Core.Prs3d import Prs3d_Drawer, Prs3d_LineAspect
from OCC.Core.Quantity import Quantity_Color, Quantity_TOC_RGB, Quantity_NOC_RED
from OCC.Core.Aspect import (
    Aspect_TOL_SOLID,
    Aspect_TOL_DASH,
    Aspect_TOL_DOT,
    Aspect_TOL_DOTDASH,
)

display, start_display, add_menu, add_function_to_menu = init_display()

p = gp_Pnt(2.0, 3.0, 4.0)
d = gp_Dir(4.0, 5.0, 6.0)
gline = Geom_Line(p, d)

ais_line = AIS_Line(gline)

# 通过 Drawer + LineAspect 设置样式
drawer = Prs3d_Drawer()

color = Quantity_Color(0.2, 0.6, 0.9, Quantity_TOC_RGB)

# 线型:可选 Aspect_TOL_SOLID / _DASH / _DOT / _DOTDASH
line_type = Aspect_TOL_SOLID

# 线宽
width = 3.0

# 组合成线样式对象
aspect = Prs3d_LineAspect(color, line_type, width)
drawer.SetLineAspect(aspect)
ais_line.SetAttributes(drawer)

display.Context.Display(ais_line, True)
display.FitAll()
start_display()

有关线型的样式,参考OCC文档:

Aspect_TOL_SOLID continuous
Aspect_TOL_DASH dashed 2.0,1.0 (MM)
Aspect_TOL_DOT dotted 0.2,0.5 (MM)
Aspect_TOL_DOTDASH mixed 10.0,1.0,2.0,1.0 (MM)
Aspect_TOL_USERDEFINED defined by Users

点的样式

import sys

from OCC.Core.gp import gp_Pnt
from OCC.Core.Geom import Geom_CartesianPoint
from OCC.Core.Quantity import Quantity_Color, Quantity_TOC_RGB
from OCC.Core.Aspect import (
    Aspect_TOM_POINT,
    Aspect_TOM_PLUS,
    Aspect_TOM_STAR,
    Aspect_TOM_X,
    Aspect_TOM_O,
    Aspect_TOM_O_POINT,
    Aspect_TOM_O_PLUS,
    Aspect_TOM_O_STAR,
    Aspect_TOM_O_X,
    Aspect_TOM_RING1,
    Aspect_TOM_RING2,
    Aspect_TOM_RING3,
    Aspect_TOM_BALL,
)
from OCC.Core.AIS import AIS_Point
from OCC.Core.Prs3d import Prs3d_PointAspect, Prs3d_Drawer

from OCC.Display.SimpleGui import init_display

display, start_display, add_menu, add_function_to_menu = init_display()

ALL_ASPECTS = [  
    Aspect_TOM_POINT,    # 实心点
    Aspect_TOM_PLUS,     # 加号
    Aspect_TOM_STAR,     # 星号
    Aspect_TOM_X,        # X形
    Aspect_TOM_O,        # 空心圆
    Aspect_TOM_O_POINT,  # 带点的圆
    Aspect_TOM_O_PLUS,   # 带加号的圆
    Aspect_TOM_O_STAR,   # 带星号的圆
    Aspect_TOM_O_X,      # 带X的圆
    Aspect_TOM_RING1,    # 单环
    Aspect_TOM_RING2,    # 双环
    Aspect_TOM_RING3,    # 三环
    Aspect_TOM_BALL,     # 球体
]


def pnt():
     # 创建10x10的点阵,每个Z层使用不同的标记类型
    for idx in range(10):
        for idy in range(10):
            for idz, aspect in enumerate(ALL_ASPECTS):
                x = 0 + idx * 0.1
                y = 0 + idy * 0.1
                z = 0 + idz / len(ALL_ASPECTS)
                p = Geom_CartesianPoint(gp_Pnt(x, y, z))
                color = Quantity_Color(x / len(ALL_ASPECTS), 0, z, Quantity_TOC_RGB)
                # 创建交互式点对象
                ais_point = AIS_Point(p)

                # 获取当前绘图器
                drawer = ais_point.Attributes()
                # 创建点显示属性:标记类型、颜色、大小(3.0)
                asp = Prs3d_PointAspect(aspect, color, 3)
                # 设置点属性并应用到对象
                drawer.SetPointAspect(asp)
                ais_point.SetAttributes(drawer)

                display.Context.Display(ais_point, False)
    display.FitAll()
    start_display()

def exit(event=None):
    sys.exit()

if __name__ == "__main__":
    pnt()

有关点的样式,参考OCC文档:

Aspect_TOM_POINT point .
Aspect_TOM_PLUS plus +
Aspect_TOM_STAR star *
Aspect_TOM_X cross x
Aspect_TOM_O circle O
Aspect_TOM_O_POINT a point in a circle
Aspect_TOM_O_PLUS a plus in a circle
Aspect_TOM_O_STAR a star in a circle
Aspect_TOM_O_X a cross in a circle
Aspect_TOM_RING1 a large ring
Aspect_TOM_RING2 a medium ring
Aspect_TOM_RING3 a small ring
Aspect_TOM_BALL a ball with 1 color and different saturations
Aspect_TOM_USERDEFINED defined by Users (custom image)