From e150e05bf1baf832de450b3141d8fac59cfc09fb Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Mon, 30 Jun 2003 17:09:12 +0000 Subject: [PATCH] Lorenz attractor demo (John Fay) git-svn-id: svn+ssh://svn.code.sf.net/p/freeglut/code/trunk/freeglut/freeglut@111 7f0cb862-5218-0410-a997-914c9d46530a --- progs/demos/Lorenz/lorenz.c | 344 +++++++++++++++++++++++++++++++++++++++++ progs/demos/Lorenz/lorenz.dsp | 101 ++++++++++++ 2 files changed, 445 insertions(+) create mode 100644 progs/demos/Lorenz/lorenz.c create mode 100644 progs/demos/Lorenz/lorenz.dsp diff --git a/progs/demos/Lorenz/lorenz.c b/progs/demos/Lorenz/lorenz.c new file mode 100644 index 0000000..4f0afc1 --- /dev/null +++ b/progs/demos/Lorenz/lorenz.c @@ -0,0 +1,344 @@ +/* + * Lorenz Strange Attractor + * + * Written by John F. Fay in honor of the "freeglut" 2.0.0 release in July 2003 + * + * What it does: + * This program starts with two particles right next to each other. The particles + * move through a three-dimensional phase space governed by the following equations: + * dx/dt = sigma * ( y - x ) + * dy/dt = r * x - y + x * z + * dz/dt = x * y + b * z + * These are the Lorenz equations and define the "Lorenz Attractor." Any two particles + * arbitrarily close together will move apart as time increases, but their tracks are + * confined within a region of the space. + * + * Commands: + * Arrow keys: Rotate the view + * PgUp, PgDn: Zoom in and out + * Mouse click: Center on the nearest point on a particle trajectory + * + * 'r'/'R': Reset the simulation + * 'm'/'M': Modify the Lorenz parameters (in the text window) + * 's'/'S': Stop (the advancement in time) + * 'g'/'G': Go + * : Single-step + * : Quit + */ + +/* Include Files */ +#include +#include +#include +#include +#include +#include + + +/************************************** Defined Constants ***************************************/ +/* Number of points to draw in the curves */ +#define NUM_POINTS 512 + +/* Angle to rotate when the user presses an arrow key */ +#define ROTATION_ANGLE 5.0 + +/* Amount to scale bu when the user presses PgUp or PgDn */ +#define SCALE_FACTOR 0.8 + + +/*************************************** Global Variables ***************************************/ +/* Lorenz Attractor variables */ +double s0 = 10.0, r0 = 28.0, b0 = 8.0/3.0 ; /* Default Lorenz attactor parameters */ +double time_step = 0.03 ; /* Time step in the simulation */ +double sigma = 10.0, r = 28.0, b = 8.0/3.0 ; /* Lorenz attactor parameters */ +double red_position[NUM_POINTS][3] ; /* Path of the red point */ +double grn_position[NUM_POINTS][3] ; /* Path of the green point */ +int array_index ; /* Position in *_position arrays of most recent point */ +double distance = 0.0 ; /* Distance between the two points */ + +/* GLUT variables */ +double yaw = 0.0, pit = 0.0 ; /* Euler angles of the viewing rotation */ +double scale = 1.0 ; /* Scale factor */ +double xcen = 0.0, ycen = 0.0, zcen = 0.0 ; /* Coordinates of the point looked at */ + +int animate = 1 ; /* 0 - stop, 1 = go, 2 = single-step */ + + +/******************************************* Functions ******************************************/ + +/* The Lorenz Attractor */ +void calc_deriv ( double position[3], double deriv[3] ) +{ + /* Calculate the Lorenz attractor derivatives */ + deriv[0] = sigma * ( position[1] - position[0] ) ; + deriv[1] = ( r + position[2] ) * position[0] - position[1] ; + deriv[2] = -position[0] * position[1] - b * position[2] ; +} + +void advance_in_time ( double time_step, double position[3], double new_position[3] ) +{ + /* Move a point along the Lorenz attractor */ + double deriv0[3], deriv1[3], deriv2[3], deriv3[3] ; + int i ; + memcpy ( new_position, position, 3 * sizeof(double) ) ; /* Save the present values */ + + /* First pass in a Fourth-Order Runge-Kutta integration method */ + calc_deriv ( position, deriv0 ) ; + for ( i = 0; i < 3; i++ ) + new_position[i] = position[i] + 0.5 * time_step * deriv0[i] ; + + /* Second pass */ + calc_deriv ( new_position, deriv1 ) ; + for ( i = 0; i < 3; i++ ) + new_position[i] = position[i] + 0.5 * time_step * deriv1[i] ; + + /* Third pass */ + calc_deriv ( position, deriv2 ) ; + for ( i = 0; i < 3; i++ ) + new_position[i] = position[i] + time_step * deriv2[i] ; + + /* Second pass */ + calc_deriv ( new_position, deriv3 ) ; + for ( i = 0; i < 3; i++ ) + new_position[i] = position[i] + 0.1666666666666666667 * time_step * + ( deriv0[i] + 2.0 * ( deriv1[i] + deriv2[i] ) + deriv3[i] ) ; +} + +/* GLUT callbacks */ + +void key_cb ( unsigned char key, int x, int y ) +{ + int i ; + char inputline [ 80 ] ; + + switch ( key ) + { + case 'r' : case 'R' : /* Reset the simulation */ + /* Reset the Lorenz parameters */ + sigma = s0 ; + b = b0 ; + r = r0 ; + /* Set an initial position */ + red_position[0][0] = (double)rand() / (double)RAND_MAX ; + red_position[0][1] = (double)rand() / (double)RAND_MAX ; + red_position[0][2] = (double)rand() / (double)RAND_MAX ; + grn_position[0][0] = (double)rand() / (double)RAND_MAX ; + grn_position[0][1] = (double)rand() / (double)RAND_MAX ; + grn_position[0][2] = (double)rand() / (double)RAND_MAX ; + array_index = 0 ; + /* Initialize the arrays */ + for ( i = 1; i < NUM_POINTS; i++ ) + { + memcpy ( red_position[i], red_position[0], 3 * sizeof(double) ) ; + memcpy ( grn_position[i], grn_position[0], 3 * sizeof(double) ) ; + } + + break ; + + case 'm' : case 'M' : /* Modify the Lorenz parameters */ + printf ( "Please enter new value for (default %lf, currently %lf): ", s0, sigma ) ; + fgets ( inputline, 79, stdin ) ; + sscanf ( inputline, "%lf", &sigma ) ; + + printf ( "Please enter new value for (default %lf, currently %lf): ", b0, b ) ; + fgets ( inputline, 79, stdin ) ; + sscanf ( inputline, "%lf", &b ) ; + + printf ( "Please enter new value for (default %lf, currently %lf): ", r0, r ) ; + fgets ( inputline, 79, stdin ) ; + sscanf ( inputline, "%lf", &r ) ; + + break ; + + case 's' : case 'S' : /* Stop the animation */ + animate = 0 ; + break ; + + case 'g' : case 'G' : /* Start the animation */ + animate = 1 ; + break ; + + case ' ' : /* Spacebar: Single step */ + animate = 2 ; + break ; + + case 27 : /* Escape key */ + glutLeaveMainLoop () ; + break ; + } +} + +void special_cb ( int key, int x, int y ) +{ + switch ( key ) + { + case GLUT_KEY_UP : /* Rotate up a little */ + glRotated ( ROTATION_ANGLE, 0.0, 1.0, 0.0 ) ; + break ; + + case GLUT_KEY_DOWN : /* Rotate down a little */ + glRotated ( -ROTATION_ANGLE, 0.0, 1.0, 0.0 ) ; + break ; + + case GLUT_KEY_LEFT : /* Rotate left a little */ + glRotated ( ROTATION_ANGLE, 0.0, 0.0, 1.0 ) ; + break ; + + case GLUT_KEY_RIGHT : /* Rotate right a little */ + glRotated ( -ROTATION_ANGLE, 0.0, 0.0, 1.0 ) ; + break ; + + case GLUT_KEY_PAGE_UP : /* Zoom in a little */ + glScaled ( 1.0 / SCALE_FACTOR, 1.0 / SCALE_FACTOR, 1.0 / SCALE_FACTOR ) ; + break ; + + case GLUT_KEY_PAGE_DOWN : /* Zoom out a little */ + glScaled ( SCALE_FACTOR, SCALE_FACTOR, SCALE_FACTOR ) ; + break ; + } + + glutPostRedisplay () ; +} + +void mouse_cb ( int button, int updown, int x, int y ) +{ + if ( updown == GLUT_DOWN ) + { + double dist = 1.0e20 ; /* A very large number */ + (void) dist; /* what's this all about? */ + } +} + +void draw_curve ( int index, double position [ NUM_POINTS ][3] ) +{ + int i = index ; + + glBegin ( GL_LINE_STRIP ) ; + do + { + i = ( i == NUM_POINTS-1 ) ? 0 : i + 1 ; + glVertex3dv ( position[i] ) ; + } + while ( i != index ) ; + + glEnd () ; +} + +void display_cb ( void ) +{ + char string [ 80 ] ; + + glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ; + + glColor3d ( 1.0, 1.0, 1.0 ) ; /* White */ + /* Draw some axes */ + glBegin ( GL_LINES ) ; + glVertex3d ( 0.0, 0.0, 0.0 ) ; + glVertex3d ( 2.0, 0.0, 0.0 ) ; + glVertex3d ( 0.0, 0.0, 0.0 ) ; + glVertex3d ( 0.0, 1.0, 0.0 ) ; + glVertex3d ( 0.0, 0.0, 0.0 ) ; + glVertex3d ( 0.0, 0.0, 1.0 ) ; + glEnd () ; + + glColor3d ( 1.0, 0.0, 0.0 ) ; /* Red */ + draw_curve ( array_index, red_position ) ; + + glColor3d ( 0.0, 1.0, 0.0 ) ; /* Green */ + draw_curve ( array_index, grn_position ) ; + + /* Print the distance between the two points */ + glColor3d ( 1.0, 1.0, 1.0 ) ; /* White */ + sprintf ( string, "Distance: %10.6lf", distance ) ; + glRasterPos2i ( 10, 10 ) ; + glutBitmapString ( GLUT_BITMAP_HELVETICA_12, string ) ; + + glutSwapBuffers(); +} + +void reshape_cb ( int width, int height ) +{ + float ar; + glViewport ( 0, 0, width, height ) ; + glMatrixMode ( GL_PROJECTION ) ; + glLoadIdentity () ; + ar = (float) width / (float) height ; + glFrustum ( -ar, ar, -1.0, 1.0, 10.0, 100.0 ) ; + glMatrixMode ( GL_MODELVIEW ) ; + glLoadIdentity () ; + xcen = 0.0 ; + ycen = 0.0 ; + zcen = 0.0 ; + glTranslated ( xcen, ycen, zcen - 50.0 ) ; +} + + +void timer_cb ( int value ) +{ + /* Function called at regular intervals to update the positions of the points */ + double deltax, deltay, deltaz ; + int new_index = array_index + 1 ; + + /* Set the next timed callback */ + glutTimerFunc ( 30, timer_cb, 0 ) ; + + if ( animate > 0 ) + { + if ( new_index == NUM_POINTS ) new_index = 0 ; + advance_in_time ( time_step, red_position[array_index], red_position[new_index] ) ; + advance_in_time ( time_step, grn_position[array_index], grn_position[new_index] ) ; + array_index = new_index ; + + deltax = red_position[array_index][0] - grn_position[array_index][0] ; + deltay = red_position[array_index][1] - grn_position[array_index][1] ; + deltaz = red_position[array_index][2] - grn_position[array_index][2] ; + distance = sqrt ( deltax * deltax + deltay * deltay + deltaz * deltaz ) ; + + if ( animate == 2 ) animate = 0 ; + } + + glutPostRedisplay () ; +} + + + +/* The Main Program */ + +int main ( int argc, char *argv[] ) +{ + int pargc = argc ; + + /* Initialize the random number generator */ + srand ( 1023 ) ; + + /* Set up the OpenGL parameters */ + /* glDrawBuffer ( GL_BACK ) ;*/ + glEnable ( GL_DEPTH_TEST ) ; + glClearColor ( 0.0, 0.0, 0.0, 0.0 ) ; + glClearDepth ( 1.0 ) ; + + /* Initialize GLUT */ + glutInitWindowSize ( 600, 600 ) ; + glutInit ( &pargc, argv ) ; + glutInitDisplayMode ( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH ) ; + + /* Create the window */ + glutCreateWindow ( "Lorenz Attractor" ) ; + glutKeyboardFunc ( key_cb ) ; + glutMouseFunc ( mouse_cb ) ; + glutSpecialFunc ( special_cb ) ; + glutDisplayFunc ( display_cb ) ; + glutReshapeFunc ( reshape_cb ) ; + glutTimerFunc ( 30, timer_cb, 0 ) ; + + /* Initialize the attractor: The easiest way is to call the keyboard callback with an + * argument of 'r' for Reset. + */ + key_cb ( 'r', 0, 0 ) ; + + /* Enter the GLUT main loop */ + glutMainLoop () ; + + return 0; +} + diff --git a/progs/demos/Lorenz/lorenz.dsp b/progs/demos/Lorenz/lorenz.dsp new file mode 100644 index 0000000..2462c24 --- /dev/null +++ b/progs/demos/Lorenz/lorenz.dsp @@ -0,0 +1,101 @@ +# Microsoft Developer Studio Project File - Name="lorenz" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=lorenz - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "lorenz.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "lorenz.mak" CFG="lorenz - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "lorenz - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "lorenz - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "lorenz - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "lorenz - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "C:\OpenGL\freeglut\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "FREEGLUT_STATIC" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"C:\OpenGL\freeglut\freeglut_static___Win32_Debug" + +!ENDIF + +# Begin Target + +# Name "lorenz - Win32 Release" +# Name "lorenz - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\lorenz.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project -- 1.7.10.4