Python_occ 学习记录 | 阵列
occ没有内置的阵列方法,用户可以在几何变换(平移、旋转)的基础上实现阵列操作,本质上计算出物体的位置,然后进行位置变换,复制出一个新的物体的过程。
线性阵列
def linear_array(shape: TopoDS_Shape,count: int,delta: Tuple[float, float, float],include_original: bool = True,
) -> Tuple[List[TopoDS_Shape], TopoDS_Compound]:"""线性阵列:沿 (dx, dy, dz) 方向等距平移复制。:param shape: 基准 shape:param count: 实例个数(>=1):param delta: 相邻两实例的位移 (dx, dy, dz):param include_original: 是否包含原件:return: (instances, compound)"""if count < 1:raise ValueError("count must be >= 1")instances: List[TopoDS_Shape] = []start_idx = 0if include_original:instances.append(shape)start_idx = 1# 逐个生成副本,循环+平移for i in range(start_idx, count):vec = (delta[0] * i, delta[1] * i, delta[2] * i)inst = transform_shape(shape, "translate", {"vec": vec})instances.append(inst)comp = _make_compound(instances)print(f"[LinearArray] Generated {len(instances)} instances.")return instances, comp
网格阵列
def grid_array(shape: TopoDS_Shape,rows: int,cols: int,dx: float,dy: float,include_original: bool = True,
) -> Tuple[List[TopoDS_Shape], TopoDS_Compound]:"""网格阵列(Grid Array):在 XY 平面内排布 rows × cols 个实例:param shape: 基准 shape:param rows: 行数 (>=1):param cols: 列数 (>=1):param dx: X 方向间距:param dy: Y 方向间距:param include_original: 是否包含原件 (默认 True):return: (instances, compound)"""if rows < 1 or cols < 1:raise ValueError("rows and cols must be >= 1")instances: List[TopoDS_Shape] = []# 按行、列双重循环+平移for i in range(rows):for j in range(cols):if i == 0 and j == 0 and include_original:instances.append(shape)continuevec = (dx * j, dy * i, 0.0)inst = transform_shape(shape, "translate", {"vec": vec})instances.append(inst)comp = _make_compound(instances)print(f"[GridArray] Generated {len(instances)} instances "f"({rows} rows × {cols} cols).")return instances, comp
环形阵列
def circular_array(shape: TopoDS_Shape,count: int,axis_point: Tuple[float, float, float],axis_dir: Tuple[float, float, float],total_angle_deg: float = 360.0,include_original: bool = True,start_angle_deg: float = 0.0,
) -> Tuple[List[TopoDS_Shape], TopoDS_Compound]:"""圆形阵列:绕指定轴等角度旋转复制。:param shape: 基准 shape:param count: 实例个数(>=1):param axis_point: 旋转轴上一点 (x, y, z):param axis_dir: 旋转轴方向 (dx, dy, dz),将会单位化:param total_angle_deg: 总旋转角度,默认 360°:param include_original: 是否包含原件:param start_angle_deg: 起始角(度),默认 0°:return: (instances, compound)"""if count < 1:raise ValueError("count must be >= 1")instances: List[TopoDS_Shape] = []step = total_angle_deg / (count if include_original else max(count, 1))if include_original:# 起始角度的一个实例(可选)if abs(start_angle_deg) > 1e-12:inst0 = transform_shape(shape,"rotate",{"axis_point": axis_point,"axis_dir": axis_dir,"angle": start_angle_deg,},)instances.append(inst0)else:instances.append(shape)start_index = 1else:start_index = 0# 生成其余实例(循环+旋转)for i in range(start_index, count):ang = start_angle_deg + step * iinst = transform_shape(shape,"rotate",{"axis_point": axis_point,"axis_dir": axis_dir,"angle": ang,},)instances.append(inst)comp = _make_compound(instances)print(f"[CircularArray] Generated {len(instances)} instances, step={step:.6f} deg.")return instances, comp
完整代码
需要结合之前的几何变换代码from transform_shape import transform_shape
arrays.py
:
"""
阵列工具:线性阵列、圆形阵列、矩形阵列
"""
from typing import Iterable, List, Tuple
from OCC.Core.TopoDS import TopoDS_Shape
from OCC.Core.BRep import BRep_Builder
from OCC.Core.TopoDS import TopoDS_Compoundfrom transform_shape import transform_shapedef _make_compound(shapes: Iterable[TopoDS_Shape]) -> TopoDS_Compound:"""把一组形体打包成复合体,便于一次性显示或导出。"""# 装配comp = TopoDS_Compound()builder = BRep_Builder()builder.MakeCompound(comp)for s in shapes:builder.Add(comp, s)return compdef linear_array(shape: TopoDS_Shape,count: int,delta: Tuple[float, float, float],include_original: bool = True,
) -> Tuple[List[TopoDS_Shape], TopoDS_Compound]:"""线性阵列:沿 (dx, dy, dz) 方向等距平移复制。:param shape: 基准 shape:param count: 实例个数(>=1):param delta: 相邻两实例的位移 (dx, dy, dz):param include_original: 是否包含原件:return: (instances, compound)"""if count < 1:raise ValueError("count must be >= 1")instances: List[TopoDS_Shape] = []start_idx = 0if include_original:instances.append(shape)start_idx = 1# 逐个生成副本for i in range(start_idx, count):vec = (delta[0] * i, delta[1] * i, delta[2] * i)inst = transform_shape(shape, "translate", {"vec": vec})instances.append(inst)comp = _make_compound(instances)print(f"[LinearArray] Generated {len(instances)} instances.")return instances, compdef circular_array(shape: TopoDS_Shape,count: int,axis_point: Tuple[float, float, float],axis_dir: Tuple[float, float, float],total_angle_deg: float = 360.0,include_original: bool = True,start_angle_deg: float = 0.0,
) -> Tuple[List[TopoDS_Shape], TopoDS_Compound]:"""圆形阵列:绕指定轴等角度旋转复制。:param shape: 基准 shape:param count: 实例个数(>=1):param axis_point: 旋转轴上一点 (x, y, z):param axis_dir: 旋转轴方向 (dx, dy, dz),将会单位化:param total_angle_deg: 总旋转角度,默认 360°:param include_original: 是否包含原件:param start_angle_deg: 起始角(度),默认 0°:return: (instances, compound)"""if count < 1:raise ValueError("count must be >= 1")instances: List[TopoDS_Shape] = []step = total_angle_deg / (count if include_original else max(count, 1))if include_original:# 起始角度的一个实例(可选)if abs(start_angle_deg) > 1e-12:inst0 = transform_shape(shape,"rotate",{"axis_point": axis_point,"axis_dir": axis_dir,"angle": start_angle_deg,},)instances.append(inst0)else:instances.append(shape)start_index = 1else:start_index = 0# 生成其余实例for i in range(start_index, count):ang = start_angle_deg + step * iinst = transform_shape(shape,"rotate",{"axis_point": axis_point,"axis_dir": axis_dir,"angle": ang,},)instances.append(inst)comp = _make_compound(instances)print(f"[CircularArray] Generated {len(instances)} instances, step={step:.6f} deg.")return instances, compdef grid_array(shape: TopoDS_Shape,rows: int,cols: int,dx: float,dy: float,include_original: bool = True,
) -> Tuple[List[TopoDS_Shape], TopoDS_Compound]:"""网格阵列(Grid Array):在 XY 平面内排布 rows × cols 个实例:param shape: 基准 shape:param rows: 行数 (>=1):param cols: 列数 (>=1):param dx: X 方向间距:param dy: Y 方向间距:param include_original: 是否包含原件 (默认 True):return: (instances, compound)"""if rows < 1 or cols < 1:raise ValueError("rows and cols must be >= 1")instances: List[TopoDS_Shape] = []for i in range(rows):for j in range(cols):if i == 0 and j == 0 and include_original:instances.append(shape)continuevec = (dx * j, dy * i, 0.0)inst = transform_shape(shape, "translate", {"vec": vec})instances.append(inst)comp = _make_compound(instances)print(f"[GridArray] Generated {len(instances)} instances "f"({rows} rows × {cols} cols).")return instances, comp
主程序调用:
from OCC.Display.SimpleGui import init_display
from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox, BRepPrimAPI_MakeCylinder
from OCC.Core.gp import gp_Ax2, gp_Pnt, gp_Dir
import OCC.Core.Quantity as Qfrom arrays import linear_array, circular_array, grid_arraybox = BRepPrimAPI_MakeBox(6, 4, 3).Shape()ax2 = gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1))
cyl = BRepPrimAPI_MakeCylinder(ax2, 2.0, 6.0).Shape()# ---------- 线性阵列----------
box_list, box_comp = linear_array(box, # 阵列对象count=6, # 数量delta=(8.0, 0.0, 0.0), # 移动方向和增量include_original=True # 包含原对象
)# ---------- 圆形阵列 ----------
cyl_list, cyl_comp = circular_array(cyl, # 阵列对象count=8, # 数量axis_point=(30.0, 0.0, 0.0), # 旋转轴过此点axis_dir=(0.0, 0.0, 1.0), # 朝向 Z+total_angle_deg=360.0, # 旋转角度include_original=True, # 包含原对象start_angle_deg=0.0 # 起始相位
)# ---------- 网格阵列 ----------
_, grid_comp = grid_array(box, # 阵列对象rows=3, # 行数cols=4, # 列数dx=10, # 水平间距dy=8 # 垂直间距
)display, start_display, *_ = init_display()# 线性阵列
display.DisplayShape(box_comp, color=Q.Quantity_NOC_BLUE3, transparency=0.35, update=False)# 圆形阵列
display.DisplayShape(cyl_comp, color=Q.Quantity_NOC_CORAL, transparency=0.45, update=False)# 网格阵列
display.DisplayShape(grid_comp, color=Q.Quantity_NOC_RED, transparency=0.55, update=True)display.FitAll()
start_display()
其中返回的instances, comp
,分别是不同层次的结果:
instances
:List[TopoDS_Shape]
阵列中每一个独立的 shape 副本(单个零件/几何体),可以后续单独对阵列中某个零件进行操作comp
:把阵列里的所有副本组合成一个复合体