阵列¶
约 183 个字 348 行代码 3 张图片 预计阅读时间 5 分钟
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 = 0
if 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)
continue
vec = (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 = 1
else:
start_index = 0
# 生成其余实例(循环+旋转)
for i in range(start_index, count):
ang = start_angle_deg + step * i
inst = 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_Compound
from transform_shape import transform_shape
def _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 comp
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 = 0
if 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 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 = 1
else:
start_index = 0
# 生成其余实例
for i in range(start_index, count):
ang = start_angle_deg + step * i
inst = 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
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)
continue
vec = (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 Q
from arrays import linear_array, circular_array, grid_array
box = 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
:把阵列里的所有副本组合成一个复合体