Permalink
Browse files

implementation of offsets on follow labels (#4399)

  • Loading branch information...
1 parent e178db7 commit 7633072f664bfc6e88bb555f4dbc3d8373a249f4 @tbonfort tbonfort committed Jul 2, 2012
Showing with 187 additions and 91 deletions.
  1. +10 −0 HISTORY.TXT
  2. +5 −0 configure
  3. +6 −0 configure.in
  4. +11 −6 mapdraw.c
  5. +21 −0 mapgeos.c
  6. +28 −2 mapprimitive.c
  7. +5 −0 mapserver.h
  8. +101 −83 maputil.c
View
@@ -15,6 +15,11 @@ For a complete change history, please see the Git log comments.
Current Version (git master, 6.3-dev, future 6.4):
--------------------------------------------------
+- implementation of offsets on follow labels (#4399)
+
+6.2.0 release (git branch-6-2) 2012/11/14:
+--------------------------------------------------
+
- Fix WFS GetFeature result bounds are not written in requested projection (#4494)
- Fixed wrong size in LegendURL of root layer (#4441)
@@ -40,6 +45,11 @@ Current Version (git master, 6.3-dev, future 6.4):
- Fixed the OGR driver to use point or line spatial filter geometries in degenerated cases (#4420)
+- implement OFFSET x -99 on ANGLE FOLLOW labels (#4399)
+
+Version 6.2 (beta1: 20120629):
+-------------------------------------------------
+
- Fix WFS filter is produced as non-standard XML (#4171)
- Fix pixmap symbol loading issue (#4329)
View
@@ -18321,6 +18321,11 @@ $as_echo "no" >&6; }
GEOS_INCDIR=`$GEOS_CONFIG --includes`
GEOS_INC="-I$GEOS_INCDIR"
+
+ if test $ac_geos_version -ge 300300; then
+ GEOS_ENABLED="-DUSE_GEOS -DHAVE_GEOS_OFFSET_CURVE"
+ fi
+
if test $ac_geos_version -ge 300300; then
GEOS_LIB="`$GEOS_CONFIG --clibs`"
else
View
@@ -1000,6 +1000,12 @@ if test -n "$with_geos" -a "$with_geos" != "no" ; then
GEOS_INCDIR=`$GEOS_CONFIG --includes`
GEOS_INC="-I$GEOS_INCDIR"
+
+ dnl Geos >=3.3 has SingleSidedBuffer for offset lines
+ if test $ac_geos_version -ge 300300; then
+ GEOS_ENABLED="-DUSE_GEOS -DHAVE_GEOS_OFFSET_CURVE"
+ fi
+
dnl Geos >=3.3 has a new config option: --clibs.
if test $ac_geos_version -ge 300300; then
GEOS_LIB="`$GEOS_CONFIG --clibs`"
View
@@ -2947,12 +2947,17 @@ int msDrawLabelCache(imageObj *image, mapObj *map)
/* TODO: treat the case with multiple labels and/or leader lines */
}
- /* apply offset and buffer settings */
- label_offset_x = labelPtr->offsetx*scalefactor;
- label_offset_y = labelPtr->offsety*scalefactor;
- label_buffer = (labelPtr->buffer*image->resolutionfactor);
- label_mindistance = (labelPtr->mindistance*image->resolutionfactor);
-
+ /* apply offset and buffer settings */
+ if(labelPtr->anglemode != MS_FOLLOW) {
+ label_offset_x = labelPtr->offsetx*scalefactor;
+ label_offset_y = labelPtr->offsety*scalefactor;
+ } else {
+ label_offset_x = 0;
+ label_offset_y = 0;
+ }
+ label_buffer = (labelPtr->buffer*image->resolutionfactor);
+ label_mindistance = (labelPtr->mindistance*image->resolutionfactor);
+
#ifdef oldcode
/* adjust the baseline (see #1449) */
if(labelPtr->type == MS_TRUETYPE) {
View
@@ -656,6 +656,27 @@ void msGEOSFreeWKT(char* pszGEOSWKT)
#endif
}
+shapeObj *msGEOSOffsetCurve(shapeObj *p, double offset) {
+#if defined USE_GEOS && defined HAVE_GEOS_OFFSET_CURVE
+ GEOSGeom g1, g2;
+
+ if(!p)
+ return NULL;
+
+ if(!p->geometry) /* if no geometry for the shape then build one */
+ p->geometry = (GEOSGeom) msGEOSShape2Geometry(p);
+
+ g1 = (GEOSGeom) p->geometry;
+ if(!g1) return NULL;
+
+ g2 = GEOSOffsetCurve(g1, offset, 4, GEOSBUF_JOIN_MITRE, fabs(offset*1.5));
+ return msGEOSGeometry2Shape(g2);
+#else
+ msSetError(MS_GEOSERR, "GEOS support is not available.", "msGEOSingleSidedBuffer()");
+ return NULL;
+#endif
+}
+
/*
** Analytical functions exposed to MapServer/MapScript.
*/
View
@@ -1748,12 +1748,34 @@ labelPathObj** msPolylineLabelPath(mapObj *map, imageObj *img,shapeObj *p, int m
segment_index = max_line_index = 0;
total_length = max_line_length = 0.0;
- if(!string) return NULL;
+ if(!string) return NULL;
labelpaths = (labelPathObj **) msSmallMalloc(sizeof(labelPathObj *) * labelpaths_size);
(*regular_lines) = (int *) msSmallMalloc(sizeof(int) * regular_lines_size);
+ if(label->offsetx != 0 && (label->offsety == -99 || label->offsety == 99)) {
+ double offset;
+ if(label->offsetx > 0) {
+ offset = label->offsetx + label->size/2;
+ } else {
+ offset = label->offsetx - label->size/2;
+ }
+ if(label->offsety == 99 && p->numlines>0 && p->line[0].numpoints > 0) {
+ /* is the line mostly left-to-right or right-to-left ?
+ * FIXME this should be done line by line, by stepping through shape->lines, however
+ * the OffsetPolyline function works on shapeObjs, not lineObjs
+ * we only check the first line
+ */
+ if(p->line[0].point[0].x < p->line[0].point[p->line[0].numpoints-1].x) {
+ /* line is left to right */
+ offset = -offset;
+ }
+ }
+ p = msOffsetPolyline(p,offset, -99);
+ if(!p) return NULL;
+ }
+
msPolylineComputeLineSegments(p, &segment_lengths, &line_lengths, &max_line_index, &max_line_length, &segment_index, &total_length);
if(label->repeatdistance > 0)
@@ -1777,6 +1799,10 @@ labelPathObj** msPolylineLabelPath(mapObj *map, imageObj *img,shapeObj *p, int m
/* set the number of paths in the array */
*numpaths = labelpaths_index;
*num_regular_lines = regular_lines_index;
+ if(label->offsety == -99 && label->offsetx != 0) {
+ msFreeShape(p);
+ msFree(p);
+ }
return labelpaths;
}
@@ -1810,7 +1836,7 @@ void msPolylineLabelPathLineString(mapObj *map, imageObj *img, shapeObj *p, int
labelPathObj *labelpath = NULL;
/* Line smoothing kernel */
- double kernel[] = {0.1, 0.2, 2, 0.2, 0.1}; /* {1.5, 2, 15, 2, 1.5}; */
+ double kernel[] = {0.1,0.2,2,0.2,0.1}; /* {1.5, 2, 15, 2, 1.5}; */
double kernel_normal = 2.6; /* Must be sum of kernel elements */
int kernel_size = 5;
View
@@ -2871,6 +2871,11 @@ extern "C" {
#define MS_IMAGE_RENDERER_CACHE(im) MS_RENDERER_CACHE(MS_IMAGE_RENDERER((im)))
#define MS_MAP_RENDERER(map) ((map)->outputformat->vtable)
+shapeObj *msOffsetCurve(shapeObj *p, double offset);
+#if defined HAVE_GEOS_OFFSET_CURVE
+shapeObj *msGEOSOffsetCurve(shapeObj *p, double offset);
+#endif
+
#ifdef __cplusplus
}
#endif
View
@@ -199,7 +199,7 @@ static void bindLabel(layerObj *layer, shapeObj *shape, labelObj *label, int dra
/* check the label styleObj's (TODO: do we need to use querymapMode here? */
for(i=0; i<label->numstyles; i++) {
/* force MS_DRAWMODE_FEATURES for label styles */
- bindStyle(layer, shape, label->styles[i], drawmode|MS_DRAWMODE_FEATURES);
+ bindStyle(layer, shape, label->styles[i], drawmode|MS_DRAWMODE_FEATURES);
}
if(label->numbindings > 0) {
@@ -1617,8 +1617,6 @@ void msTransformPoint(pointObj *point, rectObj *extent, double cellsize,
}
-
-
/*
** Helper functions supplied as part of bug #2868 solution. Consider moving these to
** mapprimitive.c for more general use.
@@ -1714,17 +1712,22 @@ static double point_cross(const pointObj a, const pointObj b)
return a.x*b.y-a.y*b.x;
}
-/*
-** For offset corner point calculation 1/sin() is used
-** to avoid 1/0 division (and long spikes) we define a
-** limit for sin().
-*/
-#define CURVE_SIN_LIMIT 0.3
-
-shapeObj *msOffsetPolyline(shapeObj *p, double offsetx, double offsety)
+shapeObj *msOffsetCurve(shapeObj *p, double offset)
{
- int i, j, first,idx;
-
+#if defined HAVE_GEOS_OFFSET_CURVE
+ ret = msGEOSOffsetCurve(p,offset);
+ /* GEOS curve offsetting can fail sometimes, we continue with our own implementation
+ if that is the case.*/
+ if(ret)
+ return ret;
+#endif
+ /*
+ ** For offset corner point calculation 1/sin() is used
+ ** to avoid 1/0 division (and long spikes) we define a
+ ** limit for sin().
+ */
+#define CURVE_SIN_LIMIT 0.3
+ int i, j, first,idx,ok=0;
shapeObj *ret = (shapeObj*)msSmallMalloc(sizeof(shapeObj));
msInitShape(ret);
ret->numlines = p->numlines;
@@ -1733,81 +1736,96 @@ shapeObj *msOffsetPolyline(shapeObj *p, double offsetx, double offsety)
ret->line[i].numpoints=p->line[i].numpoints;
ret->line[i].point=(pointObj*)msSmallMalloc(sizeof(pointObj)*ret->line[i].numpoints);
}
-
- if(offsety == -99) { /* complex calculations */
- int ok = 0;
- for (i = 0; i < p->numlines; i++) {
- pointObj old_pt, old_diffdir, old_offdir;
- if(p->line[i].numpoints<2) {
- ret->line[i].numpoints = 0;
- continue; /* skip degenerate lines */
- }
- ok =1;
- /* initialize old_offdir and old_diffdir, as gcc isn't smart enough to see that it
- * is not an error to do so, and prints a warning */
- old_offdir.x=old_offdir.y=old_diffdir.x=old_diffdir.y = 0;
-
- idx=0;
- first = 1;
-
- /* saved metrics of the last processed point */
- if (p->line[i].numpoints>0)
- old_pt=p->line[i].point[0];
- for(j=1; j<p->line[i].numpoints; j++) {
- const pointObj pt = p->line[i].point[j]; /* place of the point */
- const pointObj diffdir = point_norm(point_diff(pt,old_pt)); /* direction of the line */
- const pointObj offdir = point_rotz90(diffdir); /* direction where the distance between the line and the offset is measured */
- pointObj offpt; /* this will be the corner point of the offset line */
-
- /* offset line points computation */
- if(first == 1) { /* first point */
- first = 0;
- offpt = point_sum(old_pt,point_mul(offdir,offsetx));
- } else { /* middle points */
- /* curve is the angle of the last and the current line's direction (supplementary angle of the shape's inner angle) */
- double sin_curve = point_cross(diffdir,old_diffdir);
- double cos_curve = point_cross(old_offdir,diffdir);
- if ((-1.0)*CURVE_SIN_LIMIT < sin_curve && sin_curve < CURVE_SIN_LIMIT) {
- /* do not calculate 1/sin, instead use a corner point approximation: average of the last and current offset direction and length */
-
- /*
- ** TODO: fair for obtuse inner angles, however, positive and negative
- ** acute inner angles would need special handling - similar to LINECAP
- ** to avoid drawing of long spikes
- */
- offpt = point_sum(old_pt, point_mul(point_sum(offdir, old_offdir),0.5*offsetx));
- } else {
- double base_shift = -1.0*(1.0+cos_curve)/sin_curve;
- offpt = point_sum(old_pt, point_mul(point_sum(point_mul(diffdir,base_shift),offdir), offsetx));
- }
+ for (i = 0; i < p->numlines; i++) {
+ pointObj old_pt, old_diffdir, old_offdir;
+ if(p->line[i].numpoints<2) {
+ ret->line[i].numpoints = 0;
+ continue; /* skip degenerate points */
+ }
+ ok = 1;
+ /* initialize old_offdir and old_diffdir, as gcc isn't smart enough to see that it
+ * is not an error to do so, and prints a warning */
+ old_offdir.x=old_offdir.y=old_diffdir.x=old_diffdir.y = 0;
+
+ idx=0;
+ first = 1;
+
+ /* saved metrics of the last processed point */
+ if (p->line[i].numpoints>0)
+ old_pt=p->line[i].point[0];
+ for(j=1; j<p->line[i].numpoints; j++) {
+ const pointObj pt = p->line[i].point[j]; /* place of the point */
+ const pointObj diffdir = point_norm(point_diff(pt,old_pt)); /* direction of the line */
+ const pointObj offdir = point_rotz90(diffdir); /* direction where the distance between the line and the offset is measured */
+ pointObj offpt; /* this will be the corner point of the offset line */
+
+ /* offset line points computation */
+ if(first == 1) { /* first point */
+ first = 0;
+ offpt = point_sum(old_pt,point_mul(offdir,offset));
+ } else { /* middle points */
+ /* curve is the angle of the last and the current line's direction (supplementary angle of the shape's inner angle) */
+ double sin_curve = point_cross(diffdir,old_diffdir);
+ double cos_curve = point_cross(old_offdir,diffdir);
+ if ((-1.0)*CURVE_SIN_LIMIT < sin_curve && sin_curve < CURVE_SIN_LIMIT) {
+ /* do not calculate 1/sin, instead use a corner point approximation: average of the last and current offset direction and length */
+
+ /*
+ ** TODO: fair for obtuse inner angles, however, positive and negative
+ ** acute inner angles would need special handling - similar to LINECAP
+ ** to avoid drawing of long spikes
+ */
+ offpt = point_sum(old_pt, point_mul(point_sum(offdir, old_offdir),0.5*offset));
+ } else {
+ double base_shift = -1.0*(1.0+cos_curve)/sin_curve;
+ offpt = point_sum(old_pt, point_mul(point_sum(point_mul(diffdir,base_shift),offdir), offset));
}
- ret->line[i].point[idx]=offpt;
- idx++;
- old_pt=pt;
- old_diffdir=diffdir;
- old_offdir=offdir;
}
+ ret->line[i].point[idx]=offpt;
+ idx++;
+ old_pt=pt;
+ old_diffdir=diffdir;
+ old_offdir=offdir;
+ }
- /* last point */
- if(first == 0) {
- pointObj offpt=point_sum(old_pt,point_mul(old_offdir,offsetx));
- ret->line[i].point[idx]=offpt;
- idx++;
- }
+ /* last point */
+ if(first == 0) {
+ pointObj offpt=point_sum(old_pt,point_mul(old_offdir,offset));
+ ret->line[i].point[idx]=offpt;
+ idx++;
+ }
- if(idx != p->line[i].numpoints) {
- /* printf("shouldn't happen :(\n"); */
- ret->line[i].numpoints=idx;
- ret->line=msSmallRealloc(ret->line,ret->line[i].numpoints*sizeof(pointObj));
- }
+ if(idx != p->line[i].numpoints) {
+ /* printf("shouldn't happen :(\n"); */
+ ret->line[i].numpoints=idx;
+ ret->line=msSmallRealloc(ret->line,ret->line[i].numpoints*sizeof(pointObj));
}
- if(!ok) ret->numlines = 0; /* all lines where degenerate */
- } else { /* normal offset (eg. drop shadow) */
- for (i = 0; i < p->numlines; i++) {
- for(j=0; j<p->line[i].numpoints; j++) {
- ret->line[i].point[j].x=p->line[i].point[j].x+offsetx;
- ret->line[i].point[j].y=p->line[i].point[j].y+offsety;
- }
+ }
+ if(!ok) ret->numlines = 0; /* all lines where degenerate */
+ return ret;
+}
+
+shapeObj *msOffsetPolyline(shapeObj *p, double offsetx, double offsety)
+{
+ int i, j;
+ shapeObj *ret;
+ if(offsety == -99) { /* complex calculations */
+ return msOffsetCurve(p,offsetx);
+ }
+
+ ret = (shapeObj*)msSmallMalloc(sizeof(shapeObj));
+ msInitShape(ret);
+ ret->numlines = p->numlines;
+ ret->line=(lineObj*)msSmallMalloc(sizeof(lineObj)*ret->numlines);
+ for(i=0; i<ret->numlines; i++) {
+ ret->line[i].numpoints=p->line[i].numpoints;
+ ret->line[i].point=(pointObj*)msSmallMalloc(sizeof(pointObj)*ret->line[i].numpoints);
+ }
+
+ for (i = 0; i < p->numlines; i++) {
+ for(j=0; j<p->line[i].numpoints; j++) {
+ ret->line[i].point[j].x=p->line[i].point[j].x+offsetx;
+ ret->line[i].point[j].y=p->line[i].point[j].y+offsety;
}
}

0 comments on commit 7633072

Please sign in to comment.