球面 Voronoi

April 5, 2022

在〈半平面交集〉談到,可以透過變形的方式,建立環形的 Voronoi,如果想要建立球面的 Voronoi,也可以透過類似的方式,想辦法將 vrn2_cells_space 傳回的資料變形為球。

只不過這種方式,處理起來麻煩,而且越是靠近兩極,因為細胞的行(column)數不變,細胞越會顯得小而密集:

球面 Voronoi

極點投影

在談到球面 Voronoi 的建立方式前,先來看個有趣的東西:

球面 Voronoi

這個作品是〈極點投影〉,你可以在圖中的球體極點放一盞燈,雖然球面上的洞大小不同,然而影子會形成大小相同的正方形,原理很簡單,因為本來就是平面上整齊排列的正方形,投影至球面交集而得到的模型:

球面 Voronoi

dotSCAD 的 stereographic_extrude 模組,實現了這種模型的建構,你只要畫個平面上的圖案,就可以自動生成:

use <stereographic_extrude.scad>

dimension = 100;

stereographic_extrude(shadow_side_leng = dimension, convexity = 10)
   text("M", size = dimension, valign = "center", halign = "center");

color("black") 
   text("M", size = dimension, valign = "center", halign = "center");

這會產生以下的模型:

球面 Voronoi

球面/平面 Voronoi

方才的模型產生方式,其實是〈Stereographic projection〉的一種變化,球是在投影的平面之上,另一種投影方式是,平面橫切於球的赤道:

球面 Voronoi

這麼一來,北半球面上的點,會投影至球外的平面,南半球面上的點,會投影至球內的平面,有趣的是,如果對平面上投影的點求 Voronoi,得到的多邊形頂點投影回球面,就能構成球面 Voronoi。

dotSCAD 的 vrn_sphere 函式實現了以上的過程,可以指定球面上隨機散佈的點,生成球面 Voronoi:

use <voronoi/vrn_sphere.scad>
use <polyline_join.scad>
use <util/rand.scad>

n = 100;
radius = 2;

pts = [
    for(i = [0:n])
    let(
        theta = rand(0, 180),
        phi = rand(0, 360)
    )
    radius * [sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)]
];

cells = vrn_sphere(pts);
for(cell = cells) {
    polyline_join(concat(cell, [cell[0]]))
        sphere(.05);
}

這會構成以下的模型:

球面 Voronoi

嗯?怎麼感覺兩極還是蠻密的?這邊順便介紹一個觀念,球面上隨機點分佈,若想要儘量均勻,單純讓 theta 隨機於 0 到 180、phi 隨機於 0 至 360,這種方式是不對的;類似地,圓內隨機點分佈,單純讓半徑隨機地於 0 到 radiustheta 隨機於 0 到 360 也是不對的,為什麼呢?因為單純讓半徑隨機地於 0 到 radius,相同的一組 theta 下,越內越密不是嗎?

你應該看看〈Disk Point Picking〉、〈Sphere Point Picking〉有關圓內、球面的隨機點分佈說明。

dotSCAD 的 pp_diskpp_sphere 函式實現了其中相關的數學,可以在圓內或球面取得隨機、均勻分佈的點,例如:

use <voronoi/vrn_sphere.scad>
use <polyline_join.scad>
use <pp/pp_sphere.scad>

n = 100;
radius = 2;

pts = pp_sphere(radius, n);

cells = vrn_sphere(pts);
for(cell = cells) {
    polyline_join(concat(cell, [cell[0]]))
        sphere(.05);
}

這會繪製出以下的模型:

球面 Voronoi

那麼,你應該可以想像出來,〈哈密瓜〉是怎麼實現的了吧!

球面 Voronoi

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