Cadquery平移箱体后切割报错:Null TopoDS_Shape对象问题求助
CadQuery多边形切割箱体问题解决方案
问题描述
我有一个从GDS文件单元中导入的多边形顶点列表(命名为polygons),尝试用这些形状对箱体执行全贯穿切割,遇到两个问题:
- 仅当挤出深度设置为
-(box_h + 0.0001)时切割才能完全贯穿箱体,若设为-box_h则无法切穿; - 将箱体平移至多边形中心后,执行
cut操作抛出「ValueError: Null TopoDS_Shape object」错误,虽然可视化装配体显示正常,但无法完成切割。
未平移箱体时的代码
cellCen = (0.5841240000000001, 0.8565) # 导入多边形单元的中心坐标 (box_w, box_l, box_h) = (1.968248, 2.513, 0.038) # 箱体尺寸 slab = cq.Workplane("front").box(box_w, box_l, box_h) pols = [slab.faces(">Z").workplane().polyline(polygons[i]).close().extrude(-(box_h + 0.0001), combine = False) for i in range(len(polygons))] p0 = pols[0] for i in range(len(pols)): # p0 成为要从箱体中切除的实体组 p0 = p0.union(pols[i], glue = True) slab.cut(p0)
平移箱体后的代码
slab = cq.Workplane("front").box(box_w, box_l, box_h).translate((cellCen[0]/2 , cellCen[1]/2 , 0)) # 将箱体平移至多边形单元的XY中心 pols = [slab.faces(">Z").workplane().polyline(polygons[i]).close().extrude(-(box_h + 0.0001), combine = False) for i in range(len(polygons))] p0 = pols[0] for i in range(len(pols)): # p0 成为要从箱体中切除的实体组 p0 = p0.union(pols[i], glue = True) slab.cut(p0)
可视化装配体代码
assy = cq.Assembly() assy = addToAssembly(assy, slab, "sub", color = cq.Color("Gold")) assy = addToAssembly(assy, (p0), "trench", color = cq.Color("black")) display(assy)
问题1分析与解决
原因
CadQuery依赖的OpenCASCADE引擎对共面边界的布尔运算存在精度阈值:当挤出深度恰好等于箱体高度box_h时,挤出体的底面与箱体底面完全共面,引擎会判定两个实体没有形成有效的"贯穿交集",导致切割操作不生效。
解决方法
使用cutThruAll()方法替代指定深度的extrude(),该方法会自动识别目标实体的范围并完全贯穿,彻底避免精度问题:
# 替换原挤出语句 pols = [slab.faces(">Z").workplane().polyline(polygons[i]).close().cutThruAll(combine=False) for i in range(len(polygons))]
若坚持使用extrude,可采用相对箱体尺寸的安全偏移(如-box_h * 1.001),但cutThruAll()是最简洁可靠的方案。
问题2分析与解决
原因
- 平移量计算错误:默认
box()创建的箱体中心在原点,要与多边形单元中心cellCen对齐,应平移至cellCen而非其半值,原代码的平移量导致箱体与多边形位置不匹配; - 工作平面坐标偏移:基于平移后的箱体表面创建工作平面,会使多边形顶点的坐标系跟随箱体偏移,导致部分多边形落在箱体外部,
union后生成无效的空形状,触发Null TopoDS_Shape错误。
解决方法
- 修正平移逻辑:将箱体中心准确移至多边形单元中心:
slab = cq.Workplane("front").box(box_w, box_l, box_h).translate((cellCen[0], cellCen[1], 0))
- 使用全局坐标系创建多边形:直接基于全局XY平面构建多边形,确保坐标与导入的
polygons匹配:
pols = [cq.Workplane("XY").polyline(polygons[i]).close().cutThruAll(combine=False) for i in range(len(polygons))]
- 过滤无效实体:在
union前检查每个挤出体的有效性,跳过空形状:
p0 = None for pol in pols: if not pol.val().Shape().IsNull(): if p0 is None: p0 = pol else: p0 = p0.union(pol, glue=True) # 仅当p0有效时执行切割 if p0 is not None: slab = slab.cut(p0)
内容的提问来源于stack exchange,提问作者Shrinivas Ganti
相关产品推荐
相关产品推荐

