问题描述:

I've written a code that inputs n and draws N-pointed star,

just like this one:

when n=5 and filed

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 :

when n=7 and filled

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();

}

网友答案:

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;
相关阅读:
Top