[mapserver-commits] r7578 - trunk/mapserver

svn at osgeo.org svn at osgeo.org
Mon May 12 13:13:24 EDT 2008


Author: tbonfort
Date: 2008-05-12 13:13:24 -0400 (Mon, 12 May 2008)
New Revision: 7578

Modified:
   trunk/mapserver/HISTORY.TXT
   trunk/mapserver/mapagg.cpp
   trunk/mapserver/mapagg.h
   trunk/mapserver/mapserver.h
   trunk/mapserver/maputil.c
Log:
AGG: enable offset lines of type x -99 (#2588)

Modified: trunk/mapserver/HISTORY.TXT
===================================================================
--- trunk/mapserver/HISTORY.TXT	2008-05-12 16:32:27 UTC (rev 7577)
+++ trunk/mapserver/HISTORY.TXT	2008-05-12 17:13:24 UTC (rev 7578)
@@ -12,6 +12,8 @@
 
 Current Version (5.1-dev, SVN trunk):
 -------------------------------------
+- AGG: enable offset lines of type x -99 (#2588)
+
 - AGG: use an agg specific label size calculation function where possible (#2357)
 
 - mapogcsld.c: fetch TextSymbolizer/Label/ogc:PropertyName correctly (#2611)

Modified: trunk/mapserver/mapagg.cpp
===================================================================
--- trunk/mapserver/mapagg.cpp	2008-05-12 16:32:27 UTC (rev 7577)
+++ trunk/mapserver/mapagg.cpp	2008-05-12 17:13:24 UTC (rev 7578)
@@ -1527,7 +1527,8 @@
     double nwidth, size;
     symbolObj *symbol;
     AGGMapserverRenderer* ren = getAGGRenderer(image);
-
+    shapeObj *offsetLine = NULL;
+    
     if(style->symbol >= symbolset->numsymbols || style->symbol < 0) return; /* no such symbol, 0 is OK   */
     symbol = symbolset->symbol[style->symbol];
 
@@ -1559,8 +1560,21 @@
     }
     
     //transform the shapeobj to something AGG understands
-    line_adaptor lines(p,style->offsetx,style->offsety);
     
+    line_adaptor *lines;
+    if(style->offsety==-99) {
+        offsetLine = msOffsetPolyline(p,style->offsetx,style->offsety);
+    }
+    if(offsetLine!=NULL) {
+        lines=new line_adaptor(offsetLine);
+    } else {
+        if(style->offsetx!=0 || style->offsety!=0) {
+            lines=new offset_line_adaptor(p,style->offsetx,style->offsety);
+        } else {
+            lines=new line_adaptor(p);
+        }
+    }
+    
     // treat the easy case
     // NOTE/TODO:  symbols of type ELLIPSE are included here, as using those with a SIZE param was
     // standard practice for drawing thick lines. This should probably be removed some day
@@ -1600,7 +1614,7 @@
                 break;
             }
         }
-        ren->renderPolyline(lines,*color,nwidth,symbol->patternlength,symbol->pattern,lc,lj);
+        ren->renderPolyline(*lines,*color,nwidth,symbol->patternlength,symbol->pattern,lc,lj);
     }
     else if(symbol->type==MS_SYMBOL_TRUETYPE) {
         //specific function that treats truetype symbols
@@ -1614,7 +1628,7 @@
         switch(symbol->type) {
         case MS_SYMBOL_PIXMAP: {
              GDpixfmt img_pixf = loadSymbolPixmap(symbol);
-            ren->renderPathPixmapBGRA(lines,img_pixf);
+            ren->renderPathPixmapBGRA(*lines,img_pixf);
         }
         break;
         case MS_SYMBOL_VECTOR: {
@@ -1631,8 +1645,8 @@
             
             
             if((pw <= 1) && (ph <= 1)) { // No sense using a tile, just draw a simple line
-                ren->renderPolyline(lines,*color,size,0,NULL);
-                return;
+                ren->renderPolyline(*lines,*color,size,0,NULL);
+                break;
             }
             agg::path_storage path = imageVectorSymbolAGG(symbol,d);
             
@@ -1645,14 +1659,14 @@
             
             if(symbol->filled) {
                 //brush with a filled vector symbol, with an optional background
-                ren->renderPolylineVectorSymbol(lines,path,pw,ph,*color,agg_bcolor);
+                ren->renderPolylineVectorSymbol(*lines,path,pw,ph,*color,agg_bcolor);
             } else  {
                 //brush with a stroked vector symbol (to get width), 
                 //with an optional background
                 agg::conv_stroke <agg::path_storage > stroke(path);
                 stroke.width(style->width);            
                 strokeFromSymbol(stroke,symbol);             
-                ren->renderPolylineVectorSymbol(lines,stroke,pw,ph,*color,agg_bcolor);
+                ren->renderPolylineVectorSymbol(*lines,stroke,pw,ph,*color,agg_bcolor);
             }
             if(bRotated) { /* free the rotated symbol */
                 msFreeSymbol(symbol);
@@ -1662,12 +1676,16 @@
         break;
         case MS_SYMBOL_CARTOLINE:
             msSetError(MS_AGGERR, "Cartoline drawing is deprecated with AGG", "msDrawLineSymbolAGG()");
-            return;
         default:
             //we don't treat hatches on lines
             break;
         }
     }
+    if(offsetLine!=NULL) {
+        msFreeShape(offsetLine);
+        free(offsetLine);
+    }
+    delete lines;
     return;
 }
 
@@ -1678,7 +1696,7 @@
 {
     if(style->symbol >= symbolset->numsymbols || style->symbol < 0) return; // no such symbol, 0 is OK   
     if(p->numlines==0) return;
-
+    
     symbolObj *symbol = symbolset->symbol[style->symbol];;
     if(!MS_VALID_COLOR(style->color) && 
             MS_VALID_COLOR(style->outlinecolor) && 
@@ -1689,6 +1707,7 @@
     }
 
     double ox,oy,size, angle_radians,width;
+    shapeObj *offsetPolygon=NULL;
 
     if(!p) return;
     if(p->numlines <= 0) return;
@@ -1715,7 +1734,19 @@
     if(size < 1) return; // size too small 
 
     AGGMapserverRenderer* ren = getAGGRenderer(image);
-    polygon_adaptor polygons(p,style->offsetx,style->offsety);
+    polygon_adaptor *polygons;
+    if(style->offsety==-99) {
+        offsetPolygon = msOffsetPolyline(p,style->offsetx,style->offsety);
+    }
+    if(offsetPolygon!=NULL) {
+        polygons=new polygon_adaptor(offsetPolygon);
+    } else {
+        if(style->offsetx!=0 || style->offsety!=0) {
+            polygons = new offset_polygon_adaptor(p,style->offsetx,style->offsety);
+        } else {
+            polygons = new polygon_adaptor(p);
+        }
+    }
     agg::rgba8 agg_color,agg_ocolor,agg_bcolor;
     agg_color=getAGGColor(&style->color,style->opacity);
     agg_ocolor=getAGGColor(&style->outlinecolor,style->opacity);
@@ -1724,11 +1755,11 @@
     if(style->symbol == 0 || symbol->type==MS_SYMBOL_SIMPLE) {
         // simply draw a solid fill and outline of the specified colors
         if(MS_VALID_COLOR(style->outlinecolor))
-            ren->renderPathSolid(polygons,agg_color,agg_ocolor,style->width);
+            ren->renderPathSolid(*polygons,agg_color,agg_ocolor,style->width);
             //use outline width without scalefactor applied
         else
             //draw a one pixel outline of the same color as the fill to avoid a faint outline
-            ren->renderPathSolid(polygons,agg_color,agg_color,1); 
+            ren->renderPathSolid(*polygons,agg_color,agg_color,1); 
     }
     else {
         switch(symbol->type) {
@@ -1740,7 +1771,7 @@
             agg::path_storage hatch;
             
             //optional backgroundcolor before drawing the symbol
-            ren->renderPathSolid(polygons,agg_bcolor,AGG_NO_COLOR,1);
+            ren->renderPathSolid(*polygons,agg_bcolor,AGG_NO_COLOR,1);
             
             //create a rectangular hatch of size pw,ph starting at 0,0
             //the created hatch is of the size of the shape's bounding box
@@ -1753,11 +1784,10 @@
             stroke.width(style->width);
             
             //render the hatch clipped by the shape
-            ren->renderPathSolidClipped(stroke,polygons,agg_color);
+            ren->renderPathSolidClipped(stroke,*polygons,agg_color);
             
             //render the optional outline
-            ren->renderPathSolid(polygons,AGG_NO_COLOR,agg_ocolor,1);
-            return;
+            ren->renderPathSolid(*polygons,AGG_NO_COLOR,agg_ocolor,1);
         }
         break;
         case(MS_SYMBOL_VECTOR): {
@@ -1773,12 +1803,12 @@
             if((pw <= 1) && (ph <= 1)) {
                 //use a solid fill if the symbol is too small
                 if(MS_VALID_COLOR(style->outlinecolor))
-                    ren->renderPathSolid(polygons,agg_color,agg_ocolor,width);
+                    ren->renderPathSolid(*polygons,agg_color,agg_ocolor,width);
                 else
                     //render a one pixel outline of the same color as the fill to prevent a
                     //faint due to antialiasing with contiguous polygons
-                    ren->renderPathSolid(polygons,agg_color,agg_color,1);
-                return;
+                    ren->renderPathSolid(*polygons,agg_color,agg_color,1);
+                break;
             }
             agg::path_storage path = imageVectorSymbolAGG(symbol,d);
             if(symbol->gap>0) {
@@ -1790,13 +1820,13 @@
                 path.transform(agg::trans_affine_translation(gap/2.,gap/2.));
             }
             if(symbol->filled) {
-                ren->renderPathTiled(polygons,path,pw,ph,agg_color,agg_bcolor);
+                ren->renderPathTiled(*polygons,path,pw,ph,agg_color,agg_bcolor);
             } else  {
                 agg::conv_stroke <agg::path_storage > stroke(path);
                 stroke.width(style->width);
                 //apply symbol caps and joins
                 strokeFromSymbol(stroke,symbol);             
-                ren->renderPathTiled(polygons,stroke,pw,ph,agg_color,agg_bcolor);
+                ren->renderPathTiled(*polygons,stroke,pw,ph,agg_color,agg_bcolor);
             }
             
             //draw an outline on the shape
@@ -1807,7 +1837,7 @@
             else if(agg_bcolor.a)
                 oc=&agg_bcolor; /*avoid faint outline*/
             if(oc!=NULL)
-                ren->renderPathSolid(polygons,AGG_NO_COLOR,*oc,1);
+                ren->renderPathSolid(*polygons,AGG_NO_COLOR,*oc,1);
             
             if(bRotated) { // free the rotated symbol
                 msFreeSymbol(symbol);
@@ -1818,9 +1848,9 @@
         case MS_SYMBOL_PIXMAP: {
             //TODO: rotate and scale image before tiling
             GDpixfmt img_pixf = loadSymbolPixmap(symbol);
-            ren->renderPathSolid(polygons,agg_bcolor,agg_bcolor,1);
-            ren->renderPathTiledPixmapBGRA(polygons,img_pixf);
-            ren->renderPathSolid(polygons,AGG_NO_COLOR,agg_ocolor,style->width);
+            ren->renderPathSolid(*polygons,agg_bcolor,agg_bcolor,1);
+            ren->renderPathTiledPixmapBGRA(*polygons,img_pixf);
+            ren->renderPathSolid(*polygons,AGG_NO_COLOR,agg_ocolor,style->width);
         }
         break;
         case MS_SYMBOL_ELLIPSE: {
@@ -1829,9 +1859,9 @@
             int ph = MS_NINT(symbol->sizey*d);
             if((ph <= 1) && (pw <= 1)) { /* No sense using a tile, just fill solid */
                 if(MS_VALID_COLOR(style->outlinecolor))
-                    ren->renderPathSolid(polygons,agg_color,agg_ocolor,style->width);
+                    ren->renderPathSolid(*polygons,agg_color,agg_ocolor,style->width);
                 else
-                    ren->renderPathSolid(polygons,agg_color,agg_color,1);
+                    ren->renderPathSolid(*polygons,agg_color,agg_color,1);
             }
             else {
                 agg::path_storage path;
@@ -1846,7 +1876,7 @@
                     ph+=MS_NINT(gap);
                     path.transform(agg::trans_affine_translation(gap/2.,gap/2.));
                 }
-                ren->renderPathTiled(polygons,ellipse,pw,ph,
+                ren->renderPathTiled(*polygons,ellipse,pw,ph,
                         agg_color,agg_bcolor);
                 
                 //draw an outline on the shape
@@ -1857,29 +1887,35 @@
                 else if(agg_bcolor.a)
                     oc=&agg_bcolor;
                 if(oc!=NULL)
-                    ren->renderPathSolid(polygons,AGG_NO_COLOR,*oc,1);
+                    ren->renderPathSolid(*polygons,AGG_NO_COLOR,*oc,1);
             }
         }
         break;
         case MS_SYMBOL_TRUETYPE: {
             char *font = msLookupHashTable(&(symbolset->fontset->fonts), symbol->font);
             if(!font)
-                return;
+                break;
             double gap=(symbol->gap>0)?symbol->gap*size:0;
-            ren->renderPathTruetypeTiled(polygons,font,(unsigned int)((unsigned char)symbol->character[0]),size,
+            ren->renderPathTruetypeTiled(*polygons,font,(unsigned int)((unsigned char)symbol->character[0]),size,
                     gap,agg_color,agg_bcolor,agg_ocolor);
             //if a background was specified, draw an outline of the color
             //to avoid faint outlines in contiguous polygons
-            ren->renderPathSolid(polygons,AGG_NO_COLOR,agg_bcolor,1);
+            ren->renderPathSolid(*polygons,AGG_NO_COLOR,agg_bcolor,1);
         }
         break;
         case MS_SYMBOL_CARTOLINE:
             msSetError(MS_AGGERR, "Cartoline drawing is deprecated with AGG", "msDrawShadeSymbolAGG()");
-            return;
+            break;
         default:
         break;
         }
     }
+    if(offsetPolygon!=NULL) {
+        msFreeShape(offsetPolygon);
+        free(offsetPolygon);
+    }
+    delete polygons;
+    
     return;
 }
 

Modified: trunk/mapserver/mapagg.h
===================================================================
--- trunk/mapserver/mapagg.h	2008-05-12 16:32:27 UTC (rev 7577)
+++ trunk/mapserver/mapagg.h	2008-05-12 17:13:24 UTC (rev 7578)
@@ -153,7 +153,7 @@
  */
 class line_adaptor {
 public:
-    line_adaptor(shapeObj *shape, double ox, double oy):s(shape),ox(ox),oy(oy)
+    line_adaptor(shapeObj *shape):s(shape)
     {
         m_line=s->line; /*first line*/
         m_point=m_line->point; /*current vertex is first vertex of first line*/
@@ -167,14 +167,14 @@
         m_pend=&(m_line->point[m_line->numpoints]); /*pointer to after last vertex of first line*/
     }
     
-    unsigned vertex(double* x, double* y)
+    virtual unsigned vertex(double* x, double* y)
     {
         if(m_point < m_pend)
         {
             /*here we treat the case where a real vertex is returned*/
             bool first = m_point == m_line->point; /*is this the first vertex of a line*/
-            *x = m_point->x+ox;
-            *y = m_point->y+oy;
+            *x = m_point->x;
+            *y = m_point->y;
             m_point++;
             return first ? agg::path_cmd_move_to : agg::path_cmd_line_to;
         }
@@ -194,16 +194,34 @@
     }
 private:
     shapeObj *s;
-    double ox,oy;
     lineObj *m_line, /*current line pointer*/
     *m_lend; /*points to after the last line*/
     pointObj *m_point, /*current point*/
     *m_pend; /*points to after last point of current line*/
 };
 
+class offset_line_adaptor: public line_adaptor  {
+public:
+    offset_line_adaptor(shapeObj *shape, double ox, double oy):line_adaptor(shape),ox(ox),oy(oy)
+    {
+    }
+    
+    unsigned vertex(double* x, double* y)
+    {
+        unsigned ret = line_adaptor::vertex(x,y);
+        *x+=ox;
+        *y+=oy;
+        return ret;
+    }
+private:
+    double ox,oy;
+};
+
+
+
 class polygon_adaptor {
 public:
-    polygon_adaptor(shapeObj *shape, double ox, double oy):s(shape),ox(ox),oy(oy),m_stop(false)
+    polygon_adaptor(shapeObj *shape):s(shape),m_stop(false)
     {
         m_line=s->line; /*first lines*/
         m_point=m_line->point; /*first vertex of first line*/
@@ -219,14 +237,14 @@
         m_pend=&(m_line->point[m_line->numpoints]);
     }
     
-    unsigned vertex(double* x, double* y)
+    virtual unsigned vertex(double* x, double* y)
     {
         if(m_point < m_pend)
         {
             /*if here, we have a real vertex*/
             bool first = m_point == m_line->point;
-            *x = m_point->x+ox;
-            *y = m_point->y+oy;
+            *x = m_point->x;
+            *y = m_point->y;
             m_point++;
             return first ? agg::path_cmd_move_to : agg::path_cmd_line_to;
         }
@@ -263,5 +281,24 @@
     bool m_stop; /*should next call return stop command*/ 
 };
 
+class offset_polygon_adaptor: public polygon_adaptor  {
+public:
+    offset_polygon_adaptor(shapeObj *shape, double ox, double oy):polygon_adaptor(shape),ox(ox),oy(oy)
+    {
+    }
+    
+    unsigned vertex(double* x, double* y)
+    {
+        unsigned ret = polygon_adaptor::vertex(x,y);
+        *x+=ox;
+        *y+=oy;
+        return ret;
+    }
+private:
+    double ox,oy;
+};
 
 
+
+
+

Modified: trunk/mapserver/mapserver.h
===================================================================
--- trunk/mapserver/mapserver.h	2008-05-12 16:32:27 UTC (rev 7577)
+++ trunk/mapserver/mapserver.h	2008-05-12 17:13:24 UTC (rev 7578)
@@ -1986,7 +1986,7 @@
 MS_DLL_EXPORT int msConstrainExtent(rectObj *bounds, rectObj *rect, double overlay);
 MS_DLL_EXPORT int *msGetLayersIndexByGroup(mapObj *map, char *groupname, int *nCount);
 MS_DLL_EXPORT unsigned char *msSaveImageBuffer(imageObj* image, int *size_ptr, outputFormatObj *format);
-
+MS_DLL_EXPORT shapeObj* msOffsetPolyline(shapeObj* shape, int offsetx, int offsety);
 /* Functions to chnage the drawing order of the layers. */
 /* Defined in mapobject.c */
 MS_DLL_EXPORT int msMoveLayerUp(mapObj *map, int nLayerIndex);

Modified: trunk/mapserver/maputil.c
===================================================================
--- trunk/mapserver/maputil.c	2008-05-12 16:32:27 UTC (rev 7577)
+++ trunk/mapserver/maputil.c	2008-05-12 17:13:24 UTC (rev 7578)
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id:$
+ * $Id$
  *
  * Project:  MapServer
  * Purpose:  Various utility functions ... a real hodgepodge.
@@ -1443,6 +1443,105 @@
     msTransformShapeToPixel(shape, extent, cellsize);
 }
 
+shapeObj* msOffsetPolyline(shapeObj *p, int offsetx, int offsety) {
+    int i, j, first,idx;
+    int ox=0, oy=0, limit;
+    double dx,dy,dx0=0, dy0=0,x, y, x0=0.0, y0=0.0, k=0.0, k0=0.0, q=0.0, q0=0.0;
+    float par=(float)0.71;
+    shapeObj *ret = (shapeObj*)malloc(sizeof(shapeObj));
+    msInitShape(ret);
+    ret->numlines = p->numlines;
+    ret->line=(lineObj*)malloc(sizeof(lineObj)*ret->numlines);
+    for(i=0;i<ret->numlines;i++) {
+        ret->line[i].numpoints=p->line[i].numpoints;
+        ret->line[i].point=(pointObj*)malloc(sizeof(pointObj)*ret->line[i].numpoints);
+    }
+    if(offsety == -99) {
+        limit = offsetx*offsetx/4;
+        for (i = 0; i < p->numlines; i++) {
+            idx=0;
+            first = 1;
+            for(j=1; j<p->line[i].numpoints; j++) {        
+                ox=0; oy=0;
+                dx = (p->line[i].point[j].x - p->line[i].point[j-1].x);
+                dy = (p->line[i].point[j].y - p->line[i].point[j-1].y);
+
+                /* offset setting - quick approximation, may be changed with goniometric functions */
+                if(dx==0) { /* vertical line */
+                    if(dy==0) {
+                        continue; /* checking unique points */
+                    }
+                    ox=(dy>0) ? -offsetx : offsetx;
+                } else {
+                    k = (double)dy/(double)dx;
+                    if(MS_ABS(k)<0.5) {
+                        oy = (dx>0) ? offsetx : -offsetx;
+                    } else {
+                        if (MS_ABS(k)<2.1) {
+                            oy = (int) ((dx>0) ? offsetx*par : -offsetx*par);
+                            ox = (int) ((dy>0) ? -offsetx*par : offsetx*par);
+                        } else
+                            ox = (int)((dy>0) ? -offsetx : offsetx);
+                    }
+                    q = p->line[i].point[j-1].y+oy - k*(p->line[i].point[j-1].x+ox);
+                }
+
+                /* offset line points computation */
+                if(first==1) { /* first point */
+                    first = 0;
+                    ret->line[i].point[idx].x = p->line[i].point[j-1].x+ox;
+                    ret->line[i].point[idx].y = p->line[i].point[j-1].y+oy;
+                    idx++;
+                } else { /* middle points */
+                    if((dx*dx+dy*dy)>limit){ /* if the points are too close */
+                        if(dx0==0) { /* checking verticals */
+                            if(dx==0) {
+                                continue;
+                            }
+                            x = x0;
+                            y = k*x + q;
+                        } else {
+                            if(dx==0) {
+                                x = p->line[i].point[j-1].x+ox;
+                                y = k0*x + q0;
+                            } else {
+                                if(k==k0) continue; /* checking equal direction */
+                                x = (q-q0)/(k0-k);
+                                y = k*x+q;
+                            }
+                        }
+                    }else{/* need to be refined */
+                        x = p->line[i].point[j-1].x+ox;
+                        y = p->line[i].point[j-1].y+oy;
+                    }
+                    ret->line[i].point[idx].x=x;
+                    ret->line[i].point[idx].y=y;
+                    idx++;
+                }
+                dx0 = dx; dy0 = dy; x0 = x, y0 = y; k0 = k; q0=q;
+            }
+            /* last point */
+            if(first==0) {
+                ret->line[i].point[idx].x=p->line[i].point[p->line[i].numpoints-1].x+ox;
+                ret->line[i].point[idx].y=p->line[i].point[p->line[i].numpoints-1].y+oy;
+                idx++;
+            }
+            if(idx!=p->line[i].numpoints) {
+                /*printf("shouldn't happen :(\n");*/
+                ret->line[i].numpoints=idx;
+                ret->line=realloc(ret->line,ret->line[i].numpoints*sizeof(pointObj));
+            }
+        }
+    } else { /* normal offset (eg. drop shadow) */
+        for (i = 0; i < p->numlines; i++)
+            for(j=1; j<p->line[i].numpoints; j++) {
+                ret->line[i].point[j-1].x=p->line[i].point[j-1].x+offsetx;
+                ret->line[i].point[j-1].y=p->line[i].point[j-1].y+offsety;
+            }
+    }
+    return ret;
+}
+
 /*
 -------------------------------------------------------------------------------
  msSetup()



More information about the mapserver-commits mailing list