[mapserver-commits] r13190 - sandbox/tb-labels
svn at osgeo.org
svn at osgeo.org
Thu Mar 1 12:25:48 EST 2012
Author: tbonfort
Date: 2012-03-01 09:25:48 -0800 (Thu, 01 Mar 2012)
New Revision: 13190
Modified:
sandbox/tb-labels/mapdraw.c
Log:
leaner and faster labelcache
Modified: sandbox/tb-labels/mapdraw.c
===================================================================
--- sandbox/tb-labels/mapdraw.c 2012-03-01 10:27:49 UTC (rev 13189)
+++ sandbox/tb-labels/mapdraw.c 2012-03-01 17:25:48 UTC (rev 13190)
@@ -2592,67 +2592,39 @@
return retval;
}
-/* add "to"'s geometry to "from", without unnecessary allocations.
- * the ownership of "from"'s geometry is transfered to "to"
- */
-static void transferLabelShape(shapeObj *from, shapeObj *to) {
- int i,copybounds=0;
-
- if(!from || !to) return;
-
- if( to->numlines <= 0 ) {
- copybounds=1;
- to->line = (lineObj *) msSmallMalloc(from->numlines * sizeof(lineObj));
- to->numlines = 0;
- }
- else {
- to->line = (lineObj *) msSmallRealloc(to->line, (to->numlines+from->numlines)*sizeof(lineObj));
- }
- for(i=0; i<from->numlines; i++) {
- to->line[to->numlines].point = from->line[i].point;
- to->line[to->numlines].numpoints = from->line[i].numpoints;
- to->numlines++;
- from->line[i].point = NULL;
- from->line[i].numpoints = 0;
- }
- if(copybounds) {
- to->bounds.minx = from->bounds.minx;
- to->bounds.miny = from->bounds.miny;
- to->bounds.maxx = from->bounds.maxx;
- to->bounds.maxy = from->bounds.maxy;
- } else {
- to->bounds.minx = MS_MIN(to->bounds.minx,from->bounds.minx);
- to->bounds.miny = MS_MIN(to->bounds.miny,from->bounds.miny);
- to->bounds.maxx = MS_MAX(to->bounds.maxx,from->bounds.maxx);
- to->bounds.maxy = MS_MAX(to->bounds.maxy,from->bounds.maxy);
- }
- msFree(from->line);
- from->line = NULL;
- from->numlines = 0;
- from->bounds.minx=from->bounds.miny=from->bounds.maxx=from->bounds.maxy=-1;
-}
-
-
int computeOldStyleMarkerPoly(mapObj *map, imageObj *image, labelCacheMemberObj *cachePtr,
labelCacheSlotObj *cacheslot, shapeObj *markerPoly) {
layerObj *layerPtr = (GET_LAYER(map, cachePtr->layerindex));
+ markerPoly->numlines = 0;
+ pointObj *point = markerPoly->line[0].point;
if(layerPtr->type == MS_LAYER_ANNOTATION && cachePtr->numstyles > 0) {
/* TODO: at the moment only checks the bottom (first) marker style since it *should* be the
largest, perhaps we should check all of them and build a composite size */
double marker_width,marker_height;
- rectObj marker_rect;
if(msGetMarkerSize(&map->symbolset, &(cachePtr->styles[0]), &marker_width, &marker_height, layerPtr->scalefactor) != MS_SUCCESS)
return MS_FAILURE;
-
- marker_rect.minx = cachePtr->point.x - .5 * marker_width;
- marker_rect.miny = cachePtr->point.y - .5 * marker_height;
- marker_rect.maxx = marker_rect.minx + (marker_width-1);
- marker_rect.maxy = marker_rect.miny + (marker_height-1);
- msRectToPolygon(marker_rect, markerPoly);
+ markerPoly->numlines = 1;
+ markerPoly->bounds.minx = cachePtr->point.x - .5 * marker_width;
+ markerPoly->bounds.miny = cachePtr->point.y - .5 * marker_height;
+ markerPoly->bounds.maxx = markerPoly->bounds.minx + (marker_width-1);
+ markerPoly->bounds.maxy = markerPoly->bounds.miny + (marker_height-1);
} else if (layerPtr->type == MS_LAYER_POINT && cachePtr->markerid!=-1) { /* there is a marker already in the image that we need to account for */
markerCacheMemberObj *markerPtr = &(cacheslot->markers[cachePtr->markerid]); /* point to the right sport in the marker cache (if available) */
- msRectToPolygon(markerPtr->poly->bounds, markerPoly);
+ markerPoly->numlines = 1;
+ markerPoly->bounds = markerPtr->poly->bounds;
}
+ if(markerPoly->numlines) {
+ point[0].x = markerPoly->bounds.minx;
+ point[0].y = markerPoly->bounds.miny;
+ point[1].x = markerPoly->bounds.minx;
+ point[1].y = markerPoly->bounds.maxy;
+ point[2].x = markerPoly->bounds.maxx;
+ point[2].y = markerPoly->bounds.maxy;
+ point[3].x = markerPoly->bounds.maxx;
+ point[3].y = markerPoly->bounds.miny;
+ point[4].x = markerPoly->bounds.minx;
+ point[5].y = markerPoly->bounds.miny;
+ }
return MS_SUCCESS;
}
@@ -2660,6 +2632,7 @@
labelObj *label, shapeObj *markerPoly) {
int i;
layerObj *layerPtr = (GET_LAYER(map, cachePtr->layerindex));
+ markerPoly->numlines = 0;
for (i=0; i<label->numstyles; i++) {
styleObj *style = label->styles[i];
if(style->_geomtransform.type == MS_GEOMTRANSFORM_LABELPOINT &&
@@ -2668,27 +2641,25 @@
symbolObj *symbol = map->symbolset.symbol[style->symbol];
if(msGetMarkerSize(&map->symbolset, style, &sx, &sy, layerPtr->scalefactor) != MS_SUCCESS)
return MS_FAILURE;
- lineObj line;
- line.point = msSmallMalloc(5*sizeof(pointObj));
- line.numpoints = 5;
- line.point[0].x = sx / 2.0;
- line.point[0].y = sy / 2.0;
- line.point[1].x = line.point[0].x;
- line.point[1].y = -line.point[0].y;
- line.point[2].x = -line.point[0].x;
- line.point[2].y = -line.point[0].y;
- line.point[3].x = -line.point[0].x;
- line.point[3].y = line.point[0].y;
- line.point[4].x = line.point[0].x;
- line.point[4].y = line.point[0].y;
+ pointObj *point = markerPoly->line[0].point;
+ point[0].x = sx / 2.0;
+ point[0].y = sy / 2.0;
+ point[1].x = point[0].x;
+ point[1].y = -point[0].y;
+ point[2].x = -point[0].x;
+ point[2].y = -point[0].y;
+ point[3].x = -point[0].x;
+ point[3].y = point[0].y;
+ point[4].x = point[0].x;
+ point[4].y = point[0].y;
int p;
double aox,aoy;
if(symbol->anchorpoint_x != 0.5 || symbol->anchorpoint_y != 0.5) {
aox = (0.5 - symbol->anchorpoint_x) * sx;
aoy = (0.5 - symbol->anchorpoint_y) * sy;
for(p=0;p<5;p++) {
- line.point[p].x += aox;
- line.point[p].y += aoy;
+ point[p].x += aox;
+ point[p].y += aoy;
}
}
if(style->angle) {
@@ -2696,25 +2667,42 @@
double sina = sin(rot);
double cosa = cos(rot);
for(p=0;p<5;p++) {
- double tmpx = line.point[p].x;
- line.point[p].x = line.point[p].x * cosa - line.point[p].y * sina;
- line.point[p].y = tmpx * sina + line.point[p].y * cosa;
+ double tmpx = point[p].x;
+ point[p].x = point[p].x * cosa - point[p].y * sina;
+ point[p].y = tmpx * sina + point[p].y * cosa;
}
}
aox = cachePtr->point.x + style->offsetx * layerPtr->scalefactor;
aoy = cachePtr->point.y + style->offsety * layerPtr->scalefactor;
for(p=0;p<5;p++) {
- line.point[p].x += aox;
- line.point[p].y += aoy;
+ point[p].x += aox;
+ point[p].y += aoy;
}
- msAddLineDirectly(markerPoly,&line);
- msComputeBounds(markerPoly);
+ markerPoly->numlines = 1;
+ fastComputeBounds(markerPoly);
break;
}
}
return MS_SUCCESS;
}
+void fastComputeBounds(shapeObj *shape)
+{
+ int i,j;
+ shape->bounds.minx = shape->bounds.maxx = shape->line[0].point[0].x;
+ shape->bounds.miny = shape->bounds.maxy = shape->line[0].point[0].y;
+
+
+ for( i=0; i<shape->numlines; i++ ) {
+ for( j=0; j<shape->line[i].numpoints; j++ ) {
+ shape->bounds.minx = MS_MIN(shape->bounds.minx, shape->line[i].point[j].x);
+ shape->bounds.maxx = MS_MAX(shape->bounds.maxx, shape->line[i].point[j].x);
+ shape->bounds.miny = MS_MIN(shape->bounds.miny, shape->line[i].point[j].y);
+ shape->bounds.maxy = MS_MAX(shape->bounds.maxy, shape->line[i].point[j].y);
+ }
+ }
+}
+
int msDrawLabelCache(imageObj *image, mapObj *map)
{
int nReturnVal = MS_SUCCESS;
@@ -2724,16 +2712,30 @@
int i, l, ll, priority;
rectObj r;
- shapeObj poly; /* hold label polygon for one label, cachePtr->poly holds label polygon for the whole group */
- msInitShape(&poly);
+
labelCacheMemberObj *cachePtr=NULL;
layerObj *layerPtr=NULL;
classObj *classPtr=NULL;
labelObj *labelPtr=NULL;
/* holds the contour of the label styles that correspond to markers */
- shapeObj markerPoly;
- msInitShape(&markerPoly);
+ shapeObj marker_poly;
+ lineObj marker_line;
+ pointObj marker_points[5];
+ marker_line.point = marker_points;
+ marker_line.numpoints = 5;
+ msInitShape(&marker_poly);
+ marker_poly.line = &marker_line;
+ marker_poly.numlines = 1;
+
+ shapeObj metrics_poly;
+ lineObj metrics_line;
+ pointObj metrics_points[5];
+ metrics_line.point = metrics_points;
+ metrics_line.numpoints = 5;
+ msInitShape(&metrics_poly);
+ metrics_poly.line = &metrics_line;
+ metrics_poly.numlines = 1;
double marker_offset_x, marker_offset_y;
@@ -2763,6 +2765,11 @@
layerPtr = (GET_LAYER(map, cachePtr->layerindex)); /* set a couple of other pointers, avoids nasty references */
classPtr = (GET_CLASS(map, cachePtr->layerindex, cachePtr->classindex));
+
+ if (layerPtr->type == MS_LAYER_ANNOTATION && (cachePtr->numlabels > 1 || classPtr->leader.maxdistance)) {
+ msSetError(MS_MISCERR, "Multiple Labels and/or LEADERs are not supported with annotation layers", "msDrawLabelCache()");
+ return MS_FAILURE;
+ }
/* TODO: classes with a labelpath do not respect multi label rendering */
if(cachePtr->labelpath) { /* path-based label */
@@ -2781,7 +2788,7 @@
label_mindistance = (labelPtr->mindistance*image->resolutionfactor);
/* copy the bounds into the cache's polygon */
- transferLabelShape(&(cachePtr->labelpath->bounds), cachePtr->poly);
+ msCopyShape(&(cachePtr->labelpath->bounds), cachePtr->poly);
/* compare against image bounds, rendered labels and markers (sets cachePtr->status), if FORCE=TRUE then skip it */
cachePtr->status = MS_TRUE;
@@ -2800,22 +2807,36 @@
marker_offset_x = marker_offset_y = 0; /* assume no marker */
/* compute label bbox of a marker used in an annotation layer or a point layer with markerPtr */
- computeOldStyleMarkerPoly(map,image,cachePtr,cacheslot,&markerPoly);
- if(markerPoly.numlines) {
- marker_offset_x = (markerPoly.bounds.maxx-markerPoly.bounds.minx)/2.0;
- marker_offset_y = (markerPoly.bounds.maxy-markerPoly.bounds.miny)/2.0;
- /* add marker to cachePtr->poly */
- transferLabelShape(&markerPoly, &poly);
+ computeOldStyleMarkerPoly(map,image,cachePtr,cacheslot,&marker_poly);
+ if(marker_poly.numlines) {
+ marker_offset_x = (marker_poly.bounds.maxx-marker_poly.bounds.minx)/2.0;
+ marker_offset_y = (marker_poly.bounds.maxy-marker_poly.bounds.miny)/2.0;
+ /* if this is an annotation layer, transfer the markerPoly */
+ if(layerPtr->type == MS_LAYER_ANNOTATION) {
+ if(cachePtr->numlabels > 1 || classPtr->leader.maxdistance) {
+ msSetError(MS_MISCERR,"Multiple Labels and/or LEADERs are not supported with annotation layers","msDrawLabelCache()");
+ return MS_FAILURE;
+ }
+ tmppoly = cachePtr->poly;
+ cachePtr->poly = &marker_poly;
+ if( MS_OFF == msTestLabelCacheCollisions(map, cachePtr, 0,priority, l)) {
+ continue; /* the marker collided, no point continuing */
+ }
+ cachePtr->poly = tmppoly;
+ msAddLine(cachePtr->poly,marker_poly.line);
+ msComputeBounds(cachePtr->poly);
+ }
}
+
/*
** all other cases *could* have multiple labels defined
*/
cachePtr->status = MS_OFF; /* assume this cache element *can't* be placed */
for(ll=0; ll<cachePtr->numlabels; ll++) { /* RFC 77 TODO: Still may want to step through backwards... */
- msFreeShape(&poly);
labelPtr = &(cachePtr->labels[ll]);
labelPtr->status = MS_OFF;
+ int label_marker_status = MS_ON;
/* first check if there's anything to do with this label */
if(!labelPtr->annotext) {
@@ -2832,18 +2853,26 @@
}
/* compute the poly of the label styles */
- computeLabelMarkerPoly(map,image,cachePtr,labelPtr,&markerPoly);
- if(markerPoly.numlines) {
+ computeLabelMarkerPoly(map,image,cachePtr,labelPtr,&marker_poly);
+ if(marker_poly.numlines) {
if(cachePtr->numlabels > 1) {
- marker_offset_x = (markerPoly.bounds.maxx-markerPoly.bounds.minx)/2.0;
- marker_offset_y = (markerPoly.bounds.maxy-markerPoly.bounds.miny)/2.0;
+ marker_offset_x = (marker_poly.bounds.maxx-marker_poly.bounds.minx)/2.0;
+ marker_offset_y = (marker_poly.bounds.maxy-marker_poly.bounds.miny)/2.0;
} else {
/* we might be using an old style behavior with a markerPtr */
- marker_offset_x = MS_MAX(marker_offset_x,(markerPoly.bounds.maxx-markerPoly.bounds.minx)/2.0);
- marker_offset_y = MS_MAX(marker_offset_y,(markerPoly.bounds.maxy-markerPoly.bounds.miny)/2.0);
+ marker_offset_x = MS_MAX(marker_offset_x,(marker_poly.bounds.maxx-marker_poly.bounds.minx)/2.0);
+ marker_offset_y = MS_MAX(marker_offset_y,(marker_poly.bounds.maxy-marker_poly.bounds.miny)/2.0);
}
/* add marker to cachePtr->poly */
- transferLabelShape(&markerPoly, &poly);
+ tmppoly = cachePtr->poly;
+ cachePtr->poly = &marker_poly;
+ if(labelPtr->force != MS_TRUE)
+ label_marker_status = msTestLabelCacheCollisions(map, cachePtr, 0,priority, l);
+ cachePtr->poly = tmppoly;
+ if(label_marker_status == MS_OFF &&
+ !(labelPtr->force || classPtr->leader.maxdistance))
+ break; /* the marker collided, break from multi-label loop */
+ cachePtr->poly = tmppoly;
}
@@ -2903,8 +2932,10 @@
}
}
}
-
+
+ /* TODO: no point in using auto positionning if the marker cannot be placed? */
if(labelPtr->annotext && labelPtr->position == MS_AUTO) {
+ /* no point in using auto positionning if the marker cannot be placed */
int positions[MS_POSITIONS_LENGTH], npositions=0;
/*
@@ -2924,92 +2955,96 @@
for(i=0; i<npositions; i++) {
// RFC 77 TODO: take label_marker_offset_x/y into account
- labelPtr->annopoint = get_metrics(&(cachePtr->point), positions[i], r,
+ labelPtr->annopoint = get_metrics_line(&(cachePtr->point), positions[i], r,
marker_offset_x + label_offset_x, marker_offset_y + label_offset_y,
- labelPtr->angle, label_buffer, &poly);
+ labelPtr->angle, label_buffer, &metrics_line);
+ fastComputeBounds(&metrics_poly);
if(labelPtr->force == MS_OFF) {
/* check for collisions inside the label group */
-
- /* if cachePtr->status we're still working on the first valid label with a valid status value */
- /* was: if((ll != 0) && intersectLabelPolygons(poly, cachePtr->poly) == MS_TRUE) */
- if(ll && intersectLabelPolygons(&poly, cachePtr->poly) == MS_TRUE) {
- /* there was a self intersection, remove the label bbox added by get_metrics ? */
- msShapeDeleteLine(&poly, poly.numlines-1);
- msComputeBounds(&poly);
+ if(cachePtr->poly->numlines && intersectLabelPolygons(&metrics_poly, cachePtr->poly) == MS_TRUE) {
+ /* there was a self intersection */
continue; /* next position, labelPtr->status is left to MS_OFF */
}
}
tmppoly = cachePtr->poly;
- cachePtr->poly = &poly;
+ cachePtr->poly = &metrics_poly;
labelPtr->status = msTestLabelCacheCollisions(map, cachePtr, label_mindistance,priority, l);
cachePtr->poly = tmppoly;
/* found a suitable place for this label */
- if(labelPtr->status || (i==(npositions-1) && labelPtr->force == MS_TRUE)) {
+ if(labelPtr->status == MS_TRUE || (i==(npositions-1) && labelPtr->force == MS_ON)) {
labelPtr->status = MS_TRUE; /* set to true in case we are forcing it */
if(labelPtr->annopoly) get_metrics_line(&(cachePtr->point), positions[i], r,
marker_offset_x + label_offset_x, marker_offset_y + label_offset_y,
labelPtr->angle, 1, labelPtr->annopoly->line);
break; /* ...out of position loop */
- } else {
- /* remove the poly added by get_metrics for this label position, unless this is the last tested
- * position and we have label->force, as in that case it will be kept regardlesss of collisions */
- msShapeDeleteLine(&poly, poly.numlines-1);
- msComputeBounds(&poly);
}
} /* next position */
+
+ /* if position auto didn't manage to find a position, but we have leader configured
+ * for the class, then we want to compute the label poly anyways */
if(classPtr->leader.maxdistance && labelPtr->status == MS_FALSE) {
- labelPtr->annopoint = get_metrics(&(cachePtr->point), MS_CC, r,
+ labelPtr->annopoint = get_metrics_line(&(cachePtr->point), MS_CC, r,
marker_offset_x + label_offset_x, marker_offset_y + label_offset_y,
- labelPtr->angle, label_buffer, &poly);
+ labelPtr->angle, label_buffer, &metrics_line);
+ fastComputeBounds(&metrics_poly);
}
} else { /* explicit position */
if(labelPtr->annotext) {
if(labelPtr->position == MS_CC) { /* don't need the marker_offset */
- labelPtr->annopoint = get_metrics(&(cachePtr->point), labelPtr->position, r,
- label_offset_x, label_offset_y, labelPtr->angle, label_buffer, &poly);
+ labelPtr->annopoint = get_metrics_line(&(cachePtr->point), labelPtr->position, r,
+ label_offset_x, label_offset_y, labelPtr->angle, label_buffer, &metrics_line);
if(labelPtr->annopoly) get_metrics_line(&(cachePtr->point), labelPtr->position, r,
label_offset_x, label_offset_y, labelPtr->angle, 1, labelPtr->annopoly->line);
} else {
- labelPtr->annopoint = get_metrics(&(cachePtr->point), labelPtr->position, r,
+ labelPtr->annopoint = get_metrics_line(&(cachePtr->point), labelPtr->position, r,
marker_offset_x + label_offset_x, marker_offset_y + label_offset_y,
- labelPtr->angle, label_buffer, &poly);
+ labelPtr->angle, label_buffer, &metrics_line);
if(labelPtr->annopoly) get_metrics_line(&(cachePtr->point), labelPtr->position, r,
marker_offset_x + label_offset_x, marker_offset_y + label_offset_y,
labelPtr->angle, 1, labelPtr->annopoly->line);
}
- }
+ fastComputeBounds(&metrics_poly);
- if(labelPtr->force == MS_TRUE) {
- transferLabelShape(&poly, cachePtr->poly);
- labelPtr->status = MS_TRUE;
+ if(labelPtr->force == MS_ON) {
+ labelPtr->status = MS_ON;
+ } else {
+ if(labelPtr->force == MS_OFF) {
+ /* check for collisions inside the label group unless the label is FORCE GROUP */
+ if(cachePtr->poly->numlines && intersectLabelPolygons(&metrics_poly, cachePtr->poly) == MS_TRUE) {
+ break; /* collision within the group */
+ }
+ }
+ tmppoly = cachePtr->poly;
+ cachePtr->poly = &metrics_poly;
+ /* TODO: in case we have leader lines and multiple labels, there's no use in testing for labelcache collisions
+ * once a first collision has been found. we only need to know that the label group has collided, and the
+ * poly of the whole label group: if(label_group) testLabelCacheCollisions */
+ labelPtr->status = msTestLabelCacheCollisions(map, cachePtr, label_mindistance, priority, l);
+ cachePtr->poly = tmppoly;
+ }
} else {
- if(labelPtr->force == MS_OFF) {
- /* check for collisions inside the label group unless the label is FORCE GROUP */
-
- /* if cachePtr->status we're still working on the first valid label with a valid status value */
- if(ll && intersectLabelPolygons(&poly, cachePtr->poly) == MS_TRUE) {
- break; /* collision within the group */
- }
- }
- tmppoly = cachePtr->poly;
- cachePtr->poly = &poly;
- /* TODO: in case we have leader lines and multiple labels, there's no use in testing for labelcache collisions
- * once a first collision has been found. we only need to know that the label group has collided, and the
- * poly of the whole label group: if(label_group) testLabelCacheCollisions */
- labelPtr->status = msTestLabelCacheCollisions(map, cachePtr, label_mindistance, priority, l);
- cachePtr->poly = tmppoly;
+ labelPtr->status = MS_ON;
}
} /* end POSITION AUTO vs Fixed POSITION */
- if(!labelPtr->status && classPtr->leader.maxdistance == 0) {
+ if((!labelPtr->status || !label_marker_status) && classPtr->leader.maxdistance == 0) {
break; /* no point looking at more labels, unless their is a leader defined, in which
case we still want to compute the full cachePtr->poly to be used for offset tests */
+ labelPtr->status = MS_OFF;
} else {
- transferLabelShape(&poly, cachePtr->poly);
+ if(labelPtr->annotext) {
+ msAddLine(cachePtr->poly, metrics_poly.line);
+ }
+ if(marker_poly.numlines) {
+ msAddLine(cachePtr->poly, marker_poly.line);
+ }
+ if(!label_marker_status)
+ labelPtr->status = MS_OFF;
+ fastComputeBounds(cachePtr->poly);
}
} /* next label in the group */
@@ -3052,7 +3087,7 @@
msDrawText(image, labelPtr->annopoint, labelPtr->annotext, labelPtr, &(map->fontset), layerPtr->scalefactor); /* actually draw the label */
}
- /*
+ /*
styleObj tstyle;
static int foo =0;
if(!foo) {
@@ -3067,10 +3102,10 @@
tstyle.color.blue =random()%255;
msDrawLineSymbol(&map->symbolset, image, cachePtr->poly, &tstyle, layerPtr->scalefactor);
*/
+
} /* end else */
} /* next label(group) from cacheslot */
- msFreeShape(&poly); /* clean up label polygon */
msDrawOffsettedLabels(image, map, priority);
} /* next priority */
More information about the mapserver-commits
mailing list