從曲線到曲面

March 9, 2022

在〈polygon 與 polyhedron〉談過,怎麼實作函式圖形的繪製,dotSCAD 提供了 sf_thicken,可以給定曲面的座標點與厚度來繪製曲面模型:

use <surface/sf_thicken.scad>

function f(x, y) = (y ^ 2) / 4 - (x ^ 2) / 4;

min_value = -3;
max_value = 3;
resolution = 0.5;
thickness = 0.5;

points = [
    for(y = [min_value:resolution:max_value])
        [
            for(x = [min_value:resolution:max_value]) 
                [x, y, f(x, y)]
        ]
];

sf_thicken(points, thickness);

這會建立以下的結果:

從曲線到曲面

既然可以透過貝茲曲線Catmull-Rom 樣條 等,以控制點的方式來建立曲線,而不用特別找出曲線的數學函式,那麼能不能有提供控制點,就能建立曲面的方式呢?

談談貝茲曲面

首先你可能會想到,利用多條貝茲曲線,是不是能構成曲面呢?例如,使用四條貝茲曲線:

use <surface/sf_thicken.scad>
use <bezier_curve.scad>
use <polyline_join.scad>

ctrl_pts = [
    [[0, 0, 20],  [60, 0, -35],   [90, 0, 60],    [200, 0, 5]],
    [[0, 50, 30], [100, 60, -25], [120, 50, 120], [200, 50, 5]],
    [[0, 100, 0], [60, 120, 35],  [90, 100, 60],  [200, 100, 45]],
    [[0, 150, 0], [60, 150, -35], [90, 180, 60],  [200, 150, 45]]
];

thickness = 2;
t_step = 0.05;

points = [for(i = [0:len(ctrl_pts) - 1]) 
    bezier_curve(t_step, ctrl_pts[i])
]; 


sf_thicken(points, thickness);

// 顯示四條貝茲曲線
#for(curve = points) {
    polyline_join(curve)
        sphere(3);
}

可惜的是,雖然貝茲曲線本身看來是沒問題,然而面看來不平滑,具體而言,在列(row)看來平滑,在行(column)方向看來卻像是折線…

從曲線到曲面

在行方向仍不平滑,如果在四條貝茲曲線上各取一個控制點:

從曲線到曲面

用四個控制點來產生行方向的曲線,是不是就可以平滑了呢?

從曲線到曲面

使用 sf_splines 函式

dotSCAD 提供了 sf_splines,可以指定列與行方向的曲線函式,如果只指定一個曲線函式,那麼列與行會使用同一個曲線函式。

你指定的控制點,會逐列呼叫列曲線函式得到各列曲線的點,接著各列上取點作為行控制點,呼叫行曲線函式,從而得到曲面。例如,若要建立貝茲曲面:

use <surface/sf_thicken.scad>
use <surface/sf_splines.scad>
use <bezier_curve.scad>

ctrl_pts = [
    [[0, 0, 20],  [60, 0, -35],   [90, 0, 60],    [200, 0, 5]],
    [[0, 50, 30], [100, 60, -25], [120, 50, 120], [200, 50, 5]],
    [[0, 100, 0], [60, 120, 35],  [90, 100, 60],  [200, 100, 45]],
    [[0, 150, 0], [60, 150, -35], [90, 180, 60],  [200, 150, 45]]
];

thickness = 2;
t_step = 0.05;

bezier = function(points) bezier_curve(t_step, points);
points = sf_splines(ctrl_pts, bezier);

sf_thicken(points, thickness);

這會建立以下的模型:

從曲線到曲面

你想要 curve 作為曲線函式也是可以的:

use <surface/sf_thicken.scad>
use <surface/sf_splines.scad>
use <curve.scad>

ctrl_pts = [
    [[0, 0, 20],  [60, 0, 35],   [90, 0, 40],   [150, 0, 35],   [200, 0, 10]],
    [[0, 50, 30], [60, 60, 25],  [100, 50, 50], [150, 50, 35],   [200, 50, 10]],
    [[0, 100, 0], [60, 100, 35], [90, 100, 40], [150, 100, 45], [200, 100, 10]],
    [[0, 150, 0], [60, 150, 35], [90, 135, 45], [150, 135, 55], [200, 120, 10]],
    [[0, 155, 0], [60, 155, 35], [90, 155, 50], [150, 155, 65], [200, 155, 10]]
];

thickness = 2;
t_step = 0.05;

points = sf_splines(ctrl_pts, function(points) curve(t_step, points));

sf_thicken(points, thickness);

這會建立以下的曲面:

從曲線到曲面

關於 Golden Taiwan

在〈Golden Taiwan〉這個作品,海浪的部份,就是貝茲曲面:

從曲線到曲面

dotSCAD 有一些 _extrude 模組,可以指定形狀的座標資訊來實現擠出,黃金螺旋的臺灣,是基於 golden_spiral_extrude 模組與 shape_taiwan 產生:

use <shape_taiwan.scad>
use <golden_spiral_extrude.scad>

mirror_taiwan = [for(pt = shape_taiwan(15)) [pt.x * -1, pt.y]];

golden_spiral_extrude(
    mirror_taiwan, 
    from = 1,  
    to = 10, 
    point_distance = 2.5,
    scale = 10
);

在這段程式碼中,要將 x 座標過來是因為螺旋擠出時是由內而外,內部的臺灣是反的,螺旋擠出後才會是正,類似地,來個盤旋而上的臺灣吧!

use <shape_taiwan.scad>
use <helix_extrude.scad>

r1 = 15;
r2 = 100;
levels = 3;
level_dist = 50;

helix_extrude(shape_taiwan(80), 
    radius = [r1, r2], 
    levels = levels, 
    level_dist = level_dist,
    vt_dir = "SPI_DOWN",
    rt_dir = "CLK",
    scale = 0.1
);

從曲線到曲面

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