圓的組成


在設計 3D 模型時,圓是個很妙的東西,如果你知道圓是怎麼畫出來的,可以從中引發不少的設計靈感,那麼什麼是圓呢?

關於 $fn

圓的定義是圓心至圓周的長度始終固定,然而世上畫不出完美的圓(世事無圓滿啊XD),只能接近完美,這是什麼意思呢?在 OpenSCAD 的 circle 模組,可以指定 $fn$fn 的作用就是…

radius = 100;
circle(radius, $fn = 24);
translate([radius * 2, 0, 0]) circle(radius, $fn = 12);
translate([radius * 4, 0, 0]) circle(radius, $fn = 6);

圈的組成

畫圓時其實就是前進一小段然後轉個角度再前進一小段,因此當 $fn 為 24 或更大時看起來就像個圓,$fn 為 12 或更小時,時就覺得像正多邊型了,circle 模組的 $fn 可以讓你決定由什麼正多邊型來組成,$fn 越大,就越接近完美的圓,不過,通常對人類在視覺上,$fn 只要到 96 就足夠完美了。

自己畫圓

可不可以自已畫圓而不透過 circle 模組呢?可以的,同樣地,你要決定要幾個邊:

radius = 50;
fn = 96;
thickness = 2;

module circle_ring(radius, fn, thickness) {
    PI = 3.14159;
    circumference = 2 * PI * radius;
    length = circumference / fn;
    angle_step = 360 / fn;
    for(i = [0 :  angle_step : 360 - angle_step]) {
        rotate(i)
            translate([0, radius, 0]) 
                square([length, thickness], center = true);
    }
}

circle_ring(radius, fn, thickness);

圈的組成

這只是其中一種做法,使用了 square 來畫一小段的線,不過,因為是用一段一段的長方形來組成,放大仔細來看的話,在邊界處會有個小縫隙。

使用 polygon 模組

也可以使用 polygon 模組,這個模組是指定一個 [x, y] 座標清單,它可以將這些點連接起來並且填滿:

radius = 50;

module my_circle(radius, fn) {
    PI = 3.14159;
    circumference = 2 * PI * radius;
    length = circumference / fn;
    angle_step = 360 / fn;
    polygon(
        [
            for(i = [0 :  angle_step : 360 - angle_step])  
                [radius * cos(i), radius * sin(i)]
        ]
    );
}

my_circle(radius, 24);
translate([radius * 2, 0, 0]) my_circle(radius, 12);
translate([radius * 4, 0, 0]) my_circle(radius, 6);

這個程式畫出來的圖,跟最開頭看到的圖片是一樣的,程式中看到的這段:

[
    for(i = [0 :  angle_step : 360]) 
        [radius * cos(i), radius * sin(i)]
]

這個語法是 List Comprehensions,Functional programming 中常見的玩意兒,不過並不難,它就像是跑 for 迴圈,每跑一次就執行 [radius * cos(i), radius * sin(i)],這會得到一組 [x, y],然後收集起來,因此最後跑完的話,會是 [[50, 0], [25, 43.3013], [-25, 43.3013], [-50, 0], [-25, -43.3013], [25, -43.3013], [50, 0]] 這樣的東西,這東西餵給 polygon,預設會從第一個 [x, y] 到最後一個來畫出多邊型。

至於為什麼是 [radius * cos(i), radius * sin(i)]?不過是簡單的三角函式計算出 [x, y] 罷了:

圈的組成

三角形畫圓

如果是空心圓,可以用一個一個線段組成,如果是實心圓呢?剛剛已經看到了,可以使用 polygon 模組辦到,那麼實心圓是由什麼組成的呢?可以把它看成是無數個三角形組成:

圈的組成

既然這樣,那麼就可以用以下的程式來畫圓了:

radius = 50;

module my_circle(radius, fn) {
    PI = 3.14159;
    circumference = 2 * PI * radius;
    length = circumference / fn;
    angle_step = 360 / fn;
    for(i = [0 : angle_step : 360 - angle_step]) {
        rotate(i) 
            polygon([
                [0, 0],
                [radius, 0],
                [radius * cos(angle_step), radius * sin(angle_step)],
            ]);
    }
}

my_circle(radius, 24);
translate([radius * 2, 0, 0]) my_circle(radius, 12);
translate([radius * 4, 0, 0]) my_circle(radius, 6);

關於 $fa$fs

既然知道也可以使用三角形來組成圓,那麼就可以知道,除了使用正多邊型的邊數來看待圓之外,其實可以有別的看待方式,例如,三角形的銳角越小,需要的三角形機越多,圓就越細緻,這在 OpenSCAD 中可以使用 $fa 來控制,或者是三角形的底越小,需要的三角形就越多,圓就越細緻,這在 OpenSCAD 中可以使用 $fs 來控制:

圈的組成

大部份的情況下,我們會使用 $fn,不過,如果在需要精確定位每個接觸面的情況下,必須考慮使用 $fa$fs,有興趣可以參考〈OpenScad circle calculations〉。