Rotating globe with using quaternions and latitude/longitude

Hi,

Here’s some code which might be useful to someone. It shows a mouse controllable globe. It uses quaternions for the rotation and extracts the longitude/latitude geo location from the quaternion.

#include "ofMain.h"

class ofApp : public ofBaseApp {
public:

  ofImage earth;
  ofQuaternion qTo;
  float angle;
  ofVec3f axis;

  void setup() {
    ofBackground(0);
    ofSetFrameRate(30);
    ofDisableArbTex();
    ofEnableDepthTest();
    earth.loadImage("earth.jpg");
  }

  void draw() {
    ofTranslate(ofGetWidth()/2, ofGetHeight()/2);

    qTo.getRotate(angle,axis);
    ofRotate(angle, axis.x, axis.y, axis.z);
    ofRotateY(180);
    earth.bind();
    ofSphere(200);
    earth.unbind();

    ofPoint c = getCartesian(qTo);
    float lat = ofRadToDeg(asin(c.y));
    float lon = ofRadToDeg(-atan2(c.z,c.x))-90;
    if (lon<-180) lon+=360;
    float x = ofMap(lon,-180,180,0,256);
    float y = ofMap(lat,90,-90,0,128);

    ofSetupScreen();
    ofDrawBitmapString("lat: " + ofToString(lat,2),20,190);
    ofDrawBitmapString("lon: " + ofToString(lon,2),20,210);
    ofDisableDepthTest();
    earth.draw(0,0,256,128);
    ofFill();
    ofSetColor(255,0,0);
    ofCircle(x,y,5);
    ofSetColor(255);
    ofEnableDepthTest();
  }

  ofVec3f getCartesian(ofQuaternion &q) {
    ofMatrix4x4 m;
    q.get(m);
    return m * ofVec4f(0,0,-1,0);
  }

  void mouseDragged(int x, int y, int button){
    ofPoint from(ofGetPreviousMouseX(), ofGetPreviousMouseY());
    ofPoint to(ofGetMouseX(), ofGetMouseY());
    from = toSphere(from / ofGetWidth() - 0.5f);
    to = toSphere(to / ofGetWidth() - 0.5f);
    ofPoint axis = from.crossed(to);
    qTo *= ofQuaternion(axis.x,axis.y,axis.z,from.dot(to));
  }

  ofPoint toSphere(ofPoint v) {  //-0.5 ... +0.5
    float mag = v.x*v.x + v.y*v.y;
    if (mag>1.0f) v.normalize();
    else v.z = sqrt(1.0f - mag);
    return v;
  }

};

int main() {
  ofSetupOpenGL(1024,500,OF_WINDOW);
  ofRunApp(new ofApp());
}
1 Like