/* spring2gl.c spring and mass command line anything=double buffer */ #include #include #include #ifndef M_PI #define M_PI 3.14159265 #endif /* basic two mass and three spring data */ static int winWidth = 800; static int winHeight = 400; static int xm, ym, bm; // mouse position static int xc = 300; // disc/rectangle location static int yc = 275; static int xc1 = 500; // disc/rectangle location static int yc1 = 275; static int xp; // last mouse location during drag static int yp; static int tracking = 0; // tracking xc mouse motion static int tracking1 = 0; // tracking xc1 mouse motion static int loose = 0; // loose to move static double x = 0.0; // integrated position static double vx = 0.0; // integrated velocity static double x1 = 0.0; // integrated position static double vx1 = 0.0; // integrated velocity static int double_k1 = 0; // yellow buttons static int double_k2 = 0; static int double_k3 = 0; static int disc = 0; static int double_buffer = 1; static GLUquadricObj *obj; /* monitoring data for second window */ static int wh = 600; static int ww = 80; static int tl = 0; /* points in buffer */ static int sxc[601]; static int sxc1[601]; static int bump[601]; void displayTrace(void); static int main_display, trace_display; int in_rect(int x, int y, int w, int h) { return xm>x && xmy && (400-ym)xc1-151)xc=xc1-151; /* prevent overlap */ glutPostRedisplay(); } if(tracking1) { xc1 = xc1 + (xm-xp); // mouse moved (new-old) xp = xm; yp = ym; if(xc1704)xc1=704; glutPostRedisplay(); } } void mouseButton(int button, int state, int x, int y) { xm = x; ym = y; bm = 1; if(state==GLUT_DOWN) { /* printf("mouse down x=%d, y=%d, track=%d \n", x, y, tracking); */ if(in_rect(xc-75, yc-75, 150, 150)) { tracking = 1; loose = 0; xp = xm; yp = ym; } if(in_rect(xc1-75, yc1-75, 150, 150)) { tracking1 = 1; loose = 0; xp = xm; yp = ym; } if(in_rect(220,150,160,50)) disc = 1-disc; if(in_rect( 40,150,150,40)) double_k1 = 1-double_k1; if(in_rect(410,150,150,40)) double_k2 = 1-double_k2; if(in_rect(610,150,150,40)) double_k3 = 1-double_k3; glutPostRedisplay(); } if(state==GLUT_UP) { /* printf("mouse up x=%d, y=%d, track=%d \n", x, y, tracking); */ tracking = 0; tracking1 = 0; loose = 1; } } void physicsComputation(void) { double ax, f1, f2, f3, f; double d1, d2, d3, xold; double dt = 0.1; // time step double mass = 1.0; // mass of disc double k = 1.0; // spring constant /* box limits xmin=20+75=96 clear xmax=(800-20)-75=704 clear */ if(!loose) { x = 0.0; x1 = 0.0; vx = 0.0; vx1 = 0.0; return; } if(tl>599) tl=0; bump[tl]=0; // Get spring forces d1 = (xc-20)/280.0; d2 = (xc1-xc)/280.0; d3 = (780-xc1)/280.0; f1 = k * d1; if(double_k1) f1 = f1*2.0; f2 = k * d2; if(double_k2) f2 = f2*2.0; f3 = k * d3; if(double_k3) f3 = f3*2.0; f = f2 - f1; // f2 bigger, force to right, larger x xold = x; ax = f / mass; // f = ma or a = f / m vx = vx + ax * dt; // v = integral a dt x = x + vx * dt; // x = integral v dt xc = xc + (int)((x-xold)*35.0); if(xc<96) { xc=96; vx=0.0; bump[tl]=1; } if(xc>xc1-151) /* collision, sticksion */ { xc=xc1-151; vx=(vx+vx1)/2.0; bump[tl]=2; } f = f3 - f2; xold = x1; ax = f / mass; // f = ma or a = f / m vx1 = vx1 + ax * dt; // v = integral a dt x1 = x1 + vx1 * dt; // x = integral v dt xc1 = xc1 + (int)((x1-xold)*35.0); if(xc1704) { xc1=704; vx1=0.0; bump[tl] = 3; } sxc[tl] = xc; sxc1[tl] = xc1; tl++; glutSetWindow(main_display); glutPostRedisplay(); glutSetWindow(trace_display); glutPostRedisplay(); } void reshape(int w, int h) { glViewport(0, 0, w, h); winWidth = w; winHeight = h; glutPostRedisplay(); } void reshapeTrace(int w, int h) { glViewport(0, 0, w, h); ww = w; wh = h; glutPostRedisplay(); } static void printstring(int x, int y, char *string) { int len, i; glRasterPos2i(x, y); len = (int) strlen(string); for (i = 0; i < len; i++) glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, string[i]); } /* end printstring */ void display(void) { double x=0.0, xx=0.0; double y=0.0, yy=0.0; double xn,yn,xs; double a; double b; double t=0.0; double f1, f2, f3; /* temporary for drawing only */ int i; a = 1.0/(4.0*M_PI); b = 2.0*a; glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0, 0.0, 0.0); printstring(20, 380, "drag and drop disc to see motion"); printstring(20, 80, "Basic physics:"); /* 20, 310 */ printstring(20, 60, "f = k x the force from a spring is proportional to distance stretched times spring constant, k"); printstring(20,40, "f = m a the force on a body of mass, m, is proportional to the acceleration, a"); printstring(20,20, "acceleration a = dv / dt velocity v = dx / dt"); glColor3f(0.0, 0.0, 0.0); /* box */ glLineWidth(1.0); glBegin(GL_LINE_LOOP); glVertex2f(20, 200); glVertex2f(20, 360); glVertex2f(780,360); glVertex2f(780,200); glEnd(); glColor3f(1.0, 0.0, 0.0); /* mass */ if(disc) { glTranslatef(xc, yc, 0); gluDisk(obj, 75, 75, 20, 20); glTranslatef(-xc, -yc, 0); glTranslatef(xc1, yc1, 0); gluDisk(obj, 75, 75, 20, 20); glTranslatef(-xc1, -yc1, 0); } if(!disc) { glLineWidth(1.0); glBegin(GL_LINE_LOOP); glVertex2f(xc-74, yc-74); glVertex2f(xc-74, yc+74); glVertex2f(xc+74, yc+74); glVertex2f(xc+74, yc-74); glEnd(); glBegin(GL_LINE_LOOP); glVertex2f(xc1-74, yc1-74); glVertex2f(xc1-74, yc1+74); glVertex2f(xc1+74, yc1+74); glVertex2f(xc1+74, yc1-74); glEnd(); } glColor3f(0.0, 0.0, 1.0); /* spring ends */ glPointSize(5.0); glBegin(GL_POINTS); glVertex2f(xc, yc); glVertex2f(xc1, yc1); glVertex2f(20, 275); glVertex2f(780,275); glEnd(); glColor3f(0.0, 1.0, 1.0); /* button */ glBegin(GL_POLYGON); glVertex2f(40, 150); glVertex2f(40, 190); glVertex2f(190,190); glVertex2f(190,150); glEnd(); glColor3f(0.0, 0.0, 0.0); if(!double_k1) printstring(45, 170, "double left spring k"); if(double_k1) printstring(45, 170, "halve left spring"); printstring(45, 155, "note frequency change"); glColor3f(0.0, 1.0, 1.0); /* button */ glBegin(GL_POLYGON); glVertex2f(410, 150); glVertex2f(410, 190); glVertex2f(560,190); glVertex2f(560,150); glEnd(); glColor3f(0.0, 0.0, 0.0); if(!double_k2) printstring(415, 170, "double center spring k"); if(double_k2) printstring(415, 170, "halve center spring"); printstring(415, 155, "note frequency change"); glColor3f(0.0, 1.0, 1.0); /* button */ glBegin(GL_POLYGON); glVertex2f(610, 150); glVertex2f(610, 190); glVertex2f(760,190); glVertex2f(760,150); glEnd(); glColor3f(0.0, 0.0, 0.0); if(!double_k3) printstring(615, 170, "double right spring k"); if(double_k3) printstring(615, 170, "halve right spring"); printstring(615, 155, "note frequency change"); glColor3f(0.0, 1.0, 1.0); /* button */ glBegin(GL_POLYGON); glVertex2f(220, 150); glVertex2f(220, 190); glVertex2f(380,190); glVertex2f(380,150); glEnd(); glColor3f(0.0, 0.0, 0.0); if(disc) printstring(225, 170, "Change disc to rectangle"); if(!disc) printstring(225, 170, "Change rectangle to disc"); glColor3f(0.0, 0.0, 1.0); f1 = (double)(xc-20)/280.0; // factors < 0.5 or > 1.5 not very visible f2 = (double)(xc1-xc)/280.0; f3 = (double)(780-xc1)/280.0; t = 0.0; y = 0.0; x = 0.0; if(double_k1) glLineWidth(2.0); if(!double_k1) glLineWidth(1.0); while(t<32.0*M_PI) // heuristic { t = t+0.1; // 0.05 flicker yn = -(b - b*cos(t)); xn = f1*a*t + b*sin(t); glBegin(GL_LINES); glVertex2f(20+(int)(x *35.0), 275+(int)(y *200.0)); glVertex2f(20+(int)(xn*35.0), 275+(int)(yn*200.0)); glEnd(); x = xn; y = yn; } t = 0.0; x = 0.0; y = 0.0; if(double_k2) glLineWidth(2.0); if(!double_k2) glLineWidth(1.0); while(t<32.0*M_PI) // heuristic { t = t+0.1; // 0.05 flicker yn = -(b - b*cos(t)); xn = f2*a*t + b*sin(t); glBegin(GL_LINES); glVertex2f(xc+(int)(x *35.0), 275+(int)(y *200.0)); glVertex2f(xc+(int)(xn*35.0), 275+(int)(yn*200.0)); glEnd(); x = xn; y = yn; } t = 0.0; x = 0.0; y = 0.0; if(double_k3) glLineWidth(2.0); if(!double_k3) glLineWidth(1.0); while(t<32.0*M_PI) // heuristic { t = t+0.1; // 0.05 flicker yn = -(b - b*cos(t)); xn = f3*a*t + b*sin(t); glBegin(GL_LINES); glVertex2f(xc1+(int)(x *35.0), 275+(int)(y *200.0)); glVertex2f(xc1+(int)(xn*35.0), 275+(int)(yn*200.0)); glEnd(); x = xn; y = yn; } glFlush(); if(double_buffer) glutSwapBuffers(); /* only for double */ } void displayTrace(void) /* second window for motion trace */ { int i; glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0, 0.0, 1.0); /* spring ends */ glPointSize(2.0); glBegin(GL_POINTS); for(i=0; i1) if(argv[1][0]=='s') double_buffer=0; if(double_buffer) glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); if(!double_buffer) glutInitDisplayMode(GLUT_RGB); /* no double buffer */ glutInitWindowSize(winWidth, winHeight); glutInitWindowPosition(50,50); main_display = glutCreateWindow(argv[0]); glutReshapeFunc(reshape); glutDisplayFunc(display); glutMouseFunc(mouseButton); glutMotionFunc(mouseMotion); glutIdleFunc(physicsComputation); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0, (GLfloat)winWidth, 0.0, (GLfloat)winHeight); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glClearColor(1.0, 1.0, 1.0, 0.0); obj = gluNewQuadric(); gluQuadricDrawStyle(obj, GLU_LINE); glutInitWindowSize(ww, wh); glutInitWindowPosition(870,40); trace_display = glutCreateWindow("trace"); glutReshapeFunc(reshapeTrace); glutDisplayFunc(displayTrace); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0, (GLfloat)ww, 0.0, (GLfloat)wh); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glClearColor(1.0, 1.0, 1.0, 0.0); glutMainLoop(); return 0; }