We define the needed terms by setting up an example, which will accompany us through the whole rest of the article.

Assume, that we are given a bounding rectangle containing an arbitrary 12 x 12 cells (e.g. pixels on a screen), into which information bounded by a polygonal shape shall be drawn.

The abscissa (x axis) of the bounding rectangle runs from
the left to the right as usual in

Because we will need to clearly distinguish between upper and lower, and left and right, resp., it is advantageous to enumerate the vertical and horizontal lines in between the cells (represented by the white squares in fig. 1), not the squares themselves in between two such line pairs. Hence there are 13 lines on each axis and they are enumerated from 0 to 12 as follows.

For the rest of the article is valid, that white squares represent the value unequal 0, indicating that such are part of the polygon. Accordingly, black squares shall signify 0 and thus "not part of the polygon".

Now assume, that we are given a simple orthogonal

Because we need to know, which side needs to be treated as the inside of the polygon (and accordingly which one as its outside), we must define a direction in which we want to traverse the polygon's vertices.

Arbitrarily, we define to list the vertices in a clockwise direction, with the implication, that the interior of the polygon lies on the right side of the edges as we travel around the polygon.

This is the list with the vertex coordinates for our example:

Coordinates are given in x/y notation. [Thanks go to Brian Lewis for spotting a typo.]

As per agreement we want to render the polygon's interior in white (signifying the non zero value) and its outside in black (the zero value). Therefore our polygon eventually must look like in fig. 2.

The intent of this article is to show, how this result can be obtained by processing each vertex just once, without the need to compare opposite bounds in a time-consuming way.

The presented algorithm will set the subareas (pixels, flags, in the examples rendered as squares) of the outside area of the polygon to 0, leaving the interior as it was before.

This implies, that an initial preprocessing task must be performed in order to obtain a completely "painted" canvas in the dimensions of the bounding rectangle, i.e. the whole bounding rectangle must initially be set with the non zero value. Compare with fig. 1: the canvas is white, which is the "interior" color.

Omitting this preprocessing step will result in the complement of the desired result, i.e. white and black areas are reversed (which can be useful, too, depending on your application).

For each vertex, we consider the edge pair consisting of the edge
which leads to it *(approaching edge)* and the one moving away from it
*(receding edge)*. (This means, that although we process
only the 20 given vertices, ultimately we need to consider 20
adjacent edge *pairs* and thus a total of 21 edges:
the first vertex' approaching edge also is the last vertex' receding edge.)

Assuming, that coordinates are only given at points
at which the direction changes (there is no reason to mark
a vertex anywhere else along an edge), the two edges at the vertex
can only form an angle of either 90° or then of 270°
(else it would not be an orthogonal one).
This has the notion of a *corner*,
which term we will use from now on whenever we mean
"two consecutive edges meeting at a vertex".
There are as many corners as there are vertices:
in our example there are 20.

What we primarily are interested in, is the direction of each of the corners. Let's have a look at the first corner.

First corner? This requires some elaboration. Which one is the first corner, the one consisiting of the first vertex? Well, it does not matter, which corner we declare to be the first, as long as we process them all. However, in an actual implementation it turns out to be advantageous if we declare the corner around the second vertex to be the first corner. This is because we need to find the direction of the approaching edge, which for the corner including the first vertex originates at the last vertex of the polygon. This last vertex usually still is out of scope, and depending on implementation, possibly will not be known before having processed the whole vertex list. This is not the case for the second vertex, though: for it, the approaching edge originates at the very first vertex, which is known right from the beginning.

Throughout all following examples,
we will mark corners by coloring the two involved edges red.
Note, that an arrowhead at the end of the receding edge
marks the direction in which we travel (clockwise, as defined above).
For the first corner, see fig. 3, we speak of a "right/down"-corner
(or `RD`

corner for short), because
the approaching (first) edge goes to the right and
the receding (second) edge goes downwards.

How many distinctive corners are there? Well, the approaching edge can point to any of the 4 possible directions left, right, top and down, and so can the receding edge.

However, because a corner has an angle of either 90° or 270°, not all 4 x 4 combinations are possible: in fact, only 8 combinations exist, because for either one of the 4 possible approaching edges, only 2 "continuations" are possible (the other two possibilities would mean "continue into the same direction", and "go back into the direction where we came from", both resulting in a degenerated corner, i.e. a straight line, or no movement at all).

It should come as no surprise,
that our icosagon contains corners in all possible combinations.
The following table shows a specimen of each.
The two-letters-abbreviation above the figure identify
the directions of the two edges
(where `R`

, `L`

, `D`

and `U`

stand for Right, Left, Down, and Up, resp.)

Note, that if we just looked at the directed edges, we can distinguish 4 clockwise corners and 4 counterclockwise corners: although they involve the same edges and meet at the same vertex location, their direction is different and consequently they are named differently.

`RD`

corner`DL`

corner`LU`

corner`UR`

corner`UL`

corner`RU`

corner`DR`

corner`LD`

cornerCorners being positionally identical with the exception of the direction
belong to a different set and therefore also must be treated differently.
Therefore it is surprising, that the same is not the case
for corner pairs which involve the same directional edges
(because they indeed look different).
Despite the apparent difference,
it is irrelevant in what order the edges appear
(i.e. if a particular edge is approaching or receding):
For example is a `DR`

corner treated absolutely like
an `RD`

corner when processed.

Therefore, we in fact only have to consider 4 distinct corner types, identifiable by the corner's constituting edges. Just mark, say in a bitfield, which two edges belong to the corner, and mark them as to the left, to the right, upwards or downwards. Thus, 4 bits suffice to tell which 2 of the 4 possible edges are involved.

Notice, that in fact two bits would be enough,
because either a left or a right edge must be present,
as well as must either an upward or downward edge.
Such, we could define *horizontal*
instead of to the left and to the right,
and accordingly *vertical* instead of upward or downward.
Then we only would need to define, what 0 and 1 mean,
and could go along with just two bits.
However, for the sake of simplicity we will continue
to use the more explicit 4 values without
the burden of an imposed definition.

To easily point out involved edges, let's assume,
those 4 bits are in a dedicated position within a word.
Somewhat arbitrarily we define that order to be
`L`

, `R`

, `U`

and `F`

from the most significant to the least significant bit, as shown in fig.5.

Whenever we refer to a corner, the two not appearing edges will be greyed out, see fig. 6 for an example.

Recall, that it does not matter which edge appears first. Fig. 6 can mean "first to the left, then downward", but also "first downward, then to the left".

These are some examples of the 4 possible groups:

Once we have determined, which of the 4 cases is applicable for the corner actually being processed, we proceed by identifying the four quadrants within the bounding rectangle.

The *quadrants* are defined by extending the two involved edges,
in such a way, that the involved vertex at the given coordinate
separates the whole surrounding rectangle into 2 x 2 halves.

As an example on how to identify the 4 quadrants, consider the 6th corner with the coordinates 8/5 in fig. 8.

One of these quadrants is now manipulated by

Remains only to set out the rule, which quadrant needs to be treated that way. Here it is:

The manipulated quadrant is in that half, which is opposite to the receding edge. Of the two quadrants in that half, choose the one which is adjacent to the approaching edge.

For our example with the 6th corner this works out so: the receding edge points to the right, thus the quadrant in question must be to the left; and because the approaching edge is in the lower half, our candidate must be the lower left quadrant (fig. 9).

Notice, how the involved (directed) edges just need to be
*directly* (fig. 10).

Notabene, that the black squares in fig. 9
(and in the following quadrant figures) does not imply,
that all subareas within the bounding rectangle are converted from 1 to 0.
It rather means, that the *actual content*
of each affected subarea (black square) is `XOR`

ed
with our non zero value, writing back the result of the operation
as the subarea's new content. Such, depending on what was present
before the operation, each individual subarea within the quadrant
is "set" or "cleared" individually.

Well, that's all what there is about it. Applying this technique for each corner leaves us with the desired result. This is shown in the next section, step by step for all 20 corners.

`XOR`

QuadrantResultAfter having processed the last corner, we are left with the desired representation as initially defined in fig. 2.