int msAddLabel(mapObj *map, labelObj *label, int layerindex, int classindex, shapeObj *shape, pointObj *point, labelPathObj *labelpath, double featuresize) { int i; labelCacheSlotObj *cacheslot; labelCacheMemberObj *cachePtr=NULL; layerObj *layerPtr=NULL; classObj *classPtr=NULL; if(!label) return(MS_FAILURE); // RFC 77 TODO: set a proper message if(label->status == MS_OFF) return(MS_SUCCESS); /* not an error */ if(!label->annotext) { /* check if we have a labelpnt style */ for(i=0; i<label->numstyles; i++) { if(label->styles[i]->_geomtransform.type == MS_GEOMTRANSFORM_LABELPOINT) break; } if(i==label->numstyles) { /* label has no text or marker symbols */ return MS_SUCCESS; } } layerPtr = (GET_LAYER(map, layerindex)); /* set up a few pointers for clarity */ classPtr = GET_LAYER(map, layerindex)->class[classindex]; if(classPtr->leader.maxdistance) { if (layerPtr->type == MS_LAYER_ANNOTATION) { msSetError(MS_MISCERR, "LEADERs are not supported on annotation layers", "msAddLabel()"); return MS_FAILURE; } if(labelpath) { msSetError(MS_MISCERR, "LEADERs are not supported on ANGLE FOLLOW labels", "msAddLabel()"); return MS_FAILURE; } } /* check that the label intersects the layer mask */ if (layerPtr->mask) { int maskLayerIdx = msGetLayerIndex(map, layerPtr->mask); layerObj *maskLayer = GET_LAYER(map, maskLayerIdx); unsigned char *alphapixptr; if (maskLayer->maskimage && MS_IMAGE_RENDERER(maskLayer->maskimage)->supports_pixel_buffer) { rasterBufferObj rb; memset(&rb, 0, sizeof (rasterBufferObj)); MS_IMAGE_RENDERER(maskLayer->maskimage)->getRasterBufferHandle(maskLayer->maskimage, &rb); if (point) { int x = MS_NINT(point->x); int 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) { #ifdef USE_GD if(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) { /* label point does not intersect mask */ return MS_SUCCESS; } } else { if(!gdImageGetPixel(rb.data.gd_img,x,y)) { return MS_SUCCESS; } } #else 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) { /* label point does not intersect mask */ return MS_SUCCESS; } #endif } } else if (labelpath) { int i = 0; for (i = 0; i < labelpath->path.numpoints; i++) { int x = MS_NINT(labelpath->path.point[i].x); int y = MS_NINT(labelpath->path.point[i].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) { #ifdef USE_GD if (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) { /* label point does not intersect mask */ msFreeLabelPathObj(labelpath); return MS_SUCCESS; } } else { if (!gdImageGetPixel(rb.data.gd_img, x, y)) { msFreeLabelPathObj(labelpath); return MS_SUCCESS; } } #else 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) { /* label point does not intersect mask */ msFreeLabelPathObj(labelpath); return MS_SUCCESS; } #endif } } } } else { msSetError(MS_MISCERR, "Layer (%s) references references a mask layer, but the selected renderer does not support them", "msAddLabel()", layerPtr->name); return (MS_FAILURE); } } /* Validate label priority value and get ref on label cache for it */ if (label->priority < 1) label->priority = 1; else if (label->priority > MS_MAX_LABEL_PRIORITY) label->priority = MS_MAX_LABEL_PRIORITY; cacheslot = &(map->labelcache.slots[label->priority-1]); if(cacheslot->numlabels == cacheslot->cachesize) { /* just add it to the end */ cacheslot->labels = (labelCacheMemberObj *) realloc(cacheslot->labels, sizeof(labelCacheMemberObj)*(cacheslot->cachesize+MS_LABELCACHEINCREMENT)); MS_CHECK_ALLOC(cacheslot->labels, sizeof(labelCacheMemberObj)*(cacheslot->cachesize+MS_LABELCACHEINCREMENT), MS_FAILURE); cacheslot->cachesize += MS_LABELCACHEINCREMENT; } cachePtr = &(cacheslot->labels[cacheslot->numlabels]); cachePtr->layerindex = layerindex; /* so we can get back to this *raw* data if necessary */ cachePtr->classindex = classindex; if(shape) { cachePtr->shapetype = shape->type; } else { cachePtr->shapetype = MS_SHAPE_POINT; } cachePtr->leaderline = NULL; cachePtr->leaderbbox = NULL; /* Store the label point or the label path (Bug #1620) */ if ( point ) { cachePtr->point = *point; /* the actual label point */ cachePtr->labelpath = NULL; } else { assert(labelpath); cachePtr->labelpath = labelpath; /* Use the middle point of the labelpath for mindistance calculations */ cachePtr->point = labelpath->path.point[labelpath->path.numpoints / 2]; } /* TODO: perhaps we can get rid of this next section and just store a marker size? Why do we cache the styles for a point layer? */ /* copy the styles (only if there is an accompanying marker) * We cannot simply keeep refs because the rendering code alters some members of the style objects */ cachePtr->styles = NULL; cachePtr->numstyles = 0; if(layerPtr->type == MS_LAYER_ANNOTATION && classPtr->numstyles > 0) { cachePtr->numstyles = classPtr->numstyles; cachePtr->styles = (styleObj *) msSmallMalloc(sizeof(styleObj)*classPtr->numstyles); if (classPtr->numstyles > 0) { for(i=0; i<classPtr->numstyles; i++) { initStyle(&(cachePtr->styles[i])); msCopyStyle(&(cachePtr->styles[i]), classPtr->styles[i]); } } } /* copy the label */ cachePtr->numlabels = 1; cachePtr->labels = (labelObj *) msSmallMalloc(sizeof(labelObj)); initLabel(cachePtr->labels); msCopyLabel(cachePtr->labels, label); cachePtr->markerid = -1; cachePtr->featuresize = featuresize; //cachePtr->poly = (shapeObj *) msSmallMalloc(sizeof(shapeObj)); //msInitShape(cachePtr->poly); cachePtr->poly = NULL; cachePtr->status = MS_FALSE; if(layerPtr->type == MS_LAYER_POINT && classPtr->numstyles > 0) { /* cache the marker placement, it's already on the map */ rectObj rect; double w, h; if(cacheslot->nummarkers == cacheslot->markercachesize) { /* just add it to the end */ cacheslot->markers = (markerCacheMemberObj *) realloc(cacheslot->markers, sizeof(markerCacheMemberObj)*(cacheslot->cachesize+MS_LABELCACHEINCREMENT)); MS_CHECK_ALLOC(cacheslot->markers, sizeof(markerCacheMemberObj)*(cacheslot->cachesize+MS_LABELCACHEINCREMENT), MS_FAILURE); cacheslot->markercachesize+=MS_LABELCACHEINCREMENT; } i = cacheslot->nummarkers; cacheslot->markers[i].poly = (shapeObj *) msSmallMalloc(sizeof(shapeObj)); msInitShape(cacheslot->markers[i].poly); /* TO DO: at the moment only checks the bottom style, perhaps should check all of them */ /* #2347: after RFC-24 classPtr->styles could be NULL so we check it */ if(classPtr->styles != NULL) { if(msGetMarkerSize(&map->symbolset, classPtr->styles[0], &w, &h, layerPtr->scalefactor) != MS_SUCCESS) return(MS_FAILURE); rect.minx = point->x - .5 * w; rect.miny = point->y - .5 * h; rect.maxx = rect.minx + (w-1); rect.maxy = rect.miny + (h-1); msRectToPolygon(rect, cacheslot->markers[i].poly); cacheslot->markers[i].id = cacheslot->numlabels; cachePtr->markerid = i; cacheslot->nummarkers++; } } cacheslot->numlabels++; /* Maintain main labelCacheObj.numlabels only for backwards compatibility */ map->labelcache.numlabels++; return(MS_SUCCESS); }
int msDrawMarkerSymbol(mapObj *map, imageObj *image, pointObj *p, styleObj *style, double scalefactor) { int ret = MS_SUCCESS; if (!p) return MS_SUCCESS; if (style->symbol >= map->symbolset.numsymbols || style->symbol <= 0) return MS_SUCCESS; /* no such symbol, 0 is OK */ if (image) { if(MS_RENDERER_PLUGIN(image->format)) { rendererVTableObj *renderer = image->format->vtable; symbolStyleObj s; double p_x,p_y; symbolObj *symbol = map->symbolset.symbol[style->symbol]; /* store a reference to the renderer to be used for freeing */ symbol->renderer = renderer; if(preloadSymbol(&map->symbolset,symbol,renderer) != MS_SUCCESS) { return MS_FAILURE; } computeSymbolStyle(&s,style,symbol,scalefactor,image->resolutionfactor); s.style = style; if (!s.color && !s.outlinecolor && symbol->type != MS_SYMBOL_PIXMAP && symbol->type != MS_SYMBOL_SVG) { return MS_SUCCESS; // nothing to do if no color, except for pixmap symbols } if(s.scale == 0) { return MS_SUCCESS; } /* TODO: skip the drawing of the symbol if it's smaller than a pixel ? if (s.size < 1) return; // size too small */ p_x = p->x; p_y = p->y; if (style->polaroffsetpixel != 0 || style->polaroffsetangle != 0) { double angle = style->polaroffsetangle * MS_DEG_TO_RAD; p_x += (style->polaroffsetpixel * cos(-angle)) * scalefactor; p_y += (style->polaroffsetpixel * sin(-angle)) * scalefactor; } p_x += style->offsetx * scalefactor; p_y += style->offsety * scalefactor; if(symbol->anchorpoint_x != 0.5 || symbol->anchorpoint_y != 0.5) { double sx,sy; double ox, oy; if(UNLIKELY(MS_FAILURE == msGetMarkerSize(map, style, &sx, &sy, scalefactor))) { return MS_FAILURE; } ox = (0.5 - symbol->anchorpoint_x) * sx; oy = (0.5 - symbol->anchorpoint_y) * sy; if(s.rotation != 0) { double sina, cosa; double rox,roy; sina = sin(-s.rotation); cosa = cos(-s.rotation); rox = ox * cosa - oy * sina; roy = ox * sina + oy * cosa; p_x += rox; p_y += roy; } else { p_x += ox; p_y += oy; } } if(renderer->use_imagecache) { imageObj *tile = getTile(image, symbol, &s, -1, -1,0); if(tile!=NULL) return renderer->renderTile(image, tile, p_x, p_y); else { msSetError(MS_RENDERERERR, "problem creating cached tile", "msDrawMarkerSymbol()"); return MS_FAILURE; } } switch (symbol->type) { case (MS_SYMBOL_TRUETYPE): { unsigned int unicode; glyph_element *glyphc; face_element *face = msGetFontFace(symbol->font, &map->fontset); if(UNLIKELY(!face)) return MS_FAILURE; msUTF8ToUniChar(symbol->character,&unicode); unicode = msGetGlyphIndex(face,unicode); glyphc = msGetGlyphByIndex(face,s.scale,unicode); if(UNLIKELY(!glyphc)) return MS_FAILURE; ret = drawGlyphMarker(image, face, glyphc, p_x, p_y, s.scale, s.rotation, s.color, s.outlinecolor, s.outlinewidth); } break; case (MS_SYMBOL_PIXMAP): { assert(symbol->pixmap_buffer); ret = renderer->renderPixmapSymbol(image,p_x,p_y,symbol,&s); } break; case (MS_SYMBOL_ELLIPSE): { ret = renderer->renderEllipseSymbol(image, p_x, p_y,symbol, &s); } break; case (MS_SYMBOL_VECTOR): { ret = renderer->renderVectorSymbol(image, p_x, p_y, symbol, &s); } break; case (MS_SYMBOL_SVG): { if (renderer->supports_svg) { ret = renderer->renderSVGSymbol(image, p_x, p_y, symbol, &s); } else { #if defined(USE_SVG_CAIRO) || defined(USE_RSVG) ret = msRenderRasterizedSVGSymbol(image, p_x,p_y, symbol, &s); #else msSetError(MS_SYMERR, "SVG symbol support is not enabled.", "msDrawMarkerSymbol()"); return MS_FAILURE; #endif } } break; default: break; } return ret; } else if( MS_RENDERER_IMAGEMAP(image->format) ) msDrawMarkerSymbolIM(map, image, p, style, scalefactor); } return ret; }
int msAddLabelGroup(mapObj *map, int layerindex, int classindex, shapeObj *shape, pointObj *point, double featuresize) { int i, priority, numactivelabels=0; labelCacheSlotObj *cacheslot; labelCacheMemberObj *cachePtr=NULL; layerObj *layerPtr=NULL; classObj *classPtr=NULL; layerPtr = (GET_LAYER(map, layerindex)); /* set up a few pointers for clarity */ classPtr = GET_LAYER(map, layerindex)->class[classindex]; if(classPtr->numlabels == 0) return MS_SUCCESS; /* not an error just nothing to do */ for(i=0; i<classPtr->numlabels; i++) { if(classPtr->labels[i]->status == MS_ON) { numactivelabels++; } } if(numactivelabels == 0) return MS_SUCCESS; /* if the number of labels is 1 then call msAddLabel() accordingly */ if(numactivelabels == 1) { for(i=0; i<classPtr->numlabels; i++) { if(classPtr->labels[i]->status == MS_ON) return msAddLabel(map, classPtr->labels[i], layerindex, classindex, shape, point, NULL, featuresize); } } if (layerPtr->type == MS_LAYER_ANNOTATION && (classPtr->numlabels > 1 || classPtr->leader.maxdistance)) { msSetError(MS_MISCERR, "Multiple Labels and/or LEADERs are not supported with annotation layers", "msAddLabelGroup()"); return MS_FAILURE; } /* check that the label intersects the layer mask */ if(layerPtr->mask) { int maskLayerIdx = msGetLayerIndex(map,layerPtr->mask); layerObj *maskLayer = GET_LAYER(map,maskLayerIdx); unsigned char *alphapixptr; if(maskLayer->maskimage && MS_IMAGE_RENDERER(maskLayer->maskimage)->supports_pixel_buffer) { rasterBufferObj rb; int x,y; memset(&rb,0,sizeof(rasterBufferObj)); MS_IMAGE_RENDERER(maskLayer->maskimage)->getRasterBufferHandle(maskLayer->maskimage,&rb); 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) { #ifdef USE_GD if(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) { /* label point does not intersect mask */ return MS_SUCCESS; } } else { if(!gdImageGetPixel(rb.data.gd_img,x,y)) return MS_SUCCESS; } #else 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) { /* label point does not intersect mask */ return MS_SUCCESS; } #endif } } else { msSetError(MS_MISCERR, "Layer (%s) references references a mask layer, but the selected renderer does not support them", "msAddLabelGroup()", layerPtr->name); return (MS_FAILURE); } } /* 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) priority = 1; else if (priority > MS_MAX_LABEL_PRIORITY) priority = MS_MAX_LABEL_PRIORITY; cacheslot = &(map->labelcache.slots[priority-1]); if(cacheslot->numlabels == cacheslot->cachesize) { /* just add it to the end */ cacheslot->labels = (labelCacheMemberObj *) realloc(cacheslot->labels, sizeof(labelCacheMemberObj)*(cacheslot->cachesize+MS_LABELCACHEINCREMENT)); MS_CHECK_ALLOC(cacheslot->labels, sizeof(labelCacheMemberObj)*(cacheslot->cachesize+MS_LABELCACHEINCREMENT), MS_FAILURE); cacheslot->cachesize += MS_LABELCACHEINCREMENT; } cachePtr = &(cacheslot->labels[cacheslot->numlabels]); cachePtr->layerindex = layerindex; /* so we can get back to this *raw* data if necessary */ cachePtr->classindex = classindex; if(shape) { cachePtr->shapetype = shape->type; } else { cachePtr->shapetype = MS_SHAPE_POINT; } cachePtr->point = *point; /* the actual label point */ cachePtr->labelpath = NULL; cachePtr->leaderline = NULL; cachePtr->leaderbbox = NULL; // cachePtr->text = msStrdup(string); /* the actual text */ /* TODO: perhaps we can get rid of this next section and just store a marker size? Why do we cache the styles for a point layer? */ /* copy the styles (only if there is an accompanying marker) * We cannot simply keep refs because the rendering code might alters some members of the style objects */ cachePtr->styles = NULL; cachePtr->numstyles = 0; if(layerPtr->type == MS_LAYER_ANNOTATION && classPtr->numstyles > 0) { cachePtr->numstyles = classPtr->numstyles; cachePtr->styles = (styleObj *) msSmallMalloc(sizeof(styleObj)*classPtr->numstyles); if (classPtr->numstyles > 0) { for(i=0; i<classPtr->numstyles; i++) { initStyle(&(cachePtr->styles[i])); msCopyStyle(&(cachePtr->styles[i]), classPtr->styles[i]); } } } /* ** copy the labels (we are guaranteed to have more than one): ** we cannot simply keep refs because the rendering code alters some members of the style objects */ cachePtr->numlabels = 0; cachePtr->labels = (labelObj *) msSmallMalloc(sizeof(labelObj)*numactivelabels); for(i=0; i<classPtr->numlabels; i++) { if(classPtr->labels[i]->status == MS_OFF) continue; initLabel(&(cachePtr->labels[cachePtr->numlabels])); msCopyLabel(&(cachePtr->labels[cachePtr->numlabels]), classPtr->labels[i]); cachePtr->numlabels++; } assert(cachePtr->numlabels == numactivelabels); cachePtr->markerid = -1; cachePtr->featuresize = featuresize; //cachePtr->poly = (shapeObj *) msSmallMalloc(sizeof(shapeObj)); //msInitShape(cachePtr->poly); cachePtr->poly = NULL; cachePtr->status = MS_FALSE; if(layerPtr->type == MS_LAYER_POINT && classPtr->numstyles > 0) { /* cache the marker placement, it's already on the map */ /* TO DO: at the moment only checks the bottom style, perhaps should check all of them */ /* #2347: after RFC-24 classPtr->styles could be NULL so we check it */ rectObj rect; double w, h; if(msGetMarkerSize(&map->symbolset, classPtr->styles[0], &w, &h, layerPtr->scalefactor) != MS_SUCCESS) return(MS_FAILURE); if(cacheslot->nummarkers == cacheslot->markercachesize) { /* just add it to the end */ cacheslot->markers = (markerCacheMemberObj *) realloc(cacheslot->markers, sizeof(markerCacheMemberObj)*(cacheslot->cachesize+MS_LABELCACHEINCREMENT)); MS_CHECK_ALLOC(cacheslot->markers, sizeof(markerCacheMemberObj)*(cacheslot->cachesize+MS_LABELCACHEINCREMENT), MS_FAILURE); cacheslot->markercachesize+=MS_LABELCACHEINCREMENT; } i = cacheslot->nummarkers; cacheslot->markers[i].poly = (shapeObj *) msSmallMalloc(sizeof(shapeObj)); msInitShape(cacheslot->markers[i].poly); rect.minx = (point->x - .5 * w); rect.miny = (point->y - .5 * h); rect.maxx = rect.minx + (w-1); rect.maxy = rect.miny + (h-1); msRectToPolygon(rect, cacheslot->markers[i].poly); cacheslot->markers[i].id = cacheslot->numlabels; cachePtr->markerid = i; cacheslot->nummarkers++; } cacheslot->numlabels++; /* Maintain main labelCacheObj.numlabels only for backwards compatibility */ map->labelcache.numlabels++; return(MS_SUCCESS); }