首页/文章/ 详情

Python_occ 学习记录 | 网格划分

20小时前浏览4

基础设置

思路:

  1. Python_occ创建几何,导出.step文件
  2. Gmsh读入.step文件,进行网格划分,导出.stl文件
  3. 传入Python_occ,使用.stl文件进行网格划分(三角面片,可以大大降低渲染成本)

mesh.py

import os
import sys
import gmsh
from OCC.Core.IFSelect import IFSelect_RetDone
from OCC.Core.STEPControl import STEPControl_AsIs, STEPControl_Writer
from OCC.Core.TopoDS import TopoDS_Shape


def export_step(shape: TopoDS_Shape, path: str) -> None:
    """将OCC形状导出为STEP文件。

    参数
    ----------
    shape : TopoDS_Shape
        要导出的OCC形状对象。
    path : str
        输出的STEP文件路径(例如:"model.step")。
    """

    writer = STEPControl_Writer()
    writer.Transfer(shape, STEPControl_AsIs)
    status = writer.Write(path)
    if status != IFSelect_RetDone:
        raise RuntimeError("STEP export failed")
    print(f"[OK] STEP  -> {os.path.abspath(path)}")


def gmsh_mesh_step(
    step_path: str,
    msh_path: str,
    stl_path: str,
    lc_min: float = 3.0,
    lc_max: float = 8.0,
    optimize: bool = True,
)
 -> None:

    """使用Gmsh对STEP文件进行网格划分(生成3D四面体网格)并导出.msh文件和边界.stl文件。

    参数
    ----------
    step_path : str
        输入的STEP文件路径。
    msh_path : str
        输出的Gmsh网格文件路径(例如:"model.msh")。
    stl_path : str
        用于表面可视化的边界STL文件输出路径(例如:"surf.stl")。
    lc_min : float
        网格划分的最小特征长度。
    lc_max : float
        网格划分的最大特征长度。
    optimize : bool
        是否运行Gmsh网格优化(使用Netgen算法)。
    """

    if not os.path.exists(step_path):
        raise FileNotFoundError(step_path)

    gmsh.initialize(sys.argv)
    # 关闭 Gmsh 的内部 log 输出
    gmsh.option.setNumber("General.Terminal"0)

    gmsh.model.add("occ_from_step")
    gmsh.model.occ.importShapes(step_path)
    gmsh.model.occ.synchronize()

    gmsh.option.setNumber("Mesh.CharacteristicLengthMin", lc_min)
    gmsh.option.setNumber("Mesh.CharacteristicLengthMax", lc_max)

    gmsh.model.mesh.generate(3)

    if optimize:
        gmsh.option.setNumber("Mesh.Optimize"1)
        gmsh.model.mesh.optimize("Netgen")

    gmsh.write(msh_path)
    gmsh.write(stl_path)

    print(f"[OK] MSH   -> {os.path.abspath(msh_path)}")
    print(f"[OK] STL   -> {os.path.abspath(stl_path)}")

    gmsh.finalize()

主程序:

from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox, BRepPrimAPI_MakeCylinder
from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Cut
from OCC.Core.gp import gp_Ax2, gp_Dir, gp_Pnt
from OCC.Core.StlAPI import StlAPI_Reader
from OCC.Core.TopoDS import TopoDS_Shape
from OCC.Display.SimpleGui import init_display

from mesh import export_step, gmsh_mesh_step


def build_occ_shape() -> TopoDS_Shape:
    """occ构建几何"""
    box = BRepPrimAPI_MakeBox(100.060.040.0).Shape()
    axis = gp_Ax2(gp_Pnt(50.030.00.0), gp_Dir(0.00.01.0))
    cyl = BRepPrimAPI_MakeCylinder(axis, 12.050.0).Shape()
    cut = BRepAlgoAPI_Cut(box, cyl).Shape()
    return cut


def read_stl_as_shape(stl_file: str) -> TopoDS_Shape:
    """将边界STL文件加载回OCC中,用于表面可视化"""
    shape = TopoDS_Shape()
    ok = StlAPI_Reader().Read(shape, stl_file)
    if not ok:
        raise RuntimeError(f"Failed to read STL: {stl_file}")
    return shape


def main() -> None:
    # occ构建几何
    shape = build_occ_shape()

    # 导出stp文件
    step_path = "model.step"
    export_step(shape, step_path)

    # Gmsh网格划分:STEP文件 -> model.msh(四面体网格)+ surf.stl(边界三角形面片)
    gmsh_mesh_step(
        step_path=step_path,
        msh_path="model.msh",
        stl_path="surf.stl",
        lc_min=.0,
        lc_max=8.0,
        optimize=True,
    )

    # 在OCC中进行后处理:显示三角面片的表面网格
    stl_shape = read_stl_as_shape("surf.stl")
    display, start_display, *_ = init_display()
    display.DisplayShape(stl_shape, update=True)
    start_display()


if __name__ == "__main__":
    main()

更改网格样式

mesh_view.py

from OCC.Core.RWStl import rwstl
from OCC.Core.MeshDS import MeshDS_DataSource
from OCC.Core.MeshVS import (
    MeshVS_Mesh,
    MeshVS_MeshPrsBuilder,
    MeshVS_DA_ShowEdges,
    MeshVS_DA_DisplayNodes,
    MeshVS_DA_InteriorColor,
    MeshVS_DA_EdgeColor,
    MeshVS_DA_MarkerColor,
    MeshVS_DA_MarkerType,
    MeshVS_DA_MarkerScale,  
    MeshVS_DA_FrontMaterial
)
from OCC.Core.Graphic3d import Graphic3d_MaterialAspect, Graphic3d_NOM_STEEL
from OCC.Core.Quantity import Quantity_Color, Quantity_TOC_RGB
import OCC.Core.Quantity as Q
from OCC.Core.Aspect import Aspect_TOM_POINT, Aspect_TypeOfMarker


def _to_qcolor(c) -> Quantity_Color:
    """将 Q 常量 / Quantity_Color / (r,g,b) 转为 Quantity_Color。"""
    if isinstance(c, Quantity_Color):
        return c
    # Q.Quantity_NOC_* 常量
    try:
        return Quantity_Color(c)
    except Exception:
        pass
    # (r, g, b)
    if isinstance(c, (tuple, list)) and len(c) == 3:
        return Quantity_Color(float(c[0]), float(c[1]), float(c[2]), Quantity_TOC_RGB)
    raise ValueError("Unsupported color spec. Use Q.Quantity_NOC_*, Quantity_Color, or (r,g,b).")


def display_stl(
    basename: str,
    face_color=Q.Quantity_NOC_GRAY31,
    edge_color=Q.Quantity_NOC_BLACK,
    node_color=Q.Quantity_NOC_RED,
    show_edges: bool = True,
    show_nodes: bool = True,
    marker_size: float = 5.0,         # 节点大小(像素,部分版本等效为缩放)
    alpha: float = 0.35,              # 表面透明度(0~1,越大越透明)
    marker_type: Aspect_TypeOfMarker = Aspect_TOM_POINT,
)
:

    """使用 MeshVS 显示 STL 网格,面/边/节点统一纯色,支持透明度与节点大小。

    返回
    ----
    mesh_vs : MeshVS_Mesh
    """

    # 读取 STL → 三角网格
    stl_file  = f"{basename}.stl"
    stl_mesh = rwstl.ReadFile(stl_file)
    if stl_mesh is None:
        raise RuntimeError(f"Failed to read STL as mesh: {stl_file}")

    # 数据源
    mesh_ds = MeshDS_DataSource(stl_mesh)

    # MeshVS 对象
    mesh_vs = MeshVS_Mesh()
    mesh_vs.SetDataSource(mesh_ds)

    # 构建器与 Drawer
    prs_builder = MeshVS_MeshPrsBuilder(mesh_vs)
    mat = Graphic3d_MaterialAspect(Graphic3d_NOM_STEEL)
    mat.SetTransparency(float(alpha))

    drawer = prs_builder.GetDrawer()
    drawer.SetBoolean(MeshVS_DA_ShowEdges, bool(show_edges))
    drawer.SetBoolean(MeshVS_DA_DisplayNodes, bool(show_nodes))
    drawer.SetMaterial(MeshVS_DA_FrontMaterial, mat)

    # 纯色设置:面、边、节点(marker)
    drawer.SetColor(MeshVS_DA_InteriorColor, _to_qcolor(face_color))
    drawer.SetColor(MeshVS_DA_EdgeColor, _to_qcolor(edge_color))
    drawer.SetColor(MeshVS_DA_MarkerColor, _to_qcolor(node_color))

    # 节点形状与大小
    drawer.SetInteger(MeshVS_DA_MarkerType, int(marker_type))
    drawer.SetDouble(MeshVS_DA_MarkerScale, float(marker_size))

    prs_builder.SetDrawer(drawer)
    mesh_vs.AddBuilder(prs_builder, True)

    # 2 == MeshVS_DMF_Shading
    mesh_vs.SetDisplayMode(2)
    return mesh_vs

主程序调用:

from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox, BRepPrimAPI_MakeCylinder
from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Cut
from OCC.Core.gp import gp_Ax2, gp_Dir, gp_Pnt
from OCC.Core.TopoDS import TopoDS_Shape
from OCC.Display.SimpleGui import init_display
import OCC.Core.Quantity as Q

from mesh import export_step, gmsh_mesh_step   
from mesh_view import display_stl            


def build_occ_shape() -> TopoDS_Shape:
    """OCC 构建几何:盒体 + 贯穿圆孔。"""
    box = BRepPrimAPI_MakeBox(100.060.040.0).Shape()
    axis = gp_Ax2(gp_Pnt(50.030.00.0), gp_Dir(0.00.01.0))
    cyl = BRepPrimAPI_MakeCylinder(axis, 12.050.0).Shape()
    return BRepAlgoAPI_Cut(box, cyl).Shape()


def main() -> None:
    basename = "model" # 统一文件名
    view, start_display, *_ = init_display()

    # 1) 几何建模
    shape = build_occ_shape()

    # 2) 导出 STEP
    export_step(shape, basename)

    # 3) Gmsh 划分体网格,导出 .msh + 边界 .stl
    gmsh_mesh_step(
        basename,
        lc_min = 0.0,
        lc_max = 8.0,
        optimize = True,
    )

    # 4) 表面网格显示
    mesh_vs = display_stl(
        basename,
        face_color = Q.Quantity_NOC_GRAY31,
        edge_color = Q.Quantity_NOC_BLACK,
        node_color = Q.Quantity_NOC_ORANGE,
        show_edges = True,
        show_nodes = True,
        marker_size = 5.0,
        alpha = 0.5,
    )

    view.Context.Display(mesh_vs, True)
    view.FitAll()
    start_display()

if __name__ == "__main__":
    main()

其中材质我选择的是Graphic3d_NOM_STEEL,不同材质的光照渲染效果不同,可选材质:

import os

from OCC.Core.Graphic3d import (
    Graphic3d_NOM_BRASS,
    Graphic3d_NOM_BRONZE,
    Graphic3d_NOM_COPPER,
    Graphic3d_NOM_GOLD,
    Graphic3d_NOM_PEWTER,
    Graphic3d_NOM_PLASTER,
    Graphic3d_NOM_PLASTIC,
    Graphic3d_NOM_SILVER,
    Graphic3d_NOM_STEEL,
    Graphic3d_NOM_STONE,
    Graphic3d_NOM_SHINY_PLASTIC,
    Graphic3d_NOM_SATIN,
    Graphic3d_NOM_METALIZED,
    Graphic3d_NOM_NEON_GNC,
    Graphic3d_NOM_CHROME,
    Graphic3d_NOM_ALUMINIUM,
    Graphic3d_NOM_OBSIDIAN,
    Graphic3d_NOM_NEON_PHC,
    Graphic3d_NOM_JADE,
    Graphic3d_NOM_CHARCOAL,
    Graphic3d_NOM_WATER,
    Graphic3d_NOM_GLASS,
    Graphic3d_NOM_DIAMOND,
    Graphic3d_NOM_TRANSPARENT,
    Graphic3d_NOM_DEFAULT,
    Graphic3d_NOM_UserDefined,
)
from OCC.Core.gp import gp_Vec
from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeCylinder
from OCC.Extend.ShapeFactory import translate_shp
from OCC.Display.SimpleGui import init_display

display, start_display, add_menu, add_function_to_menu = init_display()

# User defined material names should be chosen among
available_materials = [
    Graphic3d_NOM_BRASS,
    Graphic3d_NOM_BRONZE,
    Graphic3d_NOM_COPPER,
    Graphic3d_NOM_GOLD,
    Graphic3d_NOM_PEWTER,
    Graphic3d_NOM_PLASTER,
    Graphic3d_NOM_PLASTIC,
    Graphic3d_NOM_SILVER,
    Graphic3d_NOM_STEEL,
    Graphic3d_NOM_STONE,
    Graphic3d_NOM_SHINY_PLASTIC,
    Graphic3d_NOM_SATIN,
    Graphic3d_NOM_METALIZED,
    Graphic3d_NOM_NEON_GNC,
    Graphic3d_NOM_CHROME,
    Graphic3d_NOM_ALUMINIUM,
    Graphic3d_NOM_OBSIDIAN,
    Graphic3d_NOM_NEON_PHC,
    Graphic3d_NOM_JADE,
    Graphic3d_NOM_CHARCOAL,
    Graphic3d_NOM_WATER,
    Graphic3d_NOM_GLASS,
    Graphic3d_NOM_DIAMOND,
    Graphic3d_NOM_TRANSPARENT,
    Graphic3d_NOM_DEFAULT,
    Graphic3d_NOM_UserDefined,
]

#
# Displays a cylinder with a material
#
radius = 30
s = BRepPrimAPI_MakeCylinder(radius, 200).Shape()
delta_x = 0.0
for mat in available_materials:
    s2 = translate_shp(s, gp_Vec(delta_x, 0.00.0))
    display.DisplayShape(s2, material=mat)
    delta_x += 2 * radius + 1.0

display.FitAll()
start_display()

来源:易木木响叮当
ACTpythonUMBIM渲染META
著作权归作者所有,欢迎分享,未经许可,不得转载
首次发布时间:2025-09-11
最近编辑:20小时前
易木木响叮当
硕士 有限元爱好者
获赞 264粉丝 380文章 415课程 2
点赞
收藏
作者推荐
未登录
还没有评论
课程
培训
服务
行家
VIP会员 学习计划 福利任务
下载APP
联系我们
帮助与反馈