abrash-black-book/40-01.md
2013-12-30 20:26:41 +11:00

111 lines
6 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Chapter 40\
Of Songs, Taxes, and the Simplicity of Complex Polygons {#Heading1}
--------------------------------------------------------
### Dealing with Irregular Polygonal Areas {#Heading2}
Every so often, my daughter asks me to sing her to sleep. (If you've
ever heard me sing, this may cause you concern about either her hearing
or her judgement, but love knows no bounds.) As any parent is well
aware, singing a young child to sleep can easily take several hours, or
until sunrise, whichever comes last. One night, running low on
children's songs, I switched to a Beatles medley, and at long last her
breathing became slow and regular. At the end, I softly sang "A Hard
Day's Night," then quietly stood up to leave. As I tiptoed out, she
said, in a voice not even faintly tinged with sleep, "Dad, what do they
mean, working like a dog'? Chasing a stick? That doesn't make sense;
people don't chase sticks."
That led us into a discussion of idioms, which made about as much sense
to her as an explanation of quantum mechanics. Finally, I fell back on
my standard explanation of the Universe, which is that a lot of the time
it simply doesn't make sense.
As a general principle, that explanation holds up remarkably well. (In
fact, having just done my taxes, I think Earth is actually run by
blob-creatures from the planet Mrxx, who are helplessly doubled over
with laughter at the ridiculous things they can make us do. "Let's make
them get Social Security numbers for their pets next year!" they're
saying right now, gasping for breath.) Occasionally, however, one has
the rare pleasure of finding a corner of the Universe that makes sense,
where everything fits together as if preordained.
Filling arbitrary polygons is such a case.
### Filling Arbitrary Polygons {#Heading3}
In Chapter 38, I described three types of polygons: convex, nonconvex,
and complex. *The RenderMan Companion*, a terrific book by Steve Upstill
(Addison-Wesley, 1990) has an intuitive definition of *convex*: If a
rubber band stretched around a polygon touches all vertices in the order
they're defined, then the polygon is convex. If a polygon has
intersecting edges, it's complex. If a polygon doesn't have intersecting
edges but isn't convex, it's nonconvex. Nonconvex is a special case of
complex, and convex is a special case of nonconvex. (Which, I'm well
aware, makes nonconvex a lousy name—noncomplex would have been
better—but I'm following X Window System nomenclature here.)
The reason for distinguishing between these three types of polygons is
that the more specialized types can be filled with markedly faster
approaches. Complex polygons require the slowest approach; however, that
approach will serve to fill any polygon of any sort. Nonconvex polygons
require less sorting, because edges never cross. Convex polygons can be
filled fastest of all by simply scanning the two sides of the polygon,
as we saw in Chapter 39.
Before we dive into complex polygon filling, I'd like to point out that
the code in this chapter, like all polygon filling code I've ever seen,
requires that the caller describe the type of the polygon to be filled.
Often, however, the caller doesn't know what type of polygon it's
passing, or specifies complex for simplicity, because that will work for
all polygons; in such a case, the polygon filler will use the slow
complex-fill code even if the polygon is, in fact, a convex polygon. In
Chapter 41, I'll discuss one way to improve this situation.
#### Active Edges {#Heading4}
The basic premise of filling a complex polygon is that for a given scan
line, we determine all intersections between the polygon's edges and
that scan line and then fill the spans between the intersections, as
shown in Figure 40.1. (Section 3.6 of Foley and van Dam's *Computer
Graphics*, Second Edition provides an overview of this and other aspects
of polygon filling.) There are several rules that might be used to
determine which spans are drawn and which aren't; we'll use the odd/even
rule, which specifies that drawing turns on after odd-numbered
intersections (first, third, and so on) and off after even-numbered
intersections.
The question then becomes how can we most efficiently determine which
edges cross each scan line and where? As it happens, there is a great
deal of coherence from one scan line to the next in a polygon edge list,
because each edge starts at a given Y coordinate and continues unbroken
until it ends. In other words, edges don't leap about and stop and start
randomly; the X coordinate of an edge at one scan line is a consistent
delta from that edge's X coordinate at the last scan line, and that is
consistent for the length of the line.
![](images/40-01.jpg)\
**Figure 40.1**  *Filling one scan line by finding intersecting edges.*
This allows us to reduce the number of edges that must be checked for
intersection; on any given scan line, we only need to check for
intersections with the currently active edges—edges that start on that
scan line, plus all edges that start on earlier (above) scan lines and
haven't ended yet—as shown in Figure 40.2. This suggests that we can
proceed from the top scan line of the polygon to the bottom, keeping a
running list of currently active edges—called the *active edge table*
(AET)—with the edges sorted in order of ascending X coordinate of
intersection with the current scan line. Then, we can simply fill each
scan line in turn according to the list of active edges at that line.
![](images/40-02.jpg)\
**Figure 40.2**  *Checking currently active edges (solid lines).*
Maintaining the AET from one scan line to the next involves three steps:
First, we must add to the AET any edges that start on the current scan
line, making sure to keep the AET X-sorted for efficient odd/even
scanning. Second, we must remove edges that end on the current scan
line. Third, we must advance the X coordinates of active edges with the
same sort of error term-based, Bresenham's-like approach we used for
convex polygons, again ensuring that the AET is X-sorted after advancing
the edges.