布林運算與 hull 轉換


在〈OpenSCAD CheatSheet〉中可以看到,OpenSCAD 在 2D 與 3D 建模上提供的模組並不多,都只是 circlesquarespherecube 等基本模組,然而,複雜的模型,就是從這些基本模組透過各種組合、運算而來,在這些運算中,最基本的就是 uniondifferenceintersection 布林運算,以及一個 hull 轉換。

union

在模型的布林運算中,union 是最使用的,也就是取模型的聯集,其實你早就在使用了,隨便舉個例子好了:

radius = 10;

circle(radius, $fn = 48);
translate([0, -radius, 0]) 
    square(radius * 2);

在這個程式中,你建立了一個圓與一個方塊。在幾何計算上,圓基本上可由數段直線組成,這邊使用 $fn 指定這個圓實際上有 48 個邊,接著建立一個方塊,邊長為圓直徑,並在 Y 軸負方向位移一個半徑長,結果就是…

布林運算與 hull 轉換

在 OpenSCAD 中,如果沒有特別指定,模型間就是自動進行聯集,然而,有時你會想要將聯集完成的模型,視成單一模型做進一步操作,這有兩個方式可以做到,一是為聯集完成的模型自訂模組,例如:

radius = 10;

module circle_and_square(radius) {
    circle(radius, $fn = 48);
    translate([0, -radius, 0]) 
        square(radius * 2);
}

rotate(-45) 
    circle_and_square(radius);

或者是使用 union 明確指明:

radius = 10;

rotate(-45) union() {
    circle(radius, $fn = 48);
    translate([0, -radius, 0]) 
        square(radius * 2);
}

這兩種方式都可以形成以下的圖案:

布林運算與 hull 轉換

如果你聯集完的模型,還不是什麼階段性目標,而不想多費心神為它定義模組,就可以使用 union。舉個例子來說,建立一個簡單的愛心:

radius = 10;

module heart(radius) {
    rotated_angle = 45;
    diameter = radius * 2;
    $fn = 48;

    rotate(-rotated_angle) union() {
        circle(radius);
        translate([0, -radius, 0]) 
            square(diameter);
    }

    translate([cos(rotated_angle) * diameter, 0, 0]) 
        circle(radius);
}

heart(radius);

這邊有個簡單的幾何問題,就留給你了,為什麼最後建立的 circle 要位移 cos(rotated_angle) * diameter 才能成為愛心呢?

布林運算與 hull 轉換

difference

difference 就是對模型做差集,也就是對模型做減法運算,舉個例子來說,你也許會想在愛心上刻個鏤空字:

radius = 20;

module heart(radius) {
    rotated_angle = 45;
    diameter = radius * 2;
    $fn = 48;

    rotate(-rotated_angle) union() {
        circle(radius);
        translate([0, -radius, 0]) 
            square(diameter);
    }

    translate([cos(rotated_angle) * diameter, 0, 0]) 
        circle(radius);
}

difference() {
    heart(radius);
    text("LOVE");
}

由於在建立了愛心上,使用 difference 減去了建立的文字,結果就會是…

布林運算與 hull 轉換

intersection

intersection 是做模型的交集,也就是兩個模型間彼此有接觸的部份,才可以保留下來,舉個例子來說,如何做一個球面字呢?你可以用 sphere 建立一大一小的立體球先做 difference,這樣就會是個空心球,接著,建立一個文字並用 linear_extrude 拉高,與空心球做交集…

character = "A";
font_size = 10;
thickness = 1;

module hollow_sphere(radius, thickness) {
    $fn = 48;
    inner_radius = radius - thickness;

    difference() {
        sphere(radius);
        sphere(inner_radius);
    }   
}

module sphere_character(ch, font_size, thickness) {
    font_offset = font_size / 2;

    intersection() {
        hollow_sphere(font_size, thickness);
        linear_extrude(font_size * 2) 
            translate([-font_offset, -font_offset, 0]) 
                text(ch, size = font_size);
    }
}

sphere_character(character[0], font_size, thickness);
sphere(font_size - thickness, $fn = 48);

雖說這個程式是在示範 intersection,不過,也是個 uniondifferenceintersection 的結合範例,許多看似複雜的模型,都是由這些操作建立,而且,就像這個範例中示範的,你應該用 module 適當地封裝每個階段的基本模型,一來程式碼比較容易閱讀,二來這些基本模型,未來都可能用得上。這個程式的結果會是…

布林運算與 hull 轉換

hull

hull 是列在〈OpenSCAD CheatSheet〉的 Transformations,乍看不是很清楚它的意義,hull 的意思是「殼」,從這方面來想,就是為你的模型建立一個「殼」,這麼想好了,如果你的模型是 2D,那麼 hull 會為這些模型拉一條繃緊的線圍起來,在線內的就是 hull 建立的模型,例如,底下建立兩個圓:

radius = 10;
circle(radius);
translate([2 * radius, 0, 0]) 
    circle(radius);

模型會長這樣:

布林運算與 hull 轉換

接著用 hull 將這兩個模型圍起來:

radius = 10;
hull() {
    circle(radius);
    translate([2 * radius, 0, 0]) 
        circle(radius);
}

結果就會是:

布林運算與 hull 轉換

如果是 3D 模型,那麼 hull 就像是使用一塊繃緊的布包住這些模型,這樣的話,應該就不難理解以下這個程式:

radius = 10;
hull() {
    linear_extrude(10) 
        circle(radius);
    linear_extrude(20) 
        translate([2 * radius, 0, 0]) 
            circle(radius);
}

為什麼會產生這個模型了:

布林運算與 hull 轉換

最後來出個題目吧!上頭不是建立了一個愛心嗎?那個愛心底部尖尖的,有沒有辦法建立一個愛心,底部是圓的呢?提示:使用 hull 會比較簡單喔!

布林運算與 hull 轉換