Permalink
Browse files

Calculate MINDISTANCE from label bounds instead of label center (#5369)

  • Loading branch information...
olt committed Jul 19, 2017
1 parent c73fee4 commit 90a846a72ba6d7b63fc7f2bca881aa55a34b2d84
@@ -15,6 +15,8 @@ http://mapserver.org/development/changelog/
7.2 release (FUTURE)
--------------------
- Calculate MINDISTANCE from label bounds instead of label center (#5369)
- Reposition follow labels on maxoverlapangle colisions (RFC112)
- Implement chainable compositing filters (RFC113)
102 mapdraw.c
@@ -2680,28 +2680,60 @@ int computeMarkerBounds(mapObj *map, pointObj *annopoint, textSymbolObj *ts, lab
return MS_TRUE;
}
/* check that the current entry does not fall close to a label with identical text, if configured so.
* Currently only checks the first label/text */
int msCheckLabelMinDistance(mapObj *map, labelCacheMemberObj *lc) {
double sqmindistance;
int msCheckLabelMinDistance(mapObj *map, labelCacheMemberObj *lc)
{
int i;
pointObj p;
textSymbolObj *s; /* shortcut */
if(lc->numtextsymbols == 0) return MS_FALSE; /* no label with text */
if (lc->numtextsymbols == 0)
return MS_FALSE; /* no label with text */
s = lc->textsymbols[0];
if(!s->annotext || s->label->mindistance <= 0.0 || s->label->force == MS_TRUE) return MS_FALSE; /* min distance is not checked */
sqmindistance = s->label->mindistance * s->label->mindistance * s->resolutionfactor * s->resolutionfactor;
for(i=0;i<map->labelcache.num_rendered_members;i++) {
if (!s->annotext || s->label->mindistance <= 0.0 || s->label->force == MS_TRUE)
return MS_FALSE; /* min distance is not checked */
/* we buffer the label and check for intersection instead of calculating
the distance of two textpaths. we also buffer only the bbox of lc for
faster computation (it is still compared to the full textpath
of the label cache members).
*/
rectObj buffered = lc->bbox;
buffered.minx -= s->label->mindistance * s->resolutionfactor;
buffered.miny -= s->label->mindistance * s->resolutionfactor;
buffered.maxx += s->label->mindistance * s->resolutionfactor;
buffered.maxy += s->label->mindistance * s->resolutionfactor;
for (i = 0; i < map->labelcache.num_rendered_members; i++) {
labelCacheMemberObj *ilc = map->labelcache.rendered_text_symbols[i];
double sqdistance;
if(ilc->numtextsymbols == 0 || !ilc->textsymbols[0]->annotext) continue;
sqdistance = (lc->point.x - ilc->point.x)*(lc->point.x - ilc->point.x)+
(lc->point.y - ilc->point.y)*(lc->point.y - ilc->point.y);
if(sqdistance < sqmindistance) {
if(!strcmp(s->annotext,ilc->textsymbols[0]->annotext)) {
if (ilc->numtextsymbols == 0 || !ilc->textsymbols[0]->annotext)
continue;
textSymbolObj *ts = ilc->textsymbols[0];
if (strcmp(s->annotext, ts->annotext) != 0) {
/* only check min distance against same label */
continue;
}
if (msPointInRect(&ilc->point, &buffered) == MS_TRUE) {
return MS_TRUE;
}
if(ts->textpath && ts->textpath->absolute) {
if (intersectLabelPolygons(ts->textpath->bounds.poly, &ilc->bbox, NULL, &buffered) == MS_TRUE) {
return MS_TRUE;
}
continue;
}
if (intersectLabelPolygons(NULL, &ilc->bbox, NULL, &buffered) == MS_TRUE) {
return MS_TRUE;
}
}
return MS_FALSE;
}
@@ -2792,29 +2824,33 @@ int msDrawLabelCache(mapObj *map, imageObj *image)
layerPtr = (GET_LAYER(map, cachePtr->layerindex)); /* set a couple of other pointers, avoids nasty references */
classPtr = (GET_CLASS(map, cachePtr->layerindex, cachePtr->classindex));
/* before going any futher (and maybe even computing label size for performance,
check that mindistance is respected */
if(cachePtr->numtextsymbols && cachePtr->textsymbols[0]->label->mindistance > 0.0 && cachePtr->textsymbols[0]->annotext) {
if(msCheckLabelMinDistance(map, cachePtr) == MS_TRUE) {
cachePtr->status = MS_DELETE;
MS_DEBUG(MS_DEBUGLEVEL_DEVDEBUG,map,
"Skipping labelgroup %d \"%s\" in layer \"%s\": too close to an identical label (mindistance)\n",
l, cachePtr->textsymbols[0]->annotext, layerPtr->name);
continue; /* move on to next entry, this one is too close to an already placed one */
}
}
if(cachePtr->textsymbols[0]->textpath && cachePtr->textsymbols[0]->textpath->absolute) {
/* we have an angle follow label */
cachePtr->bbox = cachePtr->textsymbols[0]->textpath->bounds.bbox;
/* before going any futher, check that mindistance is respected */
if (cachePtr->numtextsymbols && cachePtr->textsymbols[0]->label->mindistance > 0.0 && cachePtr->textsymbols[0]->annotext) {
if (msCheckLabelMinDistance(map, cachePtr) == MS_TRUE) {
cachePtr->status = MS_DELETE;
MS_DEBUG(MS_DEBUGLEVEL_DEVDEBUG, map,
"Skipping labelgroup %d \"%s\" in layer \"%s\": too close to an identical label (mindistance)\n",
l, cachePtr->textsymbols[0]->annotext, layerPtr->name);
continue; /* move on to next entry, this one is too close to an already placed one */
}
}
if(!cachePtr->textsymbols[0]->label->force)
cachePtr->status = msTestLabelCacheCollisions(map,cachePtr,&cachePtr->textsymbols[0]->textpath->bounds, priority, l);
else
cachePtr->status = MS_ON;
if(cachePtr->status) {
if(UNLIKELY(MS_FAILURE == msDrawTextSymbol(map,image,cachePtr->textsymbols[0]->annopoint /*not used*/,cachePtr->textsymbols[0]))) {
return MS_FAILURE;
}
cachePtr->bbox = cachePtr->textsymbols[0]->textpath->bounds.bbox;
insertRenderedLabelMember(map, cachePtr);
if (UNLIKELY(MS_FAILURE == msDrawTextSymbol(map, image, cachePtr->textsymbols[0]->annopoint /*not used*/, cachePtr->textsymbols[0])))
{
return MS_FAILURE;
}
insertRenderedLabelMember(map, cachePtr);
} else {
MS_DEBUG(MS_DEBUGLEVEL_DEVDEBUG,map,
"Skipping follow labelgroup %d \"%s\" in layer \"%s\": text collided\n",
@@ -3134,6 +3170,16 @@ int msDrawLabelCache(mapObj *map, imageObj *image)
}
}
/* check that mindistance is respected */
if (cachePtr->numtextsymbols && cachePtr->textsymbols[0]->label->mindistance > 0.0 && cachePtr->textsymbols[0]->annotext) {
if (msCheckLabelMinDistance(map, cachePtr) == MS_TRUE) {
cachePtr->status = MS_DELETE;
MS_DEBUG(MS_DEBUGLEVEL_DEVDEBUG, map,
"Skipping labelgroup %d \"%s\" in layer \"%s\": too close to an identical label (mindistance)\n",
l, cachePtr->textsymbols[0]->annotext, layerPtr->name);
}
}
if(cachePtr->status == MS_OFF || cachePtr->status == MS_DELETE)
continue; /* next labelCacheMemberObj, as we had a collision */
@@ -173,7 +173,7 @@ int msComputeTextPath(mapObj *map, textSymbolObj *ts) {
tgret->line_height = ceil(tgret->glyph_size * 1.33);
return msLayoutTextSymbol(map,ts,tgret);
}
void initTextSymbol(textSymbolObj *ts) {
memset(ts,0,sizeof(*ts));
}
@@ -292,7 +292,7 @@ int msAddLabelGroup(mapObj *map, imageObj *image, layerObj* layer, int classinde
classPtr = layer->class[classindex];
if(classPtr->numlabels == 0) return MS_SUCCESS; /* not an error just nothing to do */
/* check that the label intersects the layer mask */
if(layerPtr->mask) {
int maskLayerIdx = msGetLayerIndex(map,layerPtr->mask);
@@ -308,7 +308,7 @@ int msAddLabelGroup(mapObj *map, imageObj *image, layerObj* layer, int classinde
x = MS_NINT(point->x);
y = MS_NINT(point->y);
/* Using label repeatdistance, we might have a point with x/y below 0. See #4764 */
if (x >= 0 && x < rb.width && y >= 0 && y < rb.height) {
if (x >= 0 && x < rb.width && y >= 0 && y < rb.height) {
assert(rb.type == MS_BUFFER_BYTE_RGBA);
alphapixptr = rb.data.rgba.a+rb.data.rgba.row_step*y + rb.data.rgba.pixel_step*x;
if(!*alphapixptr) {
@@ -324,9 +324,9 @@ int msAddLabelGroup(mapObj *map, imageObj *image, layerObj* layer, int classinde
return (MS_FAILURE);
}
}
textsymbols = msSmallMalloc(classPtr->numlabels * sizeof(textSymbolObj*));
for(l=0; l<classPtr->numlabels; l++) {
labelObj *lbl = classPtr->labels[l];
char *annotext;
@@ -346,7 +346,7 @@ int msAddLabelGroup(mapObj *map, imageObj *image, layerObj* layer, int classinde
ts = msSmallMalloc(sizeof(textSymbolObj));
initTextSymbol(ts);
msPopulateTextSymbolForLabelAndString(ts,lbl,annotext,layerPtr->scalefactor,image->resolutionfactor, 1);
if(annotext && *annotext && lbl->autominfeaturesize && featuresize > 0) {
if(UNLIKELY(MS_FAILURE == msComputeTextPath(map,ts)))
return MS_FAILURE;
@@ -360,12 +360,12 @@ int msAddLabelGroup(mapObj *map, imageObj *image, layerObj* layer, int classinde
textsymbols[numtextsymbols] = ts;
numtextsymbols++;
}
if(numtextsymbols == 0) {
free(textsymbols);
return MS_SUCCESS;
}
/* Validate label priority value and get ref on label cache for it */
priority = classPtr->labels[0]->priority; /* take priority from the first label */
if (priority < 1)
@@ -439,10 +439,10 @@ int msAddLabel(mapObj *map, imageObj *image, labelObj *label, int layerindex, in
layerPtr=GET_LAYER(map,layerindex);
assert(layerPtr);
assert(classindex < layerPtr->numclasses);
classPtr = layerPtr->class[classindex];
assert(label);
if(ts)
@@ -508,7 +508,7 @@ int msAddLabel(mapObj *map, imageObj *image, labelObj *label, int layerindex, in
for (i = 0; i < ts->textpath->numglyphs; i++) {
int x = MS_NINT(ts->textpath->glyphs[i].pnt.x);
int y = MS_NINT(ts->textpath->glyphs[i].pnt.y);
if (x >= 0 && x < rb.width && y >= 0 && y < rb.height) {
if (x >= 0 && x < rb.width && y >= 0 && y < rb.height) {
alphapixptr = rb.data.rgba.a + rb.data.rgba.row_step * y + rb.data.rgba.pixel_step*x;
if (!*alphapixptr) {
freeTextSymbol(ts);
@@ -534,7 +534,7 @@ int msAddLabel(mapObj *map, imageObj *image, labelObj *label, int layerindex, in
initTextSymbol(ts);
msPopulateTextSymbolForLabelAndString(ts,label,annotext,layerPtr->scalefactor,image->resolutionfactor, 1);
}
if(annotext && label->autominfeaturesize && featuresize > 0) {
if(!ts->textpath) {
if(UNLIKELY(MS_FAILURE == msComputeTextPath(map,ts)))
@@ -1096,7 +1096,7 @@ int intersectLabelPolygons(lineObj *l1, rectObj *r1, lineObj *l2, rectObj *r2)
pointObj *point;
lineObj *p1,*p2,sp1,sp2;
pointObj pnts1[5],pnts2[5];
/* STEP 0: check bounding boxes */
if(!msRectOverlap(r1,r2)) { /* from alans@wunderground.com */
Binary file not shown.
Binary file not shown.
Binary file not shown.
Oops, something went wrong.

0 comments on commit 90a846a

Please sign in to comment.