使用斐波那契晶格均匀排列球面上的点

7

我试图在一个单位球面上大致均匀地排列点。

有人告诉我,虽然这个问题很困难,但斐波那契晶格提供了一个非常好的解决方案。

我已经尝试了几天,按照链接文档中提供的非常简单的方法进行操作,但我无法让它看起来正确。

我正在使用javascript,并且我有一个对象数组e,每个对象都公开了latlon参数。以下是我用于在球面上布置点的函数:(暂时假设点的数量始终为奇数)

function arrangeEntries(e)
{
    var p = e.length;
    var N = (p - 1) / 2;

    for (var i = -N; i <= N; i++)
    {
        e[i + N].lat = Math.asin((2 * i) / (2 * N + 1));
        e[i + N].lon = mod(i, 1.618034) * 3.883222;
    }
}

使用

function mod(a, b)
{
    return a - Math.floor(a / b) * b;
}

与文档中不同,我的“lat”和“lon”是以弧度为单位而非角度。这样做是为了之后使用JavaScript的“Math.sin”和“Math.cos”函数,在X/Y/Z坐标系中绘制它们。这些函数接受弧度而非角度。对于“lat”的第一行很直观。我在文档中省略了180/π的因子,因为我希望结果保持在弧度中。对于“lon”的第二行,我使用黄金比例的索引模数,并且不是乘以360/Phi的因子来以度数给出答案,而是乘以(360/Phi)*(Pi/180)以给出弧度。由于三角函数不关心弧度的范围,因此我不需要确保“lat”和“lon”在(-pi, pi]的范围内。要渲染这些点:
function render(e)
{
    var offsetX = Math.floor(canvas.width  / 2);
    var offsetY = Math.floor(canvas.height / 2);

    var r = Math.min(canvas.width, canvas.height) * 0.4;

    ctx.clearRect(0, 0, canvas.width, canvas.height);

    for (var i = 0; i < e.length; i++)
    {
        var x = Math.cos(e[i].lat) * Math.sin(e[i].lon);
        var y = Math.sin(e[i].lat) * Math.sin(e[i].lon);
        var z = Math.cos(e[i].lon);

        // Make z go from 0.1 to 1 for scaling:
        z += 1;
        z /= 2;
        z *= 0.9;
        z += 0.1;

        ctx.beginPath();
        ctx.arc(r * x + offsetX, r * y + offsetY, z*5, 0, 2 * Math.PI, false);
        ctx.fillStyle = "#990000";
        ctx.fill();
        ctx.lineWidth = 2;
        ctx.strokeStyle = "#FF0000";
        ctx.stroke();
        ctx.closePath();
    }
}

为了在未添加旋转效果前营造出深度的错觉,我将点的半径乘以z坐标,并将其线性缩放为[0.1,1.0]的范围。
以下是包含所有代码的JSFiddle链接:https://jsfiddle.net/wexpwngc/。如果你将点数从101增加到像1001这样的更大数值,那么你会发现在极点周围有很多聚集的点,并且某些地方点比较稀疏。
我已经困扰了一段时间了。有人能看出我哪里出错了吗?

请查看以下链接以获取更简单的替代方案:球体三角剖分等距顶点球体球体网格/地图 - Spektre
请参考如何在高维空间中均匀分布点?以获取一些非传统方法的启示。虽然它们不适用于ND / general,但螺旋方法对于2D,3D是准确的。 - Spektre
1个回答

0

你的 e[i + N].lon 偏差了 0.5 倍。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接