文字與圓柱


文字之塔是我最喜歡的作品之一:

文字之塔

你可以自行輸入想要的文字,字元越多,塔就越高,照片中的是 程 式寫不出來時的 20 個理由

從繞圓到繞圓柱

如果你會 繞 圓的文字,那麼下一步要讓文字繞圓柱,基本上就不太是難事,首先你要決定的是,留下哪些參數給使用者調整,你可以留下半徑、字級,然 後自動計算一圈的字數,或者是留下字數、字級,自動計算半徑,也可以留下半徑、字數,自動計算字級,其實哪種設計方式都可以,看你設定的使用對象 是誰。

如果你的對象是個設計師或者開發者之類的,那麼他可能會每個版本都想要,如果你的對象是一般使用者,那麼太多選項有時是一種困擾,至於我,其實 做模型只是想驗證腦中的想法,會留下哪些參數,有時只是興之所致,或者是覺得將來我要再印製模型時,可能會想用哪個參數來決定,反正這是我自己寫 的,大不了直接修改程式碼…XD

在這邊,我們就讓任務簡單一些,一圈就固定 40 個字,而半徑就定為 40 mm,因為我想做個筆筒,而通常大概就這個半徑左右,這麼一來,要讓字繞圓,每個字間的角度是 360 / 40,也就是 9 度,而每個字的大小就是 2 * PI * 40 / 40,也就是 2 * PI。

當然,不要有魔法數字,因此,還是這麼寫下來比較清楚:

chars = "3.141592653589793238462643383279502884197";

PI = 3.14159;
chars_per_circle = 40;
radius = 40;
step_angle = 360 / chars_per_circle;
circumference = 2 * PI * radius;
char_size = circumference / chars_per_circle;
char_thickness = 1;

for(i = [0 : chars_per_circle - 1]) {
    rotate(i * step_angle) 
        translate([0, radius + char_size / 2, 0]) 
            rotate([90, 0, 180]) linear_extrude(char_thickness) text(
                chars[i], 
                font = "Courier New; Style = Bold", 
                size = char_size, 
                valign = "center", halign = "center"
            );
}

這麼一來,就可以有以下的效果:

文字與圓柱

當然,這只是繞圓而已,接下來,要讓每個字能緩降,那麼每個字要降多少呢?一圈 40 個字,因此每個字都要降 char_size / 40,直到指定的 chars 用盡為止:

chars = "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481";

PI = 3.14159;
chars_per_circle = 40;
radius = 40;
step_angle = 360 / chars_per_circle;
circumference = 2 * PI * radius;
char_size = circumference / chars_per_circle;
char_thickness = 1;
z_offset_per_char = char_size / 40;


for(i = [0 : len(chars) - 1]) {
    rotate(i * step_angle) 
        translate([0, radius + char_size / 2, -z_offset_per_char * i]) 
            rotate([90, 0, 180]) linear_extrude(char_thickness) text(
                chars[i], 
                font = "Courier New; Style = Bold", 
                size = char_size, 
                valign = "center", halign = "center"
            );
}

畫出來的成果如下:

文字與圓柱

加上螺旋線

當然,懸空的字是不能列印的,因此我為這個模型加上螺旋線,讓字出現在螺旋線之間,螺旋線的作法之一,是可以用公式來計算每個座標點,然後每個 座標點繪製一個小方塊,只要方塊之間夠密,看來就會像是個螺旋線,而不會是一個一個分離的小方塊。

不過,雖然人類視覺上看來是螺旋線,實際上產生出來的模型還是許多小方塊組成,也就是實際上產生的線,會有許多的面組成,這樣模型檔在 render 時會很久,而且模型檔案出來容量會很大。

因此,我們採取比較經濟的作法,在每個字的上頭畫上一條線:

chars = "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481";

PI = 3.14159;
chars_per_circle = 40;
radius = 40;
step_angle = 360 / chars_per_circle;
circumference = 2 * PI * radius;
char_size = circumference / chars_per_circle;
char_thickness = 1;
z_offset_per_char = char_size / 40;
line_thickness = char_size / 8;


for(i = [0 : len(chars) - 1]) {
    rotate(i * step_angle) 
        translate([0, radius + char_size / 2, -z_offset_per_char * i]) 
            rotate([90, 0, 180]) linear_extrude(char_thickness) 
                union() {
                    text(
                        chars[i], 
                        font = "Courier New; Style = Bold", 
                        size = char_size, 
                        valign = "center", halign = "center"
                    );
                    translate([0, char_size / 2, 0])
                        square([char_size, line_thickness], center = true);
                }
}

成果會是:

文字與圓柱

這樣當然行不通,因為每個線之間沒有接起來,這不是問題,只要將每個線再稍微拉長一些,因為字的大小、半徑是固定的、一圈的字數是固定的,要拉 多長就直接試誤吧!可以剛好線與線之間接上就可以了,我試的結果,差不多是字級的 1.106 倍。

不過另一個問題是,線拉長之後,會變成這樣:

文字與圓柱

一高一低對吧!所以了,每條線必須傾斜一個角度,只是要傾斜多少角度呢?字級已知、轉一圈的長度已知,線的厚度也已知的情況下,其實就是一個三 角函式關係:

文字與圓柱

知道上面那張圖之後,就可以知道 tan 值了吧!因此要傾斜的角度就是 atan((字級 + 線厚) / 圓周長)

chars = "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481";

PI = 3.14159;
chars_per_circle = 40;
radius = 40;
step_angle = 360 / chars_per_circle;
circumference = 2 * PI * radius;
char_size = circumference / chars_per_circle;
z_offset_per_char = char_size / 40;
char_thickness = 1;
line_thickness = char_size / 8;
line_angle_offset = -atan((char_size - line_thickness)/circumference);

for(i = [0 : len(chars) - 1]) {
    rotate(i * step_angle) 
        translate([0, radius + char_size / 2, -z_offset_per_char * i]) 
            rotate([90, 0, 180]) linear_extrude(char_thickness) union() {
                text(
                    chars[i], 
                    font = "Courier New; Style = Bold", 
                    size = char_size, 
                    valign = "center", halign = "center"
                );
                rotate([0, 0, line_angle_offset]) translate([0, char_size / 2, 0])
                    square([char_size * 1.106, line_thickness], center = true);
            }
}

這樣看起來就美多了:

文字與圓柱

什麼?那個 3.14159 的小數點浮空了?這個部份就給你作為練習了,加個判斷式就可以解決掉了,至於如何做成筆筒,也當作練習吧!記得,可以將 $fn 設為 40,並讓每個面與字貼齊,可以減少模型的複雜度。

不知道你還記不記得 3D 線段 中最後的練習?想要為文字加上螺線,也可以使用那時的 polyline3D 模組喔!