/CarDemo/src/Car.cpp
https://bitbucket.org/juniormitac/session12018 · C++ · 569 lines · 370 code · 82 blank · 117 comment · 15 complexity · 76eddcfd4e23e79c2bff008455cae2af MD5 · raw file
- // Car Demo Program
- // Author: Len Hamey
- // Date: March 2015
- // Based on: Lecture notes
- // A car is displayed in three dimensions as a wire frame.
- // The wheels of the car are cylinders.
- // Each wheel has bolts drawn on it, except for the spare wheel.
- // The body of the car is a wire frame intended to resemble the model used in lectures.
- // a: Animate.
- // s: Slow animation speed
- // f: Fast animation speed
- // r: Reset animation position
- // +: Zoom in
- // -: Zoom out
- # include <ctype.h>
- # include <GL/glut.h>
- # include <iostream>
- # define PI 3.1415926535897932
- # define ANIMATION_STEP (1000/60)
- // Motion in world units per second
- # define SLOW_MOTION 0.5
- # define FAST_MOTION 2.5
- # define ASPECT_RATIO 2.0
- struct Point {
- double x, y, z;
- // Empty constructor is needed to build Point into other objects.
- Point() { x = y = z = 0.0; }
- // Constructor with parameters.
- Point(double _x, double _y, double _z) { x = _x; y = _y; z = _z; }
- };
- Point add(Point p1, Point p2)
- {
- return Point(p1.x+p2.x, p1.y+p2.y, p1.z+p2.z);
- }
- void vertex(Point p)
- {
- glVertex3d(p.x, p.y, p.z);
- }
- void translate(Point p)
- {
- glTranslated(p.x, p.y, p.z);
- }
- struct Car
- {
- // The points of the left and right panels.
- Point left[7];
- Point right[7];
- // Points where the axles attach to the body
- Point frontLeft, frontRight, rearLeft, rearRight;
- // Location of the spare wheel mounting point
- Point spareWheel;
- // Parameters for wheels
- double wheelRadius, wheelThickness;
- // Parameters for bolts on wheels
- double boltPosRadius, boltRadius, boltLength;
- // Floor height of the car body
- double floorHeight;
- };
- static Car car;
- static bool animating = false;
- static double xpos = 0.0;
- static double xposStep = FAST_MOTION;
- static double zoomFactor = 1.0;
- static double rotation_factor = 1.0; // For correct rotation, use 1.0
- // Initialise the car model data
- void initCar(void)
- {
- // First draw the wire frame of the car body.
- // The origin of the drawing is the centre of back of the car.
- // Various measurements are recorded in mm and then scaled
- // so that the length of the car is 1 unit. (i.e. it extends from 0 to 1 in X)
- // The longitudinal axis is aligned with X.
- double length = 288.0;
- double rearAxle = 60.0 / length; // Distance from rear bumper to rear axle.
- double frontAxle = 68.0 / length; // Distance from front bumper to front axle.
- double axleY = 20.0 / length; // Height of axle above the vehicle floor.
- double rearSlopeX = 13.0 / length; // X distance from rear bumper to top of sloped rear panel.
- double rearSlopeY = 55.0 / length; // Y distance from vehicle floor to bottom of sloped rear panel.
- double hoodY = 82.0 / length; // Y distance from vehicle floor to hood (bonnet, lid over the engine).
- double hoodX = 62.0 / length; // X length of the hood
- double frontSlopeX = 8.0 / length; // X distance from bottom of windscreen to top.
- double bodyHeight = 135.0 / length; // Y height of the body
- double spareY = 57.0 / length; // Height of the spare wheel mounting point
- double wheelDiameter = 100.0 / length; // Diameter of wheel
- double wheelThickness = 15.0 / length; // Thickness of the wheel itself
- double wheelClearance = 3.0 / length; // Z gap between wheel and body
- double boltDiameter = 4.0 / length; // Diameter of the bolt
- double boltLength = 3.0 / length; // Length of the bolt
- double boltPosRadius = 17.0 / length; // Distance of centre of bolt from centre of wheel
- double bodyWidth = 90.0 / length; // Z distance from left panel to right panel of the body
- double halfWidth = bodyWidth / 2.0;
- // Compute the profile points that define the shape of the body.
- // The points are numbered as follows:
- // 2---------------------------3
- // / \ .
- // / \ .
- // 1 4---------5
- // | |
- // | |
- // 0-----------------------------------------6
- // There is a left and a right point for each one.
- car.left[0] = Point(0.0, 0.0, -halfWidth);
- car.left[1] = add(car.left[0], Point(0.0, rearSlopeY, 0.0));
- car.left[2] = add(car.left[0], Point(rearSlopeX, bodyHeight, 0.0));
- car.left[6] = Point(1.0, 0.0, -halfWidth);
- car.left[5] = add(car.left[6], Point(0.0, hoodY, 0.0));
- car.left[4] = add(car.left[5], Point(-hoodX, 0.0, 0.0));
- car.left[3] = add(car.left[4], Point(-frontSlopeX, bodyHeight - hoodY, 0.0));
- // The right points are Z translations of the left points. Each one is explicitly computed here.
- Point w(0.0, 0.0, bodyWidth);
- for (int i = 0; i < 7; i++)
- car.right[i] = add(car.left[i], w);
- // The axle attachment points with wheel clearance from the body added
- car.frontLeft = add(car.left[6], Point(-frontAxle, axleY, -wheelClearance));
- car.frontRight = add(car.right[6], Point(-frontAxle, axleY, wheelClearance));
- car.rearLeft = add(car.left[0], Point(rearAxle, axleY, -wheelClearance));
- car.rearRight = add(car.right[0], Point(rearAxle, axleY, wheelClearance));
- // Attachment of the spare wheel
- car.spareWheel = add(car.left[0], Point(0.0, spareY, halfWidth));
- // Wheel parameters. Radius, thickness.
- car.wheelRadius = wheelDiameter / 2.0;
- car.wheelThickness = wheelThickness;
- // Bolt parameters. Positional radius, length and radius of the bolt.
- car.boltPosRadius = boltPosRadius;
- car.boltLength = boltLength;
- car.boltRadius = boltDiameter / 2.0;
- // Floor height of the body
- car.floorHeight = car.wheelRadius - axleY;
- return;
- }
- // Draw a cylinder using gluCylinder.
- // The cylinder is aligned with the Z axis
- void drawCylinder(double radius, double length)
- {
- // Reference: HK page 248
- GLUquadricObj *qobj = gluNewQuadric();
- gluQuadricDrawStyle(qobj, GLU_LINE);
- gluCylinder(qobj, radius, radius, length, 16, 1);
- gluDeleteQuadric(qobj);
- return;
- }
- // Draw a bolt as a cylinder
- void drawBolt()
- {
- // *******************************************
- // Draw a bolt at the current origin aligned with the Z axis
- drawCylinder(car.boltRadius, car.boltLength);
- return;
- }
- // Draw a wheel as a cylinder with bolts also drawn as cylinders
- // The bolts are on the outside surface of the cylinder.
- void drawWheel(bool bolts)
- {
- // *******************************************
- // The wheel is a cylinder
- drawCylinder(car.wheelRadius, car.wheelThickness);
- if (! bolts)
- return;
- // *******************************************
- // Draw the bolts on the surface of the wheel
- glPushMatrix();
- // Translate to the outside surface of the cylinder
- glTranslated(0.0, 0.0, car.wheelThickness);
- // ***************************************
- // Each bolt is drawn at a location in wheel coordinates
- glPushMatrix();
- glTranslated(car.boltPosRadius, 0.0, 0.0);
- drawBolt();
- glPopMatrix();
- glPushMatrix();
- glTranslated(-car.boltPosRadius, 0.0, 0.0);
- drawBolt();
- glPopMatrix();
- glPushMatrix();
- glTranslated(0.0, car.boltPosRadius, 0.0);
- drawBolt();
- glPopMatrix();
- glPushMatrix();
- glTranslated(0.0, -car.boltPosRadius, 0.0);
- drawBolt();
- glPopMatrix();
- glPopMatrix();
- return;
- }
- // Draw the car body
- void drawBody(void)
- {
- // Draw the left panel.
- glBegin(GL_LINE_LOOP);
- for (int i = 0; i < 7; i++)
- vertex(car.left[i]);
- glEnd();
- // Draw the right panel.
- glBegin(GL_LINE_LOOP);
- for (int i = 0; i < 7; i++)
- vertex(car.right[i]);
- glEnd();
- // Draw the Z-lines between the panels.
- glBegin(GL_LINES);
- for (int i = 0; i < 7; i++) {
- vertex(car.left[i]);
- vertex(car.right[i]);
- }
- glEnd();
- }
- // Draw the car
- void drawCar(double scale, double distance)
- {
- double angle, circumference;
- // Compute rotation angle for wheels when the car has driven distance.
- // A positive distance travelled in X means a negative wheel rotation on the right side.
- // Note: The scale of the vehicle affects the circumference of the wheel.
- circumference = 2.0 * PI * car.wheelRadius * scale;
- // rotation_factor is 1.0 for correct rotation. For demonstrations of errors, use 0.0, 2.0, -1.0
- angle = -distance / circumference * 360.0 * rotation_factor;
- glPushMatrix();
- // Translate the car for the distance travelled
- glTranslated(distance, 0.0, 0.0);
- // Scale the car to the required scale factor.
- glScaled(scale, scale, scale);
- // Lift the car body off the ground by the required floor height
- // Note that the wheels are defined relative to the body position
- glTranslated(0.0, car.floorHeight, 0.0);
- // *****************************************
- // Draw the car body
- drawBody();
- // *****************************************
- // Draw each wheel, one at a time.
- // Save and restore the modelview matrix each time.
- // Wheels on the left side are rotated 180 degrees about Y axis.
- // Wheels are rotated about Z axis to simulate rolling on the road;
- // wheels on the left ride rotate in the opposite direction to those on the right side.
- glPushMatrix();
- // Draw the front left wheel
- // It is on the other side of the car, so rotate about Y 180 degrees
- translate(car.frontLeft);
- glRotated(180.0, 0,1,0);
- glRotated(-angle, 0,0,1);
- drawWheel(true);
- glPopMatrix();
- glPushMatrix();
- // Draw the front right wheel
- translate(car.frontRight);
- glRotated(angle, 0,0,1);
- drawWheel(true);
- glPopMatrix();
- glPushMatrix();
- // Draw the rear left wheel
- translate(car.rearLeft);
- glRotated(180.0, 0,1,0);
- glRotated(-angle, 0,0,1);
- drawWheel(true);
- glPopMatrix();
- glPushMatrix();
- // Draw the rear right wheel
- translate(car.rearRight);
- glRotated(angle, 0,0,1);
- drawWheel(true);
- glPopMatrix();
- glPushMatrix();
- // Draw the spare wheel.
- // It does not roll on the road.
- // It is rotated -90 about Y to orient it for the rear of the vehicle
- // It has no bolts on it!
- translate(car.spareWheel);
- glRotated(-90.0, 0,1,0);
- drawWheel(false);
- glPopMatrix();
- glPopMatrix();
- }
- // Draw car with its (line) shadow.
- void drawShadowCar(double scale, double distance, float r, float g, float b)
- {
- // Draw a shadow of the car - it is a line shadow.
- // It is drawn first so that the car itself overwrites the shadow.
- glPushMatrix();
- // Colour * 0.3 + 0.7 is a pale version of the colour
- glColor3f(r*0.3 + 0.7, g*0.3 + 0.7, b*0.3 + 0.7);
- glScaled(1.0, 0.0, 1.0);
- drawCar(scale, distance);
- glPopMatrix();
- // Draw the car itself
- glColor3f(r, g, b);
- drawCar(scale, distance);
- }
- // Draw a ground-plane grid extending from -5 to +5 in X and Z.
- void drawGrid(void)
- {
- glBegin(GL_LINES);
- for (int x = -5; x <= 5; x++) {
- glVertex3f(x, 0.0, -5.0);
- glVertex3f(x, 0.0, 5.0);
- }
- for (int z = -5; z <= 5; z++) {
- glVertex3f(-5.0, 0.0, z);
- glVertex3f(5.0, 0.0, z);
- }
- glEnd();
- }
- // Draw the X Y and Z positive axes as lines from the origin.
- void drawAxes(void)
- {
- glBegin(GL_LINES);
- glVertex3f(0.0, 0.0, 0.0);
- glVertex3f(5.0, 0.0, 0.0);
- glVertex3f(0.0, 0.0, 0.0);
- glVertex3f(0.0, 5.0, 0.0);
- glVertex3f(0.0, 0.0, 0.0);
- glVertex3f(0.0, 0.0, 5.0);
- glEnd();
- }
- void init(void)
- {
- initCar();
- glClearColor(1.0, 1.0, 1.0, 1.0);
- }
- void display(void)
- // clears the screen and draws the car
- {
- glMatrixMode (GL_PROJECTION);
- glLoadIdentity ();
- glOrtho(-5.0/zoomFactor, 5.0/zoomFactor, -5.0/ASPECT_RATIO/zoomFactor, 5.0/ASPECT_RATIO/zoomFactor, 0.0, 15.0);
- glClear (GL_COLOR_BUFFER_BIT);
- glMatrixMode (GL_MODELVIEW);
- glLoadIdentity ();
- // Set up a viewpoint for looking at the car.
- gluLookAt(3.0,2.0,7.0, 0.0,0.0,0.0, 0.0,1.0,0.0);
- // Draw axes and a ground plane grid
- // Axes are drawn after the grid so that they overwrite it
- glColor3f(0.7, 1.0, 0.7); // Pale green
- drawGrid();
- glColor3f(0.0, 0.0, 0.0); // Black.
- drawAxes();
- // *******************************************
- // Draw the lead car with specified scale and road position
- // First save the modelview matrix
- glPushMatrix();
- // Position the car
- glTranslated(0.0, 0.0, 1.0);
- drawShadowCar(2.0, xpos, 1.0, 0.0, 0.0);
- glPopMatrix();
- //save the original modelview matrix
- // Draw the following car
- glPushMatrix();
- // Position the car
- glTranslated(-2.0, 0.0, 1.0);
- drawShadowCar(1.2, xpos, 0.0, 0.0, 1.0);
- glPopMatrix();
- /* glutSwapBuffers must be called for any drawing to
- * appear on the screen when in double buffered mode
- */
- glutSwapBuffers();
- }
- # define ANIMATING 1
- # define ANIMATION_FAST 2
- # define ANIMATION_SLOW 3
- # define RESET 4
- # define ZOOM_IN 5
- # define ZOOM_OUT 6
- # define ROTATION_NEGATIVE 7
- # define ROTATION_ZERO 8
- # define ROTATION_NORMAL 9
- # define ROTATION_DOUBLE 10
- void menu (int selected)
- {
- switch (selected) {
- case ANIMATING:
- animating = ! animating;
- glutPostRedisplay();
- break;
- case ANIMATION_FAST:
- xposStep = FAST_MOTION;
- glutPostRedisplay();
- break;
- case ANIMATION_SLOW:
- xposStep = SLOW_MOTION;
- glutPostRedisplay();
- break;
- case RESET: // reset
- xpos = 0.0;
- animating = 0;
- glutPostRedisplay();
- break;
- case ZOOM_IN:
- zoomFactor = zoomFactor * 1.4142135;
- if (zoomFactor > 4.0) zoomFactor = 4.0;
- glutPostRedisplay();
- break;
- case ZOOM_OUT:
- zoomFactor = zoomFactor / 1.4142135;
- if (zoomFactor < 1.01) zoomFactor = 1.0;
- glutPostRedisplay();
- break;
- case ROTATION_NEGATIVE:
- case ROTATION_ZERO:
- case ROTATION_NORMAL:
- case ROTATION_DOUBLE:
- rotation_factor = selected - ROTATION_ZERO;
- glutPostRedisplay();
- break;
- }
- }
- void keyboard (unsigned char key, int x, int y)
- {
- switch (key) {
- case 'a':
- menu(ANIMATING);
- break;
- case 'f':
- menu(ANIMATION_FAST);
- break;
- case 's':
- menu(ANIMATION_SLOW);
- break;
- case 'r': // reset
- menu(RESET);
- break;
- case '+':
- menu(ZOOM_IN);
- break;
- case '-':
- menu(ZOOM_OUT);
- break;
- case 'n':
- menu(ROTATION_NEGATIVE);
- break;
- case '0':
- case '1':
- case '2':
- menu(ROTATION_ZERO + key - '0');
- break;
- }
- }
- void timer(int v)
- {
- // Computing elapsed time for smooth animation.
- int time = glutGet(GLUT_ELAPSED_TIME); // In msec
- // Set up next timer event
- glutTimerFunc(ANIMATION_STEP, timer, time);
- if (animating) {
- xpos += xposStep * (time - v) / 1000.0;
- // When the cars disappear from the right
- // draw them entering from the left
- if (xpos > 8.1)
- xpos = -7.1;
- glutPostRedisplay();
- }
- }
- void reshape(int width, int height)
- {
- // A very minimal reshape function to ensure that the viewport has a fixed aspect ratio.
- if (width > height*ASPECT_RATIO) {
- glViewport((width-height*ASPECT_RATIO)/2, 0, height*ASPECT_RATIO, height);
- }
- else {
- glViewport(0, (height-width/ASPECT_RATIO)/2, width, width/ASPECT_RATIO);
- }
- return;
- }
- int main(int argc, char** argv)
- {
- glutInit(&argc, argv);
- //specify double buffering
- glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
- glutInitWindowSize (600*ASPECT_RATIO, 600);
- glutInitWindowPosition (0, 0);
- glutCreateWindow ("Model Car");
- init ();
- glutDisplayFunc(display);
- glutKeyboardFunc(keyboard);
- glutTimerFunc(1000/60, timer, 0);
- glutReshapeFunc(reshape);
- glutCreateMenu(menu);
- glutAddMenuEntry("a: Animating on/off", ANIMATING);
- glutAddMenuEntry("f: Fast animation", ANIMATION_FAST);
- glutAddMenuEntry("s: Slow animation", ANIMATION_SLOW);
- glutAddMenuEntry("r: Reset", RESET);
- glutAddMenuEntry("+: Zoom in", ZOOM_IN);
- glutAddMenuEntry("-: Zoom out", ZOOM_OUT);
- glutAddMenuEntry("n: Negative wheel rotation", ROTATION_NEGATIVE);
- glutAddMenuEntry("0: No wheel rotation", ROTATION_ZERO);
- glutAddMenuEntry("1: Normal wheel rotation", ROTATION_NORMAL);
- glutAddMenuEntry("2: Double wheel rotation", ROTATION_DOUBLE);
- glutAttachMenu(GLUT_RIGHT_BUTTON);
- glutMainLoop();
- return 0;
- }