Heart chain with text(後來還有盤起來的版本 Text heart chain),是還蠻受歡迎的小創作,想必是有許多人印來送給(小)情人吧!
每個愛心之間,用了個簡單的小環上下巧妙地交錯,因此可以一次列印,想要建立這簡單的小環前,需要什麼準備工作呢?每個人的想法應該都不太一 樣,我的想法是,我應該要有個能指定角度範圍畫弧形的模組。
扇形
不過,在想要建立弧形之前,應該要先能建立扇形,如果 circle
模組能提供角度的選項,就可以簡單地完成這個功能了,可惜的是,這個 OpenSCAD 也沒有提供,只好自己來了。
在 圓的組成
中,我們知道圓其實是多個三角形組成,因此嚴格說來,圓也是個多邊形,談到多邊形,就會想到 polygon
模組,如果從原點出發,算出扇形的每個頂點,不就可以使用 polygon
模組建立扇形了嗎?
radius = 10;
angles = [45, 135];
points = [
for(a = [angles[0]:1:angles[1]]) [radius * cos(a), radius * sin(a)]
];
polygon(concat([[0, 0]], points));
從結果看來,初步的想法沒錯,畫出了 45 度到 135 度的扇形:
不過,這邊在計算每個點時,每次是在角度上遞增 1 度,在 圓的組成
中談過,圓其實是多個三角形組成,就 circle
模組來說,這可以由 $fn
參數來決定,就上面的扇形來說,相當於 $fn = 360
的圓,取其中 45 度到 135 度成為扇形。
這引發了我一個考量,我要建立的扇形模組,必須能與 circle
模組一致,提供 fn
參數(或甚至 fa
、fs
),讓模組的使用者,可以指定 fn
大小建立一個圓,再從這個圓擷取指定角度範圍內的扇形。
除了與 circle
能一致之外,這麼做的好處是,我可以擷取任意角度範圍內的扇形,像是從 $fn
= 12
的圓,擷取 0 到 135 度的扇形:
看到了嗎?因為是 $fn = 12
的圓,最左邊的邊長與右邊幾個邊長不一樣,這邊是故意使用 $fn
= 12
來突顯這類的情況。
因此,現在換個角度來想,扇形也可以是建立一個圓後,再減去不想要的部份來得到,例如上面這個結果,可以是底下兩個圖的減集:
根據這個想法,可以實作出底下的 sector
模組:
radius = 20;
angles = [45, 135];
fn = 12;
module sector(radius, angles, fn = 24) {
step = -360 / fn;
points = concat([[0, 0]],
[for(a = [angles[0] : step : angles[1] - 360])
[radius * cos(a), radius * sin(a)]
],
[[radius * cos(angles[1]), radius * sin(angles[1])]]
);
difference() {
circle(radius, $fn = fn);
#polygon(points);
}
}
sector(radius, angles, fn);
不過,結果有點不是我們要的:
喔喔!本來建立用來要從圓減去的的部份,並沒有辦法涵蓋整個圓!解決這個問題方式,其實就只要讓紅色部份在建立時的半徑大於黃色部份,這樣就一
定蓋得住,至於要多大呢?可以很簡單地就讓它是 radius
的兩倍大,這樣一定蓋得住,當然,如果你覺得要龜毛一些比較有樂趣,就來算算看吧!
因為在最差的情況下,黃色部份的頂點會是與紅色部份邊長的一半處,也就是…
根據上圖,只要讓紅色的部份的半徑可以是 r
,就一定蓋得住黃色的了:
a = 180 / fn;
r = radius / cos(a);
因此,修正後的 sector
模組實作就是:
radius = 20;
angles = [45, 135];
fn = 24;
module sector(radius, angles, fn = 24) {
r = radius / cos(180 / fn);
step = -360 / fn;
points = concat([[0, 0]],
[for(a = [angles[0] : step : angles[1] - 360])
[r * cos(a), r * sin(a)]
],
[[r * cos(angles[1]), r * sin(angles[1])]]
);
difference() {
circle(radius, $fn = fn);
polygon(points);
}
}
sector(radius, angles, fn);
完成的效果如下:
弧形
有了 sector
模組,接下來要建立 arc
畫弧就簡單了,一個大扇形減去一個小扇形就可以啦!
radius = 20;
angles = [45, 290];
width = 2;
fn = 24;
module sector(radius, angles, fn = 24) {
r = radius / cos(180 / fn);
step = -360 / fn;
points = concat([[0, 0]],
[for(a = [angles[0] : step : angles[1] - 360])
[r * cos(a), r * sin(a)]
],
[[r * cos(angles[1]), r * sin(angles[1])]]
);
difference() {
circle(radius, $fn = fn);
polygon(points);
}
}
module arc(radius, angles, width = 1, fn = 24) {
difference() {
sector(radius + width, angles, fn);
sector(radius, angles, fn);
}
}
linear_extrude(1) arc(radius, angles, width);
完成的效果如下:
如果你去看我放在 Thingiverse 上的作品,裏頭若有用到扇形或弧形時,會發現裏頭的程式碼好像不是這麼一回事,這是因為實作時第一次想到的設計或者是考量,並不是那麼完整,而在寫文件記錄這些設計的同 時,我總是會想,還有沒有其他的考量,還有沒有更好的設計。
記錄,不單只是記錄!