環面扭結

November 27, 2021

在〈曲線與曲面〉中談過,CadQuery 的 Workplane 有個 parametricCurve 方法,可搭配參數方程式來建立邊(Edge)。

cqmore.curve

cqMorecqmore.curve 定義了一些常用的弧線參數方程式,例如,來畫個阿基米德螺線

from cqmore import Workplane
from cqmore.curve import archimedeanSpiral

a = 1
b = 1

spiral = (Workplane()
            .parametricCurve(
                lambda t: archimedeanSpiral(t, a, b), 
                stop = 4 
            )
         )

parametricCurve 需要的是首參數為 t 的函式,因此以上使用了 lambda 函式來銜接 archimedeanSpiral,這會畫出以下的圖形:

環面扭結

如果你覺得自行使用 lambda 來銜接不方便,cqmore.curve 提供了 parametricEquation,可以指定弧線函式、參數,它傳回的函式就可以適用於 parametricCurve,例如:

from cqmore import Workplane
from cqmore.curve import archimedeanSpiral, parametricEquation

a = 1 
b = 1

spiral = (Workplane()
            .parametricCurve(
                parametricEquation(archimedeanSpiral, a, b), 
                stop = 4
            )
         )

當然,像 archimedeanSpiral 這類函式,只不過是就是給定數值傳回對應的結果罷了,因此,要用來建立不連線的風格,也是可以的:

from cqmore import Workplane
from cqmore.curve import archimedeanSpiral

a = 1
b = 1

spiral = (Workplane()
            .polyline([
                    archimedeanSpiral(t / 360, 1, 1) 
                        for t in range(0, 360 * 4, 30)
                ])
         )

這會畫出以下結果:

環面扭結

建立環面扭結

cqmore.curve 有個 torusKnot,可以用來建立環面扭結(Torus knot),來建個切面為星形的吧!

from cqmore import Workplane
from cqmore.curve import torusKnot, parametricEquation
from cqmore.polygon import star

from cadquery import Plane, Vector

def torus_knot(p, q):
    origin = torusKnot(0, p = p, q = q)
    v1 = Vector(*torusKnot(0.9, p = p, q = q))
    v2 = Vector(*torusKnot(0.1, p = p, q = q))

    return (Workplane(Plane(origin = origin, normal = (v2 - v1)))
               .makePolygon([(p[0] * 0.5, p[1] * 0.5) for p in star()])
               .sweep(
                   Workplane().parametricCurve(
                       parametricEquation(torusKnot, p = p, q = q)
                   ), 
                   auxSpine = Workplane().rect(1, 1)
               )
           )

p = 3
q = 2

knot = torus_knot(p, q)

先來看看這會畫出什麼:

環面扭結

若是運用 Workplane 本身的 sweep 來建立模型的話,難點之一在於如何讓星形面與扭結的路徑正交,這邊使用了扭結 t 為 0 時的點作為原點,0.1 及 0.9 時的點定義向量,作為建立 Workplane 時指定的平面法向量。

另一個難點是為了讓扭結可以整個接合,設定了 auxSpine 參數,簡單來說,想像一下你拿著一個環穿過一條曲線,除了環在轉動過程,要與曲線要正交的問題之外,還有一個問題是,你的環繞著本身的法向量要怎麼轉動,如果不指定 auxSpinesweep 預設就只能根據給定的曲線資訊來轉動,這會造成環面扭結的切面在 0 度與 360 度處不接合。

auxSpine 可以指定一個固定的副法向量計算依據,每次要轉動環本身時會用來作為參考,你可以想像一下,環上有個標示,每次轉動環時,標示都要朝著某個固定點,轉了一圈後,環上的標示位置與一開始的位置也要是相同。

這個問題跟〈玩轉 p5.js〉介紹路徑擠出時的討論有點類似,有興趣也可以參考那邊的三篇文件。