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;
}