在設計 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〉。