1

I copied this ellipse code directly from the opengl textbook:

void ellipseMidpoint (int xCenter, int yCenter, int Rx, int Ry)
{
  int Rx2 = Rx * Rx;
  int Ry2 = Ry * Ry;
  int twoRx2 = 2 * Rx2;
  int twoRy2 = 2 * Ry2;
  int p;
  int x = 0;
  int y = Ry;
  int px = 0;
  int py = twoRx2 * y;

//initial points in both quadrants
ellipsePlotPoints (xCenter, yCenter, x, y);

//Region 1
p = round (Ry2 - (Rx2 * Ry) + (0.25 * Rx2));
while (px < py) {
    x++;
    px += twoRy2;
    if (p < 0)
        p += Ry2 + px;
    else {
        y--;
        py -= twoRx2;
        p += Ry2 + px - py;
    }
    ellipsePlotPoints (xCenter, yCenter, x, y);
}

//Region 2
p = round (Ry2 * (x+0.5) * (x+0.5) + Rx2 * (y-1) * (y-1) - Rx2 * Ry2);
while (y > 0) {
    y--;
    py -= twoRx2;
    if (p > 0)
        p += Rx2 - py;
    else {
        x++;
        px += twoRy2;
        p += Rx2 - py + px;
    }
    ellipsePlotPoints (xCenter, yCenter, x, y);
 }
}

void ellipsePlotPoints (int xCenter, int yCenter, int x, int y)
{
    setPixel (xCenter + x, yCenter + y);
    setPixel (xCenter - x, yCenter + y);
    setPixel (xCenter + x, yCenter - y);
    setPixel (xCenter - x, yCenter - y);
}

void setPixel (GLint xPos, GLint yPos)
{
    glBegin (GL_POINTS);
    glVertex2i(xPos, yPos);
    glEnd();
}

The smaller ellipses seem to be fine but the larger ones are pointy and sort of flat at the ends.

Any ideas why?

Here is a current screenshot:

Here's an image

MayNotBe
  • 2,110
  • 3
  • 32
  • 47
  • I edited out the "more details" part because your question doesn't need it. – yizzlez Jun 20 '14 at 00:33
  • Thanks. Couldn't get it to post without it! – MayNotBe Jun 20 '14 at 00:43
  • Aren't ellipses supposed to be "pointed"? That is kind of what differentiates them from circles. – Andon M. Coleman Jun 20 '14 at 00:46
  • They're supposed to be ovals, these look like lemons. – MayNotBe Jun 20 '14 at 00:49
  • 1
    It does not look like anything to me, perhaps you should include a screenshot in your question text? – Andon M. Coleman Jun 20 '14 at 00:50
  • What does `ellipsePlotPoints()` do? – tadman Jun 20 '14 at 00:52
  • My bad. Screenshot added. I'll edit and add the procedure for ellipsePlotPoints(). It didn't occur to me to look for the error there - probably need some rest! – MayNotBe Jun 20 '14 at 01:02
  • Is this some kind of Bresenham algorithm for an ellipsis? Not sure why that would show up in an OpenGL textbook, because it's really not a very good fit for OpenGL. Would you be interested in an answer that shows a good way to draw an ellipsis in OpenGL? Or do you only want to know why what you have is not working? – Reto Koradi Jun 20 '14 at 01:11
  • It is a Bresenham algorithm. I'm not sure either - it's an "intro to computer graphics with opengl" text. Perhaps that's why? I would be interested in both a good way to draw an ellipse and the reason this one isn't working. Curious that they would use an algorithm that's not a great fit AND doesn't work ... – MayNotBe Jun 20 '14 at 01:26

1 Answers1

0

I think you're encountering overflow. I played with your code. While I never saw exactly the same "lemon" type shapes from your pictures, things definitely fell apart at large sizes, and it was caused by overflowing the range of the int variables used in the code.

For example, look at one of the first assignments:

int py = twoRx2 * y;

If you substitute, this becomes:

int py = 2 * Rx * Rx * Ry;

If you use a value of 1000 each for Rx and Ry, this is 2,000,000,000. Which is very close to the 2^31 - 1 top of the range of a 32-bit int.

If you want to use this algorithm for larger sizes, you could use 64-bit integer variables. Depending on your system, the type would be long or long long. Or more robustly, int64_t after including <stdint.h>.

Now, if all you want to do is draw an ellipsis with OpenGL, there are much better ways. The Bresenham type algorithms used in your code are ideal if you need to draw a curve pixel by pixel. But OpenGL is a higher level API, which knows how to render more complex primitives than just pixels. For a curve, you will most typically use a connected set of line segments to approximate the curve. OpenGL will then take care of turning those line segments into pixels.

The simplest way to draw an ellipsis is to directly apply the parametric representation. With phi an angle between 0 and PI, and using the naming from your code, the points on the ellipsis are:

x = xCenter + Rx * cos(phi)
y = yCenter + Ry * sin(phi)

You can use an increment for phi that meets your precision requirements, and the code will look something to generate an ellipsis approximated by DIV_COUNT points will look something like this:

float angInc = 2.0f * m_PI / (float)DIV_COUNT;
float ang = 0.0f;
glBegin(GL_LINE_LOOP);
for (int iDiv = 0; iDiv < DIV_COUNT; ++iDiv) {
    ang += angInc;
    float x = xCenter + Rx * cos(ang);
    float y = yCenter + Ry * sin(ang);
    glVertex2f(x, y);
glEnd();

If you care about efficiency, you can avoid calculating the trigonometric functions for each point, and apply an incremental rotation to calculate each point from the previous one:

float angInc = 2.0f * M_PI / (float)DIV_COUNT;
float cosInc = cos(angInc);
float sinInc = sin(angInc);
float cosAng = 1.0f;
float sinAng = 0.0f
glBegin(GL_LINE_LOOP);
for (int iDiv = 0; iDiv < DIV_COUNT; ++iDiv) {
    float newCosAng = cosInc * cosAng - sinInc * sinAng;
    sinAng = sinInc * cosAng + cosInc * sinAng;
    cosAng = newCosAng;
    float x = xCenter + Rx * cosAng;
    float y = yCenter + Ry * sinAng;
    glVertex2f(x, y);
glEnd();

This code is of course just for illustrating the math, and to get you started. In reality, you should use current OpenGL rendering methods, which includes vertex buffers, etc.

Reto Koradi
  • 53,228
  • 8
  • 93
  • 133