|
|
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: mifpolycon.c,v 1.10 87/09/11 07:20:50 toddb Exp $ */ ! 25: #include "X.h" ! 26: #include "gcstruct.h" ! 27: #include "windowstr.h" ! 28: #include "pixmapstr.h" ! 29: #include "mifpoly.h" ! 30: ! 31: /* ! 32: * Written by Todd Newman; April. 1987. ! 33: * ! 34: * Fill a convex polygon. If the given polygon ! 35: * is not convex, then the result is undefined. ! 36: * The algorithm is to order the edges from smallest ! 37: * y to largest by partitioning the array into a left ! 38: * edge list and a right edge list. The algorithm used ! 39: * to traverse each edge is digital differencing analyzer ! 40: * line algorithm with y as the major axis. There's some funny linear ! 41: * interpolation involved because of the subpixel postioning. ! 42: * ! 43: * Given the opportunity to write non-portable code, I would replace ! 44: * this with a fixed point extended precision Bresenham line algorithm. ! 45: * Instead of doubles in the SppPointRecs, I'd use 64 bit fixed point ! 46: * values. I'd have to write a fixed point math pack in assembler, ! 47: * but these things are relatively straight forward. (Alas, not portable.) ! 48: * ! 49: * It can be shown that given 16 bit values for x and y, there's no ! 50: * room to extend the precision and still fit intermediate results in ! 51: * a 32 bit integer. It should also be clear that trying to write a ! 52: * extended precision math pack in C would not produce code that runs ! 53: * much faster than your average floating point coprocessor. Even ! 54: * floating point emulation should be able to run faster if the assembly ! 55: * language coding is handled at all well. ! 56: * ! 57: * "So why not at least use float, instead of double," my friends ask ! 58: * me. Well, C is going to cast everything to double as soon as you ! 59: * try to do anything with it anyway. (Check out K&R.) I'd rather ! 60: * trade a little space and skip all the superflous type conversions. ! 61: * (This decision could be revisited if you have an ANSI C compiler.) ! 62: * ! 63: * So, in sum, I apologize for doing all the wide lines with doubles, ! 64: * but it seems the best trade off of complexity, performance, and ! 65: * time pressure. ! 66: */ ! 67: void ! 68: miFillSppPoly(dst, pgc, count, ptsIn, xTrans, yTrans) ! 69: DrawablePtr dst; ! 70: GCPtr pgc; ! 71: int count; /* number of points */ ! 72: SppPointPtr ptsIn; /* the points */ ! 73: int xTrans, yTrans; /* Translate each point by this */ ! 74: { ! 75: double xl, xr, /* x vals of left and right edges */ ! 76: ml, /* left edge slope */ ! 77: mr, /* right edge slope */ ! 78: dy, /* delta y */ ! 79: i; /* loop counter */ ! 80: int y, /* current scanline */ ! 81: j, ! 82: imin, /* index of vertex with smallest y */ ! 83: ymin, /* y-extents of polygon */ ! 84: ymax, ! 85: *width, ! 86: *FirstWidth, /* output buffer */ ! 87: *Marked; /* set if this vertex has been used */ ! 88: register int left, right, /* indices to first endpoints */ ! 89: nextleft, ! 90: nextright; /* indices to second endpoints */ ! 91: DDXPointPtr ptsOut, ! 92: FirstPoint; /* output buffer */ ! 93: double ceil(); ! 94: ! 95: if (pgc->miTranslate && (dst->type == DRAWABLE_WINDOW) ) ! 96: { ! 97: xTrans += ((WindowPtr)dst)->absCorner.x; ! 98: yTrans += ((WindowPtr)dst)->absCorner.y; ! 99: } ! 100: ! 101: imin = GetFPolyYBounds(ptsIn, count, &ymin, &ymax); ! 102: ! 103: y = ymax - ymin + 1; ! 104: ptsOut = FirstPoint = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * y); ! 105: width = FirstWidth = (int *) ALLOCATE_LOCAL(sizeof(int) * y); ! 106: Marked = (int *) ALLOCATE_LOCAL(sizeof(int) * count); ! 107: ! 108: if(!ptsOut || !width || !Marked || (count < 3) || (y <= 0)) ! 109: { ! 110: DEALLOCATE_LOCAL(Marked); ! 111: DEALLOCATE_LOCAL(width); ! 112: DEALLOCATE_LOCAL(ptsOut); ! 113: return; ! 114: } ! 115: ! 116: for(j = 0; j < count; j++) ! 117: Marked[j] = 0; ! 118: nextleft = nextright = imin; ! 119: Marked[imin] = -1; ! 120: y = (int) ceil(ptsIn[nextleft].y); ! 121: ! 122: /* ! 123: * loop through all edges of the polygon ! 124: */ ! 125: do ! 126: { ! 127: /* add a left edge if we need to */ ! 128: if ((y > ptsIn[nextleft].y || ISEQUAL(y, ptsIn[nextleft].y)) && ! 129: Marked[nextleft] != 1) ! 130: { ! 131: Marked[nextleft]++; ! 132: left = nextleft++; ! 133: ! 134: /* find the next edge, considering the end conditions */ ! 135: if (nextleft >= count) ! 136: nextleft = 0; ! 137: ! 138: /* now compute the starting point and slope */ ! 139: dy = ptsIn[nextleft].y - ptsIn[left].y; ! 140: if (dy != 0.0) ! 141: { ! 142: ml = (ptsIn[nextleft].x - ptsIn[left].x) / dy; ! 143: dy = y - ptsIn[left].y; ! 144: xl = ptsIn[left].x + ml * max(dy, 0); ! 145: } ! 146: } ! 147: ! 148: /* add a right edge if we need to */ ! 149: if (((y > ptsIn[nextright].y) || ISEQUAL(y, ptsIn[nextright].y)) ! 150: && Marked[nextright] != 1) ! 151: { ! 152: Marked[nextright]++; ! 153: right = nextright--; ! 154: ! 155: /* find the next edge, considering the end conditions */ ! 156: if (nextright < 0) ! 157: nextright = count - 1; ! 158: ! 159: /* now compute the starting point and slope */ ! 160: dy = ptsIn[nextright].y - ptsIn[right].y; ! 161: if (dy != 0.0) ! 162: { ! 163: mr = (ptsIn[nextright].x - ptsIn[right].x) / dy; ! 164: dy = y - ptsIn[right].y; ! 165: xr = ptsIn[right].x + mr * max(dy, 0); ! 166: } ! 167: } ! 168: ! 169: ! 170: /* ! 171: * generate scans to fill while we still have ! 172: * a right edge as well as a left edge. ! 173: */ ! 174: i = min(ptsIn[nextleft].y, ptsIn[nextright].y) - y; ! 175: ! 176: if (i < EPSILON) ! 177: { ! 178: if(Marked[nextleft] && Marked[nextright]) ! 179: { ! 180: /* Arrgh, we're trapped! (no more points) ! 181: * Out, we've got to get out of here before this decadence saps ! 182: * our will completely! */ ! 183: break; ! 184: } ! 185: continue; ! 186: } ! 187: else ! 188: { ! 189: j = (int) i; ! 190: if(!j) ! 191: j++; ! 192: } ! 193: while (j > 0) ! 194: { ! 195: ptsOut->y = (y) + yTrans; ! 196: ! 197: /* reverse the edges if necessary */ ! 198: if (xl < xr) ! 199: { ! 200: *(width++) = ROUNDTOINT(xr) - ROUNDTOINT(xl); ! 201: (ptsOut++)->x = ROUNDTOINT(xl) + xTrans; ! 202: } ! 203: else ! 204: { ! 205: *(width++) = ROUNDTOINT(xl) - ROUNDTOINT(xr); ! 206: (ptsOut++)->x = ROUNDTOINT(xr) + xTrans; ! 207: } ! 208: y++; ! 209: ! 210: /* increment down the edges */ ! 211: xl += ml; ! 212: xr += mr; ! 213: j--; ! 214: } ! 215: } while (y < ymax); ! 216: ! 217: /* Finally, fill the spans we've collected */ ! 218: (*pgc->FillSpans)(dst, pgc, ! 219: ptsOut-FirstPoint, FirstPoint, FirstWidth, 1); ! 220: DEALLOCATE_LOCAL(Marked); ! 221: DEALLOCATE_LOCAL(FirstWidth); ! 222: DEALLOCATE_LOCAL(FirstPoint); ! 223: } ! 224: ! 225: ! 226: /* Find the index of the point with the smallest y.also return the ! 227: * smallest and largest y */ ! 228: static ! 229: int ! 230: GetFPolyYBounds(pts, n, by, ty) ! 231: register SppPointPtr pts; ! 232: int n; ! 233: int *by, *ty; ! 234: { ! 235: register SppPointPtr ptMin; ! 236: double ymin, ymax, ceil(); ! 237: SppPointPtr ptsStart = pts; ! 238: ! 239: ptMin = pts; ! 240: ymin = ymax = (pts++)->y; ! 241: ! 242: while (--n > 0) { ! 243: if (pts->y < ymin) ! 244: { ! 245: ptMin = pts; ! 246: ymin = pts->y; ! 247: } ! 248: if(pts->y > ymax) ! 249: ymax = pts->y; ! 250: ! 251: pts++; ! 252: } ! 253: ! 254: *by = ROUNDTOINT(ymin); ! 255: *ty = (int) ceil(ymax); ! 256: return(ptMin-ptsStart); ! 257: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.