By which I specifically mean drawing a sphere of arbitrary orientation on an HTML canvas as well as parallels and meridians and points on that sphere specified by latitude and longitude.
Let's initially assume that the "arbitrary orientation" of the sphere is restricted to a single angle alpha
.
In other words, the prime meridian is always drawn as a line but the equator may be a line, an ellipse or even a circle (if the sphere is viewed from overhead).
For other meridians we're eventually going to need to draw ellipses that are rotated. Here is some code for drawing a rotated ellipse on an HTML canvas:
context.save();
context.beginPath();
context.translate(center_x, center_y);
context.rotate(rotation);
context.scale(radius_a, radius_b);
context.arc(0, 0, 1, 0, 2* Math.PI, false);
context.restore();
context.stroke();
Drawing lines of latitude is fairly easy.
If cx
and cy
are the center of the sphere and r
is the radius...
The center of the ellipse for a given latitude is:
(cx, cy + r * Math.sin(latitude) * Math.cos(alpha))
the major radius is:
r * Math.cos(latitude)
and the minor radius is:
r * Math.cos(latitude) * Math.sin(alpha)
Here is the result:
for an alpha of Math.PI / 6
Eventually I'll calculate which part of the ellipse is visible to shade the hidden side differently (or not at all) but first I want to work out how to draw the meridians.
The only two parameters I believe will vary in the drawing of the ellipses for the meridians are the minor radius (the major radius will always be the same as the radius of the sphere) and the 2D rotation of the ellipse.
For the prime meridian, the rotation is 0
and the minor radius is effectively 0
as well.
For the meridian at longitude 90º, the rotation is 90º (Math.PI / 2
) and the minor radius is Math.cos(alpha)
.
This suggests the minor radius could be r * Math.sin(longitude) * Math.cos(alpha)
and the rotation longitude
but this doesn't work out for other values.
Note that if alpha
is 0
then the rotation of the ellipses has to basically be 0
too.
And if alpha
is Math.PI / 2
(top down view), the rotation of the ellipses would be longitude
.
This has me somewhat confused (concerned?) because I think the rotation of the ellipse for the 90º meridian, regardless of alpha
, is actually always Math.PI / 2
(which, for circles is the same as 0
hence why it works for an alpha
of 0
).
What other constraints can be said to exist on the meridians? Well, they have to pass through the poles and the center has to be the center of the sphere.
I wonder if those facts alone can be used to derive the ellipse rotation and minor radius given only the longitude (as alpha
determines the position of the poles).
The equation of an ellipse rotated by A
is
((x * cos(A) + y * sin(A)) / a) ** 2 + ((x * sin(A) - y * cos(A)) / b) ** 2 == 1
We know the (x, y)
of two points (the poles) and the major radius a
so, in theory we could solve for A
and b
, the two parameters we need.
Just plugging in numbers and seeing what looks good, a minor radius and rotation of the form:
r * Math.sin(t) * Math.cos(alpha)
and
Math.sin(alpha) * t
work very well for high alpha
and low t
but get progressively worse as alpha
approaches zero or t
approaches Math.PI / 2
.
t
here could be longitude but I'm not yet committing to that, it may just be something derived from longitude.
Based on the previous card, this works surprisingly well for the minor radius:
r * Math.sin(Math.sin(t) * Math.cos(alpha))
but it still isn't quite right.
It just occurred to me that the rotation of the great circle ellipse is the same as the latitude it touches on the edge of the sphere.
With a non-zero alpha
, the vertical offset of the latitude line, as shown earlier, is:
r * Math.sin(latitude) * Math.cos(alpha)
Which means the rotation of the great circle that touches that latitude is
Math.asin(Math.sin(latitude) * Math.cos(alpha))
Although looking at this (with a line instead of the ellipse) I wonder if that's correct :-(
This shows the problem more clearly:
I might have to resort to drawing ellipses as points under a 3D transform rather than attempting to do everything with canvas arc
.
Here's a sphere (alpha
of Math.PI / 6
) with latitude lines drawn not with arc
but with individual points transformed:
Now drawing lines of longitude are trivial
And with the transform approach, it's also very easy to do hidden point elimination:
I'll have to test whether this is fast enough for my needs but, while I do want to solve the arc
-based approach at some point, this will let me move forward easily with what I want to use this for.
Source code will be on Github shortly.
The drag controls aren't right yet but here's where I'm at with the sphere drawing:
http://jtauber.github.io/interactives/sphere/spherical_coordinates.html