Back to December Calendar            ←Previous Entry                             Next Entry→

December 2, 2005

 

OpenGLobs

 

The purpose of this paper is to describe how to use OpenGL to create a stand-along executable program for implementing drawing algorithm of yesterday…and to cut MATLAB out of the deal. 

 

Here’s the algorithm

 

  1. Input n = index of partition for the base circle of the glob. Note: this at least the genus of the glob.
  2. Compute the angle increment  for a regular partition.
  3. Draw the decorative arcs outside the glob’s base circle by
    1. Compute the common radius of these arc’s circles:  
    2. For i = 0 to n  1

                                                               i.      Find the center (h, k) of the ith  arc’s circle using
  and  

                                                             ii.      Partition the ith  arc’s interval  

                                                            iii.      Plot the arc as a sequence of line segments placed end-to-end using  

  1. Input the m-by-2 tabulation mapping circle node pairs inside the circle to define the m-glob.  For example, in the code below, a 6-glob is drawn using a 9 node partition with the hardwired declaration
             GLfloat arcs[6][2] = {{0,1},{2,8},{3,7},{4,6},{4,5},{5,6}};
    which defines 6 arcs inside the circle: the 0-node is connected to the 1-node and the 2-node is connected to the 8-node…now hear the words of The Lord…and so on.  More specifically,
    1. For i = 0 to number of rows in arcs

                                                               i.      Use the arcs table to compute the angular interval for the ith interior arc,
 deltaTheta = 2*Pi*(arcs[i][1]-arcs[i][0])/n;

                                                             ii.      Compute the radius of the ith interior arc by :  

                                                            iii.      Compute the common denominator , denom = sin(deltaTheta);

                                                           iv.      Compute the (h, k) coordinates of the center of the  interior circle
center_x = 50*(sin(2*Pi*arcs[i][1]/n)-sin(2*Pi*arcs[i][0]/n))/denom;
center_y = 50*(cos(2*Pi*arcs[i][0]/n)-cos(2*Pi*arcs[i][1]/n))/denom;

                                                             v.      Partition the ith  arc’s interval  as either  or , whichever works.

                                                           vi.      Plot the arc as a sequence of line segments placed end-to-end using  

 

Here is the complete program:

// Draw a 6-Globs

 

#include <gl/glut.h>

#include <iostream>

#include <iomanip>

#include <cmath>

using namespace std;

 

const GLfloat Pi = 3.14159265359;

void drawOutArc(GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);

void drawInArc(GLfloat, GLfloat, GLfloat, GLfloat[2], GLfloat);

 

// draw the decorative out-nubs for the globs on an n-partition

void drawOutArc(GLfloat h, GLfloat k, GLfloat r, GLfloat j, GLfloat n) {

      glColor3f(0.0,0.5,0.2);  //glColor3i(r,g,bl);

      glBegin(GL_LINES);

        for(GLfloat t=2*Pi*(j/n-0.25); t<=2*Pi*((j+1)/n+0.25); t+=0.01) {

            glVertex2f(h+r*cos(t),k+r*sin(t));

            glVertex2f(h+r*cos(t+.01),k+r*sin(t+.01));        

        }

      glEnd();

      glFlush();

}

 

// draw the defining interior arcs using a node index pair, arcs[2]

void drawInArc(GLfloat h, GLfloat k, GLfloat r, GLfloat arcs[2], GLfloat n) {

      glColor3f(0.0,0.2,0.5);  //glColor3i(r,g,bl);

      glBegin(GL_LINES);
        if(arcs[1]/n + 0.25 < arcs[0]/n + 0.75) {

            for(GLfloat t=2*Pi*(arcs[1]/n+0.25); t<=2*Pi*(arcs[0]/n+0.75); t+=.01) {

                  glVertex2f(h+r*cos(t),k+r*sin(t));

                  glVertex2f(h+r*cos(t+.01),k+r*sin(t+.01));           

            }

        }

        else {

            for(GLfloat t=2*Pi*(arcs[0]/n+0.75); t<=2*Pi*(arcs[1]/n+0.25); t+=.01) {

                  glVertex2f(h+r*cos(t),k+r*sin(t));

                  glVertex2f(h+r*cos(t+.01),k+r*sin(t+.01));

            }

        }

      glEnd();

      glFlush();

}

 

//<<<<<<<<<<<<<<<<<<<<<<< init >>>>>>>>>>>>>>>>>>>>

void init(void)

{

      glMatrixMode(GL_PROJECTION);

      glLoadIdentity();

      //set the viewing coordinates

      gluOrtho2D(-2.0, 2.0, -2.0, 2.0);//(-100, 100, -100, 100);

      glMatrixMode(GL_MODELVIEW);

      glClearColor(1.0,1.0,1.0,1.0); //(255,255,255,255); //white background

}

 

//<<<<<<<<<<<<<<<<<<<<<<<< display >>>>>>>>>>>>>>>>>

void display(void)

{

      glClear(GL_COLOR_BUFFER_BIT); // clear the screen

 

      GLfloat center_x, center_y, radius, n, denominator;

     

      cout << "\nEnter the partition number for your glob: ";

      cin >> n;

     

      GLfloat dTheta = 2*Pi/n;

      denom = sin(dTheta);

      radius = (1-cos(dTheta))/sin(dTheta);

      for(GLfloat i = 0; i < n; ++i) {

            center_x = (sin(dTheta*(i+1))-sin(dTheta*i))/denom;
            center_y = (cos(dTheta*i)-cos(dTheta*(i+1)))/denom;

            drawOutArc(center_x, center_y, radius, i, n);

      }

      // This is the defining table of node index pairs, hardwired here

      GLfloat arcs[6][2] = {{0,1},{2,8},{3,7},{4,6},{4,5},{5,6}};

      for(int i = 0; i < 6; ++i) {

            dTheta = 2*Pi*(arcs[i][1]-arcs[i][0])/n;

            denom = sin(dTheta);

            center_x = (sin(2*Pi*arcs[i][1]/n)-sin(2*Pi*arcs[i][0]/n))/denom;

            center_y = (cos(2*Pi*arcs[i][0]/n)-cos(2*Pi*arcs[i][1]/n))/denom;

            radius = (1-cos(dTheta))/sin(dTheta);

            drawInArc(center_x, center_y, radius, arcs[i], n);

      }

}

 

 

//<<<<<<<<<<<<<<<<<<<<<<<< main >>>>>>>>>>>>>>>>>>>>>>

int main(int argc, char** argv)

{

      glutInit(&argc, argv); // initialize the toolkit

      glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);

      glutInitWindowSize(300,300); // set window size

      // set window position on screen

      glutInitWindowPosition(0, 435);

      // open the screen window and set the name

      glutCreateWindow("globs");

      //register your functions

      glutDisplayFunc(display);

      init();    

      glutMainLoop(); // go into a perpetual loop

}

 

 

As it is, the program asks for the partition number of your glob, but it’ll only work out if you enter 9.  After entering a “9” at the prompt, the program first draws the decorative caps for the parts of the blobs that protrude outsided the glob’s base circle by first calculating the angular increment for each partition, dTheta = 2*Pi/n .  Then, to avoid computing these over and over, we evaluate denom = sin(deltaTheta) and radius = (1-cos(dTheta))/sin(dTheta).  Having these, we loop around the circle and calculate the center coordinates and plot the little decorative circle arcs with
for(GLfloat i = 0; i < n; ++i) {

   center_x = (sin(dTheta*(i+1))-sin(dTheta*i))/denom;
   center_y = (cos(dTheta*i)-cos(dTheta*(i+1)))/denom;

   drawOutArc(center_x, center_y, radius, i, n);

}

The glob-defining inner arcs are defined by the table

      // This is the defining table of node index pairs, hardwired here

      GLfloat arcs[6][2] = {{0,1},{2,8},{3,7},{4,6},{4,5},{5,6}};

Thus node 0 is connected to node 1, node 2 to 8 and so on.  Armed with this table, it’s not too much trouble to draw the arcs, but each may have, aside from the unique center, also a unique dTheta and radius.  So the loop looks like this:

      for(int i = 0; i < 6; ++i) {

            dTheta = 2*Pi*(arcs[i][1]-arcs[i][0])/n;

            denom = sin(dTheta);

            center_x = (sin(2*Pi*arcs[i][1]/n)-sin(2*Pi*arcs[i][0]/n))/denom;

            center_y = (cos(2*Pi*arcs[i][0]/n)-cos(2*Pi*arcs[i][1]/n))/denom;

            radius = (1-cos(dTheta))/sin(dTheta);

            drawInArc(center_x, center_y, radius, arcs[i], n);

      }

Then when it comes to drawing them, you need to figure out which part of the arc to draw.  I use a condition as shown below:

        if(arcs[1]/n + 0.25 < arcs[0]/n + 0.75) {

            for(GLfloat t=2*Pi*(arcs[1]/n+0.25); t<=2*Pi*(arcs[0]/n+0.75); t+=.01) {

                  glVertex2f(h+r*cos(t),k+r*sin(t));

                  glVertex2f(h+r*cos(t+.01),k+r*sin(t+.01));           

            }

        }

        else {

            for(GLfloat t=2*Pi*(arcs[0]/n+0.75); t<=2*Pi*(arcs[1]/n+0.25); t+=.01) {

                  glVertex2f(h+r*cos(t),k+r*sin(t));

                  glVertex2f(h+r*cos(t+.01),k+r*sin(t+.01));

            }

        }

 

Exercises: 

  1. Find a method for partitioning an arc that assures a fixed arc length that ends more precisely at the target.
  2. Compute and draw the decorative caps using a hypocycloid function.

Hit Counter