// GL3DSphere.cpp // Draw a rotating collection of random points on a // sphere. // version 0 Use the wire frame sphere from GLUT // Code is from Hill, pg 268 // tom bailey 10 oct 01 // version 1 Use a collection of random points on the // spherical surface. Pause between drawings. // tom bailey 11 oct 01 // version 2 Enter data at each left mouse click. Limit // the number of rotations. Use pauseUntil to control // (within limits) the speed of rotation. // tom bailey 11 oct 01 // version 4 Use double buffering of the pixel map to // smooth the transition from one frame to the next. // tom bailey 12 oct 01 // version 5 Revise the animation process. Use an angle // clock and repeated posting of display requests to // allow use of key and mouse events to control the // rotation of the sphere. // tom bailey 16 oct 01 // version 6 Use the view volume to hide points on the // back side of the sphere. #include #include "RanGen.h" #include #include #include #include using std::cin; using std::cout; using std::endl; using std::vector; const GLdouble pi = 3.141592654; const GLdouble twoPi = 2 * pi; GLsizei windowWidth = 600; GLsizei windowHeight = 600; // Define and instantiate a global angleClock that uses // the process clock to determine the rotational angle // of the sphere. class AngleClock { public: AngleClock( GLdouble initialRate ); // in revolutions per second void increaseRate(); void decreaseRate(); void reverseRate(); GLdouble angle(); // in degrees private: void update(); private: GLdouble lastAngle; // in degrees GLdouble lastTime; // in seconds on the process clock GLdouble rotationRate; // in degrees per second }; // Create with zero angle, current process time, and the // desired rotation rate converted to degrees per second. AngleClock::AngleClock( GLdouble initialRate ) : lastAngle( 0.0 ) { lastTime = clock() / CLOCKS_PER_SEC; rotationRate = 360.0 * initialRate; } // Update the angle and time, then change the rotation rate. void AngleClock::increaseRate() { update(); rotationRate *= 1.25; } // Update the angle and time, then change the rotation rate. void AngleClock::decreaseRate() { update(); rotationRate *= 0.8; } // Update the angle and time, then change the rotation rate. void AngleClock::reverseRate() { update(); rotationRate = - rotationRate; } // Update the angle and time, then return the current angle GLdouble AngleClock::angle() { update(); return lastAngle; } // Use the current rotation rate to update the angle to // account for the passage of time since the last update. void AngleClock::update() { GLdouble newTime = GLdouble( clock() ) / GLdouble( CLOCKS_PER_SEC ); GLdouble elapsed = newTime - lastTime; lastAngle += elapsed * rotationRate; lastTime = newTime; while( lastAngle >= 360.0 ) { lastAngle -= 360.0; } while( lastAngle < 0.0 ) { lastAngle += 360.0; } // cout << "AngleClock::update() with " << lastAngle << " at " << lastTime << endl; } // GLOBAL AngleClock with initial rotation rate of // 0.2 revolutions per second. AngleClock angleClock( 0.2 ); class SpherePoint { public: SpherePoint(); SpherePoint( float raduis, RanGen & rng ); void draw(); private: float red, green, blue; float x, y, z; }; // The vector.resize( 0 ) method requires a zero // parameter constructor for the elements. // Should never be used. SpherePoint::SpherePoint() { // cout << "SpherePoint::SpherePoint() called" << endl; red = 0.0; green = 0.0; blue = 0.0; x = 0.0; y = 0.0; z = 0.0; } SpherePoint::SpherePoint( float radius, RanGen & rng ) { red = rng.unif(); green = rng.unif(); blue = rng.unif(); x = rng.gauss(); y = rng.gauss(); z = rng.gauss(); float rsq = x*x + y*y + z*z; float factor = radius / sqrt( rsq ); x *= factor; y *= factor; z *= factor; } void SpherePoint::draw() { glColor3d( red, green, blue ); glVertex3d( x, y, z ); } class Sphere { public: Sphere(); void fill( float radius, short points, unsigned long seed ); void draw(); private: double radius; vector store; }; // Create a sphere with zero radius and no points Sphere::Sphere() : radius( 0.0 ) { } // Fill the sphere with points random SpherePoints aRadius from // the origin. Use seed to initialize the random number // generator. void Sphere::fill( float aRadius, short points, unsigned long seed ) { // cout << "Sphere::fill(" << aRadius << "," << points << "," << seed << ")" << endl; radius = aRadius; RanGen rng( seed ); store.resize( 0 ); for( short i=0; i