7

I'm trying to arrange points more-or-less uniformly along the surface of a unit sphere.

I'm told that while this problem is difficult, Fibonacci Lattices give a very good solution.

I've been trying for a couple of days to follow the very simple method provided in the linked document, but I simply cannot get it to look right.

I'm using javascript, and I have an array of objects e, each of which expose a lat and lon parameter. Here is the function I use to arrange the points on the sphere: (assume for now that the number of points is always odd)

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;
    }
}

with

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

Unlike in the document, my lat and lon are in radians, not degrees. This is so I can plot them later using X/Y/Z co-ordinates which I obtain using the javascript Math.sin and Math.cos functions, which accept radians not degrees.

The first line for the lat is fairly straight forward. I omit the factor of 180/Pi in the document because I want to keep the result in radians.

The second line for the lon takes the modulus of the index using the golden ratio, and instead of multiplying by a factor of 360/Phi to give the answer in degrees, I multiply by (360/Phi) * (Pi/180) to give the answer in radians.

Since the trig functions don't care what range the radians take, I don't need to make sure lat and lon are in the range (-pi,pi].

To render the points:

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();
    }
}

To give an illusion of depth until I put rotation in, I multiply the radius of the points by the z co-ordinate, which I linearly scale to [0.1,1.0].

Here's a JSFiddle link with all the code: https://jsfiddle.net/wexpwngc/ If you increase the point count from 101 to something much larger like 1001, then you will see that there is a lot of clumping around the poles, and there are some places sparse on points.

I've been stuck on this for a while now. Can anybody see where I've made mistake(s)?

Community
  • 1
  • 1
Ozzah
  • 10,631
  • 16
  • 77
  • 116
  • see these links: [sphere triangulation](http://stackoverflow.com/a/29139125/2521214) , [sphere with equidistant vertices](http://stackoverflow.com/a/25031737/2521214) , [sphere grid/map](http://stackoverflow.com/a/25082674/2521214) for simpler alternatives – Spektre Apr 27 '15 at 06:29
  • see [How to distribute points evenly on the surface of hyperspheres in higher dimensions?](https://stackoverflow.com/a/57240140/2521214) for someionspiration on out of the box approaches. They not exact in ND/general but the spiral approach is accurate for `2D,3D`. – Spektre Aug 01 '20 at 11:04

1 Answers1

0

Your e[i + N].lon is off by a factor 0.5.

Vyacheslav
  • 26,359
  • 19
  • 112
  • 194
Patrick Mineault
  • 741
  • 5
  • 11