#include #include #include #include "pp2d.h" /*---------------------------------------------------------------------- pp2d: Simple program for animating 2d particle motion. Copyright 1997- Matthew W Choptuik, UT Austin This program uses OpenGL and the GLUT toolkit. If linked with the MesaGL libraries, it should display on any X client. Usage: See 'help()' function below or type 'pp2d -h' ----------------------------------------------------------------------*/ /*---------------------------------------------------------------------- G L O B A L V A R I A B L E S Ltrace: Enables debugging output if non-zero Win_w: Current graphics window width (pixels) Win_h: Current graphics window height (pixels) Win_Xsize Requested graphics window width (pixels) Win_Ysize Requested graphics window height (pixels) Init: Flag specifying whether input stream has been initialized Done: Flag specifying whether input stream has been exhausted Xmin: Physical x coordinate of lower left corner of window Ymin: Physical y coordinate of lower left corner of window Xmax: Physical x coordinate of upper right corner of window Ymax: Physical y coordinate of upper right corner of window BaseSize: Base size of particles (pixels) MinSize: Minimum size of particles (pixels) MaxSize: Maximum size of particles (pixels) Np: Number of particles Time: Current display time Size: : Vector of particle sizes Coords: Vector of particle coordinates Nt: Number of time steps processed so far Pause: Pauses/Continues display. Zoom: Controls amount of zoom-in / zoom-out. DSize: Controls amount of rescale in BaseSize. Trans: Controls amount of translation. Win_Title: Buffer for window title Dbuff: Non-zero for double buffering AnitA: Non-zero for antialiasing R, G, B: RGB color vectors for markers; Ncol: # of colors to use (1 for monochrome) Dummy: "Don't care" double ----------------------------------------------------------------------*/ int Ltrace = 0; int Win_w, Win_h; double Win_Xsize = 200; double Win_Ysize = 200; int Init = 0, Done = 0; double Xmin = -2.0, Ymin = -2.0, Xmax = 2.0, Ymax = 2.0; double BaseSize = 5.0; double MinSize = 3.0; double MaxSize = 20.0; int Np = 0; double Time; double *Size = (double *) NULL; double *Coords = (double *) NULL; int Nt = 0; int Pause = 0; double Zoom = 1.2; double DSize = 1.2; double Trans = 0.05; char Win_Title[1024]; int Dbuff = 1; int AntiA = 1; double R[] = { 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0 }, G[] = { 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0 }, B[] = { 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0 }; int Ncol = sizeof(R) / sizeof(double); double Dummy; /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/ /* Returns val clamped to min ... max */ /*--------------------------------------------------------------------*/ double clamped(double val,double min,double max) { if( val < min ) { return min; } else if( val > max ) { return max; } else { return val; } } /*--------------------------------------------------------------------*/ /* Dumps help to standard output */ /*--------------------------------------------------------------------*/ void help(void) { printf("usage: pp2d [-hm]\n\n"); printf("Displays animations of two dimensional particle motion\n\n"); printf(" Flags: -h help\n"); printf(" -m monochrome\n\n"); printf("-----------------------------------------------------------------------------\n"); printf("pp2d expects the following formatted input on standard input:\n"); printf("-----------------------------------------------------------------------------\n\n"); printf(" ! Number of particles\n"); printf(" ! Relative display size of particle 1\n"); printf(" ! Relative display size of particle 2\n"); printf(" .\n"); printf(" .\n"); printf(" .\n"); printf(" ! Relative display size of particle np\n"); printf(" ! First display time\n"); printf(" ! Coordinates of particle 1 at t_1\n"); printf(" ! Coordinates of particle 2 at t_1\n"); printf(" .\n"); printf(" .\n"); printf(" .\n"); printf(" ! Coordinates of particle np at t_1\n"); printf(" ! Second display time\n"); printf(" ! Coordinates of particle 1 at t_2\n"); printf(" ! Coordinates of particle 2 at t_2\n"); printf(" .\n"); printf(" .\n"); printf(" .\n"); printf(" ! Coordinates of particle np at t_2\n"); printf(" ! Third display time\n"); printf(" .\n"); printf(" .\n"); printf(" .\n"); printf("\n"); printf(" All values are expected to be real numbers except for which is\n"); printf(" an integer. Note that 3 coordinates per particle are expected\n"); printf(" although the z coordinate will be ignored.\n"); printf("\n"); printf("-----------------------------------------------------------------------------\n"); printf("pp2d keyboard assigments (commands are case-insensitive):\n"); printf("-----------------------------------------------------------------------------\n\n"); printf(" ESC: Exit program\n"); printf(" p: Pause/continue animation\n\n"); printf(" z: Zoom-in on solution domain\n"); printf(" x: Zoom-out on solution domain\n\n"); printf(" a: Enlarge marker size\n"); printf(" s: Reduce marker size\n\n"); printf(" q: Enlarge window size\n"); printf(" w: Reduce window size\n\n"); printf(" up-arrow (k): Pan up\n"); printf(" down-arrow (j): Pan down\n"); printf(" left-arrow (h): Pan left\n"); printf(" right-arrow (l): Pan right\n"); printf("\n"); printf("-----------------------------------------------------------------------------\n"); printf("Miscellaneous\n"); printf("-----------------------------------------------------------------------------\n\n"); printf("The initial (default) viewing region is: %g <= x <= %g %g <= y <= %g\n", Xmin,Xmax,Ymin,Ymax); printf("The base marker size is %g pixels\n",BaseSize); printf("Markers can range from %g to %g pixels in size\n",MinSize,MaxSize); exit(1); } /*--------------------------------------------------------------------*/ /* Dumps error message to stderr and exits */ /*--------------------------------------------------------------------*/ void badstream_exit(char *s) { fprintf(stderr,"Error reading %s\n",s); exit(0); } /*--------------------------------------------------------------------*/ /* Processes input */ /*--------------------------------------------------------------------*/ void getinput(void) { int i; if( Done || Pause ) return; if( Init == 0 ) { glutPostRedisplay(); Init = 1; return; } if( Init == 1 ) { /*------------------------------------------------------------------- Initialization: Read number of particles and particle sizes, allocate storage for particle coordinates and sizes. -------------------------------------------------------------------*/ if( scanf("%d",&Np) == 1 ) { if( Ltrace ) { fprintf(stderr,"getinput: %d particles\n",Np); } Size = (double *) malloc(Np * sizeof(double)); Coords = (double *) malloc(2 * Np * sizeof(double)); for( i = 0; i < Np; i++ ) { if( scanf("%lf",Size + i) == 1 ) { if( Ltrace ) { fprintf(stderr,"getinput: Particle %d Size %g\n", i+1,Size[i]); } } else { badstream_exit("particle sizes"); } } } else { badstream_exit("number of particles"); } Init = 2; } /*------------------------------------------------------------------- Read new time, particle positions and post redisplay request. -------------------------------------------------------------------*/ if( scanf("%lf",&Time) == 1 ) { if( Ltrace ) fprintf(stderr,"getinput: Time %g\n",Time); for( i = 0; i < Np; i++ ) { if( scanf("%lf %lf %lf",Coords + 2*i, Coords + 2*i + 1,&Dummy) == 3 ) { if( Ltrace ) { fprintf(stderr,"getinput: Particle %d Pos (%g,%g)\n", i,Coords[2*i],Coords[2*i+1]); } } } Nt++; if( Nt == 1 ) { Pause = 1; reshape(Win_w,Win_h); } } else { Done = 1; glutSetWindowTitle("Esc exits"); } glutPostRedisplay(); } /*--------------------------------------------------------------------*/ /* 'idle' function. GLUT driver calls this whenever there's nothing */ /* else to do */ /*--------------------------------------------------------------------*/ void idle(void) { getinput(); } /*--------------------------------------------------------------------*/ /* Handles keyboard events. */ /*--------------------------------------------------------------------*/ void keyboard(unsigned char key,int x, int y) { double ocx, ocy, odx, ody; switch( key ) { case 'a': case 'A': /* A-key: Increase particle sizes ... */ BaseSize *= DSize; glutPostRedisplay(); break; case 's': case 'S': /* S-key: Decrease particle sizes ... */ BaseSize /= DSize; glutPostRedisplay(); break; case 'h': case 'H': /* H-key: Translate left ... */ odx = Xmax - Xmin; Xmax -= Trans * odx; Xmin -= Trans * odx; reshape(Win_w,Win_h); break; case 'l': case 'L': /* H-key: Translate right ... */ odx = Xmax - Xmin; Xmax += Trans * odx; Xmin += Trans * odx; reshape(Win_w,Win_h); break; case 'j': case 'J': /* J-key: Translate down ... */ ody = Ymax - Ymin; Ymax -= Trans * ody; Ymin -= Trans * ody; reshape(Win_w,Win_h); break; case 'k': case 'K': /* K-key: Translate up ... */ ody = Ymax - Ymin; Ymax += Trans * ody; Ymin += Trans * ody; reshape(Win_w,Win_h); break; case 'x': case 'X': /* X-key: Zoom-out ... */ ocx = 0.5 * (Xmin + Xmax); ocy = 0.5 * (Ymin + Ymax); odx = 0.5 * (Xmax - Xmin); ody = 0.5 * (Ymax - Ymin); Xmin = ocx - odx * Zoom; Xmax = ocx + odx * Zoom; Ymin = ocy - ody * Zoom; Ymax = ocy + ody * Zoom; reshape(Win_w,Win_h); break; case 'z': case 'Z': /* Z-key: Zoom-in ... */ ocx = 0.5 * (Xmin + Xmax); ocy = 0.5 * (Ymin + Ymax); odx = 0.5 * (Xmax - Xmin); ody = 0.5 * (Ymax - Ymin); Xmin = ocx - odx / Zoom; Xmax = ocx + odx / Zoom; Ymin = ocy - ody / Zoom; Ymax = ocy + ody / Zoom; reshape(Win_w,Win_h); break; case 'q': case 'Q': /* W-key: Make window larger ... */ Win_Xsize *= Zoom; Win_Ysize *= Zoom; glutReshapeWindow(Win_Xsize, Win_Ysize); glutPostRedisplay(); break; case 'w': case 'W': /* W-key: Make window smaller ... */ Win_Xsize /= Zoom; Win_Ysize /= Zoom; glutReshapeWindow(Win_Xsize, Win_Ysize); glutPostRedisplay(); break; case 'P': case 'p': /* P-key: Pause/Continue ... */ Pause = !Pause; reshape(Win_w,Win_h); break; case 27: /* Escape Key: Exit program ... */ exit(0); default: break; } } /*--------------------------------------------------------------------*/ /* Handles special keys. */ /*--------------------------------------------------------------------*/ void special(int key, int x, int y ) { int odx, ody; switch( key ) { case GLUT_KEY_LEFT: /* Translate left ... */ odx = Xmax - Xmin; Xmax -= Trans * odx; Xmin -= Trans * odx; reshape(Win_w,Win_h); break; case GLUT_KEY_RIGHT: /* Translate right ... */ odx = Xmax - Xmin; Xmax += Trans * odx; Xmin += Trans * odx; reshape(Win_w,Win_h); break; case GLUT_KEY_UP: /* Translate up ... */ ody = Ymax - Ymin; Ymax += Trans * ody; Ymin += Trans * ody; reshape(Win_w,Win_h); break; case GLUT_KEY_DOWN: /* Translate down ... */ ody = Ymax - Ymin; Ymax -= Trans * ody; Ymin -= Trans * ody; reshape(Win_w,Win_h); break; default: break; } } /*--------------------------------------------------------------------*/ /* Displays particles ... most of the OpenGL graphics calls are */ /* in this routine. */ /*--------------------------------------------------------------------*/ void display(void) { int i; if( Ltrace ) fprintf(stderr,"display: In routine\n"); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if( Np ) { if( Ltrace ) { fprintf(stderr,"display: glOrtho(%g,%g,%g,%g,%g,%g)\n", Xmin,Xmax,Ymin,Ymax,0.0,0.0); } for( i = 0; i < Np; i++ ) { int ic = i % Ncol; if( Ltrace ) { fprintf(stderr,"display: Particle %d Size %g Pos (%g,%g)\n", i+1,BaseSize*Size[i],Coords[2*i],Coords[2*i+1]); } glColor3d(R[ic],G[ic],B[ic]); glPointSize((GLfloat) clamped(BaseSize * Size[i],MinSize,MaxSize)); glBegin(GL_POINTS); glVertex2d(Coords[2*i],Coords[2*i+1]); glEnd(); } } if( Dbuff) glutSwapBuffers(); } /*--------------------------------------------------------------------*/ /* Routine called when window has been reshaped. */ /*--------------------------------------------------------------------*/ void reshape(int nw, int nh) { if( Ltrace ) fprintf(stderr,"reshape: New shape %d x %d\n",nw,nh); Win_w = nw; Win_h = nh; glViewport(0, 0, Win_w, Win_h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(Xmin,Xmax,Ymin,Ymax,-1.0,0.0); glMatrixMode(GL_MODELVIEW); if( Pause ) { glutSetWindowTitle("p continues"); } else if ( Done ) { glutSetWindowTitle(" exits"); } else { sprintf(Win_Title,"[%.2g,%.2g] [%.2g,%.2g]\n", Xmin,Xmax,Ymin,Ymax); glutSetWindowTitle(Win_Title); } glutPostRedisplay(); } /*--------------------------------------------------------------------*/ /* M A I N routine */ /*--------------------------------------------------------------------*/ int main(int argc,char **argv) { int c; int errflg = 0; /* Parse command line options ... see 'man getopt' for more info */ /* on the 'getopt' funcion */ while ((c = getopt(argc, argv, "hm")) != -1) { switch(c) { case 'h': help(); break; case 'm': Ncol = 1; break; default: errflg = 1; break; } } if( errflg ) { fprintf(stderr,"usage: pp2d [-hm]\n\n"); fprintf(stderr," Use 'pp2d -h' for help\n"); exit(2); } /* Set up graphics, register callbacks etc. */ glutInit(&argc, argv); if( Dbuff ) { glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB); } else { glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB); } glutInitWindowSize(Win_Xsize, Win_Ysize); glutCreateWindow("pp2d"); glutKeyboardFunc(keyboard); glutDisplayFunc(display); glutSpecialFunc(special); glutReshapeFunc(reshape); glutIdleFunc(idle); if( AntiA ) glEnable(GL_POINT_SMOOTH); /* Enter GLUT main loop. */ glutMainLoop(); return 0; }