Problems with glRotate()

I’ve been working on a relatively simple animation of a car moving on a curved road in a 2D plane. The car runs fine and follows the curve I supply, but only by translation, ie. the car’s back wheel follows the curve, but the car does not rotate so that both wheels follow the curve at their given locations. I set up a function the calculate the angle the car should rotate to alleviate that inconsistancy, but while the rotation is correct for the curve’s direction, it is not to scale, so the car jumps above and below the curve slightly and does not follow it exactly (and the back wheel no longer follows the curve, so the rotation is not around the back wheel as it should be).

The following is my code:

  
#define INTERPOLATE 0
#define HERMITE 1
#define BEZIER 2
#define M_PI 3.14159

#include <Math.h>
#include <stdlib.h>
#include <GL/glut.h>
#include <GL/glu.h>
#include "Matrix.h"

void display(void);
void drawSquare(int, int);
void myReshape(GLsizei, GLsizei);

void myinit(void);

void screen_box(int, int, int);
int pick(int, int);


/* globals */

GLsizei wh = 600, ww = 800; /* initial window size */
GLfloat size = 3.0;   /* half side length of square */
int draw_mode = 0; /* drawing mode */
int rx, ry; /*raster position*/

GLfloat r = 1.0, g = 1.0, b = 1.0; /* drawing color */
int filler = 0; /* fill flag */

double arrayMi[16] = {1, 0, 0, 0, -5.5, 9, -4.5, 1, 
		9, -22.5, 18, -4.5, -4.5, 13.5, -13.5, 4.5 };

double arrayMh[16] = {1, 0, 0, 0, 0, 0, 1, 0, 
		-3, 3, -2, -1, 2, -2, 1, 1 };

double arrayMb[16] = {1, 0, 0, 0, -3, 3, 0, 0, 
		3, -6, 3, 0, -1, 3, -3, 1 };

double d = .1, change = 1, X[4], Y[4];



GLUquadricObj *Tire1 = gluNewQuadric();//Pointer for First Tire
GLUquadricObj *Tire2 = gluNewQuadric();//Pointer for Second Tire

//*
double ms = 5*ww/20+ww/20;
double sm = 4*ww/10+ww/20;
double  w = ww/10;

double bX[4] ={ 5*ww/20-ms, 9*ww/20-ms, 9*ww/20-ms, 5*ww/20-ms};//Body X
double bY[4] ={ 3*ww/10+sm, 3*ww/10+sm, 4*ww/10+sm, 4*ww/10+sm};//Body Y
double fX[4] ={ 9*ww/20-ms,10*ww/20-ms,10*ww/20-ms, 9*ww/20-ms};//Front X
double fY[4] ={ 4*ww/10+sm,3.5*ww/10+sm,3*ww/10+sm, 3*ww/10+sm};//Front Y
double wX[4] ={5*ww/20+ww/40-ms,6*ww/20+ww/40-ms,7*ww/20+ww/40-ms,8*ww/20+ww/40-ms};//Windows X
double wY[4] ={4*ww/10-3*ww/80+sm,4*ww/10-3*ww/80+sm,4*ww/10-3*ww/80+sm,4*ww/10-3*ww/80+sm};//Windows Y
double wSX[3]={8*ww/20+2*ww/40-ms,8*ww/20+2*ww/40-ms,8*ww/20+3*ww/40-ms};//Windshield X
double wSY[3]={4*ww/10-3*ww/80+ww/40+sm,4*ww/10-3*ww/80+sm,4*ww/10-3*ww/80+sm};//Windshield Y
double tX[2] ={5*ww/20+ww/20-ms,5*ww/20+3*ww/20-ms};//Tires X
double tY[2] ={4*ww/10-ww/10+sm,4*ww/10-ww/10+sm};//Tires Y
//*/
// X 5*ww/20+ww/20-ms
// Y 4*ww/10-ww/10+sm
double dX = 0.0, dY = 0.0; //change in X and Y

int idleT = 0;//change in Time




/* rehaping routine called whenever window is resized
or moved */

void myReshape(GLsizei w, GLsizei h)
{

/* adjust clipping box */

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity(); 
        glOrtho(0.0, (GLdouble)w, 0.0, (GLdouble)h, -1.0, 1.0);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity(); 

/* adjust viewport and  clear */

        glViewport(0,0,w,h);
		glClearColor (0.0, 0.0, 20.0, 1.0);
        glClear(GL_COLOR_BUFFER_BIT);
        display();
        glFlush();

/* set global size for use by drawing routine */

        ww = w;
        wh = h; 
}

void myinit(void)
{

	glViewport(0,0,ww,wh);


/* Pick 2D clipping window to match size of X window 
This choice avoids having to scale object coordinates
each time window is resized */

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity(); 
        glOrtho(0.0, (GLdouble) ww , 0.0, (GLdouble) wh , -1.0, 1.0);

/* set clear color to black and clear window */

        glClearColor (0.8, 0.8, 0.8, 1.0);
        glClear(GL_COLOR_BUFFER_BIT);
        glFlush();
}


void screen_box(int x, int y, int s )
{
    glBegin(GL_QUADS);
      glVertex2i(x, y);
      glVertex2i(x+s, y);
      glVertex2i(x+s, y+s);
      glVertex2i(x, y+s);
    glEnd();
}

void Tree()
{
	glColor3f(20.0,20.0,0.0);
	glBegin(GL_POLYGON);
		glVertex2f(0.0, 0.0);
		glVertex2f(ww/40, 0.0);
		glVertex2f(ww/40, ww/20);
		glVertex2f(0.0, ww/20);
	glEnd();
}

void BackGround()
{
	//glPushMatrix();
	glColor3f(0.0, 0.0, 20.0);
	glBegin(GL_POLYGON);
		glVertex2f(0.0,wh);
		glVertex2f(0.0,0.0);
		glVertex2f(ww,0.0);
		glVertex2f(ww,wh);
	glEnd();

	//glTranslatef(ww/2,(ww/4),0.0);
	//Tree();
	//glPopMatrix();
}

void CarBody()
{
	glBegin(GL_POLYGON);
		glVertex2f( bX[0]+dX, bY[0]-dY);
		glVertex2f( bX[1]+dX, bY[1]-dY);
		glVertex2f( bX[2]+dX, bY[2]-dY);
		glVertex2f( bX[3]+dX, bY[3]-dY);
	glEnd();
	//Car Front
	glBegin(GL_POLYGON);
		glVertex2f( fX[0]+dX, fY[0]-dY);
		glVertex2f( fX[1]+dX, fY[1]-dY);
		glVertex2f( fX[2]+dX, fY[2]-dY);
		glVertex2f( fX[3]+dX, fY[3]-dY);
	glEnd();
}

void CarWindows()
{
	screen_box(wX[0]+dX,wY[0]-dY,ww/40);

	screen_box(wX[1]+dX,wY[1]-dY,ww/40);

	screen_box(wX[2]+dX,wY[2]-dY,ww/40);

	screen_box(wX[3]+dX,wY[3]-dY,ww/40);

	glBegin(GL_POLYGON);
		glVertex2f(wSX[0]+dX,wSY[0]-dY);
		glVertex2f(wSX[1]+dX,wSY[1]-dY);
		glVertex2f(wSX[2]+dX,wSY[2]-dY);
	glEnd();
}

void Tires()
{
	glPushMatrix();
	glTranslatef(tX[0]+dX,tY[0]-dY,0.0);
	gluDisk(Tire1,ww/80,ww/40,22,22);
	glPopMatrix();
	glFlush();

	glPushMatrix();
	glTranslatef(tX[1]+dX,tY[1]-dY,0.0);
	gluDisk(Tire2,ww/80,ww/40,22,22);
	glPopMatrix();
}

void MakeM(Matrix& M, int N)
{
	int k = 0, i, j;

	switch(N)
	{
	   case(0):
			for (i = 0; i<4; i++){
				for(j = 0; j<4; j++){ 
					M(i,j) = arrayMi[k];
					k++;
				}
			}
			k = 0;
		    break;
	   case(1):
			for (i = 0; i<4; i++){
				for(j = 0; j<4; j++){ 
					M(i,j) = arrayMh[k];
					k++;
				}
			}
			k = 0;
		    break;
	   case(2):
			for (i = 0; i<4; i++){
				for(j = 0; j<4; j++){ 
					M(i,j) = arrayMb[k];
					k++;
				}
			}
			k = 0;
		
	}
}

void move(double dx, double dy, double Theta)
{
	glPushMatrix();
		
		glRotatef(Theta,0,0,1.0);
		//glTranslatef(dx,dy,0);
		
		glColor3f(1.0, 0.5, 0.0);
		CarBody();
		//glFlush();

		glColor3f(1.0, 1.0, 1.0);
		CarWindows();
		//glFlush();

		glColor3f(0.0, 0.0, 0.0);
		Tires();
		//glFlush();

		//glRotatef(Theta,0,0,1);
		

	glPopMatrix();

	dX = dx;
	dY = dy;

	//glRotatef(Theta,0,0,1);
	//glTranslatef(dx,dy,0);
	

	//glutSwapBuffers();	
}

void plotCurve(Matrix& c, int Color)
{
	Matrix U(1,4), Curve(201,2),CurveW(201,2), point(1,2), Theta(201,1), C(4,2);

	double u=0, du=(1.0/200.0);
	for(int i=0; i<201; i++)
	{
		U(0,0) = 1;
		U(0,1) = u;
		U(0,2) = u*u;
		U(0,3) = u*u*u;
		point=U*c; //p(u)= U transpose C;
		Curve(i,0)=point(0,0); // X
		Curve(i,1)=point(0,1); // Y;
		u+=du;
	}
	
	switch(Color-6){
		case(0):
		{
			glColor3f(1.0, 0.0, 1.0);//Interpolated Polynomial Curve
		}
		break;
		case(1):
		{
			glColor3f(0.0, 1.0, 1.0);//Hermite Curve
		}
		break;
		case(2):
		{
			glColor3f(0.5, 0.5, 0.5);// Bezier
		}
	}

	/*
	glBegin(GL_LINE_STRIP);
	for(int L=0; L<201; L++)
	{
		glVertex2i(Curve(L,0),wh-Curve(L,1));
		
	}
	glEnd();

	glBegin(GL_LINE_STRIP);
	for(int l=0; l<201; l++)
	{
		glVertex2i(Curve(l,0)+ww/10,wh-Curve(l,1));
		
	}
	glEnd();
	*/
	glBegin(GL_LINE_STRIP);
	for(int n=0; n<201; n++)
	{
		glVertex2i((3*Curve(n,0)/4.0)+(ww/40),wh-Curve(n,1));
		
	}
	glEnd();

	glutSwapBuffers();
}

void driveCurve(Matrix& c, int Color)
{
	Matrix U(1,4), Curve(201,2),CurveW(201,2), point(1,2), Theta(201,1);
	
	double u=0, du=(1.0/200.0);
	for(int i=0; i<201; i++)
	{
		U(0,0) = 1;
		U(0,1) = u;
		U(0,2) = u*u;
		U(0,3) = u*u*u;
		point=U*c; //p(u)= U transpose C;
		Curve(i,0)=point(0,0); // X
		Curve(i,1)=point(0,1); // Y;
		u+=du;
	}

	switch(Color-6){
		case(0):
		{
			glColor3f(1.0, 0.0, 1.0);//Interpolated Polynomial Curve
		}
		break;
		case(1):
		{
			glColor3f(0.0, 1.0, 1.0);//Hermite Curve
		}
		break;
		case(2):
		{
			glColor3f(0.5, 0.5, 0.0);// Bezier
		}
	}

	for(int j=0; j<171; j++)
	{
		CurveW(j,0)=Curve(j+30,0); // X2
		CurveW(j,1)=Curve(j+30,1); // Y2
	}

	for(int J=171; J<201; J++)
	{
		CurveW(J,0)=Curve(200,0); // X2
		CurveW(J,1)=Curve(200,1); // Y2
	}


	for(int k=0; k<201; k++)
	{
		double opp = Curve(k,1)-CurveW(k,1);
		Theta(k,0)= (atan(opp/w))*(180.0/M_PI);
	}

	glBegin(GL_LINE_STRIP);
	for(int L=0; L<201; L++)
	{
		BackGround();
		move(Curve(L,0),Curve(L,1),Theta(L,0)/3.3);//
		plotCurve(c,BEZIER);
	}
		
	glEnd();
	
	
}


void display(void)
{

	double xp[4] = {0,ww/4,ww/4,ww};
	double yp[4] = {wh,-wh/9,2*wh/3,wh};

	Matrix M(4,4), c(4,2), p(4,2);
			  
	MakeM(M,2);

	for (int j = 0; j<4; j++){
		p(j,0) = xp[j];
		p(j,1) = yp[j];
	}

	c = M*p;
	
	for(int i=0; i<3; i++)
	{
		driveCurve(c, BEZIER);
		//plotCurve(c, BEZIER);
		glutSwapBuffers();
	}
	
}

void main(int argc, char** argv)
{
    glutInit(&argc,argv);
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(800, 600);
    glutCreateWindow("ROOP'S CAR FINAL");
    glutDisplayFunc(display);
	//glutIdleFunc(idle);
    myinit ();
    glutReshapeFunc (myReshape);
	//glutMouseFunc (mouse);
    glutMainLoop();

}

I know that the code has some changes made to Theta (the angle of rotation), but that was me trying to fit the rotation more closely to the curve. That’s why I’ve divided each instance of Theta by 3.3 and the curve’s x position by 4/3.

I also think I need to change my move() function to utilize glTranslate rather than changing each value dX, dY, but in my previous efforts glTranslate did nothing.

Thanks in advance.

You need to translate, rotate then draw the entire vehicle.

Also your decision to divide theta is utterly perplexing.

If you adjust scale in one axis in SW you need to compute the angle after the scale.