[mapserver-commits] r7979 - trunk/mapserver

svn at osgeo.org svn at osgeo.org
Mon Oct 13 18:40:39 EDT 2008


Author: sdlime
Date: 2008-10-13 18:40:39 -0400 (Mon, 13 Oct 2008)
New Revision: 7979

Modified:
   trunk/mapserver/mapprimitive.c
Log:
Initial version of new polygon label placement code. (#2793)

Modified: trunk/mapserver/mapprimitive.c
===================================================================
--- trunk/mapserver/mapprimitive.c	2008-10-12 21:59:47 UTC (rev 7978)
+++ trunk/mapserver/mapprimitive.c	2008-10-13 22:40:39 UTC (rev 7979)
@@ -971,10 +971,71 @@
   return;
 }
 
-/* Currently unused. */
-#ifdef notdef
-static int get_centroid(shapeObj *p, pointObj *lp, double *miny, double *maxy)
+static double getRingArea(lineObj *ring)
 {
+  int i;
+  double s=0;
+
+  for(i=0; i<ring->numpoints-1; i++)
+    s += (ring->point[i].x*ring->point[i+1].y - ring->point[i+1].x*ring->point[i].y);
+
+  return (MS_ABS(s/2));
+}
+
+double msGetPolygonArea(shapeObj *p) 
+{
+  int i;
+  double area=0;
+
+  for(i=0; i<p->numlines; i++) {
+    if(isOuterRing(p, i))
+      area += getRingArea(&(p->line[i]));
+    else
+      area -= getRingArea(&(p->line[i])); /* hole */
+  }
+
+  return area;
+}
+
+/*
+** Computes the center of gravity for a polygon based on it's largest outer ring only.
+*/
+static int getPolygonCenterOfGravity(shapeObj *p, pointObj *lp) 
+{
+  int i, j;
+  double area=0;
+  double sx=0, sy=0, tsx, tsy, s; /* sums */
+  double a;
+
+  double largestArea=0;
+
+  for(i=0; i<p->numlines; i++) {
+    if(isOuterRing(p, i)) {
+      tsx = tsy = s = 0; /* reset the ring sums */
+      for(j=0; j<p->line[i].numpoints-1; j++) {
+        a = p->line[i].point[j].x*p->line[i].point[j+1].y - p->line[i].point[j+1].x*p->line[i].point[j].y;
+        s += a;
+        tsx += (p->line[i].point[j].x + p->line[i].point[j+1].x)*a;
+        tsy += (p->line[i].point[j].y + p->line[i].point[j+1].y)*a;
+      }
+      area = MS_ABS(s/2);
+
+      if(area > largestArea) {
+        largestArea = area;
+        sx = tsx;
+        sy = tsy;
+      }
+    }
+  }
+
+  lp->x = sx/(6*largestArea);
+  lp->y = sy/(6*largestArea);
+
+  return MS_SUCCESS;
+}
+
+static int getPolygonCentroid(shapeObj *p, pointObj *lp, double *miny, double *maxy)
+{
   int i,j;
   double cent_weight_x=0.0, cent_weight_y=0.0;
   double len, total_len=0;
@@ -984,7 +1045,7 @@
     for(j=1; j<p->line[i].numpoints; j++) {
       *miny = MS_MIN(*miny, p->line[i].point[j].y);
       *maxy = MS_MAX(*maxy, p->line[i].point[j].y);
-      len = length(p->line[i].point[j-1], p->line[i].point[j]);
+      len = msDistancePointToPoint(&(p->line[i].point[j-1]), &(p->line[i].point[j]));
       cent_weight_x += len * ((p->line[i].point[j-1].x + p->line[i].point[j].x)/2);
       cent_weight_y += len * ((p->line[i].point[j-1].y + p->line[i].point[j].y)/2);
       total_len += len;
@@ -992,14 +1053,13 @@
   }
 
   if(total_len == 0)
-    return(-1);
+    return(MS_FAILURE);
 
   lp->x = cent_weight_x / total_len;
   lp->y = cent_weight_y / total_len;
   
-  return(0);
+  return(MS_SUCCESS);
 }
-#endif
 
 #define NUM_SCANLINES 5
 
@@ -1009,72 +1069,101 @@
 int msPolygonLabelPoint(shapeObj *p, pointObj *lp, int min_dimension)
 {
   double slope;
-  pointObj *point1=NULL, *point2=NULL;
-  int i, j, k, nfound;
-  double x, y, *xintersect, temp;
-  double hi_y, lo_y;
+  pointObj *point1=NULL, *point2=NULL, cp;
+  int i, j, nfound;
+  double x, y, *intersect, temp;
+  double min, max;
   int wrong_order, n;
   double len, max_len=0;
-  double skip, minx, maxx, maxy, miny;
+  double minx, maxx, maxy, miny;
 
+  int method = 2;
+
   msComputeBounds(p);
   minx = p->bounds.minx;
   miny = p->bounds.miny;
   maxx = p->bounds.maxx;
   maxy = p->bounds.maxy;
 
-  if(min_dimension != -1)
-    if(MS_MIN(maxx-minx,maxy-miny) < min_dimension) return(MS_FAILURE);
+  cp.x = (maxx+minx)/2.0;
+  cp.y = (maxy+miny)/2.0;
 
-  /* if(get_centroid(p, lp, &miny, &maxy) == -1) return(MS_FAILURE); */
-  lp->x = (maxx+minx)/2.0;
-  lp->y = (maxy+miny)/2.0;
+  switch (method) {
+  case 0: /* MBR */
+    lp->x = cp.x;
+    lp->y = cp.y;
+    break;
+  case 1: /* centroid */
+    if(getPolygonCentroid(p, lp, &miny, &maxy) != MS_SUCCESS) return(MS_FAILURE);  
+    break;
+  case 2: /* center of gravity */
+    if(getPolygonCenterOfGravity(p, lp) != MS_SUCCESS) return(MS_FAILURE);
+    break;
+  }
 
-  if(msIntersectPointPolygon(lp, p) == MS_TRUE) return(MS_SUCCESS);
+  if(msIntersectPointPolygon(lp, p) == MS_TRUE) {
+    double dist, min_dist=-1;
 
-  /* do it the hard way - scanline */
+    /* compute a distance to the polygon */
+    for(j=0;j<p->numlines;j++) {
+      for(i=1; i<p->line[j].numpoints; i++) {
+        dist = msDistancePointToSegment(lp, &(p->line[j].point[i-1]), &(p->line[j].point[i]));
+        if((dist < min_dist) || (min_dist < 0)) min_dist = dist;
+      }
+    }
 
-  skip = (maxy - miny)/NUM_SCANLINES;
+    if(min_dist > .1*MS_MAX(maxx-minx, maxy-miny))
+      return(MS_SUCCESS); /* point is not too close to the edge */
+  }
 
+  // printf("label: %s\n", p->text);
+  // printf("    bbox: %g %g %g %g\n",minx, miny, maxx, maxy);
+  // printf("    center: %g %g\n", cp.x, cp.y);
+  // printf("    center of gravity: %g %g\n", lp->x, lp->y);
+  // printf("    dx: %g, dy: %g\n", lp->x-cp.x, lp->y-cp.y);
+  // printf("    distance to parent shape: %g\n", min_dist);
+  // return MS_SUCCESS;
+
   n=0;
   for(j=0; j<p->numlines; j++) /* count total number of points */
     n += p->line[j].numpoints;
-  xintersect = (double *)calloc(n, sizeof(double));
+  if(!(intersect = (double *) calloc(n, sizeof(double)))) {
+    msSetError(MS_MEMERR, "Allocation of intersection array failed.", "msPolygonLabelPoint()");
+    return MS_FAILURE;
+  }
 
-  for(k=1; k<=NUM_SCANLINES; k++) { /* sample the shape in the y direction */
-    
-    y = maxy - k*skip; 
+  if(MS_ABS((int)lp->x - (int)cp.x) > MS_ABS((int)lp->y - (int)cp.y)) { /* center horizontally, fix y */
 
+    y = lp->y;
+
     /* need to find a y that won't intersect any vertices exactly */  
-    hi_y = y - 1; /* first initializing lo_y, hi_y to be any 2 pnts on either side of lp->y */
-    lo_y = y + 1;
+    max = y - 1; /* first initializing min, max to be any 2 pnts on either side of y */
+    min = y + 1;
     for(j=0; j<p->numlines; j++) {
-      if((lo_y < y) && (hi_y >= y)) 
-    break; /* already initialized */
+      if((min < y) && (max >= y))  break;
       for(i=0; i < p->line[j].numpoints; i++) {
-    if((lo_y < y) && (hi_y >= y)) 
-      break; /* already initialized */
-    if(p->line[j].point[i].y < y)
-      lo_y = p->line[j].point[i].y;
-    if(p->line[j].point[i].y >= y)
-      hi_y = p->line[j].point[i].y;
+        if((min < y) && (max >= y))  break;
+        if(p->line[j].point[i].y < y) 
+          min = p->line[j].point[i].y;
+        if(p->line[j].point[i].y >= y) 
+          max = p->line[j].point[i].y;
       }
     }
 
     n=0;
     for(j=0; j<p->numlines; j++) {
       for(i=0; i < p->line[j].numpoints; i++) {
-        if((p->line[j].point[i].y < y) && ((y - p->line[j].point[i].y) < (y - lo_y)))
-          lo_y = p->line[j].point[i].y;
-        if((p->line[j].point[i].y >= y) && ((p->line[j].point[i].y - y) < (hi_y - y)))
-          hi_y = p->line[j].point[i].y;
+        if((p->line[j].point[i].y < y) && ((y - p->line[j].point[i].y) < (y - min)))
+          min = p->line[j].point[i].y;
+        if((p->line[j].point[i].y >= y) && ((p->line[j].point[i].y - y) < (max - y)))
+          max = p->line[j].point[i].y;
       }
     }
 
-    if(lo_y == hi_y) 
+    if(min == max) 
       return (MS_FAILURE);
     else  
-      y = (hi_y + lo_y)/2.0;    
+      y = (max + min)/2.0;    
     
     nfound = 0;
     for(j=0; j<p->numlines; j++) { /* for each line */
@@ -1091,36 +1180,113 @@
             slope = (point2->x - point1->x) / (point2->y - point1->y);
       
           x = point1->x + (y - point1->y)*slope;
-          xintersect[nfound++] = x;
-        } /* End of checking this edge */
+          intersect[nfound++] = x;
+        } /* end checking this edge */
     
-        point1 = point2;  /* Go on to next edge */
+        point1 = point2; /* next edge */
       }
-    } /* Finished the scanline */
+    } /* finished line */
     
-    /* First, sort the intersections */
+    /* sort the intersections */
     do {
       wrong_order = 0;
       for(i=0; i < nfound-1; i++) {
-        if(xintersect[i] > xintersect[i+1]) {
+        if(intersect[i] > intersect[i+1]) {
           wrong_order = 1;
-          SWAP(xintersect[i], xintersect[i+1], temp);
+          SWAP(intersect[i], intersect[i+1], temp);
         }
       }
     } while(wrong_order);
     
-    /* Great, now find longest span */
+    /* find longest span */
     for(i=0; i < nfound; i += 2) {
-      len = fabs(xintersect[i] - xintersect[i+1]);
+      len = fabs(intersect[i] - intersect[i+1]);
       if(len > max_len) {
         max_len = len;
-        lp->x = (xintersect[i] + xintersect[i+1])/2;
-        lp->y = y;
+        lp->x = (intersect[i] + intersect[i+1])/2;
+        // lp->y = y;
       }
     }
+  } else { /* center vertically, fix x */
+    x = lp->x;
+
+    /* need to find a x that won't intersect any vertices exactly */  
+    max = x - 1; /* first initializing min, max to be any 2 pnts on either side of x */
+    min = x + 1;
+    for(j=0; j<p->numlines; j++) {
+      if((min < x) && (max >= x))  break;
+      for(i=0; i < p->line[j].numpoints; i++) {
+        if((min < x) && (max >= x))  break;
+        if(p->line[j].point[i].x < x) 
+          min = p->line[j].point[i].x;
+        if(p->line[j].point[i].x >= x) 
+          max = p->line[j].point[i].x;
+      }
+    }
+
+    n=0;
+    for(j=0; j<p->numlines; j++) {
+      for(i=0; i < p->line[j].numpoints; i++) {
+        if((p->line[j].point[i].x < x) && ((x - p->line[j].point[i].x) < (x - min)))
+          min = p->line[j].point[i].x;
+        if((p->line[j].point[i].x >= x) && ((p->line[j].point[i].x - x) < (max - x)))
+          max = p->line[j].point[i].x;
+      }
+    }
+
+    if(min == max) 
+      return (MS_FAILURE);
+    else  
+      x = (max + min)/2.0;
+    
+    nfound = 0;
+    for(j=0; j<p->numlines; j++) { /* for each line */
+      
+      point1 = &( p->line[j].point[p->line[j].numpoints-1] );
+      for(i=0; i < p->line[j].numpoints; i++) {
+        point2 = &( p->line[j].point[i] );
+    
+        if(EDGE_CHECK(point1->x, x, point2->x) == CLIP_MIDDLE) {
+      
+          if(point1->x == point2->x)
+            continue; /* ignore vertical edges */
+          else if(point1->y == point2->y)
+            y = point1->y; /* for a horizontal edge we know y */
+          else {
+            slope = (point2->x - point1->x) / (point2->y - point1->y);
+            y = (x - point1->x)/slope + point1->y;
+          }
+
+          intersect[nfound++] = y;
+        } /* end checking this edge */
+    
+        point1 = point2; /* next edge */
+      }
+    } /* finished line */
+    
+    /* sort the intersections */
+    do {
+      wrong_order = 0;
+      for(i=0; i < nfound-1; i++) {
+        if(intersect[i] > intersect[i+1]) {
+          wrong_order = 1;
+          SWAP(intersect[i], intersect[i+1], temp);
+        }
+      }
+    } while(wrong_order);
+    
+    /* find longest span */
+    for(i=0; i < nfound; i += 2) {
+      len = fabs(intersect[i] - intersect[i+1]);
+      if(len > max_len) {        
+        max_len = len;
+        lp->y = (intersect[i] + intersect[i+1])/2;
+        // lp->x = x;
+      }
+    }
   }
 
-  free(xintersect);
+  free(intersect);
 
   if(max_len > 0)
     return(MS_SUCCESS);
@@ -1128,6 +1294,7 @@
     return(MS_FAILURE);
 }
 
+
 /*
 ** Find center of longest segment in polyline p. The polyline must have been converted
 ** to image coordinates before calling this function.



More information about the mapserver-commits mailing list