Click here to Skip to main content
15,867,453 members
Articles / Multimedia / OpenGL

OpenGL Oval

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
14 Aug 2010CPOL3 min read 41.8K   7   4
How to draw an oval using lines or fill it using triangles?

Knowing that OpenGL only comes with commands that draw simple geometric primitives such as points, lines and polygons (see OpenGL Geometric Shapes), it would be nice to extend over these and draw more complex structures, such as those supported by the Java AWT library. In this post, I’ll show the OpenGL implementation of the drawOval, fillOval, drawArc, fillArc methods of the Java Graphics class.

Before we get to drawing an oval or an arc, let’s first see how to draw a circle. We can use points, lines or polygons. To draw the outline of the circle, we can place points around the circle, then connect the consecutive points using lines. The more points we have, the more lines we would draw and the more realistic the circle would look like. Below are samples of a circle drawn using 3, 4, 5, 10 and 50 segments.

So if we figure out how to draw the points on the circle’s perimeter, we’ll be able to connect those points with lines and thus have a circle. To draw a point, all we need to know is its x and y coördinates (assuming z = 0). Relative to the center of the circle , the coördinates of a point at the circle’s perimeter are calculated as follows (rule in trigonometry):

x = r * cos θ
y = r * sin θ

where r is the radius and θ (theta) is the angle between the x-axis and the radius that connects the point to the center. So to draw a point, we need to know its angle θ. The angle θ of each point will depend on how many points we’ll use to draw the circle. As we know, the angle all around the circle is 360 degrees, which is equivalent to 2Π radians. If we are to use 10 points to draw the circle, the angle increment between each point and the next will be 2Π / 10. Thus, θ of point 1 is 0, θ of point 2 is 2Π / 10, θ of point 3 is 4Π / 10, …, and θ of point 10 is 18Π / 10. So here is how we can get the coördinates of all the points of a circle with radius r and segments n.

δ = 2Π / n;
for (θ = 0; θ< 2Π; θ+= δ)
{
    x = r * cos (θ);
    y = r * sin (θ);
}

To draw the circle from those points, we should use the GL_LINE_LOOP OpenGL mode, which will draw a connected group of line segments from the first vertex to the last, then back to the first. That’s how we draw the circle. To implement the more generic case of drawing an oval, all we have to do is make the trigonometric rule for the coordinates of a point more generic. In order to be able to derive such a rule, we should imagine a bounding rectangle around the oval. In the case of a circle, that bounding rectangle is a square with side s equal to the diameter of the circle, which is 2 * r. So r is equal to s / 2.

x = s/2 * cos θ
y = s/2 * sin θ

The bounding rectangle has a width w and height h. A bit of intuition leads us to the rule that defines the coordinates of a point on an oval:

x = w/2 * cos θ
y = h/2 * sin θ

The full source code of the drawOval function is shown below:

C#
//-------------------------------------------------------------------------
//  Draws an oval centered at (x_center, y_center)
//
// The oval is bound inside a rectangle whose width is w
// and height is h.
//
// n represents the number of line segments used to draw the oval.
//-------------------------------------------------------------------------
void drawOval (float x_center, float y_center, float w, float h, int n)
{
    float theta, angle_increment;
    float x, y;
    if (n <= 0)
        n = 1;
    angle_increment = PI_2 / n;
    glPushMatrix ();
 
    //  center the oval at x_center, y_center
    glTranslatef (x_center, y_center, 0);
    //  draw the oval using line segments
    glBegin (GL_LINE_LOOP);
 
    for (theta = 0.0f; theta < PI_2; theta += angle_increment)
    {
        x = w/2 * cos (theta);
        y = h/2 * sin (theta);
  
        //  Color the vertices!
        if (color[currentShape])
            glColor3f (x, y, x*y);
        glVertex2f (x, y);
    }
    glEnd ();
    glPopMatrix ();
}

To fill the circle, instead of using lines, we need to use polygons. The best mode to use here is the GL_TRIANGLE_FAN, which draws a connected group of triangles. One triangle is defined for each vertex presented after the first two vertices.

To draw or fill an arc, we use the same rules for drawing an oval, except that we control the angles θ of the points based on the start angle and the arc angle.

δ = 2Π / n;
for (θ = startAngle; θ< startAngle + arcAngle; θ+= δ)
{
    x = w/2 * cos (θ);
    y = h/2 * sin (θ);
}

You can find the source code on my GitHub page.

If you have any issues compiling or running the app, check out this section for details about compiling and running an OpenGL app that uses the GLUT library. Below is a screenshot from the demo app showing a circle with every vertex colored based on its coordinates. When you run the app, press the ‘h’ key for help on how to use it.

Filed under: C, OpenGL
Tagged: circle, drawArc, drawOval, fillArc, fillOval

This article was originally posted at http://mycodelog.com/2010/03/22/opengl-oval

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
https://open-gl.com

Comments and Discussions

 
GeneralChoosing N Pin
YDaoust16-Aug-10 21:48
YDaoust16-Aug-10 21:48 
Ali,

as a complement to the nice polygonization code that you published, it is good to get a hint on the choice of n. Too low a value causes the polygon to be visible; too high a value is overkill.

My favourite rule is to pick n such that in every wedge the deviation between the arc and the chord is exactly one pixel. A little bit of trigonometry gives you this equation: R.(1-Cos(Pi/n))=1, or n=Pi/acos(1-1/R); take the ceiling for safety.

For ovals, using the small radius leaves you on the safe side.

Yves
GeneralRe: Choosing N Pin
Ali BaderEddin17-Aug-10 4:56
Ali BaderEddin17-Aug-10 4:56 
GeneralSource Code unreachable Pin
merano7-Aug-10 3:03
merano7-Aug-10 3:03 
GeneralRe: Source Code unreachable Pin
Ali BaderEddin14-Aug-10 17:57
Ali BaderEddin14-Aug-10 17:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.