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]);
  }
}

My Supercomp front page.
This page was created by Gary Sivek for 7th Period Supercomp.