[mapserver-commits] r7888 - trunk/mapserver

svn at osgeo.org svn at osgeo.org
Tue Aug 26 23:36:19 EDT 2008


Author: sdlime
Date: 2008-08-26 23:36:18 -0400 (Tue, 26 Aug 2008)
New Revision: 7888

Modified:
   trunk/mapserver/mapgd.c
Log:
Applied improved polygon scan conversion patch supplied by Brage F?\195?\184rland. (#2734)

Modified: trunk/mapserver/mapgd.c
===================================================================
--- trunk/mapserver/mapgd.c	2008-08-25 22:39:42 UTC (rev 7887)
+++ trunk/mapserver/mapgd.c	2008-08-27 03:36:18 UTC (rev 7888)
@@ -861,136 +861,168 @@
   }
 }
 
+
+/*
+ * Polygon fill. Based on "Concave Polygon Scan Conversion" by Paul
+ * Heckbert from "Graphics Gems", Academic Press, 1990 
+ */
+
 static void imageFilledPolygon(gdImagePtr im, shapeObj *p, int c, int offsetx, int offsety)
 {
-  float *slope;
-  pointObj *point1, *point2, *testpoint1, *testpoint2;
-  int i, j, k, l, m, nfound, *xintersect, temp, sign;
-  int x, y, ymin, ymax, *horiz, wrong_order;
-  int n;
+     
+     typedef struct {		 /* a polygon edge */
+          double x;          /* x coordinate of edge's intersection with current scanline */
+          double dx;         /* change in x with respect to y */
+          int i;             /* point index  */
+          int l;             /* line number */
+          int s;             /* scanline */
+     } pEdge;
+     
+     pointObj *point1, *point2;
+     
+     int k, l, i, j, xl, xr, ymin, ymax, y, n,nvert, nact, m;
+     int wrong_order;
+     
+     pEdge *edge, *temp;
+     pEdge  **active;
+     int *yhist, *edgeindex;
+     
+     if(p->numlines == 0) return;
+     n=0;
+     
+     for(i=0; i<p->numlines; i++) {
+          n += p->line[i].numpoints;
+     }
+     
+     if(n == 0)   return;
 
-  if(p->numlines == 0) return;
- 
-#if 0
-  if( c & 0xFF000000 )
-	gdImageAlphaBlending( im, 1 );
-#endif
-  
-  /* calculate the total number of vertices */
-  n=0;
-  for(i=0; i<p->numlines; i++)
-    n += p->line[i].numpoints;
+     edge = (pEdge *) calloc(n,sizeof(pEdge));           /* All edges in the polygon */
+     edgeindex =  (int *) calloc(n,sizeof(int));         /* Index to edges sorted by scanline */
+     active = (pEdge **) calloc(n,sizeof(pEdge*));       /* Pointers to active edges for current scanline */
+    
+     nvert=0;
+     
+     ymin= (int) ceil(p->line[0].point[0].y-0.5);
+     ymax= (int) floor(p->line[0].point[0].y-0.5);
+     
+     /* populate the edge table */
+     for(l=0; l<p->numlines; l++) {
+          for(i=0; i < p->line[l].numpoints; i++) {
+               j = i < p->line[l].numpoints -1 ? i+1 : 0;
+               if (p->line[l].point[i].y  < p->line[l].point[j].y ) {
+                    point1 = &(p->line[l].point[i]);
+                    point2 = &(p->line[l].point[j]);
+               }  else {
+                    point2 = &(p->line[l].point[i]);
+                    point1 = &(p->line[l].point[j]);
+               }
+               
+               edge[nvert].dx  = point2->y == point1->y ? 0 :  (point2->x - point1->x) / (point2->y - point1->y);
+               edge[nvert].s = MS_NINT( p->line[l].point[i].y );  //ceil( p->line[l].point[i].y  - 0.5 );
+               edge[nvert].x = point1->x ;
+               edge[nvert].i = nvert;
+               edge[nvert].l = l;
+               
+               ymin = MS_MIN(ymin,edge[nvert].s);
+               ymax = MS_MAX(ymax,edge[nvert].s);
 
-  /* Allocate slope and horizontal detection arrays */
-  slope = (float *)calloc(n, sizeof(float));
-  horiz = (int *)calloc(n, sizeof(int));
-  
-  /* Since at most only one intersection is added per edge, there can only be at most n intersections per scanline */
-  xintersect = (int *)calloc(n, sizeof(int));
-  
-  /* Find the min and max Y */
-  ymin = (int)(p->line[0].point[0].y);
-  ymax = ymin;
-  
-  for(l=0,j=0; j<p->numlines; j++) {
-    point1 = &( p->line[j].point[p->line[j].numpoints-1] );
-    for(i=0; i < p->line[j].numpoints; i++,l++) {
-      point2 = &( p->line[j].point[i] );
-      if(point1->y == point2->y) {
-	horiz[l] = 1;
-	slope[l] = 0.0;
-      } else {
-	horiz[l] = 0;
-	slope[l] = (float)((point2->x - point1->x) / (point2->y - point1->y));
-      }
-      ymin = (int) (MS_MIN(ymin, point1->y));
-      ymax = (int) (MS_MAX(ymax, point2->y));
-      point1 = point2;
-    }
-  }  
+               nvert++;
+          }
+     }
+          
+     
+     /* Use histogram sort to create a bucket-sorted edgeindex by scanline */
+     yhist = (int*) calloc(ymax - ymin + 2,sizeof(int));
+     for(i=0;i<nvert;i++) {
+          yhist[ edge[i].s - ymin + 1 ]++;
+     }
+     for(i=0; i<=(ymax - ymin); i++)  {/* Calculate starting point in edgeindex for each scanline */
+          yhist[i+1] += yhist[i]; 
+     }
+     for(i=0;i<nvert;i++){ /* Bucket sort edges into edgeindex */
+          y = edge[i].s;
+          edgeindex[yhist[y-ymin]] = i;
+          yhist[y-ymin]++;
+     }
+     free(yhist);
 
-  for(y = ymin; y <= ymax; y++) { /* for each scanline */
+     
+     k=0;
+     nact=0;
 
-    nfound = 0;
-    for(j=0, l=0; j<p->numlines; j++) { /* for each line, l is overall point counter */
+     for (y=ymin; y<=ymax; y++) {		/* step through scanlines */
+          /* scanline y is at y+.5 in continuous coordinates */
+          
+          /* check vertices between previous scanline and current one, if any */
+          for (; k<nvert && edge[edgeindex[k]].s <= y; k++) {
+               i = edge[edgeindex[k]].i;
+               
+               /* vertex previous to i */
+               if(i==0 || edge[i].l != edge[i-1].l)
+                    j = i +  p->line[edge[i].l].numpoints - 1;
+               else
+                    j = i - 1;
+               
+               if (edge[j].s  <=  y  ) { /* old edge, remove from active list */
+                    for (m=0; m<nact && active[m]->i!=j; m++);
+                    if (m<nact) {
+                         nact--;
+                         active[m]=active[nact];
+                    }
+               } else if (edge[j].s > y) { /* new edge,  insert into active list */
+                    active[nact]= & edge[j];
+                    nact++;
+               }
+               
+               /* vertex next  after i */
+               if(i==nvert-1 || edge[i].l != edge[i+1].l)
+                    j = i - p->line[edge[i].l].numpoints  + 1;
+               else
+                    j = i + 1;
 
-      m = l; /* m is offset from begining of all vertices */
-      point1 = &( p->line[j].point[p->line[j].numpoints-1] );
-      for(i=0; i < p->line[j].numpoints; i++, l++) {
-	point2 = &( p->line[j].point[i] );
-	if(EDGE_CHECK(point1->y, y, point2->y) == CLIP_MIDDLE) {
-	  
-	  if(horiz[l]) /* First, is this edge horizontal ? */
-	    continue;
+               if (edge[j].s  <=  y - 1 ) {     /* old edge, remove from active list */
+                    for (m=0; m<nact && active[m]->i!=i; m++);
+                    if (m<nact) {
+                         nact--;
+                         active[m]=active[nact];
+                    }
+               } else if (edge[j].s > y ) { /* new edge, insert into active list */
+                    active[nact]= & edge[i];
+                    nact++;
+               }
+          }
+          
+          /* Sort active edges by x */
+          do {
+               wrong_order = 0;
+               for(i=0; i < nact-1; i++) {
+                    if(active[i]->x > active[i+1]->x) {
+                         wrong_order = 1;
+                         SWAP(active[i], active[i+1], temp);
+                    }
+               }
+          } while(wrong_order);
 
-	  /* Did we intersect the first point point ? */
-	  if(y == point1->y) {
-	    /* Yes, must find first non-horizontal edge */
-	    k = i-1;
-	    if(k < 0) k = p->line[j].numpoints-1;
-	    while(horiz[m+k]) {
-	      k--;
-	      if(k < 0) k = p->line[j].numpoints-1;
-	    }
-	    /* Now perform sign test */
-	    if(k > 0)
-	      testpoint1 = &( p->line[j].point[k-1] );
-	    else
-	      testpoint1 = &( p->line[j].point[p->line[j].numpoints-1] );
-	    testpoint2 = &( p->line[j].point[k] );
-	    sign = (int) ((testpoint2->y - testpoint1->y) *
-                          (point2->y - point1->y));
-	    if(sign < 0)
-                xintersect[nfound++] = (int) point1->x;
-	    /* All done for point matching case */
-	  } else {  
-	    /* Not at the first point,
-	       find the intersection*/
-	    x = (int)(ROUND(point1->x + (y - point1->y)*slope[l]));
-	    xintersect[nfound++] = x;
-	  }
-	}                 /* End of checking this edge */
-	
-	point1 = point2;  /* Go on to next edge */
-      }
-    } /* Finished this scanline, draw all of the spans */
-    
-    /* First, sort the intersections */
-    do {
-      wrong_order = 0;
-      for(i=0; i < nfound-1; i++) {
-	if(xintersect[i] > xintersect[i+1]) {
-	  wrong_order = 1;
-	  SWAP(xintersect[i], xintersect[i+1], temp);
-	}
-      }
-    } while(wrong_order);
-    
-    /* Great, now we can draw the spans */
-    for(i=0; i < nfound; i += 2)
-      imageScanline(im, xintersect[i]+offsetx, xintersect[i+1]+offsetx, y+offsety, c);
-  } /* End of scanline loop */
-  
-  /* Finally, draw all of the horizontal edges */
-  for(j=0, l=0; j<p->numlines; j++) {
-    point1 = &( p->line[j].point[p->line[j].numpoints - 1] );
-    for(i=0; i<p->line[j].numpoints; i++, l++) {
-      point2 = &( p->line[j].point[i] );
-      if(horiz[l])
-	imageScanline(im, (int)(point1->x+offsetx), (int)(point2->x+offsetx), (int)(point2->y+offsety), c);
-      point1 = point2;
-    }
-  }
-  
-#if 0
-   gdImageAlphaBlending( im, 0 );
-#endif
-
-  free(slope);
-  free(horiz);
-  free(xintersect);
+          /* draw horizontal spans for scanline y */
+          for (j=0; j<nact; j+=2) {	
+               /*  j -> j+1 is inside,  j+1 -> j+2 is outside */
+               xl = (int) MS_NINT(active[j]->x );  
+               xr = (int) (active[j+1]->x - 0.5) ;
+               
+               if(active[j]->x != active[j+1]->x) 
+                    imageScanline(im, xl+offsetx, xr+offsetx, y+offsety, c);
+               
+               active[j]->x += active[j]->dx;	/* increment edge coords */
+               active[j+1]->x += active[j+1]->dx;
+          }
+     }
+     
+     free(active);
+     free(edgeindex);
+     free(edge);
 }
 
+
 /*
 ** Function to draw a vector symbol, using a given style in an image. Image could be a map
 ** or a tile/brush. Use will vary by point, line or polygon renderer.



More information about the mapserver-commits mailing list