跳转至

三维模型创建

约 579 个字 265 行代码 18 张图片 预计阅读时间 5 分钟

本次给大家分享的是Python_occ的基础API接口OCC.Core.BRepPrimAPI的使用。对于occ库的安装可在网上自行搜索,比较麻烦。最近在学习open cascade库,会更新比较多有关occ的内容,欢迎正在使用、准备使用Python_occ的开发者一起探讨。

本期内容主要包括:

  1. 长方体构建
  2. 球体
  3. 圆锥
  4. 圆柱
  5. 环形
  6. 旋转体
  7. 拉伸体

主要流程

  1. 导入occ
  2. 创建几何对象
  3. 几何操作
  4. 后处理显示

注意⚠️:OCCT没有单位的概念;所有旋转体的角度值都是弧度值

长方体 MakeBox

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

# 创建尺寸为 X=10, Y=20, Z=30 的长方体
box = BRepPrimAPI_MakeBox(10, 20, 30).Shape()

if __name__ == "__main__":
    # 初始可视化窗口
    display, start_display, _, _ = init_display()

    # 显示几何
    display.DisplayShape(box, update=True)
    # 窗口包围所有可见对象
    display.FitAll()

    # 交互渲染(阻塞直到窗口关闭)
    start_display()

可以在这个基础上进行模型颜色、透明度等的操作:

display.DisplayShape(box, update=True, color='BLUE1', transparency=0.2)

原方法:

DisplayShape(_shapes_, _material=None_, _texture=None_, _color=None_, _transparency=None_, _update=False_)

关于occt内置的颜色,见下图:

共有521种颜色,数字还挺浪漫~

不同视角

  • display.View_Front():正视图
  • View_Bottom():仰视图
  • View_Left():左视图
  • View_Right():右视图
  • View_Top():俯视图

更多显示操作可查看:OCC.Display.OCCViewer module

球体 MakeSphere

from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeSphere
from OCC.Core.gp import gp_Pnt
from OCC.Display.SimpleGui import init_display

center=gp_Pnt(5,5,10) # 三维点:球心
radius=19 # 半径
# 球体几何构造器:BRepPrimAPI_MakeSphere
sphere =BRepPrimAPI_MakeSphere(center ,radius).Shape()

if __name__ == "__main__":
    display, start_display, _, _ = init_display()

    display.DisplayShape(sphere, update=True)
    display.FitAll()

    start_display()

可以在这个球体几何基础上增加剖面显示:

from OCC.Core.BRepPrimAPI import (
    BRepPrimAPI_MakeSphere,
    BRepPrimAPI_MakeHalfSpace,
)
from OCC.Core.BRepAlgoAPI import (
    BRepAlgoAPI_Common,
    BRepAlgoAPI_Section,
)
from OCC.Core.BRepBuilderAPI import (
    BRepBuilderAPI_MakeFace,
    BRepBuilderAPI_MakeEdge,
    BRepBuilderAPI_MakeWire,
)
from OCC.Core.gp import (
    gp_Pnt, gp_Dir, gp_Pln, gp_Ax2, gp_Circ,
)
from OCC.Core.Geom import Geom_Plane
from OCC.Display.SimpleGui import init_display


def make_halves_by_plane(solid, plane_origin: gp_Pnt, plane_normal: gp_Dir):
    """
    用平面把封闭体分成两半(上半 / 下半)。
    原理:用平面构造两个相反的 half-space,然后分别与 solid 取 Common。
    """
    pln = gp_Pln(plane_origin, plane_normal)
    face = BRepBuilderAPI_MakeFace(pln).Face()

    # 选择在平面两侧的两个点来确定 half-space 的朝向
    # 点在平面法向 +/− 方向各偏移 1 个单位
    p_above = gp_Pnt(
        plane_origin.X() + plane_normal.X(),
        plane_origin.Y() + plane_normal.Y(),
        plane_origin.Z() + plane_normal.Z(),
    )
    p_below = gp_Pnt(
        plane_origin.X() - plane_normal.X(),
        plane_origin.Y() - plane_normal.Y(),
        plane_origin.Z() - plane_normal.Z(),
    )

    hs_above = BRepPrimAPI_MakeHalfSpace(face, p_above).Solid()
    hs_below = BRepPrimAPI_MakeHalfSpace(face, p_below).Solid()

    # 与 half-space 求交,得到两半
    upper_half = BRepAlgoAPI_Common(solid, hs_above).Shape()
    lower_half = BRepAlgoAPI_Common(solid, hs_below).Shape()
    return upper_half, lower_half, pln


def make_bigger_section_disk(pln: gp_Pln, center: gp_Pnt, radius: float, scale: float = 1.05):
    """
    在给定平面上生成一个“比球稍大”的圆盘(用于高亮剖面区域)。
    """
    ax2 = gp_Ax2(center, pln.Axis().Direction())  # 圆所在的平面坐标系
    circ = gp_Circ(ax2, radius * scale)           # 放大一点点
    edge = BRepBuilderAPI_MakeEdge(circ).Edge()
    wire = BRepBuilderAPI_MakeWire(edge).Wire()

    # 用该 wire 在此平面上生成面(圆盘)
    geom_plane = Geom_Plane(pln)
    face = BRepBuilderAPI_MakeFace(geom_plane, wire, True).Face()
    return face


if __name__ == "__main__":
    # ---------- 1) 构造球体 ----------
    center = gp_Pnt(5, 5, 10)
    radius = 19
    sphere = BRepPrimAPI_MakeSphere(center, radius).Shape()

    # ---------- 2) 定义剖切平面(过球心,法向 +Z) ----------
    plane_normal = gp_Dir(0, 0, 1)

    # ---------- 3) 切成上下两半 ----------
    upper_half, lower_half, pln = make_halves_by_plane(sphere, center, plane_normal)

    # ---------- 4) 剖切曲线(红色线条) ----------
    section_curve = BRepAlgoAPI_Section(sphere, pln).Shape()

    # ---------- 5) 生成更大的剖面圆盘(半透明高亮) ----------
    section_disk = make_bigger_section_disk(pln, center, radius, scale=1.2)

    # ---------- 6) 显示 ----------
    display, start_display, _, _ = init_display()

    # 上半球:蓝色,半透明
    display.DisplayShape(upper_half, color="BLUE1", transparency=0.35)

    # 下半球:绿色,半透明
    display.DisplayShape(lower_half, color="GREEN", transparency=0.35)

    # 剖面圆盘:金色,更透明(更大一些便于观察边界)
    display.DisplayShape(section_disk, color="RED", transparency=0.65)

    # 剖切曲线:红色、加粗
    display.DisplayShape(section_curve, color="RED")

    display.FitAll()
    start_display()

圆锥 MakeCone

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

cone = BRepPrimAPI_MakeCone(1,0,4).Shape()

if __name__ == "__main__":
    display, start_display, _, _ = init_display()

    display.DisplayShape(cone, update=True, color='BLUE1', transparency=0.5)
    display.FitAll()

    start_display()

也可以通过指定顶点和方向向量来构造圆锥:

cone_dn = BRepPrimAPI_MakeCone(gp_Ax2(gp_Pnt(0,0,0), gp_Dir(0,0,-1)), 0.0, 2.0, 4.0).Shape()
  • MakeCone:“底半径 R1、顶半径 R2、高度 H”生成实体圆锥/圆台
  • gp_Ax2:带原点+法向+X方向的**坐标系**(定义几何的“放置/朝向”)
  • gp_Dir:单位方向向量
  • cone = BRepPrimAPI_MakeCone(1, 0, 4).Shape():底半径为1,顶半径为0,高度为4

指定上下半径都有值时,可构造圆台几何:

cone_dn = BRepPrimAPI_MakeCone(gp_Ax2(gp_Pnt(0,0,0), gp_Dir(0,0,-1)), 1.0, 2.0, 4.0).Shape()

圆柱体 MakeCylinder

from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeCylinder
from OCC.Display.SimpleGui import init_display
import OCC.Core.Quantity as Q

cylinder = BRepPrimAPI_MakeCylinder(10,30).Shape()

display, start_display, _, _ = init_display()
display.DisplayShape(cylinder, color = Q.Quantity_NOC_GRAY31,  transparency=0.45)
display.FitAll()
start_display()
  • OCC.Core.Quantity,导入occ内置的颜色,当然也可以使用自定义的RGB颜色
  • BRepPrimAPI_MakeCylinder,构造圆柱体实体几何

该方法的文档已经非常详细,传入参数还可指定轴、角度。

部分圆柱

angle = radians(210.0)
cyl_partial = BRepPrimAPI_MakeCylinder(10.0, 30.0, angle).Shape()

指定轴

# 轴向沿-Z;底面过 (60, 0, 0)
ax2_down = gp_Ax2(gp_Pnt(60, 0, 0), gp_Dir(0, 0, -1))
cyl_ax = BRepPrimAPI_MakeCylinder(ax2_down, 8.0, 25.0).Shape()

带放置的部分圆柱

ax2_x = gp_Ax2(gp_Pnt(0, 60, 0), gp_Dir(1, 0, 0))
cyl_ax_partial = BRepPrimAPI_MakeCylinder(ax2_x, 12.0, 20.0, radians(120.0)).Shape()

厚壁圆柱(空心):外圆柱 - 内圆柱

outer = BRepPrimAPI_MakeCylinder(14.0, 26.0).Shape()
inner = BRepPrimAPI_MakeCylinder(10.0, 26.0).Shape()
cyl_hollow = BRepAlgoAPI_Cut(outer, inner).Shape()

在这里调用了BRepAlgoAPI_Cut方法,后续会分享该方法的具体用法。

环形 MakeTorus

from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeTorus
from OCC.Display.SimpleGui import init_display
import OCC.Core.Quantity as Q
from OCC.Core.gp import gp_Pnt
from OCC.Core.gp import gp_Ax2,gp_Dir

torus = BRepPrimAPI_MakeTorus(gp_Ax2 (gp_Pnt (0,0,2),gp_Dir (0,0,1)),0.55,0.1).Shape()

display, start_display, _, _ = init_display()
display.DisplayShape(torus, color = Q.Quantity_NOC_GRAY31,  transparency=0.45)
display.FitAll()
start_display()

  • 核心参数:BRepPrimAPI_MakeTorus(外半径,内半径)
  • 在这个基础上也可以传入angleAxes等参数

部分环面

from math import radians
torus_sector = BRepPrimAPI_MakeTorus(0.55, 0.1, radians(210)).Shape()

旋转体 MakeRevol

Edge旋转

# 轴:过原点、沿 Z
axis = gp_Ax1(gp_Pnt(0,0,0), gp_Dir(0,0,1))

R, H = 10.0, 25.0
e1 = BRepBuilderAPI_MakeEdge(gp_Pnt(R,0,0), gp_Pnt(R,0,H)).Edge()
surf = BRepPrimAPI_MakeRevol(e1, axis, radians(270)).Shape()  # 旋转 270°
display.DisplayShape(surf, color=Q.Quantity_NOC_SKYBLUE, transparency=0.35, update=False)

Face旋转

# 在 XZ 平面做一个矩形截面:内半径 ri,外半径 ro,高 H
ri, ro, H = 6.0, 10.0, 20.0
# 面的轮廓: (ri,0,0)->(ro,0,0)->(ro,0,H)->(ri,0,H)->回到(ri,0,0)
e21 = BRepBuilderAPI_MakeEdge(gp_Pnt(ri,0,0), gp_Pnt(ro,0,0)).Edge()
e22 = BRepBuilderAPI_MakeEdge(gp_Pnt(ro,0,0), gp_Pnt(ro,0,H)).Edge()
e23 = BRepBuilderAPI_MakeEdge(gp_Pnt(ro,0,H), gp_Pnt(ri,0,H)).Edge()
e24 = BRepBuilderAPI_MakeEdge(gp_Pnt(ri,0,H), gp_Pnt(ri,0,0)).Edge()
w2  = BRepBuilderAPI_MakeWire(e21, e22, e23, e24).Wire()
f2  = BRepBuilderAPI_MakeFace(w2).Face()
solid = BRepPrimAPI_MakeRevol(f2, axis).Shape()  # 默认 2π
display.DisplayShape(solid, color=Q.Quantity_NOC_SEAGREEN, transparency=0.25, update=False)

完整代码:

from math import radians
import OCC.Core.Quantity as Q
from OCC.Display.SimpleGui import init_display
from OCC.Core.gp import gp_Pnt, gp_Ax1, gp_Dir
from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeRevol
from OCC.Core.BRepBuilderAPI import (
    BRepBuilderAPI_MakeEdge, BRepBuilderAPI_MakeWire, BRepBuilderAPI_MakeFace
)

display, start_display, _, _ = init_display()

# 轴:过原点、沿 Z
axis = gp_Ax1(gp_Pnt(0,0,0), gp_Dir(0,0,1))

# -----------------------------------------------------------
# 例1:把一条母线(边)绕 Z 轴旋转,得到“圆柱侧面”(曲面,没有端盖)
# 母线:XZ 平面的线段 (R,0,0) -> (R,0,H)
R, H = 10.0, 25.0
e1 = BRepBuilderAPI_MakeEdge(gp_Pnt(R,0,0), gp_Pnt(R,0,H)).Edge()
surf = BRepPrimAPI_MakeRevol(e1, axis, radians(270)).Shape()  # 旋转 270°
display.DisplayShape(surf, color=Q.Quantity_NOC_SKYBLUE, transparency=0.35, update=False)

# -----------------------------------------------------------
# 例2:把闭合面绕 Z 轴旋转 2π,得到“空心圆柱实体”(有内外壁与端盖)
# 在 XZ 平面做一个矩形截面:内半径 ri,外半径 ro,高 H
ri, ro, H = 6.0, 10.0, 20.0
# 轮廓: (ri,0,0)->(ro,0,0)->(ro,0,H)->(ri,0,H)->回到(ri,0,0)
e21 = BRepBuilderAPI_MakeEdge(gp_Pnt(ri,0,0), gp_Pnt(ro,0,0)).Edge()
e22 = BRepBuilderAPI_MakeEdge(gp_Pnt(ro,0,0), gp_Pnt(ro,0,H)).Edge()
e23 = BRepBuilderAPI_MakeEdge(gp_Pnt(ro,0,H), gp_Pnt(ri,0,H)).Edge()
e24 = BRepBuilderAPI_MakeEdge(gp_Pnt(ri,0,H), gp_Pnt(ri,0,0)).Edge()
w2  = BRepBuilderAPI_MakeWire(e21, e22, e23, e24).Wire()
f2  = BRepBuilderAPI_MakeFace(w2).Face()
solid = BRepPrimAPI_MakeRevol(f2, axis).Shape()  # 不给角度=默认 2π
display.DisplayShape(solid, color=Q.Quantity_NOC_SEAGREEN, transparency=0.25, update=False)

display.FitAll()
start_display()

拉伸体 MakePrism

BRepPrimAPI_MakePrism(S: TopoDS_Shape, V: gp_Vec):用于把一个二维形体(轮廓、面等)沿某个方向拉伸成棱柱体。

from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakePrism
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeFace, BRepBuilderAPI_MakeWire
from OCC.Core.gp import gp_Pnt, gp_Vec
import OCC.Core.Quantity as Q
from OCC.Display.SimpleGui import init_display

# 1) 构造一个矩形 Wire
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeEdge
e1 = BRepBuilderAPI_MakeEdge(gp_Pnt(0,0,0), gp_Pnt(10,0,0)).Edge()
e2 = BRepBuilderAPI_MakeEdge(gp_Pnt(10,0,0), gp_Pnt(10,5,0)).Edge()
e3 = BRepBuilderAPI_MakeEdge(gp_Pnt(10,5,0), gp_Pnt(0,5,0)).Edge()
e4 = BRepBuilderAPI_MakeEdge(gp_Pnt(0,5,0), gp_Pnt(0,0,0)).Edge()

wire = BRepBuilderAPI_MakeWire(e1, e2, e3, e4).Wire()
face = BRepBuilderAPI_MakeFace(wire).Face()

# 2) 拉伸:沿 Z 方向 20
vec = gp_Vec(0, 0, 20)
prism = BRepPrimAPI_MakePrism(face, vec).Shape()

# 3) 显示
display, start_display, _, _ = init_display()
display.DisplayShape(face, color=Q.Quantity_NOC_YELLOWGREEN, transparency=0.1, update=False)
display.DisplayShape(prism, color=Q.Quantity_NOC_TURQUOISE3, transparency=0.6, update=True)
display.FitAll()
start_display()