www.pudn.com > CG2Programs.rar > primitives.c
#include#include "graphics.h" #include "primitives.h" pLinetype gsLinetype = SOLID; /** Low-level graphics primitives **/ /***********************************/ /* ============================================================ */ void line (int xa, int ya, int xb, int yb) { lineDDA (xa, ya, xb, yb); } /* ============================================================ lineDDA */ void lineDDA (int xa, int ya, int xb, int yb) { int dx = xb - xa; int dy = yb - ya; int steps, k; double xIncrement, yIncrement; double x = xa; double y = ya; if (abs (dx) > abs (dy)) steps = abs (dx); else steps = abs (dy); xIncrement = (double) dx / steps; yIncrement = (double) dy / steps; setPixel ((int) rint (x), (int) rint (y)); for (k = 0; k < steps; k++) { x += xIncrement; y += yIncrement; setPixel ((int) rint (x), (int) rint (y)); } } /* ============================================================ circleMidpoint */ void circleMidpoint (int xCenter, int yCenter, int radius) { int x = 0; int y = radius; int p = 1 - radius; void circlePlotPoints (int xCenter, int yCenter, int x, int y); circlePlotPoints (xCenter, yCenter, x, y); while (x < y) { if (p < 0) { x++; p += 2 * x + 1; } else { x++; y--; p += 2 * (x - y) + 1; } circlePlotPoints (xCenter, yCenter, x, y); } } void circlePlotPoints (int xCenter, int yCenter, int x, int y) { setPixel (xCenter + x, yCenter + y); setPixel (xCenter - x, yCenter + y); setPixel (xCenter + x, yCenter - y); setPixel (xCenter - x, yCenter - y); setPixel (xCenter + y, yCenter + x); setPixel (xCenter - y, yCenter + x); setPixel (xCenter + y, yCenter - x); setPixel (xCenter - y, yCenter - x); } /* ============================================================ ellipseMidpoint, p 109-110 */ void ellipseMidpoint (int xCenter, int yCenter, int Rx, int Ry) { int Rx2 = Rx * Rx; int Ry2 = Ry * Ry; int twoRx2 = 2 * Rx2; int twoRy2 = 2 * Ry2; int x = 0; int y = Ry; int p = round (Ry2 - (Rx2 * Ry) + (0.25 * Rx2)); int px = 0; int py = twoRx2 * y; void ellipsePlotPoints (int, int, int, int); printf ("%d %d %d %d\n", xCenter, yCenter, Rx, Ry); /* Region 1 */ while (px < py) { x++; px += twoRy2; if (p >= 0) { y--; py -= twoRx2; } if (p < 0) p += Ry2 + px; else p += Ry2 + px - py; ellipsePlotPoints (xCenter, yCenter, x, y); } /* Region 2 */ p = round (Ry2 * (x + 0.5) * (x + 0.5) + Rx2 * (y - 1) * (y - 1) - Rx2 * Ry2); while (y > 0) { y--; py -= twoRx2; if (p <= 0) { x++; px += twoRy2; } if (p > 0) p += Rx2 - py; else p += Rx2 - py + px; ellipsePlotPoints (xCenter, yCenter, x, y); } } void ellipsePlotPoints (int xCenter, int yCenter, int x, int y) { setPixel (xCenter + x, yCenter + y); setPixel (xCenter - x, yCenter + y); setPixel (xCenter + x, yCenter - y); setPixel (xCenter - x, yCenter - y); } /* ============================================================ scanFill */ typedef struct tEdge { int yUpper; float xIntersect; float dxPerScan; struct tEdge * next; } Edge; /* Inserts edge into list in order of increasing xIntersect field. */ void insertEdge (Edge * list, Edge * edge) { Edge * q = list; Edge * p = q->next; while (p != NULL) { if (edge->xIntersect < p->xIntersect) p = NULL; else { q = p; p = p->next; } } edge->next = q->next; q->next = edge; } /* Given an index, return the y-coordinate of next nonhorizontal line */ int yNext (int k, int cnt, dcPt * pts) { int j; if ((k+1) > (cnt-1)) j = 0; else j = k + 1; while (pts[k].y == pts[j].y) if ((j+1) > (cnt-1)) j = 0; else j++; return (pts[j].y); } void makeEdgeRec (dcPt lower, dcPt upper, int yComp, Edge * edge, Edge * edges[]) { edge->dxPerScan = (float) (upper.x - lower.x) / (upper.y - lower.y); edge->xIntersect = lower.x; if (upper.y < yComp) edge->yUpper = upper.y - 1; else edge->yUpper = upper.y; insertEdge (edges[lower.y], edge); } void buildEdgeList (int cnt, dcPt * pts, Edge * edges[]) { Edge * edge; dcPt v1, v2; int i; int yPrev = pts[cnt - 2].y; v1.x = pts[cnt-1].x; v1.y = pts[cnt-1].y; for (i = 0; i < cnt; i++) { v2 = pts[i]; if (v1.y != v2.y) { /* a nonhorizontal line */ edge = (Edge *) malloc (sizeof (Edge)); if (v1.y < v2.y) makeEdgeRec (v1, v2, yNext (i, cnt, pts), edge, edges); else makeEdgeRec (v2, v1, yPrev, edge, edges); } yPrev = v1.y; v1 = v2; } } void buildActiveList (int scan, Edge * active, Edge * edges[]) { Edge * p, * q; p = edges[scan]->next; while (p) { q = p->next; insertEdge (active, p); p = q; } } void fillScan (int scan, Edge * active) { Edge * p1, * p2; int i; p1 = active->next; while (p1) { p2 = p1->next; for (i = round (p1->xIntersect); i < round (p2->xIntersect); i++) setPixel (i, scan); /* Advance to next pair of intersections */ p1 = p2->next; } } void deleteAfter (Edge * q) { Edge * p = q->next; q->next = p->next; free (p); } void updateActiveList (int scan, Edge * active) { Edge * p = active->next; Edge * q = active; while (p) { if (scan >= p->yUpper) { p = p->next; deleteAfter (q); } else { p->xIntersect = p->xIntersect + p->dxPerScan; q = p; p = p->next; } } } void resortActiveList (Edge * active) { Edge * p = active->next; Edge * q; active->next = NULL; while (p) { q = p->next; insertEdge (active, p); p = q; } } void scanFill (int cnt, dcPt * pts) { Edge * edges[WINDOW_HEIGHT]; Edge * active; int i, scan; active = (Edge *) malloc (sizeof (Edge)); for (i = 0; i < WINDOW_HEIGHT; i++) { edges[i] = (Edge *) malloc (sizeof (Edge)); edges[i]->next = NULL; } active->next = NULL; buildEdgeList (cnt, pts, edges); for (scan = 0; scan < WINDOW_HEIGHT; scan++) { buildActiveList (scan, active, edges); if (active->next) { fillScan (scan, active); updateActiveList (scan, active); resortActiveList (active); } } } /** Other **/ /***********/ /* void ellipse (wcPt2 center, float xRadius, float yRadius) { ellipseMidpoint (round(center.x), round(center.y), round(xRadius), round(yRadius)); } */ /** Low-level graphics primitives **/ /***********************************/ void lineDDA_withType (int xa, int ya, int xb, int yb) { int dx = xb - xa; int dy = yb - ya; int steps, k; double xIncrement, yIncrement; double x = xa; double y = ya; int i = 0; int cnt; if (abs (dx) > abs (dy)) steps = abs (dx); else steps = abs (dy); xIncrement = (float) dx/steps; yIncrement = (float) dy/steps; setPixel (round(x), round(y)); for (k = 0; k < steps; k++) { x += xIncrement; y += yIncrement; switch (gsLinetype) { case DASHED: if (i == 1) /* line is on */ if (cnt > 6) { i = 0; cnt = 0; } else cnt++; else /* line is off */ if (cnt > 2) { i = 1; cnt = 0; } else cnt++; break; case DOTTED: if (i == 1) /* line is on */ if (cnt > 1) { i = 0; cnt = 0; } else cnt++; else /* line is off */ if (cnt > 1) { i = 1; cnt = 0; } else cnt++; break; case SOLID: i = 1; break; } setPixel (round(x), round(y)); } /* for k */ } /* line */ /** PHIGS-like graphics primitives **/ /************************************/ void pPolyline (int npts, wcPt2 * pts) { int i; for (i = 0; i < npts-1; i++) lineDDA (round (pts[i].x), round (pts[i].y), round (pts[i+1].x), round (pts[i+1].y)); } void pPolyline3 (int npts, wcPt3 *pts) { int i; for (i = 0; i < npts-1; i++) lineDDA_withType (round(pts[i].x), round(pts[i].y), round(pts[i+1].x), round(pts[i+1].y)); } void pPolymarker (int npts, wcPt2 * pts) { int charWidth = 8; int charHeight = 8; char str[] = { "*" }; int i; for (i = 0; i < npts; i++) { cmov2 (pts[i].x - 0.5 * charWidth, pts[i].y - 0.5 * charHeight); charstr (str); } } void pFillArea (int npts, wcPt2 * pts) { dcPt * dcpts; int i; dcpts = (dcPt *) malloc ((npts+1) * (sizeof (dcPt))); for (i = 0; i < npts; i++) { dcpts[i].x = round (pts[i].x); dcpts[i].y = round (pts[i].y); } dcpts[npts] = dcpts[0]; scanFill (npts+1, dcpts); free (dcpts); } void pText (wcPt2 position, char * outString) { cmov2 (position.x, position.y); charstr (outString); } void pSetLinetype (pLinetype typ) { gsLinetype = typ; }