Replace invalid characters with HTML entities
— with — ’ with ’ + with + × with x ç with ç “ with “ ” with ” ‘ with ‘ • with • – with - µ with µ † with † Fix C++ θ with θ Yen symbol instead of times Fix broken apos Bullet again E-circumflex
This commit is contained in:
parent
9e52de9586
commit
500e7f5654
353 changed files with 5091 additions and 5091 deletions
60
40-02.html
60
40-02.html
|
|
@ -36,9 +36,9 @@
|
|||
</TABLE>
|
||||
</CENTER>
|
||||
<P><BR></P>
|
||||
<P>Advancing the X coordinates is easy. For each edge, we’ll store the current X coordinate and all required error term information, and we’ll use that to advance the edge one scan line at a time; then, we’ll resort the AET by X coordinate as needed. Removing edges as they end is also easy; we’ll just count down the length of each active edge on each scan line and remove an edge when its count reaches zero. Adding edges as their tops are encountered is a tad more complex. While there are a number of ways to do this, one particularly efficient approach is to start out by putting all the edges of the polygon, sorted by increasing Y coordinate, into a single list, called the <I>global edge table</I> (GET). Then, as each scan line is encountered, all edges at the start of the GET that begin on the current scan line are moved to the AET; because the GET is Y-sorted, there’s no need to search the entire GET. For still greater efficiency, edges in the GET that share common Y coordinates can be sorted by increasing X coordinate; this ensures that no more than one pass through the AET per scan line is ever needed when adding new edges from the GET in such a way as to keep the AET sorted in ascending X order.</P>
|
||||
<P>What form should the GET and AET take? Linked lists of edge structures, as shown in Figure 40.3. With linked lists, all that’s required to move edges from the GET to the AET as they become active, sort the AET, and remove edges that have been fully drawn is the exchanging of a few pointers.</P>
|
||||
<P>In summary, we’ll initially store all the polygon edges in Y-primary/X-secondary sort order in the GET, complete with initial X and Y coordinates, error terms and error term adjustments, lengths, and directions of X movement for each edge. Once the GET is built, we’ll do the following:</P>
|
||||
<P>Advancing the X coordinates is easy. For each edge, we’ll store the current X coordinate and all required error term information, and we’ll use that to advance the edge one scan line at a time; then, we’ll resort the AET by X coordinate as needed. Removing edges as they end is also easy; we’ll just count down the length of each active edge on each scan line and remove an edge when its count reaches zero. Adding edges as their tops are encountered is a tad more complex. While there are a number of ways to do this, one particularly efficient approach is to start out by putting all the edges of the polygon, sorted by increasing Y coordinate, into a single list, called the <I>global edge table</I> (GET). Then, as each scan line is encountered, all edges at the start of the GET that begin on the current scan line are moved to the AET; because the GET is Y-sorted, there’s no need to search the entire GET. For still greater efficiency, edges in the GET that share common Y coordinates can be sorted by increasing X coordinate; this ensures that no more than one pass through the AET per scan line is ever needed when adding new edges from the GET in such a way as to keep the AET sorted in ascending X order.</P>
|
||||
<P>What form should the GET and AET take? Linked lists of edge structures, as shown in Figure 40.3. With linked lists, all that’s required to move edges from the GET to the AET as they become active, sort the AET, and remove edges that have been fully drawn is the exchanging of a few pointers.</P>
|
||||
<P>In summary, we’ll initially store all the polygon edges in Y-primary/X-secondary sort order in the GET, complete with initial X and Y coordinates, error terms and error term adjustments, lengths, and directions of X movement for each edge. Once the GET is built, we’ll do the following:</P>
|
||||
<DL>
|
||||
<DD><B>1.</B> Set the current Y coordinate to the Y coordinate of the first edge in the GET.
|
||||
<DD><B>2.</B> Move all edges with the current Y coordinate from the GET to the AET, removing them from the GET and maintaining the X-sorted order of the AET.
|
||||
|
|
@ -46,12 +46,12 @@
|
|||
<DD><B>4.</B> Count down the lengths of all edges in the AET, removing any edges that are done, and advancing the X coordinates of all remaining edges in the AET by one scan line.
|
||||
<DD><B>5.</B> Sort the AET in order of ascending X coordinate.
|
||||
<DD><B>6.</B> Advance the current Y coordinate by one scan line.
|
||||
<DD><B>7.</B> If either the AET or GET isn’t empty, go to step 2.
|
||||
<DD><B>7.</B> If either the AET or GET isn’t empty, go to step 2.
|
||||
</DL>
|
||||
<P><A NAME="Fig3"><!-- </A><A HREF="javascript:displayWindow('images/40-03.jpg',407,199 )"> --><IMG SRC="images/40-03.jpg"><BR><!-- </A>
|
||||
<BR><A HREF="javascript:displayWindow('images/40-03.jpg',407,199)"> --><FONT COLOR="#000077"><B>Figure 40.3</B></FONT></A> <I>The global and active edge tables as linked lists.</I>
|
||||
</P>
|
||||
<P>That’s really all there is to it. Compare Listing 40.1 to the fast convex polygon filling code from Chapter 39, and you’ll see that, contrary to expectation, complex polygon filling is indeed one of the more sane and sensible corners of the universe.
|
||||
<P>That’s really all there is to it. Compare Listing 40.1 to the fast convex polygon filling code from Chapter 39, and you’ll see that, contrary to expectation, complex polygon filling is indeed one of the more sane and sensible corners of the universe.
|
||||
</P>
|
||||
<P><B>LISTING 40.1 L40-1.C</B></P>
|
||||
<!-- CODE //-->
|
||||
|
|
@ -60,12 +60,12 @@
|
|||
If the first and last points in VertexList are not the same, the path
|
||||
around the polygon is automatically closed. All vertices are offset
|
||||
by (XOffset, YOffset). Returns 1 for success, 0 if memory allocation
|
||||
failed. All C code tested with Borland C++.
|
||||
failed. All C code tested with Borland C++.
|
||||
If the polygon shape is known in advance, speedier processing may be
|
||||
enabled by specifying the shape as follows: “convex” - a rubber band
|
||||
enabled by specifying the shape as follows: “convex” - a rubber band
|
||||
stretched around the polygon would touch every vertex in order;
|
||||
“nonconvex” - the polygon is not self-intersecting, but need not be
|
||||
convex; “complex” - the polygon may be self-intersecting, or, indeed,
|
||||
“nonconvex” - the polygon is not self-intersecting, but need not be
|
||||
convex; “complex” - the polygon may be self-intersecting, or, indeed,
|
||||
any sort of polygon at all. Complex will work for all polygons; convex
|
||||
is fastest. Undefined results will occur if convex is specified for a
|
||||
nonconvex or complex polygon.
|
||||
|
|
@ -82,7 +82,7 @@
|
|||
#else /* MSC */
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#include “polygon.h”
|
||||
#include “polygon.h”
|
||||
|
||||
#define SWAP(a,b) {temp = a; a = b; b = temp;}
|
||||
|
||||
|
|
@ -129,7 +129,7 @@
|
|||
if ((EdgeTableBuffer =
|
||||
(struct EdgeState *) (malloc(sizeof(struct EdgeState) *
|
||||
VertexList->Length))) == NULL)
|
||||
return(0); /* couldn’’t get memory for the edge table */
|
||||
return(0); /* couldn’’t get memory for the edge table */
|
||||
/* Build the global edge table */
|
||||
BuildGET(VertexList, EdgeTableBuffer, XOffset, YOffset);
|
||||
/* Scan down through the polygon edges, one scan line at a time,
|
||||
|
|
@ -141,9 +141,9 @@
|
|||
ScanOutAET(CurrentY, Color); /* draw this scan line from AET */
|
||||
AdvanceAET(); /* advance AET edges 1 scan line */
|
||||
XSortAET(); /* resort on X */
|
||||
CurrentY++; /* advance to the next scan line */
|
||||
CurrentY++; /* advance to the next scan line */
|
||||
}
|
||||
/* Release the memory we’ve allocated and we’re done */
|
||||
/* Release the memory we’ve allocated and we’re done */
|
||||
free(EdgeTableBuffer);
|
||||
return(1);
|
||||
}
|
||||
|
|
@ -165,29 +165,29 @@
|
|||
the GET, sorted by increasing Y start coordinate */
|
||||
VertexPtr = VertexList->PointPtr; /* point to the vertex list */
|
||||
GETPtr = NULL; /* initialize the global edge table to empty */
|
||||
for (i = 0; i < VertexList->Length; i++) {
|
||||
for (i = 0; i < VertexList->Length; i++) {
|
||||
/* Calculate the edge height and width */
|
||||
StartX = VertexPtr[i].X + XOffset;
|
||||
StartY = VertexPtr[i].Y + YOffset;
|
||||
StartX = VertexPtr[i].X + XOffset;
|
||||
StartY = VertexPtr[i].Y + YOffset;
|
||||
/* The edge runs from the current point to the previous one */
|
||||
if (i == 0) {
|
||||
/* Wrap back around to the end of the list */
|
||||
EndX = VertexPtr[VertexList->Length-1].X + XOffset;
|
||||
EndY = VertexPtr[VertexList->Length-1].Y + YOffset;
|
||||
EndX = VertexPtr[VertexList->Length-1].X + XOffset;
|
||||
EndY = VertexPtr[VertexList->Length-1].Y + YOffset;
|
||||
} else {
|
||||
EndX = VertexPtr[i-1].X + XOffset;
|
||||
EndY = VertexPtr[i-1].Y + YOffset;
|
||||
EndX = VertexPtr[i-1].X + XOffset;
|
||||
EndY = VertexPtr[i-1].Y + YOffset;
|
||||
}
|
||||
/* Make sure the edge runs top to bottom */
|
||||
if (StartY > EndY) {
|
||||
SWAP(StartX, EndX);
|
||||
SWAP(StartY, EndY);
|
||||
}
|
||||
/* Skip if this can’t ever be an active edge (has 0 height) */
|
||||
/* Skip if this can’t ever be an active edge (has 0 height) */
|
||||
if ((DeltaY = EndY - StartY) != 0) {
|
||||
/* Allocate space for this edge’s info, and fill in the
|
||||
/* Allocate space for this edge’s info, and fill in the
|
||||
structure */
|
||||
NewEdgePtr = NextFreeEdgeStruc++;
|
||||
NewEdgePtr = NextFreeEdgeStruc++;
|
||||
NewEdgePtr->XDirection = /* direction in which X moves */
|
||||
((DeltaX = EndX - StartX) > 0) ? 1 : -1;
|
||||
Width = abs(DeltaX);
|
||||
|
|
@ -198,7 +198,7 @@
|
|||
if (DeltaX >= 0) /* initial error term going L->R */
|
||||
NewEdgePtr->ErrorTerm = 0;
|
||||
else /* initial error term going R->L */
|
||||
NewEdgePtr->ErrorTerm = -DeltaY + 1;
|
||||
NewEdgePtr->ErrorTerm = -DeltaY + 1;
|
||||
if (DeltaY >= Width) { /* Y-major edge */
|
||||
NewEdgePtr->WholePixelXMove = 0;
|
||||
NewEdgePtr->ErrorTermAdjUp = Width;
|
||||
|
|
@ -269,12 +269,12 @@
|
|||
/* This edge is finished, so remove it from the AET */
|
||||
*CurrentEdgePtr = CurrentEdge->NextEdge;
|
||||
} else {
|
||||
/* Advance the edge’s X coordinate by minimum move */
|
||||
CurrentEdge->X += CurrentEdge->WholePixelXMove;
|
||||
/* Determine whether it’s time for X to advance one extra */
|
||||
if ((CurrentEdge->ErrorTerm +=
|
||||
/* Advance the edge’s X coordinate by minimum move */
|
||||
CurrentEdge->X += CurrentEdge->WholePixelXMove;
|
||||
/* Determine whether it’s time for X to advance one extra */
|
||||
if ((CurrentEdge->ErrorTerm +=
|
||||
CurrentEdge->ErrorTermAdjUp) > 0) {
|
||||
CurrentEdge->X += CurrentEdge->XDirection;
|
||||
CurrentEdge->X += CurrentEdge->XDirection;
|
||||
CurrentEdge->ErrorTerm -= CurrentEdge->ErrorTermAdjDown;
|
||||
}
|
||||
CurrentEdgePtr = &CurrentEdge->NextEdge;
|
||||
|
|
@ -289,7 +289,7 @@
|
|||
int CurrentX;
|
||||
|
||||
/* The GET is Y sorted. Any edges that start at the desired Y
|
||||
coordinate will be first in the GET, so we’ll move edges from
|
||||
coordinate will be first in the GET, so we’ll move edges from
|
||||
the GET to AET until the first edge left in the GET is no longer
|
||||
at the desired Y coordinate. Also, the GET is X sorted within
|
||||
each Y coordinate, so each successive edge we add to the AET is
|
||||
|
|
|
|||
Loading…
Reference in a new issue