Python_occ 学习记录 | 几何变换

几何变换 (Transformation) ------ 在 OpenCascade (OCC) 里主要通过 gp_Trsf来完成,搭配 BRepBuilderAPI_Transform 对形体应用。

基础类 gp_Trsf

gp_Trsf表示一个仿射变换,常用方法:

  • SetTranslation 平移
  • SetRotation 旋转
  • SetScale 缩放
  • SetMirror 镜像

平移 Translation

python 复制代码
from OCC.Core.gp import gp_Trsf, gp_Vec
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_Transform

trsf = gp_Trsf()
trsf.SetTranslation(gp_Vec(10, 0, 0))   # 沿 X 平移 10
moved_shape = BRepBuilderAPI_Transform(shape, trsf).Shape()

旋转 Rotation

python 复制代码
from OCC.Core.gp import gp_Trsf, gp_Ax1, gp_Pnt, gp_Dir
import math

trsf = gp_Trsf()
axis = gp_Ax1(gp_Pnt(0,0,0), gp_Dir(0,0,1))  # 旋转轴:过原点,沿 Z
trsf.SetRotation(axis, math.radians(45))     # 旋转 45°
rotated_shape = BRepBuilderAPI_Transform(shape, trsf).Shape()

缩放 Scale

python 复制代码
from OCC.Core.gp import gp_Trsf, gp_Pnt

trsf = gp_Trsf()
center = gp_Pnt(0,0,0)     # 缩放中心
trsf.SetScale(center, 2.0) # 放大 2 倍
scaled_shape = BRepBuilderAPI_Transform(shape, trsf).Shape()

镜像 (Mirror)

镜像有三种方式:

  • 关于点对称SetMirror(P)
  • 关于直线对称SetMirror(Ax1)
  • 关于平面对称SetMirror(Ax2)
python 复制代码
from OCC.Core.gp import gp_Ax1, gp_Ax2, gp_Pnt, gp_Dir

trsf = gp_Trsf()

# 1) 关于点对称
trsf.SetMirror(gp_Pnt(0,0,0))

# 2) 关于直线对称(X 轴)
trsf.SetMirror(gp_Ax1(gp_Pnt(0,0,0), gp_Dir(1,0,0)))

# 3) 关于平面对称(XY 平面)
trsf.SetMirror(gp_Ax2(gp_Pnt(0,0,0), gp_Dir(0,0,1)))

mirrored_shape = BRepBuilderAPI_Transform(shape, trsf).Shape()

包装

我们可以写一个transform_shape方法,专门用于几何形状变换,传入关键参数即可:

python 复制代码
from OCC.Core.gp import gp_Trsf, gp_Vec, gp_Pnt, gp_Dir, gp_Ax1, gp_Ax2
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_Transform
import math

def transform_shape(shape, mode, params):
    """
    通用几何变换工具函数
    :param shape: TopoDS_Shape
    :param mode: 变换类型 ["translate", "rotate", "scale", "mirror"]
    :param params: 参数字典
        - translate: {"vec": (x,y,z)}
        - rotate: {"axis_point": (x,y,z), "axis_dir": (dx,dy,dz), "angle": deg}
        - scale: {"center": (x,y,z), "factor": f}
        - mirror:
            {"point": (x,y,z)}                             # 点对称
            {"axis_point": (x,y,z), "axis_dir": (dx,dy,dz)} # 轴对称
            {"plane_point": (x,y,z), "plane_dir": (dx,dy,dz)} # 平面对称
    :return: 新的 TopoDS_Shape
    """
    trsf = gp_Trsf()
    
    if mode == "translate":
        v = gp_Vec(*params["vec"])
        trsf.SetTranslation(v)

    elif mode == "rotate":
        p = gp_Pnt(*params["axis_point"])
        d = gp_Dir(*params["axis_dir"])
        axis = gp_Ax1(p, d)
        angle = math.radians(params["angle"])
        trsf.SetRotation(axis, angle)

    elif mode == "scale":
        p = gp_Pnt(*params["center"])
        f = params["factor"]
        trsf.SetScale(p, f)

    elif mode == "mirror":
        if "point" in params:   # 点对称
            trsf.SetMirror(gp_Pnt(*params["point"]))
        elif "axis_point" in params and "axis_dir" in params: # 轴对称
            p = gp_Pnt(*params["axis_point"])
            d = gp_Dir(*params["axis_dir"])
            trsf.SetMirror(gp_Ax1(p, d))
        elif "plane_point" in params and "plane_dir" in params: # 平面对称
            p = gp_Pnt(*params["plane_point"])
            d = gp_Dir(*params["plane_dir"])
            trsf.SetMirror(gp_Ax2(p, d))
        else:
            raise ValueError("Invalid mirror parameters")

    else:
        raise ValueError("Unknown transformation mode: " + str(mode))

    return BRepBuilderAPI_Transform(shape, trsf).Shape()

然后直接一行代码调用即可:

python 复制代码
from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox
from OCC.Display.SimpleGui import init_display
import OCC.Core.Quantity as Q
from transform_shape import transform_shape

display, start_display, *_ = init_display()

box = BRepPrimAPI_MakeBox(10,20,30).Shape()
display.DisplayShape(box, color=Q.Quantity_NOC_BLUE3, transparency=0.5, update=False)

# 平移
# box_t = transform_shape(box, "translate", {"vec": (40,0,0)})
# display.DisplayShape(box_t, color=Q.Quantity_NOC_GRAY31, transparency=0.5, update=False)

# # 旋转
# box_r = transform_shape(box, "rotate",
#                         {"axis_point": (0,0,0), "axis_dir": (0,0,1), "angle": 45})
# display.DisplayShape(box_r, color=Q.Quantity_NOC_GRAY31, update=False)

# # 缩放
# box_s = transform_shape(box, "scale", {"center": (0,0,0), "factor": 0.5})
# display.DisplayShape(box_s, color=Q.Quantity_NOC_GRAY31, update=False)

# # 镜像(XY 平面)
box_m = transform_shape(box, "mirror", {"plane_point": (0,0,0), "plane_dir": (0,0,1)})
display.DisplayShape(box_m, color=Q.Quantity_NOC_GRAY31, update=False)

display.FitAll()
start_display()