PDA

View Full Version : rotate around arbitrary point



thinhare
01-03-2010, 03:24 PM
Hi, all

I'd like to do something like Gooogle earth e.g., if I click on an arbitrary location on the map and drag the mouse, the whole map should rotate about the location where mouse is clicked at.

http://i46.tinypic.com/2ce6ovd.png

Up to now, what I achieved is when I click on a point on the white line, the sheet rotate around that point, but if I click not on the white line, the sheet will rotate around a point on the white line, and that point is aligned vertically with the point I click.

Not sure if I have made myself clear, maybe the code explains better.

(You can press ESC to reset the scene)



#include <GL/gl.h>
#include <GL/glu.h>
#include <glut.h>
#include <math.h>

int mWidth, mHeight;
float mZTrans;
float mYAngle;
int mMouseX, mMouseY;
double mPosX, mPosY, mPosZ;
int mMouseMove;

void getClickCoord(int x, int y, double *posX, double *posY, double *posZ)
{
int viewport[4];
double modelview[16];
double projection[16];
float winX, winY, winZ;

glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glGetIntegerv(GL_VIEWPORT, viewport);

winX = (float)x;
winY = (float)(viewport[3] - y - 1);
glReadPixels((int)winX, (int)winY, 1, 1,
GL_DEPTH_COMPONENT, GL_FLOAT, &amp;winZ );
gluUnProject(winX, winY, winZ, modelview, projection, viewport,
posX, posY, posZ);
}

float normalizeAngle(float angle)
{
angle -= (360*(int)(angle/360));
if (angle < 0) angle += 360;
return angle;
}

void glOrthoBegin()
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, mWidth, 0, mHeight, -1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
}

void glOrthoEnd()
{
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}

void paintCircle(float radius, GLint xoffset, GLint yoffset)
{
float delta = 0.05;
glPushAttrib(GL_CURRENT_BIT);
glColor3f(0.0, 1.0, 0.0);
glBegin(GL_LINE_LOOP);
float theta;
for (theta = 0; theta < 2*M_PI; theta += delta) {
glVertex2i((int)(radius*cos(theta))+xoffset,
(int)(radius*sin(theta))+yoffset);
}
glEnd();
glPopAttrib();
}

void paintQuads()
{
int row, col;
float xoffset, zoffset;

glPushAttrib(GL_CURRENT_BIT);
glBegin(GL_QUADS);
for (row = 0; row < 10; row++) {
zoffset = 1*row+0.5 - 5;
for (col = 0; col < 10; col++) {
xoffset = 1*col+0.5 - 5;
glColor3f(row*0.1, col*0.1, 0.0);
glVertex3f(-0.5+xoffset, 0, -0.5+zoffset);
glVertex3f(-0.5+xoffset, 0, 0.5+zoffset);
glVertex3f( 0.5+xoffset, 0, 0.5+zoffset);
glVertex3f( 0.5+xoffset, 0, -0.5+zoffset);
}
}
glEnd();
glPopAttrib();
}

void reset()
{
mZTrans = -15.0;
mYAngle = 0.0;
mMouseX = mMouseY = 0;
mMouseMove = 0;
}

void init()
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glClearDepth(1.0);
glShadeModel(GL_SMOOTH);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);

float ambient[] = {0.5, 0.5, 0.5, 1.0};
float diffuse[] = {0.8, 0.8, 0.8, 1.0};
float specular[] = {1.0, 1.0, 1.0, 1.0};
float position[] = {0.0, 0.0, 0.0, 1.0};
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
}

void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0, 0, mZTrans);
if (mMouseMove) glTranslatef(mPosX, mPosY, mPosZ);
glRotatef(45.0, 1, 0, 0);
glRotatef(mYAngle, 0, 1, 0);
if (mMouseMove) glTranslatef(-mPosX, -mPosY, -mPosZ);
paintQuads();
if (mMouseMove) {
glOrthoBegin();
paintCircle(20.0, mMouseX, (mHeight-mMouseY-1));
glOrthoEnd();
}
mMouseMove = 0;
glutSwapBuffers();
}

void reshape(int width, int height)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
mWidth = width; mHeight = height;
float aspect = (float)width/(float)height;

float top, bottom, left, right;
top = 0.1*tan(20.0/180.0*M_PI);
if (aspect < 1.0) top *= (1.0/aspect);
bottom = -top;
right = top*aspect;
left = -right;
glFrustum(left, right, bottom, top, 0.1, 100);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

void mouse(int button, int state, int x, int y)
{
if (state == GLUT_DOWN) {
mMouseX = x; mMouseY = y;
getClickCoord(x, y, &amp;mPosX, &amp;mPosY, &amp;mPosZ);
}
else if (state == GLUT_UP) {
glutPostRedisplay();
}
}

void motion(int x, int y)
{
mYAngle = normalizeAngle(mYAngle + 5);
mMouseMove = 1;
glutPostRedisplay();
}

void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 27:
reset();
glutPostRedisplay();
break;

case '=':
case '+':
mZTrans /= 1.2;
glutPostRedisplay();
break;

case '-':
case '_':
mZTrans *= 1.2;
glutPostRedisplay();
break;

case 'Q':
case 'q':
exit(0);
break;

default:
break;
}
}

int main(int argc, char** argv)
{
glutInit(&amp;argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(640, 480);
glutInitWindowPosition(100, 60);
glutCreateWindow(argv[0]);
reset();
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}