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:
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 ();
glTranslatef (x_center, y_center, 0);
glBegin (GL_LINE_LOOP);
for (theta = 0.0f; theta < PI_2; theta += angle_increment)
{
x = w/2 * cos (theta);
y = h/2 * sin (theta);
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