阿基米德螺線

March 8, 2022

見過蚊香嗎?現代年輕一代,可能還真沒看過蚊香,來看看維基上的蚊香照

阿基米德螺線

使用公式繪製

漩渦形蚊香的路徑就是阿基米德螺線,阿基米德螺線的公式是:

阿基米德螺線

根據公式,θ 為徑度,為 0 時的 ra,也就是 a 控制了由內而外的起點位置,若 θ 為某徑度 radianr1 = a + b * angle,轉一圈後 r2 = a + b * (angle + 2 * PI)``,r2 - r1 = 2 * PI * b,也就是從螺線起點、任意角往外畫一直線,與螺線任兩個的連續交點,距離一定是固定的 2 * PI * b

那麼製作蚊香時,是依公式在轉動鋪料上去的嗎?這太麻煩了!只要等角速度轉動圓盤,然後直線地以等速由內往外鋪料就可以了,因為從公式來看,θ 的角速度相同,r 的增加速度也就相同,這就是阿基米德螺線也被稱為等速螺線的原因。

有公式的話,要畫螺線基本上不是難事,若 a 為 0:

use <polyline_join.scad>
use <util/radians.scad>

b = 3;
degrees = 1080;
degree_step = 20;

points = [
    for(d = [0:degree_step:degrees]) 
    let(
        theta = radians(d),
        r = b * theta
    )
    r * [cos(d), sin(d)]
];

polyline_join(points)
    circle(1);

可以畫出以下的螺線:

阿基米德螺線

喂!不是要畫阿基米德螺線嗎?怎麼畫出來的像是折線?而且還越往外越長?這是因為 degree_step 的增量故意設較大的原因,如果你只是要畫螺線,不希望看來像折線,degree_step 的增量設小一些就可以了,例如設為 1,就目前的繪圖大小而言,就應該不會看來像折線了。

然而,如果你的繪圖區夠大,螺線圈數夠多,其實到一定的圈數之後,還是會看來像個折線,這是因為程式中 degree_step 的增量是固定的,螺線圈數越多,r 越大,固定的轉動 degree_step,弧長本來就會越長,polyline_join 是將每個計算得到的點以直線連接,才會越外圈越看得出折線。

這會有什麼問題呢?如果想在阿基米德螺線上,等距地放上一些字,或者一些圖案,以上的寫法就不適合。

等距點的問題

可是我曾經用 OpenSCAD 建立的 Moving fish,看來是用了阿基米德螺線:

阿基米德螺線

看來魚的骨節與骨節之間是等距,這是怎麼辦到的?最簡單的想法當然是,在螺線上每越一段距離,就畫一個愛心,確實地,是可以求得阿基米德螺線的螺線長,搜尋「archimedean spiral arc length」就可以找到公式,例如 Wolfram MathWorld 的 Archimedes’ Spiral 就有了:

阿基米德螺線

如果你的點距是固定的 d,只要找出 sd2 * d3 * d 等對應的 θ,也就是推導出 θ(s) 的公式就可以了,對吧!嗯!如果無誤差地推導出公式了,請跟我說聲…XD

因為要無誤差地推導出公式有其難度,而且化為程式運算也很麻煩,也就有了一些近似的做法,例如〈Draw equidistant points on a spiral〉有提到一些,各有其優缺點。

在〈玩轉 p5.js〉的〈阿基米德螺線〉談到其中一種近似的公式推導,有興趣可以看看!

dotSCAD 的 archimedean_spiral 實作了一種近似方式:

use <polyline_join.scad>
use <archimedean_spiral.scad>

points_angles = archimedean_spiral(
    arm_distance = 10,
    init_angle = 180,
    point_distance = 5,
    num_of_points = 100 
); 

points = [for(pa = points_angles) pa[0]];

polyline_join(points)
    circle(1);

其中各參數的意義為:

阿基米德螺線

對於 archimedean_spiral 的實作方式,越外圈的點越平均分配,然而相對地,init_angle 不能太小,我主要目的是 3D 建模,因此這個限制對我來說沒有什麼困擾。

等距點的應用

有了等距點,就可以安排每個點看要放些什麼,例如放上些文字:

use <archimedean_spiral.scad>

t = "3.141592653589793238462643383279502884197169399375105820974944592307816406286";

points_angles = archimedean_spiral(
    arm_distance = 15,
    init_angle = 450, 
    point_distance = 12, 
    num_of_points = len(t) 
); 

for(i = [0: len(points_angles) - 1]) {
    translate(points_angles[i][0])          
    rotate(points_angles[i][1] + 90)  
        text(t[i], valign = "center", halign = "center");
}

這會繪製出以下的模型:

阿基米德螺線

剩下的就是看你怎麼將這些字連起來了,例如 Heart chain 設計了愛心來連結:

阿基米德螺線

或者可以像 Spiral city,在每個間隔放上一棟房子,形成一個螺旋城:

阿基米德螺線

分享到 LinkedIn 分享到 Facebook 分享到 Twitter