0% found this document useful (0 votes)
37 views24 pages

Unit 3

Uploaded by

codingwala1137
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
37 views24 pages

Unit 3

Uploaded by

codingwala1137
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 24

UNIT 3

FILLING ALGORITHMS
ALGORITHMS

Structure Page No.

3.1 Introduction 59
Objectives
3.2 Filled-Area Primitives 60
3.3 Scanline Polygon Fill Algorithm 61
3.4 Boundary Fill Algorithm 69
3.5 Character Generation 75
3.6 Summary 77
3.7 Solutions/Answers 77

3.1 INTRODUCTION
In Unit 2, you learnt how some basic geometric objects such as line segments,
circles, ellipses and other curves are processed for plotting on a display unit.
In most of the graphics packages you will find that polygons are also used as
standard output primitives. Filled polygons with single solid color (or other
alternatives for filling the interior) are provided as shape primitives.

In this unit, we shall discuss what we mean by filled area primitives and list two
basic methods to fill polygonal or arbitrary shaped closed regions in Section
3.2. We consider here methods for solid fill of specified areas. One of these
methods, called the Scanline Polygon Fill Algorithm, is discussed with full C-
implementation in Section 3.3. The second type of methods are generally
called seed fill algorithms, and we shall present two such algorithms in Section
3.4 with full implementation of Boundary Fill Algorithm. While creating or
editing a document in a word processing software, you might have used
letters, numbers and other characters in various font types and styles. We
shall discuss in Section 3.3 how different fonts are generated using 2D
drawing primitives.
Block 1 Fundamentals of Computer Graphics
Objectives
After reading this unit, you should be able to
• describe, implement and use the Scanline Polygon Fill Algorithm;
• apply the Odd-Even rule and the Nonzero Winding Number rule;
• differentiate between a 4-connected region and an 8-connected region;
• implement the Boundary Fill Algorithm for any type of closed region;
• generate a character or a font from the alphabet of any language.

3.2 FILLED-AREA PRIMITIVES


Filled-area primitives are one of the most important types of methods meant to
fill a given closed region with a single colour/multiple colours or with some fill
pattern. You will find later that almost all types of curves are approximated by
polylines surfaces for the purposes of scan conversion. Therefore, polygon fill
algorithms are extensively used in applications involved in 2D geometry
processing. This section deals with some of the important and most common
algorithms being used for defining and implementing filled area primitives.

Two basic approaches are followed in area filling on raster systems. In the first
approach overlap intervals for scanlines that cross the area are determined
per scanline (see Fig. 1 (a)). Second approach begins with an interior point
and fills the area moving outward from this point until the boundary condition is
reached (see Fig. 1(b)). An algorithm following the first approach is classified
as scan line algorithm and that falling under second class is called a seed
fill algorithm. Simple objects such as polygons, circles etc. are efficiently
filled with scan line fill algorithms and more complex regions use the seed fill
method. The scan line algorithm is mostly used in general graphics packages.

Pixels between two


intersections filled with
color

Scan line Seed point

(a) (b)
Fig. 1

Let us begin with scan line polygon fill algorithm. Notice that polygons can be
as simple as a triangle and could be as complicated as the one shown in Fig.
2 below.
60
Unit 3 Filling Algorithms

Fig. 2: A self intersecting polygon

We broadly keep the polygons in one of the three categories (i) convex (ii)
concave (iii) self intersecting. Mathematically, a self intersecting polygon is
concave. You will deal with such polygons in greater details for the purpose of
area filling.

Before we go ahead with area filling algorithms, a word about pixel addressing
and object geometry. You know that line segments are discretized into finite
number of pixels and each pixel has its height and width depending upon the
aspect ratio of the display unit. Therefore, if you plot a single pixel it will
occupy some area on display unit. This contributes to the object geometry
resulting in aberrations from the actual size. For example, if you have to plot a
line segment starting from (10, 10) to (15, 10) , then length of the segment is 5
whereas, in plotting this line segment, six pixel areas will be contributing to this
segment, resulting in increased length of line segment by one unit. In this
situation one can plot the line from (10, 10) to (14, 10). For closed regions we
can plot pixels that are interior to the boundary.

Or one can also map the world coordinates (object coordinates) to the screen
coordinates between pixels.

3.3 SCANLINE POLYGON FILL ALGORITHM


As the name suggests, this algorithm fills the region inside a polygon scanline
by scanline. The basic idea is to compute the intersections of the edges of the
polygon with each scanline, and sort them from the smallest to the highest
value of x -coordinates. Next, the intersection points are paired and pixels are
drawn between every pair of x -coordinates with a specified colour. A major
point to be noted is that a scanline may not always intersect the edges in an
even number of points, for instance when it passes through a vertex.

Such scanlines need to be processed carefully. For instance, look at the


following polygon.
61
Block 1 Fundamentals of Computer Graphics

The scanline y intersects the polygon edges in an even number of points

which can be paired as ( x1 , x2 ), ( x3 , x4 ). So one can fill the scanline y from

x1 to x2 , and from x3 to x4 with the given colour. The scanline y ′ passes

through the vertex x′2 . Note that the edges meeting x2′ are both lying above

x′2 . In this case, we can duplicate x2′ to get the pairs ( x1′ , x2′ ) and ( x′2 , x3′ ).
The same approach can be adopted in the cases where a scanline passes
through a vertex and both the edges incident to the vertex lie below it.

Now let us look at the scanline y ′′, which passes through the polygon vertices

x1′′ and x2′′. The edges incident on x1′′ lie on the opposite side of the scanline
y ′′, and the same is the case with x2′′. In such cases, each intersection point
is counted once. This can be done easily if we slightly shorten the upper end
of the lower edge at an intersection point.

Observe that for any scanline y we need to fill the area between pairs of x -
coordinates where y intersects the polygon edges. So, we need to process
only the nonhorizontal edges. Now let us look at the detailed procedure.

Procedure (Scanline Polynomial Fill Algorithm):

Let P be a polygon with n vertices given by vi = ( xi , yi ), i = 0, 1, K , n − 1 in

the counterclockwise orientation. For the sake of convenience, it will be


assumed that vertices have non-negative integer coordinates.

Step 1: Input polygon vertices vi = ( xi , yi ), i = 0, 1, K , n − 1 with vn = v0 .

Further, define the edges ei = vi vi +1 , i = 0, 1, K , n − 1 .

Step 2: Find out y min = min i {y i }, y max = max i {y i } .

Step 3: Create a sorted edge table to store the nonhorizontal edges. The
table consists of as many rows as there are scanlines. Each edge has
three members:

(a) upper y -coordinate,

62
Unit 3 Filling Algorithms
(b) lower x -coordinate,
(c) inverse of the edge slope.

While moving along a particular direction, say clockwise, record the


edges that cross a scanline y, put these edges in a sorted list indexed
at the location y in the edge table, where the sorting is done on the
lower x -coordinates of the edges. Moreover, if the successor or the
predecessor of an edge e (along the moving direction) is lying above
e, then the upper y -coordinate of e is reduced by 1.

Step 4: Set y = y min . While y < ymax do the following:

i) Create an active edge list (AEL) that consists of all those edges
whose lower y -coordinate is less than or equal to y. The
edges are stored in AEL in the ascending order of their lower
x -coordinate values.

ii) Make pairs of the lower x -coordinate values of the edges in


AEL, and fill each portion of the scanline enclosed by a pair of
x -coordinate values with the specified colour. For a particular
pair ( xi , x j ) we fill the pixels starting at xi till the pixel

preceding x j .

iii) Update AEL as follows. For each edge e in AEL if the upper y -
coordinate of e is smaller than or equal to y, remove e from
AEL, otherwise increase its lower x -coordinate value by slope
inverse.

iv) Sort the edges in AEL in the ascending order of lower x -


coordinate values.

v) Set y = y + 1.

Let us look at an example.

Example 1: Consider a polygon with vertices v0 (10, 10), v1 = (15, 15),

v2 = (16, 13), v3 = (16,15), v4 = (20, 15), v5 = (20, 10), v6 = v0 and edges

e j = v j v j +1 , j = 0, 1, 2, 3, 4, 5 . Use the Scanline Polygon Fill Algorithm to fill


this polygon.

Solution: The polygon can be drawn as below.

63
Block 1 Fundamentals of Computer Graphics

Step 1: Store the vertices and edges in the order given.


Step 2: y min = min i { yi } = 10 and y max = max i { yi } = 15 .

Step 3: Sorted edge table is created as follows. Start with y = 10 and

continue till y = 15 . Clearly for y = 10 there are only two edges that

begin with this y -value namely, e0 and e4 . Slope of e0 is 1 and that

of e4 is ∞ . As described in Step 3, the sorted edge table is given


below.

15

14

13 15 16 –½ 15 16 0

12

11

y = 10 15 10 1 15 20 0

Notice that the edges e3 and e5 do not appear in the edge table, being

horizontal line segments.

Step 4: Active edge list and x -coordinate pairs for all scanlines
y = 10, AEL = {e0 , e4 }, x -pairs = (10, 20)
y = 11, AEL = {e0 , e4 }, x -pairs = (11, 20)
y = 12, AEL = {e0 , e4 }, x -pairs = (12, 20)
y = 13, AEL = {e0 , e1 , e2 , e4 }, x -pairs = (13, 16) (16, 20)
y = 14, AEL = {e0 , e1 , e2 , e4 }, x -pairs = (14, 15.5) (16, 20)
y = 15, AEL = «

The resulting filled polygon is shown below.


64
Unit 3 Filling Algorithms

(20, 15)
(15, 15)

(10, 10) (20, 10)

Note that the polygon filling scheme will not fill the pixels on the horizontal
edge e4 joining (16,15) and ( 20,15). But the boundary of the polygon will
display the edge. Similarly the vertex (15, 15) is plotted by virtue of it being a
boundary point.
***

To implement the Scanline Polygon Fill Algorithm, we shall define two struct
variables namely point and Edge as follows:

typedef struct point { int x, y; }Point;


typedef struct edge
{ int yupper;
float x_intersect, slope_inverse;
struct edge *next;
}Edge;
So, to store the vertices of the input polygon we can create an array of type
point. Note that Edge contains four members–yupper to store the y -
coordinate of the upper endpoint of the edge, x_intersect to store the x -
coordinate of the lower endpoint of the edge, slop_inverse to store the
inverse of the slope of the edge, and next which is a pointer to a variable of
type Edge. To store the edgelist we create an array of pointers of type Edge.
This can be done using the following command:

Edge* edges[GLUT_INNIT_WINDOW_HEIGHT];
Here GLUT_INNIT_WINDOW_HEIGHT is an OpenGL constant indicating the
height of the window initialised in terms of the number of scanlines. The full C-
program that implements the Scanline Polygon Fill Algorithm is given below, in
Listing 1.

// Scanline Polygon Fill Algorithm


#include<stdio.h>
#include<GL/glut.h>

//insert the definitions of Point and Edge.

void insert_edge(Edge *list, Edge *e)


{
65
Block 1 Fundamentals of Computer Graphics
Edge *prev = list, *curr;
for(curr = list->next; curr != NULL; curr = curr->next)
{ if(e->x_intersect < curr->x_intersect)
break;
prev = curr;
}
e->next = curr;
prev->next = e;
}

int y_next(int i, int n, Point *points)


{
int j = (i+1)%n; // j becomes 0 if it crosses n-1
while(points[j].y == points[i].y)
j = (j+1)%n;
return (points[j].y);
}

void create_edgelist(int n, Point *points, Edge *edges[])


{
Edge *e;
Point u = points[n-1], v;
int i, j, yprev = points[n-2].y, ynext;
for(i = 0; i < n; i++)
{ v = points[i];
if(u.y != v.y)
{ e = (Edge *)malloc(sizeof(Edge));
e->slope_inverse = (float)(u.x-v.x)/(u.y - v.y);
if(u.y < v.y)
{ e->x_intersect = u.x;
e->yupper = v.y;
ynext = y_next(i, n, points);
if(v.y < ynext)
e->yupper--; //shorten edge upper end by 1
insert_edge(edges[u.y], e);
}
else
{ e->x_intersect = v.x;
e->yupper = u.y;
if(u.y < yprev)
e->yupper--; //shorten edge upper end by 1
insert_edge(edges[v.y], e);
}
}
yprev = u.y;
u = v;
}
}

void create_active_list(int line, Edge *active, Edge *edges[])


{
Edge *prev, *current;
for(prev = edges[line]->next; prev != NULL; prev = current)
{ current = prev->next;
insert_edge(active, prev);
}
}

void fillscan(int line, Edge *active)


{
Edge *curr, *prev = active->next;
int x;
glColor3f(0, 1.0, 0.0);
while(prev != NULL)
{ curr = prev->next; //prev->next is not NULL. (Why?)
glBegin(GL_LINES);
66
Unit 3 Filling Algorithms
for(x = prev->x_intersect; x < curr->x_intersect; x++)
glVertex2i(x, line);
glEnd();
prev = curr->next;
}
}

void update_active_list(int line, Edge *active)


{
Edge *prev = active, *curr = active->next;
while(curr != NULL)
if(line >= curr->yupper)
{ prev->next = curr->next;
free(curr);
curr = prev->next;
}
else
{ curr->x_intersect += curr->slope_inverse;
prev = curr;
curr = curr->next;
}
}

void sort_active_list(Edge *active)


{
Edge *curr, *prev = active->next;
active->next = NULL;
for( ; prev != NULL; prev = curr)
{ curr = prev->next;
insert_edge(active, prev);
}
}

void scanline_polygon_fill(int n, Point *points)


{
Edge *edges[GLUT_INIT_WINDOW_HEIGHT], *active;
int i, line, ymax = points[0].y, ymin = points[0].y;
for(line = 0; line < GLUT_INIT_WINDOW_HEIGHT; line++)
{ edges[line] = (Edge *)malloc(sizeof(Edge));
edges[line]->next = NULL;
}
create_edgelist(n, points, edges);
active = (Edge *) malloc(sizeof(Edge));
active->next = NULL;

for(i = 1; i < n; i++)


{ if(points[i].y > ymax)
ymax = points[i].y;
if(points[i].y < ymin)
ymin = points[i].y;
}
for(line = ymin; line < ymax; line++)
{ create_active_list(line, active, edges);
if(active->next)
{ fillscan(line, active);
update_active_list(line, active);
sort_active_list(active);
}
}
glFlush();
}
// function to initialize
void myInit (void)
{
gluOrtho2D(0, 1000, 0, 1000);
glClearColor(0.5, 0.5, 0.5, 0.0);
67
Block 1 Fundamentals of Computer Graphics
glColor3f(1, 0, 0);
glPointSize(2);
}

void display()
{
glClear(GL_COLOR_BUFFER_BIT);
int n, i;
Point points[50];
printf("How many polygon vertices? ");
scanf("%d", &n);
printf("Enter vertices line by line.\n");
for(i = 0; i < n; i++)
scanf("%d%d", &points[i].x, &points[i].y);
glBegin(GL_LINE_LOOP);
for(i = 0; i < n; i++)
glVertex2i(points[i].x, points[i].y);
glEnd();
glFlush();

scanline_polygon_fill(n, points);

int main (int argc, char** argv)


{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);

// giving window size in X- and Y- direction


glutInitWindowSize(1000, 1000);
glutInitWindowPosition(0, 0);
glutCreateWindow("Scanline Polygon Fill Algorithm");

myInit();
glutDisplayFunc(display);
glutMainLoop();
}
Listing 1: Scanline Polygon Fill Algorithm Implementation

Let us look at the function scanline polygon_fill ( ).

Note that the first for loop prepares the array edges to reserve blocks of
memory in order to store the edglist for each scanline. Next, the function call
create_edgelist() actually creates an edgelist. Then the pointer active
is initialised. The next for loop computes the minimum and maximum values
of the y -coordinates of the polygon vertices. The last for loop fills the
polygon line by line starting from ymin to ymax-1. For each scanline in the
range, an active edglist is created using the function call
create_active_edglist(). If the active list is nonempty, the current
scanline is filled through the function fillscan(), the active edgelist is
updated through update_active_list() and then sorted using
sort_active_list() .

You may now try the following exercises.

68
Unit 3 Filling Algorithms

E1) For the following polygon, prepare an array of sorted edge lists and then
make the active edge list for scanlines y = 5, 20, 30, 35 . Coordinates of

the vertices are v0 = (10, 20), v1 = (20, 0), v2 = (30, 10), v3 = (40, 0),

v4 = (40, 40), v5 = (30, 30), v6 = (20, 40), v7 = (30, 20). Also find the
pairs of x -coordinate values for y = 5.

40

30

20

10

0
0 10 20 30 40 50

E2) For the polygon shown below how many times will the vertex V1 appear
in the set of intersection points for the scan line passing through that
point? How many times will you count it when you form the pairs of
intersection points? Justify your answer.

V0 V5

V1 = V4

V2 V3

In the next section, we shall look at a different approach to area filling.

3.4 BOUNDARY FILL ALGORITHM


As you saw the Scan Line Polygon Fill Algorithm works for polygons only. The
seed fill algorithms do not require any such constraints. You only need to know
an interior point of the closed boundary object to fill it. This interior point is
called a seed point. However, determination of interior point for complex
polygons such as the one shown in Fig. 2 itself is a challenging task. The
following methods are used to determine an interior point of the area to be
filled.
69
Block 1 Fundamentals of Computer Graphics
1. Odd-Even rule,
2. Winding Number Rule.

Once an interior point of the object is determined, the boundary-fill algorithm


or, flood-fill algorithm may be applied to fill the given area.

Odd-Even Rule: Consider any polygon A and a point P in the plane of the
polygon. To check whether P lies inside or outside A, we draw a line from P

to a reference point O chosen far enough from A. Note that we choose O in


such a way that the line OP does not pass through any vertex of A. Then P
lies inside A if OP cuts an odd number of the edges of A, otherwise P lies

outside A. Applying the Odd-Even rule to the following polygon you can easily
see that its interior region.

Winding Number Rule: Again consider a polygon A and a point P . In this


rule, the edges of A are first oriented in a particular direction (clockwise or
anti-clockwise). Then a reference point O is chosen far enough from A in
such a way that the line OP does not pass through any vertices of A. Denote
the Winding Number of P by ω ( P) . To compute ω ( P), we move along the

line OP , starting at P, and count how many edges of A cross OP from left

to right and how many from right to left. Then ω ( P) is essentially the
difference of the two numbers. That is,

ω ( P) = edges crossing OP from left


− edges crossing OP from right
If ω ( P) ≠ 0, then P lies inside A, otherwise P lies outside A . For instance,
the above polygon edges can be oriented as follows.

70
Unit 3 Filling Algorithms

Consider a point P and the reference point O as shown above. As we move


from P to O, the edge v1v2 crosses OP from left, and the edge v3v4 also

from left. Thus, ω ( P) = 2 ≠ 0. Therefore, P lies inside the polygon. Note that
both the rules do not give the same interior and exterior regions. Let us look at
one more example.

Example 2: Apply the Odd-Even Rule and the Winding Number Rule to find
the interior and exterior regions of the following polygon. Do both the rules
produce the same exterior regions?

Solution: Using the Odd-Even Rule, it is easy to observe that the shaded
region as shown below is the interior region, and the rest is the exterior.

In order the apply the Winding Number Rule, we orient the edges of the
polygon as follows.
71
Block 1 Fundamentals of Computer Graphics

You can now see that all the interior regions that were obtained by the Odd-
Even Rule are also the interior regions by the Nonzero Winding Number Rule.
Now consider a point P in the region shaded dark above, and a reference
point O . When we move from P to O, the edges v2 v3 and v4 v5 cross the line

PO from right. Therefore, ω ( P) = 2 ≠ 0. This means P is also an interior


point, and hence the whole shaded region (dark and light) is an interior region.

Thus the exterior regions produced by the two rules are not the same.

***

After understanding how to select an interior point of a closed region we turn


to the procedure of Seed Fill Algorithm. The algorithm starts with an interior
point as the seed point and recursively checks whether the neighbouring
pixels have the same colour as the boundary colour or not. If yes, the call
terminates, otherwise the neighbouring pixel is coloured with given fill colour
and the next recursive call is made from the current pixel.

Given a pixel position ( x, y ), the question arises: What are the neighbours of

( x, y ) ? There are two ways to determine this. (See picture below.)

4-connected 8-connected

If we consider only the top, down, left or right pixels as the neighbours of
( x, y ), then the region defined this way is called a 4-connected region.
Thus, in a 4-connected region the neighbouring pixels of ( x, y ) are ( x, y + 1),

( x, y − 1), ( x − 1, y ), ( x + 1, y ). On the other hand, if we include the four


diagonal pixels as well in addition to the top, down, left and right, we get a

72 region that is called 8-connected. Depending on the type of region, there are
Unit 3 Filling Algorithms
two versions of Boundary Fill Algorithm (4-connected and 8-connected). Here
we have implemented the 4-connected version.

// Boundary Fill Algorithm (4 connected regions)


#include<stdio.h>
#include<GL/glut.h>
#define width 1000
#define height 1000
typedef struct point { int x, y; } Point;
int equal(float *colour1, float *colour2)
{
for(int i = 0; i < 3; i++)
if(colour1[i] != colour2[i])
return 0;
return 1;
}
void draw_point(int x, int y, float *colour)
{
glColor3fv(colour);
glBegin(GL_POINTS);
glVertex2i(x, y);
glEnd();
glFlush();
}

void boundary_fill4(int x, int y, float* fill, float* boundary)


{ The function
float colour[3]; glReadPixels ( ) reads
glReadPixels(x, y, 1, 1, GL_RGB, GL_FLOAT, colour); the colour of the pixel
if(!equal(colour, fill) && !equal(colour, boundary)) (x, y) and stores it in
{ draw_point(x, y, fill); the array colour.
boundary_fill4(x+1, y, fill, boundary);
boundary_fill4(x-1, y, fill, boundary);
boundary_fill4(x, y+1, fill, boundary);
boundary_fill4(x, y-1, fill, boundary);
}
}

void mouse(int button, int state, int x, int y)


{
y = height-y;
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{ float boundary[] = {1, 0, 0};
float fill[] = {0, 0, 1};
boundary_fill4(x, y, fill, boundary);
}
}

void myInit (void)


{
gluOrtho2D(0, 1000, 0, 1000);
glClearColor(0.5, 0.5, 0.5, 0.0);
glColor3f(1, 0, 0);
glPointSize(2);
}

void display()
{
glClear(GL_COLOR_BUFFER_BIT);
int n, i;
Point points[50];
printf("How many polygon vertices? ");
scanf("%d", &n);
printf("Enter (nonnegative) coordinates of vertices:\n");
73
Block 1 Fundamentals of Computer Graphics
for(i = 0; i < n; i++)
scanf("%d%d", &points[i].x, &points[i].y);
glBegin(GL_LINE_LOOP);
for(i = 0; i < n; i++)
glVertex2i(points[i].x, points[i].y);
glEnd();
glFlush();

int main (int argc, char** argv)


{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);

glutInitWindowSize(width, height);
glutInitWindowPosition(0, 0);
glutCreateWindow("Boundary Fill Algorithm (4-connected)");

myInit();
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMainLoop();
}

Listing 2: Boundary Fill Algorithm (4-connected)

You may now try the following exercises.

E3) Shade the interior of the following polygon using Odd-Even Rule and
Winding Number Rule.

E4) Devise an algorithm for determining the interior regions for any input
set of vertices using the nonzero winding number rule and dot-product
calculations to identify the direction of edge-crossings.

E5) Explain how an ellipse displayed with the midpoint method could be
properly filled with a boundary fill algorithm.

E6) Develop and implement the Flood Fill Algorithm.

Next, we shall discuss the character generation techniques.


74
Unit 3 Filling Algorithms

3.5 CHARACTER GENERATION


You know that graphics displays often contain components which are text
based such as graph labels, annotations, descriptions on data flow diagrams,
fill patterns containing text strings and information for simulation and visual
applications. Routines for generating characters are available in most of the
graphics systems and graphics application softwares. Here you will learn
some simple techniques used in creating texts.

There are two main approaches followed in character or font generation (i)
Bitmap font method (ii) Outline font method. In the bitmap method, a matrix of
bits (0 or 1) is formed which approximates the shape of the font. Every entry in
the matrix corresponds to a pixel and those pixels are plotted for which the
matrix entry is 1.

In the outline method the font boundary shape is approximated by spline


curves. You have already done some practice on character generation using
multiple Bezier curve segments (see E15) of Unit 2).

In order to understand how fonts are converted to bitmap, just think of a letter
drawn on a graph paper. Measure its span in terms of number of maximum x
and y units it covers. Then map the letter grid to a frame buffer position. For
example, in the picture given below, the letter R spans in an area
corresponding to the matrix of order 14 × 10. On the right is shown the
corresponding frame buffer positions with 1 indicating the pixel to be drawn,
and 0 indicating the pixel not to be drawn.

R
(a) Letter R drawn on a graph paper (b) Corresponding frame buffer positions

In the outline method we simply identify a few shape control points and draw
the corresponding Bezier curves for different segments of the outline.

Some predefined character sets are available in the OpenGL Utility Toolkit
(GLUT). So you need not create fonts as bitmap shapes unless you want to
display a font that is not available in GLUT. For example, you may want to 75
Block 1 Fundamentals of Computer Graphics
generate a font of your own mother tongue. The GLUT library contains
routines for displaying both bitmapped and outline fonts. Bitmapped GLUT
fonts are rendered using the glutBitmapCharacter( ) function, as shown
below
glutBitmapCharacter (font, character);

where parameter font is assigned a symbolic GLUT constant identifying a


particular set of type faces, and parameter character is assigned either the
ASCII code or the specific character we wish to display. Thus, to display the
upper-case letter “A”, we can either use the ASCII value 65 or the designation
'A'. Similarly, a code 97 corresponds to the lower-case letter 'a' and so on.
You can also use fixed-width fonts and proportionally spaced fonts. For
example, to select a fixed-width font of 8 × 13 , you need to assign either
GLUT_BITMAP_8_BY_13 or GLUT_BITMAP_9_BY_15. For a proportionally
spaced font of Times Roman type with size 10 point, you need to select
GLUT_BITMAP_TIMES_ROMAN_10 to parameter font. The choice
GLUT_BITMAP_TIMES_ROMAN_12 is also available. For example, to draw
the bitmap font Times Roman of size 10 at the raster position (20, 20), you
need to use the following statements.

glRasterPos2i(20, 20);
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10,'B');
An outline character is displayed with the following function call.

glutStrokeCharacter(font, character);

You can assign parameter 'font' either the value GLUT_STROKE_ROMAN, which
displays a proportionally spaced font, or the value
GLUT_STROKE_MONO_ROMAN, which displays a font with constant spacing.
You can specify and control the size and position of these characters by using
certain geometric transformations that you will study in the next block. You
may refer to OpenGL reference manual for more options.

The following code demonstrates displaying the string 'OpenGL' using the
function glutStrokeCharacter( ).

char text[] = {'O', 'p', 'e', 'n','G', 'L'};


for(int k = 0; k < 6 ; k++)
glutStrokeCharacter(GLUT_STROKE_ROMAN, text[k]);

You may now test your understanding by trying out the following exercises.

E7) Use the outline method to plot the following font boundaries (style should
remain the same). Implement your method in C language using OpenGL.
76
Unit 3 Filling Algorithms

Gt
E8) Design a bitmap for the English vowels A, E, I, O, U for two different
sizes and then implement the bitmaps to plot these vowels on the
display. Keep in mind that baseline of all the bitmaps should remain the
same when plotting, just as it is printed in English language.

We now end this unit by giving a summary of what we have covered in it.

3.6 SUMMARY
In this unit, we have covered the following points.

1. We have described the Scanline Polygon Fill Algorithm and two seed fill
algorithms for filled-area primitives.

2. Boundary fill algorithm is suitable when the boundary has single colour
while flood fill algorithm is more suitable for filling regions which are
defined with boundary having more than one color, for example, a map
of a country surrounded with other countries.

3. We have also discussed two basic approaches used in character


generation namely – Bitmap method and outline method.

3.7 SOLUTIONS/ANSWERS
E1) First label the vertices and edges as shown below.

V6 V4
40
E5 E4

30
E6 V5
V0 E7
20
V7 E3
E0 V2
10
E1
E2
0 V1 V3
0 10 20 30 40 50

77
Block 1 Fundamentals of Computer Graphics
Let ei = vi vi +1 , for i = 0, 1, K , 6. If mi is the slope of edge ei , then we

find that m0 = −2, m1 = 2, m2 = −1, m3 = ∞, m4 = 1, m5 = −1, m6 = −2,

m7 = 0.
Start with y = 0 and continue till y = 40 . For y = 0 there are four

edges, namely e0 , e1 , e 2 and e3 . Then for y = 20, we get the edge e6

only, and for y = 30 the edges are e5 , e4 . The sorted edge table is

created as follows:

y=30 40 30 –1 40 30 1

y=20 40 20 –½ (Horizontal edge ignored)

y=0 20 20 –½ 10 20 1 10 40 –1 40 40 0

Active edge lists (AEL) for scan lines y = 5, 20, 30, 35 are as follows.
y = 5, AEL = {e0 , e1 , e2 , e3 }
y = 20, AEL = {e6 , e3 }
y = 30, AEL = {e6 , e5 , e 4 , e3 }
y = 35, AEL = {e6 , e5 , e 4 , e3 }
We start with y = 0 and iteratively compute the x -coordinate values for

each edge till we reach the scanline y = 5, as shown in the following


table.

Scanline x -coordinate values


e0 e1 e2 e3
y=0 20 20 40 40
y =1 19.5 21 39 40
y=2 19 22 38 40
y=3 18.5 23 37 40
y=4 18 24 36 40
y=5 17.5 25 35 40

E2) Note that as we move from v0 v1 to v1v 2 the lower y -values of these

edges are monotonically decreasing. Therefore, the upper endpoint of


v1v 2 is shortened. As a result there is only one intersection at v1 .
Likewise, when we move from v3 v 4 to v 4 v5 there is one intersection at

v 4. . Since v1 = v 4 , the intersection is counted once.


78
Unit 3 Filling Algorithms
E3) Both the rules produce the following shaded region as the interior.

E4) Let P be a given polygon with n vertices given by


Vi = ( xi , yi ), i = 0, 1, K , n − 1 in the counter clockwise orientation.

Find out x min = min i {xi }, x max = max i {xi } and


y min = min i { yi }, y max = max i { yi }
Let Q = ( x, y ) be the point to be tested. Initialize the winding number

ω n = 0 . If any of the following conditions is satisfied Q cannot be inside


the polygon.

(i) x < x min (ii) x > x max (iii) y < y min (ii) y > y max

In case none of the conditions is satisfied, you are required to have a ray
starting from Q and extending to a distant point from the polygon and
then construct a vector in the direction of this ray. For simplifying the
computations, you can choose a vector u from Q in the direction (1, 0) .

Basically, this vector is on the scan line on which point Q lies. If no


vertex is on this scan line, your choice of vector is correct. Else choose
a vector with a slightly modified direction so that no vertex falls on the ray
from Q in the chosen direction. Create an active edge list (AEL) for this
ray. Each edge whose one of the x-extents is greater than x is included
in the AEL. Next make a vector v perpendicular to u. If u = (u x , u y ), v

can be defined as v = ( −u y , u x ) . For each edge ViVi +1 in the AEL, take

the dot product of the vector Vi +1 − Vi with v . Let d i = (Vi +1 − Vi ).v (dot

product). If d i > 0 , the edge Vi Vi +1 crosses the ray from right to left.

Update the ω n = ω n + 1 , else the edge crosses the ray from left to right

and ω n = ω n − 1 . When all the edges are processed and ω n ≠ 0 , the

point Q is inside the polygon else it is outside.

79
Block 1 Fundamentals of Computer Graphics
E5) Modify the function plot_ellipse_points() given in E12 of Unit 2 as follows.

void plot_ellipse_points(int xc, int yc, int x, int y)


{
glBegin(GL_POINTS);
for(int i = xc - x ; i < xc + x ; i++)
{ glVertex2i(i, yc + y);
glVertex2i(i, yc - y);
}
glEnd();
}

E6) A code for flood fill algorithm with 4-connected cells is given below.

void flood_fill4(int x, int y, float* fill, float* old)


{
float colour[3];
glReadPixels(x, y, 1, 1, GL_RGB, GL_FLOAT, colour);
if(equal(colour, old))
{ draw_point(x, y, fill);
boundary_fill4(x+1, y, fill, old);
boundary_fill4(x-1, y, fill, old);
boundary_fill4(x, y+1, fill, old);
boundary_fill4(x, y-1, fill, old);
}
}

E7) Here letter G is produced using linear segments for outline method. You
may also use Bezier curves of higher degree to approximate the outline
of the character. The outline will be drawn using the code given here. For
filling the interior, you need to employ one of the fill area methods.
Vertices of the line segments are given as follows.
GLint vt[][2]={{315,245}, { 315,195}, {316,190},{333,183},
{ 251,183}, {263,186}, { 270, 190},{272,195}, {272,225}, {
253, 238}, {242,236}, {235,229}, {231,219}, {227,198}, {
227,169}, { 228,152}, {233,133}, {242,124}, {248,120}, {
253,120}, {269,119}, { 273,121}, { 280,126}, {292,134}, {
299,141}, {305,149}, {312,162}, {312,111}, {307,110}, {307,
120}, {304, 130}, {301, 133}, {298, 131}, { 289, 125},
{279, 120}, {266, 113}, {251, 109}, {239, 110},{229,110},
{219,114}, {208,120}, {196,129}, {190,138}, {185,148},
{181, 158}, {180,172},{180,184}, {180,196}, {184, 203},
{189, 214}, {198, 226}, {211, 235}, {220,242}, {230,245},
{245,247}, {260, 247}, {271, 241}, {284, 236}, {293, 231},
{299, 231}, {306, 235}, {315,245}};

The code uses simple line loop to produce the character.

void lineG(void)
{glBegin(GL_LINE_LOOP);
for(int i = 0;i<62;i++) {
vt[i][1]=480-vt[i][1];
glVertex2iv(vt[i]);}
glEnd();
}

Call the function lineG in your display function. Similar is the code for
letter ' t'.

80
Unit 3 Filling Algorithms
E8) Here we discuss the bitmap for letter 'E'. You need to place the
character 'E' on a square grid of sufficiently large size. If the character's
area is overlapping more than 50% of a cell of the square grid, assign
that cell a bit 1, otherwise assign the cell bit 0. This way you will have a
rectangular grid having cells either assigned 0 or 1. Map this onto a
rectangular matrix and plot the character 'E' using the bitmap method as
shown below.

1 1 1 1 1 1 1
 
1 1 1 1 1 1 1

1 1 0 0 0 0 1
1 1 0 0 0 0 0
1 1 0 0 0 0 0

 
1 1 0 0 0 0 1
1 1 1 1 1 1 1
1 1 0 0 0 0 1
 
1 1 0 0 0 0 0
1 1 0 0 0 0 0
1 1 0 0 0 0 1
 
 1 1 1 1 1 1 1

1 1 1 1 1 1 1

Other characters can also be modelled using the same technique.


Repeat your process for a larger size font also.

81
Block 1 Fundamentals of Computer Graphics
Notes

82

You might also like