螺旋字塔

March 8, 2022

螺絲釘的螺旋路徑怎麼做呢?一邊繞圓、一邊升高就可以了:

use <polyline_join.scad>;

$fn = 36;

radius = 10;
levels = 10;
level_distance = 3;

a_step = 360 / $fn;
l_step = level_distance / $fn;

for(a = [0:a_step:360 * levels]) {
    translate([radius * cos(a), radius * sin(a), -a / a_step * l_step])
        cube(1);
}   

points = [
    for(a = [0:a_step:360 * levels]) 
    [radius * cos(a), radius * sin(a), -a / a_step * l_step]
];

translate([radius * 2.5, 0, 0])
polyline_join(points)
    cube(1);

這會建立以下的模型:

螺旋字塔

若將左邊的方塊取代為文字,就可以建立螺旋字塔,這是設計的出發點,因為是參數化建模,接下來你要決定設計哪些參數,然後有彈性地變化文字大小、層高、層數等參數,也就是建立參數間的約束。

參數間的約束

單純只是想建立螺旋路徑的話,dotSCAD 提供了 helix 函式,例如,可以用以下的程式來建立如上圖的模型:

use <polyline_join.scad>;
use <helix.scad>;

$fn = 36;

radius = 10;
levels = 10;
level_distance = 3;

points = helix(
    radius = radius, 
    levels = levels, 
    level_dist = level_distance, 
    vt_dir = "SPI_DOWN"
);

for(p = points) {
    translate(p)
        cube(1, center = true);
}   

translate([radius * 2.5, 0, 0])
polyline_join(points)
    cube(1, center = true);

接下來就是將左邊的方塊替換為文字,字型大小取決於一圈要有幾個字,如果這由 $fn 決定,那麼就是周長除以 $fn,每一層的高度也會是一個字的高度。

如果想依輸入的文字自動決定層數,可以取得文字數量,除以 $fn 後取整數部份。

文字必須是向外,這可以在擠出文字後繞 x 軸、z 軸各轉 90 度,使得文字面向 x 軸正方向,然後依座標點與 x 軸的夾角,繞 z 軸轉動。

接下來將文字與右邊的螺旋重疊並略作微調(因為相同字型尺寸下,指定的字型實際繪製範圍會不同),讓兩者可以接合。

以上四個步驟是逐步完成,每次會要調整出參數間的約束,具體而言,是調整出 levelslevel_distance 等變數與 radius$fn 參數間的關係,然後每一步要確認達到階段性目標,再繼續往下一步進行。

最後才是完成以下的程式碼:

use <polyline_join.scad>;
use <helix.scad>;

t = "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006";
$fn = 36;
radius = 10;
thickness = 1;

// 參數與變數間的約束
font_size = 2 * PI * radius / $fn;
level_distance = font_size + thickness;
levels = floor(len(t) / $fn);

points = helix(
    radius = radius, 
    levels = levels, 
    level_dist = level_distance, 
    vt_dir = "SPI_DOWN"
);

// 文字螺旋
for(i = [0:len(points) - 1]) {
    p = points[i];
    a = atan2(p.y, p.x);
    translate(p)
    rotate([90, 0, 90 + a])  // 依序繞 x 軸、y 軸、z 軸旋轉 
    linear_extrude(thickness, center = true)
        text(
            t[i], 
            size = font_size, 
            font = "Arial Black",
            valign = "center", 
            halign = "center"
        );
}   

// 螺旋線
rotate(-180 / $fn)
translate([0, 0, level_distance / 2])
polyline_join(points)
    cube(thickness * 1.05, center = true);

這會繪製出以下的模型:

螺旋字塔

我的〈Text tower〉就是基於以上步驟設計出來的:

螺旋字塔

螺旋字球

基於類似的設計概念,你也可以建立螺旋字球,例如〈Text sphere〉:

螺旋字塔

螺旋字球的螺旋路徑,可以基於 dotSCAD 的 sphere_spiral 函式建立,例如以下是個簡單的示範:

use <sphere_spiral.scad>;

points_angles = sphere_spiral(
    radius = 40, 
    za_step = 20, 
    z_circles = 40, 
    begin_angle = 900
);

for(pa = points_angles) {
    translate(pa[0]) rotate(pa[1])
    rotate([90, 0, 90]) linear_extrude(1) 
        text("A", valign = "center", halign = "center");
}

%sphere(40);

這會建立以下的結果:

螺旋字塔

如果要建立的螺旋字球不大,使用 sphere_spiral 就足夠了,不過,sphere_spiral 函式建立的路徑,每個點間的距離,越接近赤道會越大,這是因為它實作時,只是單純地基於〈球座標系〉。

螺旋字塔

極角 φ 越小,投影在 xy 平面的長度越小,旋轉方位角 θ 後的弧長越小;相對地,極角 φ 越大,旋轉方位角 θ 後的弧長越大,這就是越接近赤道的點與點間距離會越大的原因。

想在球上平均分佈點距,除了五個〈柏拉圖立體〉,沒有其他的可能性,只能儘量平均分佈,視需求不同,會有不同的分佈方式,在球上儘量平均地佈點,其實也是一些數學家會研究、探討的題目。

就以螺旋方式排列文字而言,你需要的其實是類似〈阿基米德螺線〉的球面版本,在 dotSCAD 有個 bauer_spiral 函式,可以建立近似平均佈點的螺線。例如:

use <bauer_spiral.scad>;
use <polyline_join.scad>;

n = 200;
radius = 20;
pts = bauer_spiral(n, radius);

for(p = pts) {
    translate(p)
        sphere(1, $fn = 24);
}

polyline_join(pts) 
    sphere(0.5);

這會建立以下的結果:

螺旋字塔

我的作品〈Bauer text sphere〉,就是基於 bauer_spiral 函式,可以應付球面上文字量多的情況,例如心經球:

螺旋字塔

因為我的作品,都是使用 OpenSCAD 建立,想知道怎麼設計,可以研究一下原始碼,dotSCAD 的 examples 都可以找到作品相對應的原始碼檔案。

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