• 基于约束的装配设计【CadQuery】


    本教程介绍在CadQuery中如何使用装配约束功能来构建逼真的模型,我们将组装一个由 20x20 V 型槽型材制成的门组件。
    在这里插入图片描述

    1、定义参数

    我们希望从定义模型参数开始,以便以后可以轻松更改尺寸:

    import cadquery as cq
    
    # Parameters
    H = 400
    W = 200
    D = 350
    
    PROFILE = cq.importers.importDXF("vslot-2020_1.dxf").wires()
    
    SLOT_D = 5
    PANEL_T = 3
    
    HANDLE_D = 20
    HANDLE_L = 50
    HANDLE_W = 4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    值得注意的是,v 槽轮廓是从 DXF 文件导入的。 这样就很容易更换为其他铝型材,例如博世或其他供应商提供的 DXF 文件。

    2、定义可重用组件

    接下来我们要定义根据指定参数生成装配组件的函数。

    def make_vslot(l):
    
        return PROFILE.toPending().extrude(l)
    
    
    def make_connector():
    
        rv = (
            cq.Workplane()
            .box(20, 20, 20)
            .faces("X").tag("X").end()
        rv.faces(">Z").tag("Z").end()
    
        return rv
    
    
    def make_panel(w, h, t, cutout):
    
        rv = (
            cq.Workplane("XZ")
            .rect(w, h)
            .extrude(t)
            .faces(">Y")
            .vertices()
            .rect(2*cutout,2*cutout)
            .cutThruAll()
            .faces("Y").edges("%CIRCLE").edges(">Z").tag("hole1")
        rv.faces(">Y").edges("%CIRCLE").edges("Y").tag("mate1")
        rv.faces("
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    3、初始装配

    接下来我们要实例化所有组件并将它们添加到组件中。

    # define the elements
    door = (
        cq.Assembly()
        .add(make_vslot(H), name="left")
        .add(make_vslot(H), name="right")
        .add(make_vslot(W), name="top")
        .add(make_vslot(W), name="bottom")
        .add(make_connector(), name="con_tl", color=cq.Color("black"))
        .add(make_connector(), name="con_tr", color=cq.Color("black"))
        .add(make_connector(), name="con_bl", color=cq.Color("black"))
        .add(make_connector(), name="con_br", color=cq.Color("black"))
        .add(
            make_panel(W + SLOT_D, H + SLOT_D, PANEL_T, SLOT_D),
            name="panel",
            color=cq.Color(0, 0, 1, 0.2),
        )
        .add(
            make_handle(HANDLE_D, HANDLE_L, HANDLE_W),
            name="handle",
            color=cq.Color("yellow"),
        )
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    4、约束定义

    然后我们要定义所有的约束:

    # define the constraints
    (
        door
        # left profile
        .constrain("left@faces@Z", "con_tl?Z", "Plane")
        .constrain("left@faces@Y", "Axis")
        # bottom
        .constrain("bottom@faces@Y", "Axis")
        .constrain("bottom@faces@>Z", "con_bl?X", "Plane")
        # right connectors
        .constrain("top@faces@>Z", "con_tr@faces@>X", "Plane")
        .constrain("bottom@faces@X", "Plane")
        .constrain("left@faces@>Z", "con_tr?Z", "Axis")
        .constrain("left@faces@Z", "con_tr@faces@>Z", "Plane")
        .constrain("right@faces@X[-4]", "panel@faces@Z", "panel@faces@>Z", "Axis")
        # handle
        .constrain("panel?hole1", "handle?mate1", "Plane")
        .constrain("panel?hole2", "handle?mate2", "Point")
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    如果你需要做一些基于字符串的选择器不可能做的不寻常的事情,例如使用 cadquery.selectors.BoxSelector 或用户定义的选择器类,可以直接将 cadquery.Shape 对象传递给 cadquery.Assembly.constrain( ) 方法。 例如,上面的

    .constrain('part1@faces@>Z','part3@faces@
    • 1

    等效于:

    .constrain('part1',part1.faces('>z').val(),'part3',part3.faces('

此方法需要一个 cadquery.Shape 对象,因此请记住使用 cadquery.Workplane.val() 方法传递单个 cadquery.Shape 而不是整个 cadquery.Workplane 对象。

5、最终结果

下面是完整的代码,包括最后的求解步骤。
在这里插入图片描述

import cadquery as cq

# Parameters
H = 400
W = 200
D = 350

PROFILE = cq.importers.importDXF("vslot-2020_1.dxf").wires()

SLOT_D = 6
PANEL_T = 3

HANDLE_D = 20
HANDLE_L = 50
HANDLE_W = 4


def make_vslot(l):

    return PROFILE.toPending().extrude(l)


def make_connector():

    rv = (
        cq.Workplane()
        .box(20, 20, 20)
        .faces("X").tag("X").end()
    rv.faces(">Z").tag("Z").end()

    return rv


def make_panel(w, h, t, cutout):

    rv = (
        cq.Workplane("XZ")
        .rect(w, h)
        .extrude(t)
        .faces(">Y")
        .vertices()
        .rect(2*cutout,2*cutout)
        .cutThruAll()
        .faces("Y").edges("%CIRCLE").edges(">Z").tag("hole1")
    rv.faces(">Y").edges("%CIRCLE").edges("Y").tag("mate1")
    rv.faces("Z", "con_tl?Z", "Plane")
    .constrain("left@faces@Y", "Axis")
    # bottom
    .constrain("bottom@faces@Y", "Axis")
    .constrain("bottom@faces@>Z", "con_bl?X", "Plane")
    # right connectors
    .constrain("top@faces@>Z", "con_tr@faces@>X", "Plane")
    .constrain("bottom@faces@X", "Plane")
    .constrain("left@faces@>Z", "con_tr?Z", "Axis")
    .constrain("left@faces@Z", "con_tr@faces@>Z", "Plane")
    .constrain("right@faces@X[-4]", "panel@faces@Z", "panel@faces@>Z", "Axis")
    # handle
    .constrain("panel?hole1", "handle?mate1", "Plane")
    .constrain("panel?hole2", "handle?mate2", "Point")
)

# solve
door.solve()

show_object(door,name='door')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146

6、数据导出

生成的程序集可以导出为 STEP 文件或内部 OCCT XML 格式。

STEP 可以加载到所有 CAD 工具中,例如在 FreeCAD 中,XML 可用于其他使用 OCCT 的应用程序。

 door.save('door.step')
 door.save('door.xml')
  • 1
  • 2

当保存为STEP格式时,颜色被保留但不透明。
在这里插入图片描述

7、对象位置

可以将对象添加到具有提供的初始位置的装配中,例如:
在这里插入图片描述

import cadquery as cq

cone = cq.Solid.makeCone(1, 0, 2)

assy = cq.Assembly()
assy.add(
    cone,
    loc=cq.Location(cq.Vector(0, 0, 0), cq.Vector(1, 0, 0), 180),
    name="cone0",
    color=cq.Color("green")
)
assy.add(cone, name="cone1", color=cq.Color("blue"))

show_object(assy)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

作为用户计算位置的替代方法,约束的 solve() 方法可用于在装配结果中定位对象。

如果同时使用初始位置和 solve() 方法,求解器将用它的解覆盖这些初始位置,但是初始位置仍然会影响最终解。 在欠约束系统中,如果对象对成本函数没有贡献,或者如果存在多个解决方案(即成本函数最小的多个实例),求解器可能不会移动对象,初始位置可能导致求解器收敛于一个特定的解决方案。 对于非常复杂的组件,设置近似正确的初始位置也可以减少所需的计算时间。

8、约束

约束通常比直接提供位置更好地表示用户想要建模的现实世界关系。 在上面的例子中,真实世界的关系是每个圆锥体的底面应该接触,这可以用平面约束建模。 当用户提供明确的位置(而不是约束)时,也会进行更新,例如,当 cone1 的位置发生变化时。

当至少提供一个约束并运行方法 solve() 时,就定义了一个优化问题。 每个约束都提供一个成本函数,该函数取决于创建约束时指定的两个对象的位置和方向(由 Location 表示)。 解算器改变装配子项的位置并尝试最小化所有成本函数的总和。 因此,通过阅读下面的成本函数公式,你可以准确理解每个约束的作用。

9、点约束

点约束是一种经常使用的约束,它可以最小化两点之间的距离。 一些示例用途是居中面或对齐顶点,但它也可用于虚拟顶点以在两个部件之间创建偏移。

成本函数是:
在这里插入图片描述

其中:

创建点约束时, param 参数可用于指定两个中心之间的所需偏移量。 这个偏移量没有与之关联的方向,如果你想指定一个特定方向的偏移量,那么你应该使用一个虚拟顶点。

点约束使用 Center() 来查找参数的中心。 因此它适用于 Shape 的所有子类。
在这里插入图片描述

import cadquery as cq

# Use the Point constraint to position boxes relative to an arc
line = cq.Edge.makeCircle(radius=10, angle1=0, angle2=90)
box = cq.Workplane().box(1, 1, 1)

assy = cq.Assembly()
assy.add(line, name="line")

# position the red box on the center of the arc
assy.add(box, name="box0", color=cq.Color("red"))
assy.constrain("line", "box0", "Point")

# position the green box at a normalized distance of 0.8 along the arc
position0 = line.positionAt(0.8)
assy.add(box, name="box1", color=cq.Color("green"))
assy.constrain(
    "line", cq.Vertex.makeVertex(*position0.toTuple()), "box1", box.val(), "Point",
)

# position the orange box 2 units in any direction from the green box
assy.add(box, name="box2", color=cq.Color("orange"))
assy.constrain(
    "line",
    cq.Vertex.makeVertex(*position0.toTuple()),
    "box2",
    box.val(),
    "Point",
    param=2,
)

# position the blue box offset 2 units in the x direction from the green box
position1 = position0 + cq.Vector(2, 0, 0)
assy.add(box, name="box3", color=cq.Color("blue"))
assy.constrain(
    "line", cq.Vertex.makeVertex(*position1.toTuple()), "box3", box.val(), "Point",
)

assy.solve()
show_object(assy)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

10、轴约束

轴约束最小化两个向量之间的角度。 它经常用于对齐面和控制对象的旋转。

成本函数是:
在这里插入图片描述

其中:

参数 param默认为π弧度,它将两个方向设置为彼此相反。 这代表了通常所说的“配对”关系,即两个物体的外表面接触。

在这里插入图片描述

import cadquery as cq

cone = cq.Solid.makeCone(1, 0, 2)

assy = cq.Assembly()
assy.add(cone, name="cone0", color=cq.Color("green"))
assy.add(cone, name="cone1", color=cq.Color("blue"))
assy.constrain("cone0@faces@

如果 param 参数设置为零,则两个对象将指向同一方向。 这通常在一个物体穿过另一个物体时使用,例如一根钉进入板上的孔:
在这里插入图片描述

import cadquery as cq

plate = cq.Workplane().box(10, 10, 1).faces(">Z").workplane().hole(2)
cone = cq.Solid.makeCone(0.8, 0, 4)

assy = cq.Assembly()
assy.add(plate, name="plate", color=cq.Color("green"))
assy.add(cone, name="cone", color=cq.Color("blue"))
# place the center of the flat face of the cone in the center of the upper face of the plate
assy.constrain("plate@faces@>Z", "cone@faces@Z", "cone@faces@

在创建轴约束时,将根据对象的类型以三种不同方式之一提取方向矢量:

使用任何其他类型的对象都会引发 ValueError。 到目前为止,最常见的用例是从面定义轴约束。
在这里插入图片描述

import cadquery as cq
from math import cos, sin, pi

# Create a sinusoidal surface:
surf = cq.Workplane().parametricSurface(
    lambda u, v: (u, v, 5 * sin(pi * u / 10) * cos(pi * v / 10)),
    N=40,
    start=0,
    stop=20,
)

# Create a cone with a small, flat tip:
cone = (
    cq.Workplane()
    .add(cq.Solid.makeCone(1, 0.1, 2))
    # tag the tip for easy reference in the constraint:
    .faces(">Z")
    .tag("tip")
    .end()
)

assy = cq.Assembly()
assy.add(surf, name="surf", color=cq.Color("lightgray"))
assy.add(cone, name="cone", color=cq.Color("green"))
# set the Face on the tip of the cone to point in
# the opposite direction of the center of the surface:
assy.constrain("surf", "cone?tip", "Axis")
# to make the example clearer, move the cone to the center of the face:
assy.constrain("surf", "cone?tip", "Point")
assy.solve()

show_object(assy)

11、平面约束

平面约束只是 点约束和 轴约束的组合。 它是常用约束组合的便捷快捷方式。 它可用于将前面的示例从两个约束缩短为一个:

assy = cq.Assembly()
assy.add(surf, name="surf", color=cq.Color("lightgray"))
assy.add(cone, name="cone", color=cq.Color("green"))
-# set the Face on the tip of the cone to point in
-# the opposite direction of the center of the surface:
-assy.constrain("surf", "cone?tip", "Axis")
-# to make the example clearer, move the cone to the center of the face:
-assy.constrain("surf", "cone?tip", "Point")
+assy.constrain("surf", "cone?tip", "Plane")
assy.solve()

show_object(assy)

此代码的结果与上述两个约束示例相同。

面约束的成本函数,请参见 点约束 和 轴约束 部分。 param 参数应用于 Axis 并且应该保留为“mate”样式约束(两个表面接触)的默认值,或者可以设置为 0 用于通过表面约束(参见 轴约束部分中的描述)。

12、点平面约束

点平面约束将第一个对象的中心定位在第二个对象定义的平面内。 成本函数是:

在这里插入图片描述

其中:

import cadquery as cq

# Create an L-shaped object:
bracket = (
    cq.Workplane("YZ")
    .hLine(1)
    .vLine(0.1)
    .hLineTo(0.2)
    .vLineTo(1)
    .hLineTo(0)
    .close()
    .extrude(1)
    # tag some faces for easy reference:
    .faces(">Y[1]")
    .tag("inner_vert")
    .end()
    .faces(">Z[1]")
    .tag("inner_horiz")
    .end()
)

box = cq.Workplane().box(0.5, 0.5, 0.5)

assy = cq.Assembly()
assy.add(bracket, name="bracket", color=cq.Color("gray"))
assy.add(box, name="box", color=cq.Color("green"))

# lock bracket orientation:
assy.constrain("bracket@faces@>Z", "box@faces@>Z", "Axis", param=0)
assy.constrain("bracket@faces@>X", "box@faces@>X", "Axis", param=0)

# constrain the bottom of the box to be on the plane defined by inner_horiz:
assy.constrain("box@faces@X", "bracket@faces@>X", "PointInPlane", param=-0.1)

assy.solve()
show_object(assy)

13、点线约束

点线约束将第一个对象的中心定位在第二个对象定义的线上。 成本函数是:
在这里插入图片描述

其中:

import cadquery as cq

b1 = cq.Workplane().box(1,1,1)
b2 = cq.Workplane().sphere(0.15)

assy = (
    cq.Assembly()
    .add(b1,name='b1')
    .add(b2, loc=cq.Location(cq.Vector(0,0,4)), name='b2', color=cq.Color('red'))
)

# fix the position of b1
assy.constrain('b1','Fixed')
# b2 on one of the edges of b1
assy.constrain('b2','b1@edges@>>Z and >>Y','PointOnLine')
# b2 on another of the edges of b1
assy.constrain('b2','b1@edges@>>Z and >>X','PointOnLine')
# effectively b2 will be constrained to be on the intersection of the two edges

assy.solve()
show_object(assy)

14、固定点约束

固定点约束将给定参数的位置固定为等于通过约束参数指定的给定点。 此约束锁定参数的所有平移自由度。 成本函数是:
在这里插入图片描述

其中:

在这里插入图片描述

import cadquery as cq

b1 = cq.Workplane().box(1,1,1)
b2 = cq.Workplane().sphere(0.15)

assy = (
    cq.Assembly()
    .add(b1,name='b1')
    .add(b2, loc=cq.Location(cq.Vector(0,0,4)), name='b2', color=cq.Color('red'))
)

# fix the position of b1
assy.constrain('b1','Fixed')
# b2 on one of the edges of b1
assy.constrain('b2','b1@edges@>>Z and >>Y','PointOnLine')
# b2 on another of the edges of b1
assy.constrain('b2','b1@edges@>>Z and >>X','PointOnLine')
# effectively b2 will be constrained to be on the intersection of the two edges

assy.solve()
show_object(assy)

15、固定旋转约束

固定旋转约束将给定对象的旋转固定为等于通过约束参数指定的值。 对象首先绕原点旋转 Z 角,然后是 Y,最后是 X。

该约束锁定对象的所有旋转自由度。 成本函数是:
在这里插入图片描述

其中:

在这里插入图片描述

import cadquery as cq

b1 = cq.Workplane().box(1,1,1)
b2 = cq.Workplane().rect(0.1, 0.1).extrude(1,taper=-15)

assy = (
    cq.Assembly()
    .add(b1,name='b1')
    .add(b2, loc=cq.Location(cq.Vector(0,0,4)), name='b2', color=cq.Color('red'))
)

# fix the position of b1
assy.constrain('b1','Fixed')
# fix b2 bottom face position (but not rotation)
assy.constrain('b2@faces@

16、固定轴约束

固定轴约束将给定参数的法线或切线的方向固定为等于通过约束参数指定的矢量的方向。 此约束锁定参数的两个旋转自由度。 成本函数是:
在这里插入图片描述

其中:

import cadquery as cq

b1 = cq.Workplane().box(1,1,1)
b2 = cq.Workplane().rect(0.1, 0.1).extrude(1,taper=-15)

assy = (
    cq.Assembly()
    .add(b1,name='b1')
    .add(b2, loc=cq.Location(cq.Vector(0,0,4)), name='b2', color=cq.Color('red'))
)

# fix the position of b1
assy.constrain('b1','Fixed')
# fix b2 bottom face position (but not rotation)
assy.constrain('b2@faces@Z','FixedAxis',(1,0,2))

assy.solve()
show_object(assy)

原文链接:CadQuery装配约束教程 — BimAnt

  • 相关阅读:
    数据治理之springboot项目入门
    ORA-22992 cannot use LOB locators selected from remote tables
    智慧铁路:机车整备场数字孪生
    【K8S】初探Kubernetes
    (计算机组成原理)第二章数据的表示和运算-第二节2:补码加减运算器和标志位的生成
    Redis实战篇(三)秒杀
    C++基础知识(十五)--- deque 容器
    jvm 面试题
    【无标题】
    STL容器之list类
  • 原文地址:https://blog.csdn.net/shebao3333/article/details/127893115