/* Structure 3 A surface filled with one hundred medium to small sized circles. Each circle has a different size and direction, but moves at the same slow rate. Display: >>> A. The instantaneous intersections of the circles B. The aggregate intersections of the circles Implemented by Casey Reas <http://groupc.net> 8 March 2004 C++ / OpenGL Writing this program in C++ required three files: s3_A.cpp The controller file, opens/updates the window Circle.cpp Defines the behavior for the circles Circle.h Skematic information about the circles */ #include <GL/glut.h> #include <stdlib.h> #include <math.h> #include "Circle.h" static GLfloat spin = 0.0; static GLint once = 1; static int width; static int height; Circle *circles[numCircle]; void display(void) { if(once == 1) { glClear(GL_COLOR_BUFFER_BIT); once = 0; } for(int i=0; i<numCircle; i++) { circles[i]->update(); circles[i]->move(); } glutSwapBuffers(); glutPostRedisplay(); } GLfloat random() { return (GLfloat) ((float)(rand() >> 0) / 16384.0) - 1.0; } void init(void) { glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glClearColor (1.0, 1.0, 1.0, 1.0); glShadeModel (GL_FLAT); width = 1024; height = 786; for (int i=0; i<numCircle; i++) { circles[i] = new Circle(random()*512, random()*384, (random() + 1) * 60, random()*0.25, random()*0.25, i, circles); } } void reshape(int w, int h) { glViewport (0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(-512.0, 512.0, -384.0, 384.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glClear(GL_COLOR_BUFFER_BIT); } void mouse(int button, int state, int x, int y) { switch (button) { case GLUT_LEFT_BUTTON: break; case GLUT_MIDDLE_BUTTON: case GLUT_RIGHT_BUTTON: break; default: break; } } void keyboard(unsigned char c, int x, int y) { if(c == 'q' || c == 'Q') { exit(0); } } /* * Request double buffer display mode. * Register mouse input callback functions */ int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB); glutCreateWindow("Structure3"); glutFullScreen(); init (); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMouseFunc(mouse); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; /* ANSI C requires main to return int. */ } #include "Circle.h" Circle::Circle(float px, float py, float pr, float psp, float pysp, int pid, Circle *circles[numCircle]) { others = circles; x = px; y = py; r = pr; r2 = r*r; id = pid; sp = psp; ysp = pysp; } void Circle::update() { for(int i=0; i<numCircle; i++) { if(i != id) { intersect( others[id], others[i] ); } } } void Circle::move() { x += sp; y += ysp; if(sp > 0) { if(x > width/2+r) { x = -width/2-r; } } else { if(x < -width/2-r) { x = width/2+r; } } if(ysp < 0) { if(y < -height/2-r) { y = height/2+r; } } else { if(y > height/2+r) { y = -height/2-r; } } } void Circle::intersect(Circle *cA, Circle *cB) { float dx = cA->x - cB->x; float dy = cA->y - cB->y; float d2 = dx*dx + dy*dy; float d = sqrt( d2 ); if ( d>cA->r+cB->r || d<abs(cA->r-cB->r) ) return; // no solution float a = (cA->r2 - cB->r2 + d2) / (2*d); float h = sqrt( cA->r2 - a*a ); float x2 = cA->x + a*(cB->x - cA->x)/d; float y2 = cA->y + a*(cB->y - cA->y)/d; float paX = x2 + h*(cB->y - cA->y)/d; float paY = y2 - h*(cB->x - cA->x)/d; float pbX = x2 - h*(cB->y - cA->y)/d; float pbY = y2 + h*(cB->x - cA->x)/d; float dist = distance(paX, paY, pbX, pbY) *2 / 255.0f; glColor4f(dist, dist, dist, 0.05f); glBegin(GL_LINES); glVertex2f(paX, paY); glVertex2f(pbX, pbY); glEnd(); } float Circle::distance(float x1, float y1, float x2, float y2) { return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)); } #include "math.h" #include <GL/glut.h> #ifndef _Circle_H_ #define _Circle_H_ #define PI 3.14159265358979323846 #define TWO_PI 6.28318530717958647693 #define numCircle 100 class Circle { public: float x, y, r, r2, sp, ysp; int id; Circle **others; Circle(); Circle(float, float, float, float, float, int, Circle *[numCircle]); void update(); void move(); void intersect(Circle *, Circle *); float distance(float, float, float, float); }; #endif