00001 // @(#)root/asimage:$Id: TASPolyUtils.c 20882 2007-11-19 11:31:26Z rdm $ 00002 // Author: Valeriy Onuchin 20/04/2005 00003 00004 /************************************************************************* 00005 * Copyright (C) 1995-2001, Rene Brun, Fons Rademakers and Reiner Rohlfs * 00006 * All rights reserved. * 00007 * * 00008 * For the licensing terms see $ROOTSYS/LICENSE. * 00009 * For the list of contributors see $ROOTSYS/README/CREDITS. * 00010 *************************************************************************/ 00011 00012 /************************************************************************ 00013 00014 Copyright 1987, 1998 The Open Group 00015 00016 All Rights Reserved. 00017 00018 The above copyright notice and this permission notice shall be included in 00019 all copies or substantial portions of the Software. 00020 00021 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00022 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00023 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00024 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 00025 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00026 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00027 00028 Except as contained in this notice, the name of The Open Group shall not be 00029 used in advertising or otherwise to promote the sale, use or other dealings 00030 in this Software without prior written authorization from The Open Group. 00031 00032 00033 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 00034 00035 All Rights Reserved 00036 00037 Permission to use, copy, modify, and distribute this software and its 00038 documentation for any purpose and without fee is hereby granted, 00039 provided that the above copyright notice appear in all copies and that 00040 both that copyright notice and this permission notice appear in 00041 supporting documentation, and that the name of Digital not be 00042 used in advertising or publicity pertaining to distribution of the 00043 software without specific, written prior permission. 00044 00045 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 00046 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 00047 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 00048 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 00049 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 00050 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 00051 SOFTWARE. 00052 00053 ************************************************************************/ 00054 00055 #include "TPoint.h" 00056 00057 /* 00058 * This file contains a few macros to help track 00059 * the edge of a filled object. The object is assumed 00060 * to be filled in scanline order, and thus the 00061 * algorithm used is an extension of Bresenham's line 00062 * drawing algorithm which assumes that y is always the 00063 * major axis. 00064 * Since these pieces of code are the same for any filled shape, 00065 * it is more convenient to gather the library in one 00066 * place, but since these pieces of code are also in 00067 * the inner loops of output primitives, procedure call 00068 * overhead is out of the question. 00069 * See the author for a derivation if needed. 00070 */ 00071 00072 00073 /* 00074 * In scan converting polygons, we want to choose those pixels 00075 * which are inside the polygon. Thus, we add .5 to the starting 00076 * x coordinate for both left and right edges. Now we choose the 00077 * first pixel which is inside the pgon for the left edge and the 00078 * first pixel which is outside the pgon for the right edge. 00079 * Draw the left pixel, but not the right. 00080 * 00081 * How to add .5 to the starting x coordinate: 00082 * If the edge is moving to the right, then subtract dy from the 00083 * error term from the general form of the algorithm. 00084 * If the edge is moving to the left, then add dy to the error term. 00085 * 00086 * The reason for the difference between edges moving to the left 00087 * and edges moving to the right is simple: If an edge is moving 00088 * to the right, then we want the algorithm to flip immediately. 00089 * If it is moving to the left, then we don't want it to flip until 00090 * we traverse an entire pixel. 00091 */ 00092 00093 #define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \ 00094 int dx;\ 00095 \ 00096 if ((dy) != 0) { \ 00097 xStart = (x1); \ 00098 dx = (x2) - xStart; \ 00099 if (dx < 0) { \ 00100 m = dx / (dy); \ 00101 m1 = m - 1; \ 00102 incr1 = -2 * dx + 2 * (dy) * m1; \ 00103 incr2 = -2 * dx + 2 * (dy) * m; \ 00104 d = 2 * m * (dy) - 2 * dx - 2 * (dy); \ 00105 } else { \ 00106 m = dx / (dy); \ 00107 m1 = m + 1; \ 00108 incr1 = 2 * dx - 2 * (dy) * m1; \ 00109 incr2 = 2 * dx - 2 * (dy) * m; \ 00110 d = -2 * m * (dy) + 2 * dx; \ 00111 } \ 00112 } \ 00113 } 00114 00115 #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \ 00116 if (m1 > 0) { \ 00117 if (d > 0) { \ 00118 minval += m1; \ 00119 d += incr1; \ 00120 } \ 00121 else { \ 00122 minval += m; \ 00123 d += incr2; \ 00124 } \ 00125 } else {\ 00126 if (d >= 0) { \ 00127 minval += m1; \ 00128 d += incr1; \ 00129 } \ 00130 else { \ 00131 minval += m; \ 00132 d += incr2; \ 00133 } \ 00134 } \ 00135 } 00136 00137 00138 /* 00139 * This structure contains all of the information needed 00140 * to run the bresenham algorithm. 00141 * The variables may be hardcoded into the declarations 00142 * instead of using this structure to make use of 00143 * register declarations. 00144 */ 00145 typedef struct { 00146 int minor_axis; /* minor axis */ 00147 int d; /* decision variable */ 00148 int m, m1; /* slope and slope+1 */ 00149 int incr1, incr2; /* error increments */ 00150 } BRESINFO; 00151 00152 00153 #define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \ 00154 BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \ 00155 bres.m, bres.m1, bres.incr1, bres.incr2) 00156 00157 #define BRESINCRPGONSTRUCT(bres) \ 00158 BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2) 00159 00160 00161 /* 00162 * These are the data structures needed to scan 00163 * convert regions. Two different scan conversion 00164 * methods are available -- the even-odd method, and 00165 * the winding number method. 00166 * The even-odd rule states that a point is inside 00167 * the polygon if a ray drawn from that point in any 00168 * direction will pass through an odd number of 00169 * path segments. 00170 * By the winding number rule, a point is decided 00171 * to be inside the polygon if a ray drawn from that 00172 * point in any direction passes through a different 00173 * number of clockwise and counter-clockwise path 00174 * segments. 00175 * 00176 * These data structures are adapted somewhat from 00177 * the algorithm in (Foley/Van Dam) for scan converting 00178 * polygons. 00179 * The basic algorithm is to start at the top (smallest y) 00180 * of the polygon, stepping down to the bottom of 00181 * the polygon by incrementing the y coordinate. We 00182 * keep a list of edges which the current scanline crosses, 00183 * sorted by x. This list is called the Active Edge Table (AET) 00184 * As we change the y-coordinate, we update each entry in 00185 * in the active edge table to reflect the edges new xcoord. 00186 * This list must be sorted at each scanline in case 00187 * two edges intersect. 00188 * We also keep a data structure known as the Edge Table (ET), 00189 * which keeps track of all the edges which the current 00190 * scanline has not yet reached. The ET is basically a 00191 * list of ScanLineList structures containing a list of 00192 * edges which are entered at a given scanline. There is one 00193 * ScanLineList per scanline at which an edge is entered. 00194 * When we enter a new edge, we move it from the ET to the AET. 00195 * 00196 * From the AET, we can implement the even-odd rule as in 00197 * (Foley/Van Dam). 00198 * The winding number rule is a little trickier. We also 00199 * keep the EdgeTableEntries in the AET linked by the 00200 * nextWETE (winding EdgeTableEntry) link. This allows 00201 * the edges to be linked just as before for updating 00202 * purposes, but only uses the edges linked by the nextWETE 00203 * link as edges representing spans of the polygon to 00204 * drawn (as with the even-odd rule). 00205 */ 00206 00207 /* 00208 * for the winding number rule 00209 */ 00210 #define CLOCKWISE 1 00211 #define COUNTERCLOCKWISE -1 00212 00213 typedef struct _EdgeTableEntry { 00214 int ymax; /* ycoord at which we exit this edge. */ 00215 BRESINFO bres; /* Bresenham info to run the edge */ 00216 struct _EdgeTableEntry *next; /* next in the list */ 00217 struct _EdgeTableEntry *back; /* for insertion sort */ 00218 struct _EdgeTableEntry *nextWETE; /* for winding num rule */ 00219 int ClockWise; /* flag for winding number rule */ 00220 } EdgeTableEntry; 00221 00222 00223 typedef struct _ScanLineList{ 00224 int scanline; /* the scanline represented */ 00225 EdgeTableEntry *edgelist; /* header node */ 00226 struct _ScanLineList *next; /* next in the list */ 00227 } ScanLineList; 00228 00229 00230 typedef struct { 00231 int ymax; /* ymax for the polygon */ 00232 int ymin; /* ymin for the polygon */ 00233 ScanLineList scanlines; /* header node */ 00234 } EdgeTable; 00235 00236 00237 /* 00238 * Here is a struct to help with storage allocation 00239 * so we can allocate a big chunk at a time, and then take 00240 * pieces from this heap when we need to. 00241 */ 00242 #define SLLSPERBLOCK 25 00243 00244 typedef struct _ScanLineListBlock { 00245 ScanLineList SLLs[SLLSPERBLOCK]; 00246 struct _ScanLineListBlock *next; 00247 } ScanLineListBlock; 00248 00249 00250 00251 /* 00252 * 00253 * a few macros for the inner loops of the fill code where 00254 * performance considerations don't allow a procedure call. 00255 * 00256 * Evaluate the given edge at the given scanline. 00257 * If the edge has expired, then we leave it and fix up 00258 * the active edge table; otherwise, we increment the 00259 * x value to be ready for the next scanline. 00260 * The winding number rule is in effect, so we must notify 00261 * the caller when the edge has been removed so he 00262 * can reorder the Winding Active Edge Table. 00263 */ 00264 #define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \ 00265 if (pAET->ymax == y) { /* leaving this edge */ \ 00266 pPrevAET->next = pAET->next; \ 00267 pAET = pPrevAET->next; \ 00268 fixWAET = 1; \ 00269 if (pAET) \ 00270 pAET->back = pPrevAET; \ 00271 } \ 00272 else { \ 00273 BRESINCRPGONSTRUCT(pAET->bres); \ 00274 pPrevAET = pAET; \ 00275 pAET = pAET->next; \ 00276 } \ 00277 } 00278 00279 00280 /* 00281 * Evaluate the given edge at the given scanline. 00282 * If the edge has expired, then we leave it and fix up 00283 * the active edge table; otherwise, we increment the 00284 * x value to be ready for the next scanline. 00285 * The even-odd rule is in effect. 00286 */ 00287 #define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \ 00288 if (pAET->ymax == y) { /* leaving this edge */ \ 00289 pPrevAET->next = pAET->next; \ 00290 pAET = pPrevAET->next; \ 00291 if (pAET) \ 00292 pAET->back = pPrevAET; \ 00293 } \ 00294 else { \ 00295 BRESINCRPGONSTRUCT(pAET->bres); \ 00296 pPrevAET = pAET; \ 00297 pAET = pAET->next; \ 00298 } \ 00299 } 00300 00301 #define LARGE_COORDINATE 1000000 00302 #define SMALL_COORDINATE -LARGE_COORDINATE 00303 00304 //______________________________________________________________________________ 00305 static void InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE, int scanline, 00306 ScanLineListBlock **SLLBlock, int *iSLLBlock) 00307 { 00308 // Insert the given edge into the edge table. 00309 // First we must find the correct bucket in the 00310 // Edge table, then find the right slot in the 00311 // bucket. Finally, we can insert it. 00312 00313 EdgeTableEntry *start, *prev; 00314 ScanLineList *pSLL, *pPrevSLL; 00315 ScanLineListBlock *tmpSLLBlock; 00316 00317 /* 00318 * find the right bucket to put the edge into 00319 */ 00320 pPrevSLL = &ET->scanlines; 00321 pSLL = pPrevSLL->next; 00322 while (pSLL && (pSLL->scanline < scanline)) { 00323 pPrevSLL = pSLL; 00324 pSLL = pSLL->next; 00325 } 00326 00327 /* 00328 * reassign pSLL (pointer to ScanLineList) if necessary 00329 */ 00330 if ((!pSLL) || (pSLL->scanline > scanline)) { 00331 if (*iSLLBlock > SLLSPERBLOCK-1) { 00332 tmpSLLBlock = new ScanLineListBlock; 00333 (*SLLBlock)->next = tmpSLLBlock; 00334 tmpSLLBlock->next = (ScanLineListBlock *)0; 00335 *SLLBlock = tmpSLLBlock; 00336 *iSLLBlock = 0; 00337 } 00338 pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]); 00339 00340 pSLL->next = pPrevSLL->next; 00341 pSLL->edgelist = (EdgeTableEntry *)0; 00342 pPrevSLL->next = pSLL; 00343 } 00344 pSLL->scanline = scanline; 00345 00346 /* 00347 * now insert the edge in the right bucket 00348 */ 00349 prev = (EdgeTableEntry *)0; 00350 start = pSLL->edgelist; 00351 while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) { 00352 prev = start; 00353 start = start->next; 00354 } 00355 ETE->next = start; 00356 00357 if (prev) { 00358 prev->next = ETE; 00359 } else { 00360 pSLL->edgelist = ETE; 00361 } 00362 } 00363 00364 //______________________________________________________________________________ 00365 static void CreateETandAET(int count, TPoint *pts, EdgeTable *ET, EdgeTableEntry *AET, 00366 EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock) 00367 { 00368 // This routine creates the edge table for 00369 // scan converting polygons. 00370 // The Edge Table (ET) looks like: 00371 // 00372 // EdgeTable 00373 // -------- 00374 // | ymax | ScanLineLists 00375 // |scanline|-->------------>-------------->... 00376 // -------- |scanline| |scanline| 00377 // |edgelist| |edgelist| 00378 // --------- --------- 00379 // | | 00380 // | | 00381 // V V 00382 // list of ETEs list of ETEs 00383 // 00384 // where ETE is an EdgeTableEntry data structure, 00385 // and there is one ScanLineList per scanline at 00386 // which an edge is initially entered. 00387 00388 TPoint *top, *bottom; 00389 TPoint *PrevPt, *CurrPt; 00390 int iSLLBlock = 0; 00391 int dy; 00392 00393 if (count < 2) return; 00394 00395 /* 00396 * initialize the Active Edge Table 00397 */ 00398 AET->next = (EdgeTableEntry *)0; 00399 AET->back = (EdgeTableEntry *)0; 00400 AET->nextWETE = (EdgeTableEntry *)0; 00401 AET->bres.minor_axis = SMALL_COORDINATE; 00402 00403 /* 00404 * initialize the Edge Table. 00405 */ 00406 ET->scanlines.next = (ScanLineList *)0; 00407 ET->ymax = SMALL_COORDINATE; 00408 ET->ymin = LARGE_COORDINATE; 00409 pSLLBlock->next = (ScanLineListBlock *)0; 00410 00411 PrevPt = &pts[count-1]; 00412 00413 /* 00414 * for each vertex in the array of points. 00415 * In this loop we are dealing with two vertices at 00416 * a time -- these make up one edge of the polygon. 00417 */ 00418 while (count--) { 00419 CurrPt = pts++; 00420 00421 /* 00422 * find out which point is above and which is below. 00423 */ 00424 if (PrevPt->fY > CurrPt->fY) { 00425 bottom = PrevPt, top = CurrPt; 00426 pETEs->ClockWise = 0; 00427 } else { 00428 bottom = CurrPt, top = PrevPt; 00429 pETEs->ClockWise = 1; 00430 } 00431 00432 /* 00433 * don't add horizontal edges to the Edge table. 00434 */ 00435 if (bottom->fY != top->fY) { 00436 pETEs->ymax = bottom->fY-1; /* -1 so we don't get last scanline */ 00437 00438 /* 00439 * initialize integer edge algorithm 00440 */ 00441 dy = bottom->fY - top->fY; 00442 BRESINITPGONSTRUCT(dy, top->fX, bottom->fX, pETEs->bres); 00443 00444 InsertEdgeInET(ET, pETEs, top->fY, &pSLLBlock, &iSLLBlock); 00445 00446 if (PrevPt->fY > ET->ymax) ET->ymax = PrevPt->fY; 00447 if (PrevPt->fY < ET->ymin) ET->ymin = PrevPt->fY; 00448 pETEs++; 00449 } 00450 PrevPt = CurrPt; 00451 } 00452 } 00453 00454 //______________________________________________________________________________ 00455 static void loadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs) 00456 { 00457 // This routine moves EdgeTableEntries from the 00458 // EdgeTable into the Active Edge Table, 00459 // leaving them sorted by smaller x coordinate. 00460 00461 EdgeTableEntry *pPrevAET; 00462 EdgeTableEntry *tmp; 00463 00464 pPrevAET = AET; 00465 AET = AET->next; 00466 while (ETEs) { 00467 while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis)) { 00468 pPrevAET = AET; 00469 AET = AET->next; 00470 } 00471 tmp = ETEs->next; 00472 ETEs->next = AET; 00473 if (AET) { 00474 AET->back = ETEs; 00475 } 00476 ETEs->back = pPrevAET; 00477 pPrevAET->next = ETEs; 00478 pPrevAET = ETEs; 00479 00480 ETEs = tmp; 00481 } 00482 } 00483 00484 //______________________________________________________________________________ 00485 static int InsertionSort(EdgeTableEntry * AET) 00486 { 00487 // InsertionSort 00488 // 00489 // Just a simple insertion sort using 00490 // pointers and back pointers to sort the Active 00491 // Edge Table. 00492 00493 EdgeTableEntry *pETEchase; 00494 EdgeTableEntry *pETEinsert; 00495 EdgeTableEntry *pETEchaseBackTMP; 00496 int changed = 0; 00497 00498 AET = AET->next; 00499 while (AET) { 00500 pETEinsert = AET; 00501 pETEchase = AET; 00502 while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis) { 00503 pETEchase = pETEchase->back; 00504 } 00505 00506 AET = AET->next; 00507 if (pETEchase != pETEinsert) { 00508 pETEchaseBackTMP = pETEchase->back; 00509 pETEinsert->back->next = AET; 00510 if (AET) { 00511 AET->back = pETEinsert->back; 00512 } 00513 pETEinsert->next = pETEchase; 00514 pETEchase->back->next = pETEinsert; 00515 pETEchase->back = pETEinsert; 00516 pETEinsert->back = pETEchaseBackTMP; 00517 changed = 1; 00518 } 00519 } 00520 return (changed); 00521 } 00522 00523 //______________________________________________________________________________ 00524 static void FreeStorage(ScanLineListBlock *pSLLBlock) 00525 { 00526 // Clean up our act. 00527 00528 ScanLineListBlock *tmpSLLBlock; 00529 00530 while (pSLLBlock) { 00531 tmpSLLBlock = pSLLBlock->next; 00532 delete pSLLBlock; 00533 pSLLBlock = tmpSLLBlock; 00534 } 00535 } 00536