/*
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