|
October 21, 2005
Drawing Necklaces
My goal today is to draw necklaces as sort of "colored beads"
in a circle. First the Monte Carlo method will develop all
the beads and then we'll just pick a random one and draw it.
It's been a while since I trotted out the openGL tools, so
I'll start by just reminding everyone (at least, Me, Myself and
I) how one goes about making a filled polygon to resemble a
circle. Remember that circles are not primitive in openGL.
Here's the code I wrote:
#include <GL/glut.h> #include <cmath>
#include <iostream>
using namespace std;
void circle(GLfloat *, GLfloat, GLfloat);
void display(void);
void init();
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500,500);
glutInitWindowPosition(0,0);
glutCreateWindow("whimple");
glutDisplayFunc(display);
init();
glutMainLoop();
}
void display(void) {
glClear(GL_COLOR_BUFFER_BIT);
glPolygonMode(GL_FRONT, GL_LINE);
GLfloat smoothness = 25.0;
GLfloat center[2] = {0.0,0.0};
GLfloat radius = 1.0; circle(center, radius, smoothness);
glFlush();
}
void init() {
glClearColor(1.0,1.0,1.0,1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1.1,1.1,-1.1,1.0);
}
void circle(GLfloat *center, GLfloat radius, GLfloat EDGES) {
#define PI 3.14159265
glColor3f(1.0,0.0,0.0);
cout << "\nbefore";
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBegin(GL_POLYGON);
for (GLfloat i = 0; i < EDGES; i++) {
glVertex2f(center[0]+radius*cos((2*PI*i)/EDGES),
center[1]+radius*sin((2*PI*i)/EDGES));
glVertex2f(center[0]+radius*cos((2*PI*(i+1))/EDGES),
center[1]+radius*sin((2*PI*(i+1))/EDGES));
}
glEnd();
cout << "\nafter";
}
|
The code produces output that looks like this:

This is actually a 30-gon. In the picture above, the
graphics window is partially covering the console window.
Since the code outputs "before" to console before entering the
gl-loop, and "after" after leaving, and the loop is reentered
after each resizing/positioning of the window, in the process of
placing the graph window over the console window, we see the
repeated glutMainLoop manifest
in the console window.
Now we'd like to allow the user to enter the bead
set, have the program generate all necklaces and then,
depict a random necklace as arrangement of little
circles evenly spaced along the perimeter of a large
circle. So, if there are N beads to distribute
around the necklace, then the center points (A and C in
the diagram at right) can be placed at

where i = 0, 1, ... , N
– 1.
The radii of the beads will be
π/N, so
positioning the beads should be a fairly simple matter,
especially if you don't mind a slight overlap. |
 |
So we need to mesh the circle and necklace routines to draw a
necklace of beads (circle of circles) with the various color
schemes possible for a given bead set, independent of rotation
and reflection. This means making the necklace program a
function, which I actually split into two functions:
getBeads() which has the user
input a bead set (whole numbers) & returns the number of beads
input--something we need to know if we're going place the beads
around the necklace circle--and
getNecklaces() which takes the bead set and generates a
bunch of (if not all) distinct necklaces.
As you'd expect, most of the action of this program is in the
display() function which gets
passed to the glutDisplayFunc()
as a parameter in main().
Essentially, the user is asked to supply a bead set, which can
be entered as, say, "1 1 1 2 2 2 3 3 3
4 4 4 5 5 5 6 6 6," and then "0"
to indicate the end. The necklaces are generated in a
vector of
vectors of type
int, and a nested
while loop structure is used to
draw each bead for each necklace, allowing the user to pause
between necklaces.
To do:
- Use the reshape function to make the window reshapable.
- Generate necklaces only as needed, instead of all at
once.
- Use mouse click to get next necklace.
- Animate the necklace to spin slowly?
- Throw a wiggle into the animation.
- Make the beads shiny with a glint from a light source.
Here is some output from the program:
The current necklace is
4 2 3 1 3 4 1 2 3 2 1 3 1 4 2 4
beadCounter = 0
Draw circle with center at (0.6,0)
radius = 0.11781
beadCounter = 1
Draw circle with center at (0.554328,0.22961)
beadCounter = 2
Draw circle with center at (0.424264,0.424264)
beadCounter = 3
Draw circle with center at (0.22961,0.554328)
beadCounter = 4
Draw circle with center at (-2.62268e-008,0.6)
beadCounter = 5
Draw circle with center at (-0.22961,0.554328)
beadCounter = 6
Draw circle with center at (-0.424264,0.424264)
beadCounter = 7
Draw circle with center at (-0.554328,0.22961)
beadCounter = 8
Draw circle with center at (-0.6,-5.24537e-008)
beadCounter = 9
Draw circle with center at (-0.554328,-0.22961)
beadCounter = 10
Draw circle with center at (-0.424264,-0.424264)
beadCounter = 11
Draw circle with center at (-0.22961,-0.554328)
beadCounter = 12
Draw circle with center at (7.15493e-009,-0.6)
beadCounter = 13
Draw circle with center at (0.22961,-0.554328)
beadCounter = 14
Draw circle with center at (0.424264,-0.424264)
beadCounter = 15
Draw circle with center at (0.554328,-0.22961)
Enter a character to continue: -
The current necklace is
3 4 4 3 2 1 1 1 4 2 1 2 3 2 3 4
beadCounter = 0
Draw circle with center at (0.6,0)
radius = 0.11781
beadCounter = 1
Draw circle with center at (0.554328,0.22961)
beadCounter = 2
Draw circle with center at (0.424264,0.424264)
beadCounter = 3
Draw circle with center at (0.22961,0.554328)
beadCounter = 4
Draw circle with center at (-2.62268e-008,0.6)
beadCounter = 5
Draw circle with center at (-0.22961,0.554328)
beadCounter = 6
Draw circle with center at (-0.424264,0.424264)
beadCounter = 7
Draw circle with center at (-0.554328,0.22961)
beadCounter = 8
Draw circle with center at (-0.6,-5.24537e-008)
beadCounter = 9
Draw circle with center at (-0.554328,-0.22961)
beadCounter = 10
Draw circle with center at (-0.424264,-0.424264)
beadCounter = 11
Draw circle with center at (-0.22961,-0.554328)
beadCounter = 12
Draw circle with center at (7.15493e-009,-0.6)
beadCounter = 13
Draw circle with center at (0.22961,-0.554328)
beadCounter = 14
Draw circle with center at (0.424264,-0.424264)
beadCounter = 15
Draw circle with center at (0.554328,-0.22961)
Enter a character to continue: - |




|
Here's the complete program for this:
#include <GL/glut.h> #include <cmath>
#include <iostream>
#include<cstdlib>
#include<ctime>
#include <vector>
using namespace std;
const GLfloat twoPi = 6.28318530718;
int getBeads(vector<int> &);
GLfloat getNecklaces(vector<int> &, int, vector<vector<int> > &);
void circle(GLfloat *, GLfloat, GLfloat);
void display(void);
void init();
void Swap(vector<int> &v, int, int);
void printVector( const vector< int > &);
bool itsNew(const vector<vector<int> > &, const vector<int> &, int, int &);
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500,500);
glutInitWindowPosition(0,0);
glutCreateWindow("whimple");
glutDisplayFunc(display);
init();
glutMainLoop();
}
void display(void) {
GLfloat R = 0.3, center[2], radius;
vector<vector<int> > V(0);
vector<int> beadSet;
V.clear();
GLfloat numBeads;
numBeads = getBeads(beadSet);
int numNecks;
numNecks = getNecklaces(beadSet, numBeads, V);
cout << "\nThere are : " << numBeads << " beads in "
<< numNecks << " necklaces.";
glClear(GL_COLOR_BUFFER_BIT);
glPolygonMode(GL_FRONT, GL_LINE);
GLfloat smoothness = 30.0;
radius = R*twoPi/(2*numBeads);
cout << "\n\nThere are " << numNecks << " necklaces to display. "
<< "\nWe'll draw a random collection of these after drawing the one "
<< "\nyou entered first.";
int neckCounter = 0;
while(neckCounter < numNecks ) {
GLfloat beadCounter = 0;
cout << "\nThe current necklace is ";
printVector(V[neckCounter]);
while(beadCounter < numBeads) {
cout << "\nbeadCounter = " << beadCounter;
center[0] = R*cos(beadCounter*twoPi/numBeads);
center[1] = R*sin(beadCounter*twoPi/numBeads);
switch(V[neckCounter][beadCounter])
{
case(1) :
glColor3f(1.0,0.0,0.0);
break;
case(2) :
glColor3f(0.0,1.0,0.0);
break;
case(3) :
glColor3f(0.0,0.0,1.0);
break;
case(4) :
glColor3f(0.5,0.0,0.5);
break;
case(5) :
glColor3f(0.5,0.5,0.0);
break;
case(6) :
glColor3f(0.0,0.5,0.5);
break;
default :
break;
}
cout << "\nDraw circle with center at ("
<< center[0] << "," << center[1]
<< ")"; << "\nradius = " << radius;
circle(center, radius, smoothness);
++beadCounter;
glFlush(); } ++neckCounter;
cout << "\nEnter a character to continue: "; cin >> n;
glClear(GL_COLOR_BUFFER_BIT);
glFlush(); } }
void init() {
glClearColor(1.0,1.0,1.0,1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1.1,1.1,-1.1,1.0);
}
void circle(GLfloat *center, GLfloat radius, GLfloat EDGES) {
#define PI 3.14159265
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBegin(GL_POLYGON);
for (GLfloat i = 0; i < EDGES; i++) {
glVertex2f(center[0]+radius*cos((2*PI*i)/EDGES),
center[1]+radius*sin((2*PI*i)/EDGES));
glVertex2f(center[0]+radius*cos((2*PI*(i+1))/EDGES),
center[1]+radius*sin((2*PI*(i+1))/EDGES));
}
glEnd();
} void Swap(vector<int> &v, int m, int n) {
int temp = v[m];
v[m] = v[n];
v[n] = temp;
}
void printVector(const std::vector< int > &v) {
std::vector<int>::const_iterator i = v.begin();
cout << endl;
for( ; i != v.end(); ++i) {
cout << *i << " ";
}
}
bool itsNew(const vector<vector<int> > &V,
const vector<int> &W, int n, int &k) {
bool same;
int rot = 0;
int i = 0, j;
do {
do { j = 0; do {
same = (V[i][j] == W[(j+rot)%n]);
++j;
} while(same && j<n);
if(!same) { j = 0;
do {
same = (V[i][j] == W[n-1-(j+rot)%n]);
++j;
} while(same && j<n); } ++rot;
} while(!same && rot<n);
++i;
rot=0; } while(!same && i<=k);
if(same) return false;
else return true;
}
int getBeads(vector<int> &beadSet) {
srand(time(0));
cout << "\nEnter bead set as whole numbers. Enter zero to quit: \n";
int numBeads = 0, x;
cin >> x;
while(x!=0) {
beadSet.push_back(x);
cin >> x;
++numBeads;
}
return numBeads;
}
GLfloat getNecklaces(vector<int> &beadSet,
int numBeads,
vector<vector<int> > &V) {
cout << "\nIn getNecklaces.";
V.clear();
V.push_back(beadSet); int Src, Dest;
char a = 'n';
int numNecks = 0;
int count = 0;
while(count < 1000) {
for (Dest = numBeads-1; Dest > 0; Dest--)
{
Src = rand() % (Dest+1); Swap (beadSet,Src,Dest);
}
if(itsNew(V,beadSet,numBeads,numNecks)) {
++numNecks;
V.push_back(beadSet);
}
++count;
}
return numNecks; }
|
|