znlgis 博客

GIS开发与技术分享 — GDAL · GeoServer · PostGIS · QGIS · OpenLayers · Cesium · FreeCAD · NPOI

第07章:高级建模技巧

7.1 参数化设计

7.1.1 参数化设计概述

参数化设计是CadQuery的核心优势之一。通过将尺寸和几何关系定义为参数,可以轻松生成不同规格的模型。

参数化设计的优点:

  • 快速生成变体模型
  • 易于修改和维护
  • 支持批量生产
  • 便于设计优化

7.1.2 基本参数化

import cadquery as cq

# 定义参数
length = 80.0
width = 60.0
height = 20.0
hole_diameter = 15.0
fillet_radius = 3.0
wall_thickness = 3.0

# 使用参数创建模型
result = (
    cq.Workplane("XY")
    .box(length, width, height)
    .faces(">Z")
    .shell(-wall_thickness)
    .faces(">Z")
    .workplane()
    .hole(hole_diameter)
    .edges("|Z")
    .fillet(fillet_radius)
)

cq.exporters.export(result, "parametric_box.step")

7.1.3 参数化函数

import cadquery as cq

def make_enclosure(length, width, height, wall=2.0, corner_radius=3.0):
    """
    创建参数化外壳
    
    Args:
        length: 长度
        width: 宽度
        height: 高度
        wall: 壁厚
        corner_radius: 圆角半径
    """
    result = (
        cq.Workplane("XY")
        .box(length, width, height)
        .edges("|Z")
        .fillet(corner_radius)
        .faces(">Z")
        .shell(-wall)
    )
    return result

# 生成不同尺寸的外壳
small = make_enclosure(50, 30, 20)
medium = make_enclosure(80, 50, 30, wall=3.0)
large = make_enclosure(120, 80, 40, wall=4.0, corner_radius=5.0)

cq.exporters.export(small, "enclosure_small.step")
cq.exporters.export(medium, "enclosure_medium.step")
cq.exporters.export(large, "enclosure_large.step")

7.1.4 参数关联

import cadquery as cq

# 参数定义
bolt_diameter = 8
bolt_spacing = 30
num_bolts_x = 4
num_bolts_y = 3

# 派生参数(自动计算)
plate_length = bolt_spacing * (num_bolts_x - 1) + bolt_diameter * 4
plate_width = bolt_spacing * (num_bolts_y - 1) + bolt_diameter * 4
plate_thickness = bolt_diameter * 0.5
edge_distance = bolt_diameter * 2

# 创建带关联参数的安装板
result = (
    cq.Workplane("XY")
    .box(plate_length, plate_width, plate_thickness)
    .faces(">Z")
    .workplane()
    .rarray(bolt_spacing, bolt_spacing, num_bolts_x, num_bolts_y)
    .cboreHole(bolt_diameter, bolt_diameter * 1.8, plate_thickness * 0.3)
    .edges()
    .fillet(plate_thickness * 0.2)
)

cq.exporters.export(result, "mounting_plate.step")

7.1.5 配置驱动设计

import cadquery as cq

# 配置字典
configs = {
    "M6": {
        "thread_diameter": 6,
        "head_diameter": 10,
        "head_height": 4,
        "length": 20
    },
    "M8": {
        "thread_diameter": 8,
        "head_diameter": 13,
        "head_height": 5,
        "length": 25
    },
    "M10": {
        "thread_diameter": 10,
        "head_diameter": 16,
        "head_height": 6.4,
        "length": 30
    }
}

def make_hex_bolt(config):
    """根据配置创建六角螺栓"""
    td = config["thread_diameter"]
    hd = config["head_diameter"]
    hh = config["head_height"]
    length = config["length"]
    
    return (
        cq.Workplane("XY")
        .polygon(6, hd)
        .extrude(hh)
        .faces("<Z")
        .workplane()
        .circle(td / 2)
        .extrude(-length)
        .edges(">Z")
        .chamfer(hh * 0.1)
    )

# 生成不同规格的螺栓
for name, config in configs.items():
    bolt = make_hex_bolt(config)
    cq.exporters.export(bolt, f"bolt_{name}.step")

7.2 复杂曲面建模

7.2.1 样条曲面

import cadquery as cq
import math

# 创建样条曲线并放样
points1 = [(0, 0), (20, 10), (40, 5), (60, 15), (80, 0)]
points2 = [(0, 0), (20, -10), (40, -5), (60, -15), (80, 0)]

result = (
    cq.Workplane("XZ")
    .spline(points1)
    .close()
    .workplane(offset=30)
    .spline(points2)
    .close()
    .loft()
)

cq.exporters.export(result, "spline_surface.step")

7.2.2 旋转曲面

import cadquery as cq
import math

def vase_profile(height, base_radius, neck_radius, belly_radius):
    """创建花瓶轮廓"""
    points = []
    segments = 50
    
    for i in range(segments + 1):
        t = i / segments
        h = t * height
        
        # 使用正弦函数创建曲线轮廓
        if t < 0.3:
            r = base_radius + (belly_radius - base_radius) * math.sin(t / 0.3 * math.pi / 2)
        elif t < 0.7:
            r = belly_radius * (1 + 0.1 * math.sin((t - 0.3) / 0.4 * 2 * math.pi))
        else:
            r = belly_radius + (neck_radius - belly_radius) * math.sin((t - 0.7) / 0.3 * math.pi / 2)
        
        points.append((r, h))
    
    return points

# 创建花瓶
profile = vase_profile(100, 15, 10, 30)
vase = (
    cq.Workplane("XZ")
    .moveTo(0, 0)
    .spline(profile)
    .lineTo(0, 100)
    .close()
    .revolve(360, (0, 0, 0), (0, 1, 0))
    .shell(-2)  # 创建空心
)

cq.exporters.export(vase, "vase.step")

7.2.3 扫略曲面

import cadquery as cq
import math

# 创建螺旋路径
def helix_path(radius, pitch, turns):
    points = []
    segments = int(turns * 36)
    
    for i in range(segments + 1):
        angle = 2 * math.pi * i / 36
        x = radius * math.cos(angle)
        y = radius * math.sin(angle)
        z = pitch * i / 36
        points.append((x, y, z))
    
    return points

# 使用内置的螺旋线
helix = cq.Wire.makeHelix(pitch=10, height=80, radius=25)

# 创建截面
# 异形截面
profile = (
    cq.Workplane("XY")
    .ellipse(5, 3)
)

# 沿螺旋线扫略
result = profile.sweep(helix, isFrenet=True)

cq.exporters.export(result, "helix_sweep.step")

7.2.4 放样曲面进阶

import cadquery as cq
from cadquery import Sketch

# 多截面放样
s1 = Sketch().rect(40, 40).vertices().fillet(5)
s2 = Sketch().circle(15)
s3 = Sketch().polygon(8, 20).vertices().fillet(2)
s4 = Sketch().rect(30, 30).vertices().fillet(8)

result = (
    cq.Workplane("XY")
    .placeSketch(s1)
    .workplane(offset=20)
    .placeSketch(s2)
    .workplane(offset=20)
    .placeSketch(s3)
    .workplane(offset=20)
    .placeSketch(s4)
    .loft()
)

cq.exporters.export(result, "multi_loft.step")

7.3 图案和阵列

7.3.1 矩形阵列

import cadquery as cq

# 使用rarray创建矩形阵列
result = (
    cq.Workplane("XY")
    .box(100, 80, 10)
    .faces(">Z")
    .workplane()
    .rarray(15, 15, 5, 4)  # x间距, y间距, x数量, y数量
    .hole(5)
)

cq.exporters.export(result, "rect_array.step")

7.3.2 极坐标阵列

import cadquery as cq

# 圆周阵列
result = (
    cq.Workplane("XY")
    .circle(50)
    .extrude(10)
    .faces(">Z")
    .workplane()
    .polarArray(35, 0, 360, 8)  # 半径, 起始角, 结束角, 数量
    .hole(8)
    .faces(">Z")
    .workplane()
    .hole(20)  # 中心孔
)

cq.exporters.export(result, "polar_array.step")

7.3.3 自定义点阵列

import cadquery as cq
import math

# 自定义点位置
custom_points = [
    (0, 0),
    (30, 0),
    (15, 26),  # 三角形布局
    (-30, 15),
    (30, 30),
]

result = (
    cq.Workplane("XY")
    .box(100, 80, 10)
    .faces(">Z")
    .workplane()
    .pushPoints(custom_points)
    .hole(8)
)

cq.exporters.export(result, "custom_array.step")

7.3.4 沿路径阵列

import cadquery as cq
import math

# 沿曲线分布
def points_along_curve(num_points):
    points = []
    for i in range(num_points):
        t = i / (num_points - 1)
        x = 80 * t - 40
        y = 20 * math.sin(t * 2 * math.pi)
        points.append((x, y))
    return points

# 创建基板
base = cq.Workplane("XY").box(100, 60, 5)

# 沿曲线放置凸台
curve_points = points_along_curve(10)
result = (
    base
    .faces(">Z")
    .workplane()
    .pushPoints(curve_points)
    .circle(3)
    .extrude(8)
)

cq.exporters.export(result, "curve_array.step")

7.4 镜像与对称

7.4.1 平面镜像

import cadquery as cq

# 创建半边模型
half = (
    cq.Workplane("XY")
    .moveTo(0, 0)
    .lineTo(30, 0)
    .lineTo(30, 20)
    .lineTo(20, 20)
    .lineTo(20, 10)
    .lineTo(0, 10)
    .close()
    .extrude(10)
)

# 镜像得到完整模型
result = half.mirror("XZ")

# 或者使用union合并原始和镜像
full = half.union(half.mirror("XZ"))

cq.exporters.export(full, "mirrored.step")

7.4.2 多轴对称

import cadquery as cq

# 创建四分之一模型
quarter = (
    cq.Workplane("XY")
    .moveTo(0, 0)
    .lineTo(20, 0)
    .threePointArc((28, 8), (20, 20))
    .lineTo(0, 20)
    .close()
    .extrude(10)
)

# X和Y方向都镜像
half = quarter.union(quarter.mirror("YZ"))
full = half.union(half.mirror("XZ"))

cq.exporters.export(full, "quad_symmetric.step")

7.4.3 旋转对称

import cadquery as cq
import math

# 创建一个扇区
sector = (
    cq.Workplane("XY")
    .moveTo(0, 0)
    .lineTo(30, 0)
    .threePointArc((30 * math.cos(math.pi/3), 30 * math.sin(math.pi/3)), 
                   (30 * math.cos(math.pi/6), 30 * math.sin(math.pi/6)))
    .lineTo(0, 0)
    .close()
    .extrude(5)
)

# 旋转复制
result = sector
for i in range(1, 6):
    angle = i * 60
    rotated = sector.rotate((0, 0, 0), (0, 0, 1), angle)
    result = result.union(rotated)

cq.exporters.export(result, "rotational_symmetric.step")

7.5 布尔运算进阶

7.5.1 复杂布尔组合

import cadquery as cq

# 创建基础形状
box = cq.Workplane("XY").box(50, 50, 30)
cylinder = cq.Workplane("XY").cylinder(40, 15)
sphere = cq.Workplane("XY").sphere(20)

# 复杂布尔运算
# box和cylinder的并集,减去sphere
result = box.union(cylinder).cut(sphere)

cq.exporters.export(result, "complex_boolean.step")

7.5.2 交集应用

import cadquery as cq

# 使用交集创建特殊形状
# 两个圆柱的交集(双曲抛物面)
cyl1 = cq.Workplane("XY").cylinder(60, 25)
cyl2 = cq.Workplane("XZ").cylinder(60, 25)

result = cyl1.intersect(cyl2)

cq.exporters.export(result, "cylinder_intersect.step")

7.5.3 条件布尔运算

import cadquery as cq

def make_part_with_holes(add_holes=True, num_holes=4):
    """根据条件添加特征"""
    result = (
        cq.Workplane("XY")
        .box(80, 60, 10)
        .edges("|Z")
        .fillet(5)
    )
    
    if add_holes and num_holes > 0:
        result = (
            result
            .faces(">Z")
            .workplane()
            .rarray(60 / (num_holes - 1), 40, num_holes, 2)
            .hole(5)
        )
    
    return result

# 生成不同版本
part_no_holes = make_part_with_holes(add_holes=False)
part_4_holes = make_part_with_holes(num_holes=4)
part_6_holes = make_part_with_holes(num_holes=6)

7.6 特征识别与操作

7.6.1 面积筛选

import cadquery as cq

# 创建模型
model = (
    cq.Workplane("XY")
    .box(50, 30, 20)
    .faces(">Z")
    .workplane()
    .circle(10)
    .extrude(10)
)

# 获取所有面并按面积排序
faces = model.faces().vals()
face_areas = [(f, f.Area()) for f in faces]
face_areas.sort(key=lambda x: x[1], reverse=True)

print("面积从大到小:")
for f, area in face_areas[:5]:
    print(f"  {area:.2f} mm²")

7.6.2 边长筛选

import cadquery as cq

# 创建模型
model = cq.Workplane("XY").box(50, 30, 20)

# 获取所有边
edges = model.edges().vals()

# 按长度筛选
long_edges = [e for e in edges if e.Length() > 25]
print(f"长度>25mm的边数: {len(long_edges)}")

7.6.3 几何中心定位

import cadquery as cq

# 创建模型
model = (
    cq.Workplane("XY")
    .box(50, 30, 20)
    .faces(">Z")
    .workplane()
    .rect(30, 15)
    .cutBlind(-10)
)

# 获取边界框信息
bb = model.val().BoundingBox()
center = ((bb.xmin + bb.xmax) / 2, 
          (bb.ymin + bb.ymax) / 2, 
          (bb.zmin + bb.zmax) / 2)

print(f"模型中心: {center}")
print(f"尺寸: {bb.xmax - bb.xmin} x {bb.ymax - bb.ymin} x {bb.zmax - bb.zmin}")

7.7 性能优化

7.7.1 减少布尔运算

import cadquery as cq

# 低效:多次布尔运算
# def inefficient():
#     result = cq.Workplane("XY").box(100, 100, 10)
#     for i in range(10):
#         for j in range(10):
#             hole = cq.Workplane("XY").center(i*10, j*10).circle(3).extrude(15)
#             result = result.cut(hole)
#     return result

# 高效:使用阵列一次性操作
def efficient():
    result = (
        cq.Workplane("XY")
        .box(100, 100, 10)
        .faces(">Z")
        .workplane()
        .rarray(10, 10, 10, 10)
        .hole(6)
    )
    return result

model = efficient()
cq.exporters.export(model, "optimized_holes.step")

7.7.2 简化几何

import cadquery as cq

# 使用合理的精度
# 对于大型模型,可以降低某些特征的精度

def make_model(fillet_segments=20):
    """控制圆角分段数"""
    result = (
        cq.Workplane("XY")
        .box(50, 50, 20)
        .edges()
        .fillet(3)
    )
    return result

model = make_model()

7.7.3 延迟求值

import cadquery as cq

# 构建操作链而不立即求值
operations = [
    lambda wp: wp.box(50, 50, 20),
    lambda wp: wp.faces(">Z").workplane().hole(10),
    lambda wp: wp.edges("|Z").fillet(2),
]

# 按需执行
def build_model(ops):
    result = cq.Workplane("XY")
    for op in ops:
        result = op(result)
    return result

model = build_model(operations)

7.8 调试技巧

7.8.1 中间结果可视化

import cadquery as cq

# 在CQ-editor中分步显示
# step1 = cq.Workplane("XY").box(50, 50, 20)
# show_object(step1, name="step1_box", options={"color": "blue"})

# step2 = step1.faces(">Z").workplane().hole(10)
# show_object(step2, name="step2_hole", options={"color": "green"})

# step3 = step2.edges("|Z").fillet(3)
# show_object(step3, name="step3_fillet", options={"color": "red"})

7.8.2 几何信息打印

import cadquery as cq

def debug_model(model, name="model"):
    """打印模型的详细信息"""
    print(f"\n=== {name} 信息 ===")
    
    # 边界框
    bb = model.val().BoundingBox()
    print(f"边界框: ({bb.xmin:.2f}, {bb.ymin:.2f}, {bb.zmin:.2f}) - "
          f"({bb.xmax:.2f}, {bb.ymax:.2f}, {bb.zmax:.2f})")
    
    # 体积
    vol = model.val().Volume()
    print(f"体积: {vol:.2f} mm³")
    
    # 面数和边数
    num_faces = len(model.faces().vals())
    num_edges = len(model.edges().vals())
    print(f"面数: {num_faces}")
    print(f"边数: {num_edges}")

# 使用
model = cq.Workplane("XY").box(30, 20, 10)
debug_model(model, "测试盒子")

7.8.3 选择器验证

import cadquery as cq

model = cq.Workplane("XY").box(30, 20, 10)

# 验证选择器
def test_selector(model, selector_str, element_type="faces"):
    """测试选择器是否正确选择元素"""
    try:
        if element_type == "faces":
            selected = model.faces(selector_str)
        elif element_type == "edges":
            selected = model.edges(selector_str)
        elif element_type == "vertices":
            selected = model.vertices(selector_str)
        
        count = len(selected.vals())
        print(f"选择器 '{selector_str}' ({element_type}): 选中 {count} 个元素")
        return True
    except Exception as e:
        print(f"选择器 '{selector_str}' 错误: {e}")
        return False

# 测试各种选择器
test_selector(model, ">Z")
test_selector(model, "<Z")
test_selector(model, "|Z", "edges")
test_selector(model, "#Z", "edges")

7.9 自由函数API形状操作

第1章介绍了自由函数(Free Function)API 的基本概念和 cq.cutcq.fusecq.intersect 等基础操作。本节进一步介绍 v2.6+ 引入的形状级操作方法,以及更丰富的自由函数应用场景。

7.9.1 自由函数布尔运算

与 Workplane 方法链不同,自由函数直接操作 Shape 对象,适合在非 Workplane 上下文中组合已有实体:

import cadquery as cq

# 创建两个独立形状
box = cq.Workplane("XY").box(30, 30, 20).val()
cyl = cq.Workplane("XY").cylinder(12, 25).val()

# 自由函数版布尔运算
union = cq.fuse(box, cyl)       # 并集
diff = cq.cut(box, cyl)          # 差集(box减去cyl)
inter = cq.intersect(box, cyl)   # 交集

# 将结果包装回 Workplane 以便导出
cq.exporters.export(cq.Workplane("XY").newObject([union]), "ff_union.step")
cq.exporters.export(cq.Workplane("XY").newObject([diff]), "ff_diff.step")
方法链 自由函数 说明
wp1.union(wp2) cq.fuse(shape1, shape2) 布尔并集
wp1.cut(wp2) cq.cut(shape1, shape2) 布尔差集
wp1.intersect(wp2) cq.intersect(shape1, shape2) 布尔交集

7.9.2 形状级移除:Shape.remove()

v2.6+ 引入的 Shape.remove() 方法直接在形状层面执行切除操作,无需 Workplane 上下文:

import cadquery as cq

# 创建底板
plate = cq.Workplane("XY").box(50, 40, 10).val()

# 在形状级别切除孔洞
hole = cq.Workplane("XY").workplane(offset=15).cylinder(4, 15).val()
result = plate.remove(hole)

cq.exporters.export(cq.Workplane("XY").newObject([result]), "shape_remove.step")

7.9.3 面沿法向拉伸:Face.extend()

Face.extend(amount) 将单个面沿其法线方向拉伸指定距离,返回拉伸后的实体。这一操作在需要对面进行局部增厚时非常有用:

import cadquery as cq

# 创建基础块并提取顶面
block = cq.Workplane("XY").box(30, 30, 10)
top_face = block.faces(">Z").val()

# 将顶面沿法向(Z轴正方向)拉伸5mm
extended = top_face.extend(5)

# 与原块合并
result = block.union(cq.Workplane("XY").newObject([extended]))

cq.exporters.export(result, "face_extend.step")

7.9.4 实体内部挖腔:Solid.addCavity()

Solid.addCavity(cavity) 从一个实体内挖去另一个实体,形成空腔结构:

import cadquery as cq

# 创建外壳实体
outer = cq.Workplane("XY").box(40, 40, 30).val()

# 创建内部空腔形状
inner = cq.Workplane("XY").box(30, 30, 25).val()

# 挖腔
hollow = outer.addCavity(inner)

cq.exporters.export(cq.Workplane("XY").newObject([hollow]), "cavity.step")

7.9.5 缝合操作:cq.stitch()

cq.stitch() 将一组共边的面缝合为壳体(Shell)或实体(Solid)。适用于从零散面片构建模型或修复非流形几何:

import cadquery as cq

# 创建盒子的六个面
box = cq.Workplane("XY").box(30, 30, 20)
faces = box.faces().vals()

# 将所有面重新缝合为壳
shell = cq.stitch(faces)

# 从壳生成实体
solid = cq.Workplane("XY").newObject([cq.Solid.makeSolid(shell)])

cq.exporters.export(solid, "stitched.step")

7.10 选择器与形状集合操作

v2.5+ 版本增强了选择器返回的形状集合,使其支持类似 Python 列表的函数式遍历操作。这些操作让筛选和批量处理形状变得简洁高效。

7.10.1 按索引访问:[]

形状集合支持下标索引访问,可以直接获取第N个形状:

import cadquery as cq

model = cq.Workplane("XY").box(50, 30, 20)
faces = model.faces().vals()

# 直接访问第0个面
first_face = faces[0]
print(f"第0个面面积: {first_face.Area():.2f} mm²")

# 访问前三个面
first_three = faces[:3]
print(f"前三个面总面积: {sum(f.Area() for f in first_three):.2f} mm²")

7.10.2 按条件筛选:filter()

使用列表推导式按自定义条件筛选形状,返回满足条件的新集合:

import cadquery as cq

model = cq.Workplane("XY").box(50, 30, 20)

# 筛选面积大于500的面
large_faces = [f for f in model.faces().vals() if f.Area() > 500]

print("大面积面:")
for f in large_faces:
    print(f"  面积: {f.Area():.2f} mm²")

# 筛选长度大于30的边
long_edges = [e for e in model.edges().vals() if e.Length() > 30]
print(f"长度>30mm的边: {len(long_edges)} 条")

7.10.3 映射操作:map()

对形状集合中的每个元素应用操作,返回结果集合:

import cadquery as cq

model = cq.Workplane("XY").box(50, 30, 20)

# 获取所有面的中心点坐标
centers = [f.Center() for f in model.faces().vals()]

for i, c in enumerate(centers):
    print(f"面{i} 中心: ({c.x:.1f}, {c.y:.1f}, {c.z:.1f})")

7.10.4 排序操作:sort()

按指定属性对形状集合排序:

import cadquery as cq

model = cq.Workplane("XY").box(50, 30, 20)

# 按面积从小到大排序
faces = model.faces().vals()
sorted_faces = sorted(faces, key=lambda f: f.Area())

print("面按面积升序:")
for f in sorted_faces:
    print(f"  {f.Area():.2f} mm²")

7.10.5 批量操作:apply()

对集合中的每个形状应用选择器操作,实现批量特征提取:

import cadquery as cq

model = (
    cq.Workplane("XY")
    .box(50, 30, 20)
    .faces(">Z")
    .workplane()
    .rect(30, 15)
    .cutBlind(-10)
)

# 获取每个面中的所有边
all_faces = model.faces().vals()
for i, face in enumerate(all_faces):
    edges = face.Edges()
    print(f"面{i} 包含 {len(edges)} 条边")

7.10.6 方法调用:invoke()

在形状集合的每个元素上直接调用方法:

import cadquery as cq

model = cq.Workplane("XY").box(50, 30, 20)

# 获取所有面的类型信息
for face in model.faces().vals():
    surf_type = type(face).__name__
    print(f"面类型: {surf_type}, 面积: {face.Area():.2f} mm²")

7.11 本章小结

本章介绍了CadQuery的高级建模技巧:

  1. 参数化设计
    • 参数定义和关联
    • 参数化函数
    • 配置驱动设计
  2. 复杂曲面
    • 样条曲面
    • 旋转曲面
    • 扫略和放样
  3. 图案和阵列
    • 矩形阵列
    • 极坐标阵列
    • 自定义阵列
  4. 镜像与对称
    • 平面镜像
    • 多轴对称
    • 旋转对称
  5. 布尔运算进阶
    • 复杂组合
    • 条件布尔
  6. 特征识别与操作
    • 面积与边长筛选
    • 几何中心定位
  7. 性能优化
    • 减少布尔运算
    • 简化几何
  8. 调试技巧
    • 中间结果可视化
    • 几何信息打印
  9. 自由函数API形状操作
    • 自由函数布尔运算
    • 形状级移除与拉伸
    • 内部挖腔与缝合
  10. 选择器与形状集合操作
    • 按条件筛选与映射
    • 排序与索引访问
    • 批量操作

通过本章学习,您应该能够:

  • 创建参数化的复杂模型
  • 使用高级曲面建模技术
  • 高效地创建图案和阵列
  • 使用自由函数API进行形状级操作
  • 灵活运用选择器与形状集合操作
  • 优化模型性能
  • 有效调试CadQuery脚本

下一章我们将进入二次开发部分,学习如何扩展CadQuery功能。


← 上一章 目录 下一章 →