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)?