简体   繁体   中英

Drawing N-Pointed Star in OpenGL - C++

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM