I'm working on a SceneKit project in iOS, trying to rotate a sphere (representing a planet) so that a point at a given longitude/latitude coordinate is facing "forward" (i.e. that point moves to the {0,0} position). So for example, we're looking at Earth's {0,0} point, off the coast of Africa, but I need to know what rotation vector would have us looking at {37,-122}, aka San Francisco. Ideally, the planet would remain "naturally" oriented, with north remaining generally "up" from our perspective, but that's flexible.

I've got the animation working and I can rotate to a given longitude OR latitude using SCNVector4, but as soon as I try to rotate to a given longitude AND latitude, it gets wildly messed up. So I've been doing some research, and I've found some resources that seem to do exactly what I need, but to be honest they're a bit beyond me. I'm a complete newbie in the world of trigonometry and matrices, and it seems there's no way around this problem without them.

Can anyone help me understand how these concepts can take long/lat coordinates, and calculate a rotation vector? A method for creating a SCNVector4 would be perfect, but even just help with calculating the components individually would be greatly appreciated!

  • \$\begingroup\$ What's a rotation vector? (I know what a rotation matrix is and a quaternion, and Euler angles are, is this related to any of those?). If it's something SceneKit specific maybe at that to the tags and someone who knows better might find this question. \$\endgroup\$
    – Jeff Gates
    Dec 1, 2015 at 0:31
  • \$\begingroup\$ @JeffGates I may be misusing the term. iOS defines a SCNVector4 as "A representation of a four-component vector", used for defining rotation as {x, y, z, w}, so I figured a "rotation vector" was a decent description. But euler angles should work just as well, since you can define the rotation property using either. \$\endgroup\$
    – Nerrolken
    Dec 1, 2015 at 0:45
  • \$\begingroup\$ Reading a little deeper into the links it sounds like what you are going for is an "Axis/Angle" representation of a rotation, stored in 4vector, withx,y,z represent and axis and w an angle in radians. \$\endgroup\$
    – Jeff Gates
    Dec 1, 2015 at 3:10

1 Answer 1


Ok, Here's what I got, with the understanding the goal is an axis-angle 4 vector representation, and the goal is provide that to something that can rotate the earth.

(Axis,Angle) CalcEarthAxisAngleRotationFromLatLong(float lat, float long) {
   if (lat == 0)
    return up, long;            // up is 'to the north pole'
   else if (long == 0)
    return cross(up, fwd), lat; // forward is 'to the 0,0 africa point', cross assume right hand coords
   else // what we need to do is compose the two pieces
    AxisAngle aaLat  = RotateEarthToLatLong(lat, 0);
    AxisAngle aaLong = RotateEarthToLatLong(0, long);
    ?? composableLat = f(aaLat);
    ?? composableLong = f(aaLat);
    ?? composedLatLong = Compose(composableLat, composableLong);
    AxisAngle aaLatLong = invF(composedLatLong);
    return aaLatLong;

?? are typically rotation matricies or unit quaternions, Compose is matrix or quaternion multiplication, and F and invF the associated conversion functions. As an example in quaternions:

?? = struct Quat {
    float s;
    Vec3  v;

f = QuatFromAxisAngle(Vec3 axis, float angle) {
    q.v = sin(.5*angle) * axis;
    q.s = cos(.5*angle);
    return q;

invF = AxisAngleFromQuat(Quat q) {
    axis = normalize(q.v);
    angle = acos(q.s)*2;
    return axis,angle;

Compose = QuaternionMultiplication(Quat q0, Quat q1) {
    Quat q;
    q.s = q0.s*q1.s - Dot(q0.v, q1.v);
    q.v = q0.s*q1.v + q1.s*q0.v + Cross(q0.v, q1.v);
    return q;

This is actually why people bother to use quaternions (or matricies), instead of axis angle, because they compose well.

Notes: You could go directly from lat,long to quaternions rather than needlessly converting to AxisAngle rep, I did so in the example just to build off of what you already had done, and show that the piece that is missing is 'how do i compose rotations' - which you alluded to in your question. (2) I might have the order wrong argument in Compose().


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .