|
|
1.1 root 1: /***********************************************************
2: Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
3: and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
4:
5: All Rights Reserved
6:
7: Permission to use, copy, modify, and distribute this software and its
8: documentation for any purpose and without fee is hereby granted,
9: provided that the above copyright notice appear in all copies and that
10: both that copyright notice and this permission notice appear in
11: supporting documentation, and that the names of Digital or MIT not be
12: used in advertising or publicity pertaining to distribution of the
13: software without specific, written prior permission.
14:
15: DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
16: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
17: DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
18: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
20: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
21: SOFTWARE.
22:
23: ******************************************************************/
24: /* $Header: mipolyutil.c,v 1.12 87/09/11 07:19:12 toddb Exp $ */
25: #include "miscstruct.h"
26: #include "gc.h"
27: #include "miscanfill.h"
28: #include "mipoly.h"
29:
30: #define MAXINT 0x7fffffff
31: #define MININT -MAXINT
32:
33: /*
34: * fillUtils.c
35: *
36: * Written by Brian Kelleher; Oct. 1985
37: *
38: * This module contains all of the utility functions
39: * needed to scan convert a polygon.
40: *
41: */
42:
43: /*
44: * InsertEdgeInET
45: *
46: * Insert the given edge into the edge table.
47: * First we must find the correct bucket in the
48: * Edge table, then find the right slot in the
49: * bucket. Finally, we can insert it.
50: *
51: */
52: void
53: miInsertEdgeInET(ET, ETE, scanline, SLLBlock, iSLLBlock)
54: EdgeTable *ET;
55: EdgeTableEntry *ETE;
56: int scanline;
57: ScanLineListBlock **SLLBlock;
58: int *iSLLBlock;
59: {
60: register EdgeTableEntry *start, *prev;
61: register ScanLineList *pSLL, *pPrevSLL;
62: ScanLineListBlock *tmpSLLBlock;
63:
64: /*
65: * find the right bucket to put the edge into
66: */
67: pPrevSLL = &ET->scanlines;
68: pSLL = pPrevSLL->next;
69: while (pSLL && (pSLL->scanline < scanline))
70: {
71: pPrevSLL = pSLL;
72: pSLL = pSLL->next;
73: }
74:
75: /*
76: * reassign pSLL (pointer to ScanLineList) if necessary
77: */
78: if ((!pSLL) || (pSLL->scanline > scanline))
79: {
80: if (*iSLLBlock > SLLSPERBLOCK-1)
81: {
82: tmpSLLBlock =
83: (ScanLineListBlock *)Xalloc(sizeof(ScanLineListBlock));
84: (*SLLBlock)->next = tmpSLLBlock;
85: tmpSLLBlock->next = (ScanLineListBlock *)NULL;
86: *SLLBlock = tmpSLLBlock;
87: *iSLLBlock = 0;
88: }
89: pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
90:
91: pSLL->next = pPrevSLL->next;
92: pSLL->edgelist = (EdgeTableEntry *)NULL;
93: pPrevSLL->next = pSLL;
94: }
95: pSLL->scanline = scanline;
96:
97: /*
98: * now insert the edge in the right bucket
99: */
100: prev = (EdgeTableEntry *)NULL;
101: start = pSLL->edgelist;
102: while (start && (start->bres.minor < ETE->bres.minor))
103: {
104: prev = start;
105: start = start->next;
106: }
107: ETE->next = start;
108:
109: if (prev)
110: prev->next = ETE;
111: else
112: pSLL->edgelist = ETE;
113: }
114:
115: /*
116: * CreateEdgeTable
117: *
118: * This routine creates the edge table for
119: * scan converting polygons.
120: * The Edge Table (ET) looks like:
121: *
122: * EdgeTable
123: * --------
124: * | ymax | ScanLineLists
125: * |scanline|-->------------>-------------->...
126: * -------- |scanline| |scanline|
127: * |edgelist| |edgelist|
128: * --------- ---------
129: * | |
130: * | |
131: * V V
132: * list of ETEs list of ETEs
133: *
134: * where ETE is an EdgeTableEntry data structure,
135: * and there is one ScanLineList per scanline at
136: * which an edge is initially entered.
137: *
138: */
139:
140: void
141: miCreateETandAET(count, pts, ET, AET, pETEs, pSLLBlock)
142: register int count;
143: register DDXPointPtr pts;
144: EdgeTable *ET;
145: EdgeTableEntry *AET;
146: register EdgeTableEntry *pETEs;
147: ScanLineListBlock *pSLLBlock;
148: {
149: register DDXPointPtr top, bottom;
150: register DDXPointPtr PrevPt, CurrPt;
151: int iSLLBlock = 0;
152:
153: int dy;
154:
155: if (count < 2) return;
156:
157: /*
158: * initialize the Active Edge Table
159: */
160: AET->next = (EdgeTableEntry *)NULL;
161: AET->back = (EdgeTableEntry *)NULL;
162: AET->nextWETE = (EdgeTableEntry *)NULL;
163: AET->bres.minor = MININT;
164:
165: /*
166: * initialize the Edge Table.
167: */
168: ET->scanlines.next = (ScanLineList *)NULL;
169: ET->ymax = MININT;
170: ET->ymin = MAXINT;
171: pSLLBlock->next = (ScanLineListBlock *)NULL;
172:
173: PrevPt = &pts[count-1];
174:
175: /*
176: * for each vertex in the array of points.
177: * In this loop we are dealing with two vertices at
178: * a time -- these make up one edge of the polygon.
179: */
180: while (count--)
181: {
182: CurrPt = pts++;
183:
184: /*
185: * find out which point is above and which is below.
186: */
187: if (PrevPt->y > CurrPt->y)
188: {
189: bottom = PrevPt, top = CurrPt;
190: pETEs->ClockWise = 0;
191: }
192: else
193: {
194: bottom = CurrPt, top = PrevPt;
195: pETEs->ClockWise = 1;
196: }
197:
198: /*
199: * don't add horizontal edges to the Edge table.
200: */
201: if (bottom->y != top->y)
202: {
203: pETEs->ymax = bottom->y-1; /* -1 so we don't get last scanline */
204:
205: /*
206: * initialize integer edge algorithm
207: */
208: dy = bottom->y - top->y;
209: BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
210:
211: miInsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock);
212:
213: ET->ymax = max(ET->ymax, PrevPt->y);
214: ET->ymin = min(ET->ymin, PrevPt->y);
215: pETEs++;
216: }
217:
218: PrevPt = CurrPt;
219: }
220: }
221:
222: /*
223: * loadAET
224: *
225: * This routine moves EdgeTableEntries from the
226: * EdgeTable into the Active Edge Table,
227: * leaving them sorted by smaller x coordinate.
228: *
229: */
230:
231: void
232: miloadAET(AET, ETEs)
233: register EdgeTableEntry *AET, *ETEs;
234: {
235: register EdgeTableEntry *pPrevAET;
236: register EdgeTableEntry *tmp;
237:
238: pPrevAET = AET;
239: AET = AET->next;
240: while (ETEs)
241: {
242: while (AET && (AET->bres.minor < ETEs->bres.minor))
243: {
244: pPrevAET = AET;
245: AET = AET->next;
246: }
247: tmp = ETEs->next;
248: ETEs->next = AET;
249: if (AET)
250: AET->back = ETEs;
251: ETEs->back = pPrevAET;
252: pPrevAET->next = ETEs;
253: pPrevAET = ETEs;
254:
255: ETEs = tmp;
256: }
257: }
258:
259: /*
260: * computeWAET
261: *
262: * This routine links the AET by the
263: * nextWETE (winding EdgeTableEntry) link for
264: * use by the winding number rule. The final
265: * Active Edge Table (AET) might look something
266: * like:
267: *
268: * AET
269: * ---------- --------- ---------
270: * |ymax | |ymax | |ymax |
271: * | ... | |... | |... |
272: * |next |->|next |->|next |->...
273: * |nextWETE| |nextWETE| |nextWETE|
274: * --------- --------- ^--------
275: * | | |
276: * V-------------------> V---> ...
277: *
278: */
279: void
280: micomputeWAET(AET)
281: register EdgeTableEntry *AET;
282: {
283: register EdgeTableEntry *pWETE;
284: register int inside = 1;
285: register int isInside = 0;
286:
287: AET->nextWETE = (EdgeTableEntry *)NULL;
288: pWETE = AET;
289: AET = AET->next;
290: while (AET)
291: {
292: if (AET->ClockWise)
293: isInside++;
294: else
295: isInside--;
296:
297: if ((!inside && !isInside) ||
298: ( inside && isInside))
299: {
300: pWETE->nextWETE = AET;
301: pWETE = AET;
302: inside = !inside;
303: }
304: AET = AET->next;
305: }
306: pWETE->nextWETE = (EdgeTableEntry *)NULL;
307: }
308:
309: /*
310: * InsertionSort
311: *
312: * Just a simple insertion sort using
313: * pointers and back pointers to sort the Active
314: * Edge Table.
315: *
316: */
317:
318: int
319: miInsertionSort(AET)
320: register EdgeTableEntry *AET;
321: {
322: register EdgeTableEntry *pETEchase;
323: register EdgeTableEntry *pETEinsert;
324: register EdgeTableEntry *pETEchaseBackTMP;
325: register int changed = 0;
326:
327: AET = AET->next;
328: while (AET)
329: {
330: pETEinsert = AET;
331: pETEchase = AET;
332: while (pETEchase->back->bres.minor > AET->bres.minor)
333: pETEchase = pETEchase->back;
334:
335: AET = AET->next;
336: if (pETEchase != pETEinsert)
337: {
338: pETEchaseBackTMP = pETEchase->back;
339: pETEinsert->back->next = AET;
340: if (AET)
341: AET->back = pETEinsert->back;
342: pETEinsert->next = pETEchase;
343: pETEchase->back->next = pETEinsert;
344: pETEchase->back = pETEinsert;
345: pETEinsert->back = pETEchaseBackTMP;
346: changed = 1;
347: }
348: }
349: return(changed);
350: }
351:
352: /*
353: * Clean up our act.
354: */
355: void
356: miFreeStorage(pSLLBlock)
357: register ScanLineListBlock *pSLLBlock;
358: {
359: register ScanLineListBlock *tmpSLLBlock;
360:
361: while (pSLLBlock)
362: {
363: tmpSLLBlock = pSLLBlock->next;
364: Xfree(pSLLBlock);
365: pSLLBlock = tmpSLLBlock;
366: }
367: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.