Go Back
#include <iostream.h>
#include "complex.h"
#include <GL/glut.h>
// DECLARATIONS
GLint mainWindow, iterWindow, graphWindow, width = 420, height = 480;
// Number of iterations to do
long nIter = 0;
// Number of endpoints received
int endPts = 0;
// Array to hold endpoints
double pts[2][2];
// Display all iterations or not
int toggle = 0;
// Point about which to rotate
complex rotator = complex(-0.2, 0.6);
// Tolerance for testing doubles for equality
const double TOL = 1E-5, INF = 1E5;
// OVERALL WINDOW
void dispMain();
void reshape(int w, int h);
void keyPress(unsigned char key, int x, int y);
// GRAPH DISPLAY WINDOW
void display();
void mouse(int button, int state, int x, int y);
// ITERATION INFO WINDOW
void dispIter();
int main(int argc, char **argv)
{
// INITIALIZE EVERYTHING
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB);
glutInitWindowSize(width, height);
// Overall window and functions
mainWindow = glutCreateWindow("Twist and Flip, Complex Style!");
glutDisplayFunc(dispMain);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyPress);
// Iteration info window and functions
iterWindow = glutCreateSubWindow(mainWindow, 10, 10, 400, 50);
glutDisplayFunc(dispIter);
glutKeyboardFunc(keyPress);
// Graph display window and functions
graphWindow = glutCreateSubWindow(mainWindow, 10, 70, 400, 400);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutKeyboardFunc(keyPress);
// Start!
glutMainLoop();
return 0;
}
void dispMain()
{
// Set black background for main window
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
}
void reshape(int w, int h)
{
// If reshaping is attempted, restore everything!
glutSetWindow(mainWindow);
glutReshapeWindow(width, height);
glutSetWindow(iterWindow);
glutPositionWindow(10, 10);
glutReshapeWindow(400, 50);
glutSetWindow(graphWindow);
glutPositionWindow(10, 70);
glutReshapeWindow(400, 400);
// Redraw stuff
glFlush();
glutPostRedisplay();
}
void keyPress(unsigned char key, int x, int y)
{
// Toggle displaying all iterations upon keypress
if (key != 'T' && key != 't') return;
toggle = 1-toggle;
display();
}
void display()
{
long i, j;
double x, y;
complex region[100000], unit = complex(1, 0);
// Initialize graph, set it to white
glutSetWindow(graphWindow);
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glOrtho(-5.0, 5.0, -5.0, 5.0, -1.0, 1.0);
// DRAW AXES
glBegin(GL_LINES);
glColor3f(0.0, 0.0, 0.0);
glVertex3f(-5.0, 0.0, 0.0);
glVertex3f(5.0, 0.0, 0.0);
glVertex3f(0.0, -5.0, 0.0);
glVertex3f(0.0, 5.0, 0.0);
// Tick marks
for (i = -5; i <= 5; i++)
{
glVertex3f(-0.1, i, 0.0);
glVertex3f(0.1, i, 0.0);
glVertex3f(i, -0.1, 0.0);
glVertex3f(i, 0.1, 0.0);
}
glEnd();
// LABEL AXES
glRasterPos3f(5.0, 0.25, 0.0);
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, 'x');
glRasterPos3f(0.25, 5.0, 0.0);
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, 'y');
if (endPts < 2)
{
glBegin(GL_POINTS);
glColor3f(1.0, 0.0, 0.0);
if (endPts >= 1)
glVertex3f(pts[0][0], pts[0][1], 0.0);
glEnd();
}
if (endPts == 2)
{
// Define colors in terms of red, yellow, green, blue
double colors[4][3] =
{{1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}};
double colortemp[3];
// Plot initial point and point of rotation
glBegin(GL_POINTS);
glColor3f(0.0, 1.0, 0.0);
glVertex3f(rotator.re(), rotator.im(), 0.0);
for (i = 0; i < 100000; i++)
{
// Get point on the line
region[i] = complex(pts[0][0]+0.00001*(pts[1][0]-pts[0][0])*i,
pts[0][1]+0.00001*(pts[1][1]-pts[0][1])*i);
// and do the shading by scaling color values.
colortemp[0] = colors[int(i/25000)][0]*double(25000-i%25000)/25000;
colortemp[0] += colors[int(i/25000)+1][0]*double(i%25000)/25000;
colortemp[1] = colors[int(i/25000)][1]*double(25000-i%25000)/25000;
colortemp[1] += colors[int(i/25000)+1][1]*double(i%25000)/25000;
colortemp[2] = colors[int(i/25000)][2]*double(25000-i%25000)/25000;
colortemp[2] += colors[int(i/25000)+1][2]*double(i%25000)/25000;
// Plot the beast.
glColor3f(colortemp[0], colortemp[1], colortemp[2]);
glVertex3f(region[i].re(), region[i].im(), 0.0);
}
// PLOT ITERATIONS
for (j = 1; j <= nIter; j++)
{
for (i = 0; i < 100000; i++)
{
// Iteration algorithm: shrink a point by a factor of its argument,
// then rotate it by an angle equal to its distance from the rotator.
region[i] *= polar2rect(1 / region[i].arg(),
complex(rotator-region[i]).mod() / PI);
// Then invert it with respect to the unit circle unless it's 0
if (region[i].mod() > TOL) region[i] = (unit / region[i]).conj() * -1;
// in which case just send it to infinity.
else region[i] = complex(INF, INF);
// If all iterations should be displayed or this is the last iteration
// (which is always displayed), then display it.
if (!toggle || j == nIter)
{
colortemp[0] = colors[int(i/25000)][0]*double(25000-i%25000)/25000;
colortemp[0] += colors[int(i/25000)+1][0]*double(i%25000)/25000;
colortemp[1] = colors[int(i/25000)][1]*double(25000-i%25000)/25000;
colortemp[1] += colors[int(i/25000)+1][1]*double(i%25000)/25000;
colortemp[2] = colors[int(i/25000)][2]*double(25000-i%25000)/25000;
colortemp[2] += colors[int(i/25000)+1][2]*double(i%25000)/25000;
glColor3f(colortemp[0], colortemp[1], colortemp[2]);
glVertex3f(region[i].re(), region[i].im(), 0.0);
}
}
}
glEnd();
}
}
void mouse(int button, int state, int x, int y)
{
// If they clicked at all, proceed.
if (state == GLUT_DOWN)
{
// If we don't have a line to start with, then the click means
// to get one of the end points.
if (endPts < 2)
{
double xp = (double(x)-200) / 40.0;
double yp = (200-double(y)) / 40.0;
cout << "(" << xp << "," << yp << ")\n";
pts[endPts][0] = xp;
pts[endPts][1] = yp;
endPts++;
display();
}
// We have a line, so either increase or decrease the number of
// iterations (left = increase, right = decrease)
else
{
if (button == 0)
nIter++;
if (button == 2 && nIter > 0)
nIter--;
dispIter();
display();
}
}
}
void dispIter()
{
int i, j, len;
if (len > 0) len = int(log10(nIter))+1;
double nIterCopy = nIter+TOL;
while (nIterCopy > 10-TOL) nIterCopy /= 10;
// Initialize info window and color it white.
glutSetWindow(iterWindow);
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glOrtho(0.0, 8.0, 0.0, 1.0, -1.0, 1.0);
// Print the number of iterations
char msg[13] = "Iterations: ";
glColor3f(0.0, 0.0, 0.0);
glRasterPos3f(1.0, 0.5, 0.0);
for (i = 0; i < 12; i++)
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, msg[i]);
if (nIter == 0)
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, '0');
else for (i = 0; i < len; i++)
{
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, char(int(nIterCopy)+'0'));
nIterCopy = nIterCopy - int(nIterCopy);
nIterCopy *= 10;
}
// Print toggle instructions
char toggleMsg[26] = "<T> Toggle All Iterations";
glRasterPos3f(1.0, 0.1, 0.0);
for (i = 0; i < 25; i++)
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, toggleMsg[i]);
// Print personal info
char id[2][11] = {"Gary Sivek","Period 7 "};
for (i = 0; i < 2; i++)
{
glRasterPos3f(6.0, 0.65-0.4*double(i), 0.0);
for (j = 0; j < 10; j++)
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, id[i][j]);
}
}