挖洞與切除
November 25, 2021在 3D 模型設計中,為了各種理由,經常會需要挖洞,CadQuery 在這方面提供了許多選擇,例如在 2D 操作後擠出、在 3D 建構切除,或者透過一些高階的 API 來處理。
2D 減集
在〈基本 2D 操作〉就看過了,2D 操作若構成了兩個以上的封閉曲線,若其中一個封閉曲線涵蓋了其他封閉曲線,在擠出時,其他封閉曲線會用來挖洞,其中舉了幾個例子,像是在建立大圓後,透過 center
指定圓中的位置建立方形,或者透過 forConstruction
僅建立幾何資訊,取得頂點位置來建立方形,擠出後的圓中就會有方形的洞。
如果已知一組要挖洞的點,可以透過 pushPoints
加入 Workplane
的堆疊,然後用來建立幾何資訊,例如,在大圓內側沿著小圓挖 24 個洞:
from math import cos, sin, pi
import cadquery as cq
r1 = 10
r2 = 8
r3 = 1
n = 12
thickness = 1
a_step = 2 * pi / n
points = [(r2 * cos(i * a_step), r2 * sin(i * a_step)) for i in range(n)]
plate = (cq.Workplane()
.circle(r1)
.pushPoints(points)
.circle(r3)
.extrude(thickness)
)
這會顯示以下的模型:
接下來的示範,建立的模型都會像上圖。
若是圓形的相關位置,也可以透過 polarArray
來指定,以上範例可以簡化如下:
import cadquery as cq
r1 = 10
r2 = 8
r3 = 1
n = 12
thickness = 1
plate = (cq.Workplane()
.circle(r1)
.polarArray(r2, 0, 360, n)
.circle(r3)
.extrude(thickness)
)
如果你有使用過其他 CAD 軟體的經驗,也許直覺上,會建立一個 3D 物件,並以減集來達到目的,例如:
import cadquery as cq
r1 = 10
r2 = 8
r3 = 1
n = 12
thickness = 1
plate = (cq.Workplane()
.circle(r1)
.extrude(thickness)
)
sticks = (cq.Workplane()
.polarArray(r2, 0, 360, n)
.circle(r3)
.extrude(thickness)
)
result = plate - sticks
show_object(result)
cut 相關方法
不過,CadQuery 可以直接用 2D 幾何資訊來作為切除的依據。例如:
import cadquery as cq
r1 = 10
r2 = 8
r3 = 1
n = 12
thickness = 1
plate = (cq.Workplane()
.circle(r1)
.extrude(thickness)
.faces('>Z') # 選擇 Z 正方向最遠的面
.workplane() # 建立一個工作平面
.polarArray(r2, 0, 360, n) # 位置資訊
.circle(r3) # 建立 Wire
.cutThruAll() # 切穿
)
cutThruAll
會利用尚未被處理的 Wire
來切穿實體,另一個跟切除有關的方式是 cutBlind
,它就像是把 Wire
拿來 extrude
,擠出後的結果會被用來切除實體,例如:
import cadquery as cq
r1 = 10
r2 = 8
r3 = 1
n = 12
thickness = 1
plate = (cq.Workplane()
.circle(r1)
.extrude(thickness)
.polarArray(r2, 0, 360, n)
.circle(r3)
.cutBlind(thickness)
)
如果 cutBlind(thickness)
改成 cutBlind(thickness / 2)
,就不會切穿了:
hole 相關方法
單純就挖洞而言,Workplane
可以直接使用 hole
方法:
import cadquery as cq
r1 = 10
r2 = 8
r3 = 1
n = 12
thickness = 1
plate = (cq.Workplane()
.circle(r1)
.extrude(thickness)
.faces('>Z')
.workplane()
.polarArray(r2, 0, 360, n)
.hole(r3 * 2) # 指定直徑
)
如果不想打穿,hole
有個 depth
可以指定深度。
Workplane
還有兩個挖洞的方法,可以用來埋頭孔,通常作為鎖螺絲後可以藏起螺絲頭的孔,cboreHole
可以建立圓柱形的平底孔,例如,將上例的 hole(r3 * 2)
改為 cboreHole(r3, r3 * 2, thickness / 2)
,可以看到:
cskHole
可以用來建立圓錐形孔,例如將上例的 hole(r3 * 2)
改為 cskHole(r3, r3 * 2, 45, thickness / 42)
,可以看到:
說是打洞,這些方法也不只可以用來打洞,例如:
import cadquery as cq
r1 = 10
r2 = 1
n = 12
thickness = 1
plate = (cq.Workplane()
.circle(r1)
.extrude(thickness)
.faces('>Z')
.workplane()
.polarArray(r1, 0, 360, n)
.hole(r2 * 2)
)
這會構成以下的效果:
CadQuery 因為 API 豐富,一個模型可以有多樣化的建構方式,沒有一定要怎麼做,以清楚易懂為主,例如,以下的程式碼會建立打穿的立方塊模型:
import cadquery as cq
w = 1
half_w = w / 2
box = (cq.Workplane()
.box(w, w, w)
.faces('+X')
.workplane()
.hole(half_w)
.faces('+Y')
.workplane()
.center(half_w, 0)
.hole(half_w)
.faces('+Z')
.workplane()
.center(0, -half_w)
.hole(half_w)
)
這會顯示以下結果:
然而,平面的選擇與中心的處理有點麻煩,不如用以下的程式碼會好懂一些:
import cadquery as cq
w = 1
cylinder = (cq.Workplane()
.circle(w / 4)
.extrude(w)
.translate((0, 0, -w / 2))
)
cylinders = (cylinder +
cylinder.rotate((0, 0, 0), (1, 0, 0), 90) +
cylinder.rotate((0, 0, 0), (0, 1, 0), 90)
)
box = cq.Workplane().box(w, w, w) - cylinders
show_object(box)
雖然 CadQuery 鼓勵使用方法鏈,不過別過火了,適當地建立各個部件,或者是將相關模型的建立邏輯,封裝函式甚至類別,讓程式碼容易理解,會是最重要的。