Reputation: 351
I've written a code that inputs n and draws N-pointed star,
just like this one:
the problem that is whenever n=7 or 8 or 16 or 25...
I get a problem in the star drawing it becomes like this :
Here's my code:
#include <iostream>
#include <ctime>
#include <vector>
#include <glut.h>
using namespace std;
float starCenterX, starCenterY, starRadius;
int numPoints;
bool bDrawFill = false;
void DrawStar (float cx, float cy, float radius, int numPoints);
void DrawStarFilled (float cx, float cy, float radius, int numPoints);
float width, height; // global variables to store window width and height
// render text
void renderBitmapString (float x, float y, float z, void* font, const char* string)
{
const char *c;
glRasterPos3f (x, y,z);
for (c = string; *c != '\0'; c++)
glutBitmapCharacter (font, *c);
}
void init ()
{
glClearColor (1.0, 1.0, 1.0, 0.0); // set display-window color to white
}
void reshape (int width, int height)
{
::width = width;
::height = height;
glViewport (0, 0, width, height);
glMatrixMode (GL_PROJECTION); // set projection parameters
glLoadIdentity ();
gluOrtho2D (0.0, width, 0.0, height);
glMatrixMode (GL_MODELVIEW); // set projection parameters
glLoadIdentity ();
}
void display ()
{
glClear (GL_COLOR_BUFFER_BIT); // clear display window
glColor3f (0, 0, 1);
renderBitmapString (10, height - 20, 0, GLUT_BITMAP_TIMES_ROMAN_24, "Name : Saif Badran");
renderBitmapString (10, height - 50, 0, GLUT_BITMAP_TIMES_ROMAN_24, "ID : 0142852");
renderBitmapString (10, height - 80, 0, GLUT_BITMAP_TIMES_ROMAN_24, "Section : 2");
DrawStar(starCenterX,starCenterY,starRadius,numPoints);
if(bDrawFill)
DrawStarFilled(starCenterX,starCenterY,starRadius,numPoints);
glFlush (); // process all openGl routines as quickly as possible
}
void processNormalKeys (unsigned char key, int x, int y)
{
if(key=='w' || key=='W')
starCenterY+=4;
else if(key=='z' || key=='Z')
starCenterY-=4;
else if(key=='a' || key=='A')
starCenterX-=4;
else if(key=='d' || key=='D')
starCenterX+=4;
else if(key=='f' || key=='F')
bDrawFill = (bDrawFill==1?0:1);
}
void mouseClick (int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
starCenterX = x;
starCenterY = height - y;
}
}
void activeMouseMotion (int x, int y)
{
starRadius = abs(starCenterX-x);
}
void main (int argc, char** argv)
{
cout<<"Enter number of points : ";
cin>>numPoints;
numPoints = (numPoints < 2) ? 2 : numPoints;
glutInit (&argc, argv); // initialize GLUT
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); // set display mode
glutInitWindowPosition (20, 20); // set top left display window position
glutInitWindowSize (600, 600); // set display window width and height
glutCreateWindow ("Homework#2 : Star Drawing"); // create display window
init (); // execute initialization function
glutKeyboardFunc (processNormalKeys);
glutMouseFunc (mouseClick);
glutMotionFunc (activeMouseMotion);
glutReshapeFunc (reshape);
glutDisplayFunc (display); // send graphics to display window
glutIdleFunc (display);
glutMainLoop (); // dispaly everthing and wait
}
void DrawStar (float cx, float cy, float radius, int numPoints)
{
const float DegToRad = 3.14159 / 180;
glColor3f(1.0,0.0,0.0);
glBegin (GL_POINTS);
int count = 1;
for (int i = 0; i <= 360; i+=360/(numPoints*2)) {
float DegInRad = i * DegToRad;
if(count%2!=0)
glVertex2d (cx + cos (DegInRad) * radius, cy + sin (DegInRad) * radius);
else
glVertex2d ((cx + cos (DegInRad) * radius/2), (cy + sin (DegInRad) * radius/2));
count++;
}
glEnd();
glBegin (GL_LINE_LOOP);
count = 1;
for (int i = 0; i <= 360; i+=360/(numPoints*2)) {
float DegInRad = i * DegToRad;
if(count%2!=0)
glVertex2d (cx + cos (DegInRad) * radius, cy + sin (DegInRad) * radius);
else
glVertex2d ((cx + cos (DegInRad) * radius/2), (cy + sin (DegInRad) * radius/2));
count++;
}
glEnd();
}
void DrawStarFilled (float cx, float cy, float radius, int numPoints)
{
const float DegToRad = 3.14159 / 180;
glBegin (GL_TRIANGLE_FAN);
int count = 1;
glVertex2f(starCenterX, starCenterY);
for (int i = 0; i <= 360; i+=360/(numPoints*2)) {
float DegInRad = i * DegToRad;
if(count%2!=0)
glVertex2d (cx + cos (DegInRad) * radius, cy + sin (DegInRad) * radius);
else
glVertex2d ((cx + cos (DegInRad) * radius/2), (cy + sin (DegInRad) * radius/2));
count++;
}
glEnd();
}
Upvotes: 4
Views: 6507
Reputation: 4220
The issue is in this line:
for (int i = 0; i <= 360; i+=360/(numPoints*2)) {
For numPoints = 5
, for each step i
will be incremented with 360/(2*5) = 36
.
For numPoints = 7
, for each step i
will be incremented with 360/(2*7) = 25
(integer division, truncating 25.714...
to 25
). So, at each step there is a 0.714..
degrees loss. Cummulated, this is: 360 - 14 * 25 = 10
degrees. This can be seen on the output picture.
To solve this we can use a floating point variable for the step counter, and to increment it with a floating point value obtained from a floating point division, using for example 360.0 as the numerator. (Actually 360.0
is stored as a double
, to store it as a single precision float
it should be 360.0f
).
for (float i = 0; i <= 360; i+=360.0/(numPoints*2)) {
But doing so, we may have trouble at the i <= 360
comparison, there are quantization errors resulting from floating point operations (i
could be slightly smaller or bigger than the "mathematical" value). So it would be better to keep the integer counter for the loop, and do the floating point operations afterwards. This code part:
for (int i = 0; i <= 360; i+=360/(numPoints*2)) {
float DegInRad = i * DegToRad;
would then be changed to:
for (int i = 0; i <= numPoints*2; i++) {
float DegInRad = i * 360.0/(numPoints*2) * DegToRad;
Upvotes: 3