1 /******************************************************************************
2 * $Id$
3 *
4 * Project: MapServer
5 * Purpose: Rendering utility functions
6 * Author: Thomas Bonfort and the MapServer team.
7 *
8 ******************************************************************************
9 * Copyright (c) 1996-2011 Regents of the University of Minnesota.
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies of this Software or works derived from this Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 *****************************************************************************/
29
30 #include "mapserver.h"
31 #include "mapcopy.h"
32 #include "fontcache.h"
33
computeSymbolStyle(symbolStyleObj * s,styleObj * src,symbolObj * symbol,double scalefactor,double resolutionfactor)34 void computeSymbolStyle(symbolStyleObj *s, styleObj *src, symbolObj *symbol, double scalefactor,
35 double resolutionfactor)
36 {
37 double default_size;
38 double target_size;
39 double style_size;
40
41 default_size = msSymbolGetDefaultSize(symbol);
42 style_size = (src->size==-1)?default_size:src->size;
43
44 INIT_SYMBOL_STYLE(*s);
45 if(symbol->type == MS_SYMBOL_PIXMAP) {
46 s->color = s->outlinecolor = NULL;
47 } else if(symbol->filled || symbol->type == MS_SYMBOL_TRUETYPE) {
48 if(MS_VALID_COLOR(src->color))
49 s->color = &src->color;
50 if(MS_VALID_COLOR(src->outlinecolor))
51 s->outlinecolor = &src->outlinecolor;
52 } else {
53 if(MS_VALID_COLOR(src->color))
54 s->outlinecolor = &(src->color);
55 else if(MS_VALID_COLOR(src->outlinecolor))
56 s->outlinecolor = &(src->outlinecolor);
57 s->color = NULL;
58 }
59
60
61 if(MS_VALID_COLOR(src->backgroundcolor)) {
62 s->backgroundcolor = &(src->backgroundcolor);
63 }
64
65 target_size = style_size * scalefactor;
66 target_size = MS_MAX(target_size, src->minsize*resolutionfactor);
67 target_size = MS_MIN(target_size, src->maxsize*resolutionfactor);
68 s->scale = target_size / default_size;
69 s->gap = src->gap * target_size / style_size;
70
71 if(s->outlinecolor) {
72 s->outlinewidth = src->width * scalefactor;
73 s->outlinewidth = MS_MAX(s->outlinewidth, src->minwidth*resolutionfactor);
74 s->outlinewidth = MS_MIN(s->outlinewidth, src->maxwidth*resolutionfactor);
75 } else {
76 s->outlinewidth = 0;
77 }
78
79 s->rotation = src->angle * MS_DEG_TO_RAD;
80 }
81
82
83 #define COMPARE_COLORS(a,b) (\
84 ((a).red==(b).red) && \
85 ((a).green==(b).green) && \
86 ((a).blue==(b).blue) && \
87 ((a).alpha==(b).alpha))
88
searchTileCache(imageObj * img,symbolObj * symbol,symbolStyleObj * s,int width,int height)89 tileCacheObj *searchTileCache(imageObj *img, symbolObj *symbol, symbolStyleObj *s, int width, int height)
90 {
91 tileCacheObj *cur = img->tilecache;
92 while(cur != NULL) {
93 if( cur->width == width
94 && cur->height == height
95 && cur->symbol == symbol
96 && cur->outlinewidth == s->outlinewidth
97 && cur->rotation == s->rotation
98 && cur->scale == s->scale
99 && (!s->color || COMPARE_COLORS(cur->color,*s->color))
100 && (!s->backgroundcolor || COMPARE_COLORS(cur->backgroundcolor,*s->backgroundcolor))
101 && (!s->outlinecolor || COMPARE_COLORS(cur->outlinecolor,*s->outlinecolor)))
102 return cur;
103 cur = cur->next;
104 }
105 return NULL;
106 }
107
preloadSymbol(symbolSetObj * symbolset,symbolObj * symbol,rendererVTableObj * renderer)108 int preloadSymbol(symbolSetObj *symbolset, symbolObj *symbol, rendererVTableObj *renderer) {
109 switch(symbol->type) {
110 case MS_SYMBOL_VECTOR:
111 case MS_SYMBOL_ELLIPSE:
112 case MS_SYMBOL_SIMPLE:
113 case (MS_SYMBOL_TRUETYPE):
114 break;
115 case (MS_SYMBOL_SVG):
116 #if defined(USE_SVG_CAIRO) || defined(USE_RSVG)
117 return msPreloadSVGSymbol(symbol);
118 #else
119 msSetError(MS_SYMERR, "SVG symbol support is not enabled.", "preloadSymbol()");
120 return MS_FAILURE;
121 #endif
122 break;
123 case (MS_SYMBOL_PIXMAP): {
124 if(!symbol->pixmap_buffer) {
125 if(MS_SUCCESS != msPreloadImageSymbol(renderer,symbol))
126 return MS_FAILURE;
127 }
128 }
129 break;
130 default:
131 msSetError(MS_MISCERR,"unsupported symbol type %d", "preloadSymbol()", symbol->type);
132 return MS_FAILURE;
133 }
134 return MS_SUCCESS;
135 }
136
137 /* add a cached tile to the current image's cache */
addTileCache(imageObj * img,imageObj * tile,symbolObj * symbol,symbolStyleObj * style,int width,int height)138 tileCacheObj *addTileCache(imageObj *img,
139 imageObj *tile, symbolObj *symbol, symbolStyleObj *style, int width, int height)
140 {
141 tileCacheObj *cachep;
142
143 if(img->ntiles >= MS_IMAGECACHESIZE) { /* remove last element, size stays the same */
144 cachep = img->tilecache;
145
146 /*go to the before last cache object*/
147 while(cachep->next && cachep->next->next) cachep = cachep->next;
148
149 /*free the last tile's data*/
150 msFreeImage(cachep->next->image);
151
152 /*reuse the last tile object*/
153 /* make the cache point to the start of the list*/
154 cachep->next->next = img->tilecache;
155 /* point the global cache to the new first */
156 img->tilecache = cachep->next;
157 /* the before last cache is now last, so it has no successor*/
158 cachep->next = NULL;
159
160 } else {
161 img->ntiles += 1;
162 cachep = (tileCacheObj*)malloc(sizeof(tileCacheObj));
163 MS_CHECK_ALLOC(cachep, sizeof(tileCacheObj), NULL);
164 cachep->next = img->tilecache;
165 img->tilecache = cachep;
166 }
167
168 cachep = img->tilecache;
169
170 cachep->image = tile;
171 cachep->outlinewidth = style->outlinewidth;
172 cachep->scale = style->scale;
173 cachep->rotation = style->rotation;
174 cachep->outlinewidth = style->outlinewidth;
175 if(style->color) MS_COPYCOLOR(&cachep->color,style->color);
176 if(style->outlinecolor) MS_COPYCOLOR(&cachep->outlinecolor,style->outlinecolor);
177 if(style->backgroundcolor) MS_COPYCOLOR(&cachep->backgroundcolor,style->backgroundcolor);
178 cachep->width = width;
179 cachep->height = height;
180 cachep->symbol = symbol;
181 return(cachep);
182 }
183
184 /* helper function to center glyph on the desired point */
drawGlyphMarker(imageObj * img,face_element * face,glyph_element * glyphc,double px,double py,int size,double rotation,colorObj * clr,colorObj * oclr,int olwidth)185 int WARN_UNUSED drawGlyphMarker(imageObj *img, face_element *face, glyph_element *glyphc, double px, double py, int size, double rotation,
186 colorObj *clr, colorObj *oclr, int olwidth)
187 {
188 double ox, oy;
189 textPathObj path;
190 glyphObj glyph;
191 rendererVTableObj *renderer = img->format->vtable;
192 if(!renderer->renderGlyphs) return MS_FAILURE;
193 path.numglyphs = 1;
194 glyph.glyph = glyphc;
195 glyph.face = face;
196 path.glyphs = &glyph;
197 path.glyph_size = size;
198 glyph.rot = rotation;
199 ox = (glyphc->metrics.maxx + glyphc->metrics.minx) / 2.0;
200 oy = (glyphc->metrics.maxy + glyphc->metrics.miny) / 2.0;
201 if(rotation != 0) {
202 double sina, cosa;
203 double rox,roy;
204 sina = sin(rotation);
205 cosa = cos(rotation);
206 rox = ox * cosa - oy * sina;
207 roy = ox * sina + oy * cosa;
208 px -= rox;
209 py += roy;
210 glyph.pnt.x = px;
211 glyph.pnt.y = py;
212 } else {
213 glyph.pnt.x = px - ox;
214 glyph.pnt.y = py + oy;
215 }
216 return renderer->renderGlyphs(img, &path, clr, oclr, olwidth, MS_TRUE);
217 }
218
219
getTile(imageObj * img,symbolObj * symbol,symbolStyleObj * s,int width,int height,int seamlessmode)220 imageObj *getTile(imageObj *img, symbolObj *symbol, symbolStyleObj *s, int width, int height,
221 int seamlessmode)
222 {
223 tileCacheObj *tile;
224 int status = MS_SUCCESS;
225 rendererVTableObj *renderer = img->format->vtable;
226 if(width==-1 || height == -1) {
227 width=height=MS_MAX(symbol->sizex,symbol->sizey);
228 }
229 tile = searchTileCache(img,symbol,s,width,height);
230
231 if(tile==NULL) {
232 imageObj *tileimg;
233 double p_x,p_y;
234 tileimg = msImageCreate(width,height,img->format,NULL,NULL,img->resolution, img->resolution, NULL);
235 if(UNLIKELY(!tileimg)) {
236 return NULL;
237 }
238 if(!seamlessmode) {
239 p_x = width/2.0;
240 p_y = height/2.0;
241 switch(symbol->type) {
242 case (MS_SYMBOL_TRUETYPE):
243 {
244 unsigned int unicode;
245 glyph_element *glyphc;
246 face_element *face = msGetFontFace(symbol->font, &img->map->fontset);
247 if(UNLIKELY(!face)) { status = MS_FAILURE; break; }
248 msUTF8ToUniChar(symbol->character, &unicode);
249 unicode = msGetGlyphIndex(face,unicode);
250 glyphc = msGetGlyphByIndex(face, MS_MAX(MS_NINT(s->scale),1), unicode);
251 if(UNLIKELY(!glyphc)) { status = MS_FAILURE; break; }
252 status = drawGlyphMarker(tileimg, face, glyphc, p_x, p_y, s->scale, s->rotation,
253 s->color, s->outlinecolor, s->outlinewidth);
254 }
255 break;
256 case (MS_SYMBOL_PIXMAP):
257 status = msPreloadImageSymbol(renderer,symbol);
258 if(UNLIKELY(status == MS_FAILURE)) { break; }
259 status = renderer->renderPixmapSymbol(tileimg, p_x, p_y, symbol, s);
260 break;
261 case (MS_SYMBOL_ELLIPSE):
262 status = renderer->renderEllipseSymbol(tileimg, p_x, p_y,symbol, s);
263 break;
264 case (MS_SYMBOL_VECTOR):
265 status = renderer->renderVectorSymbol(tileimg, p_x, p_y, symbol, s);
266 break;
267
268 case (MS_SYMBOL_SVG):
269 #if defined(USE_SVG_CAIRO) || defined(USE_RSVG)
270 status = msPreloadSVGSymbol(symbol);
271 if(LIKELY(status == MS_SUCCESS)) {
272 if (renderer->supports_svg) {
273 status = renderer->renderSVGSymbol(tileimg, p_x, p_y, symbol, s);
274 } else {
275 status = msRenderRasterizedSVGSymbol(tileimg,p_x,p_y,symbol, s);
276 }
277 }
278 #else
279 msSetError(MS_SYMERR, "SVG symbol support is not enabled.", "getTile()");
280 status = MS_FAILURE;
281 #endif
282 break;
283 default:
284 msSetError(MS_SYMERR, "Unknown symbol type %d", "getTile()", symbol->type);
285 status = MS_FAILURE;
286 break;
287 }
288 if(UNLIKELY(status == MS_FAILURE)) {
289 msFreeImage(tileimg);
290 return NULL;
291 }
292 } else {
293 /*
294 * in seamless mode, we render the the symbol 9 times on a 3x3 grid to account for
295 * antialiasing blending from one tile to the next. We finally keep the center tile
296 */
297 imageObj *tile3img = msImageCreate(width*3,height*3,img->format,NULL,NULL,
298 img->resolution, img->resolution, NULL);
299 int i,j;
300 rasterBufferObj tmpraster;
301 for(i=1; i<=3; i++) {
302 p_x = (i+0.5)*width;
303 for(j=1; j<=3; j++) {
304 p_y = (j+0.5) * height;
305 switch(symbol->type) {
306 case (MS_SYMBOL_TRUETYPE):
307 {
308 unsigned int unicode;
309 glyph_element *glyphc;
310 face_element *face = msGetFontFace(symbol->font, &img->map->fontset);
311 if(UNLIKELY(!face)) { status = MS_FAILURE; break; }
312 msUTF8ToUniChar(symbol->character, &unicode);
313 unicode = msGetGlyphIndex(face,unicode);
314 glyphc = msGetGlyphByIndex(face, MS_MAX(MS_NINT(s->scale),1), unicode);
315 if(UNLIKELY(!glyphc)) { status = MS_FAILURE; break; }
316 status = drawGlyphMarker(tileimg, face, glyphc, p_x, p_y, s->scale, s->rotation,
317 s->color, s->outlinecolor, s->outlinewidth);
318 }
319 break;
320 case (MS_SYMBOL_PIXMAP):
321 status = msPreloadImageSymbol(renderer,symbol);
322 if(UNLIKELY(status == MS_FAILURE)) { break; }
323 status = renderer->renderPixmapSymbol(tile3img, p_x, p_y, symbol, s);
324 break;
325 case (MS_SYMBOL_ELLIPSE):
326 status = renderer->renderEllipseSymbol(tile3img, p_x, p_y,symbol, s);
327 break;
328 case (MS_SYMBOL_VECTOR):
329 status = renderer->renderVectorSymbol(tile3img, p_x, p_y, symbol, s);
330 break;
331 default:
332 msSetError(MS_SYMERR, "BUG: Seamless mode is only for vector symbols", "getTile()");
333 return NULL;
334 }
335 if(UNLIKELY(status == MS_FAILURE)) {
336 msFreeImage(tile3img);
337 return NULL;
338 }
339 }
340 }
341 if(UNLIKELY(status == MS_FAILURE)) {
342 msFreeImage(tile3img);
343 return NULL;
344 }
345
346 status = MS_IMAGE_RENDERER(tile3img)->getRasterBufferHandle(tile3img,&tmpraster);
347 if(UNLIKELY(status == MS_FAILURE)) {
348 msFreeImage(tile3img);
349 return NULL;
350 }
351 status = renderer->mergeRasterBuffer(tileimg,
352 &tmpraster,
353 1.0,width,height,0,0,width,height
354 );
355 msFreeImage(tile3img);
356 }
357 if(UNLIKELY(status == MS_FAILURE)) {
358 msFreeImage(tileimg);
359 return NULL;
360 }
361 tile = addTileCache(img,tileimg,symbol,s,width,height);
362 }
363 return tile->image;
364 }
365
msImagePolylineMarkers(imageObj * image,shapeObj * p,symbolObj * symbol,symbolStyleObj * style,double spacing,double initialgap,int auto_angle)366 int msImagePolylineMarkers(imageObj *image, shapeObj *p, symbolObj *symbol,
367 symbolStyleObj *style, double spacing,
368 double initialgap, int auto_angle)
369 {
370 rendererVTableObj *renderer = MS_IMAGE_RENDERER(image);
371 int i,j;
372 pointObj point;
373 double original_rotation = style->rotation;
374 double symbol_width,symbol_height;
375 glyph_element *glyphc = NULL;
376 face_element *face = NULL;
377 int ret = MS_SUCCESS;
378 if(symbol->type != MS_SYMBOL_TRUETYPE) {
379 symbol_width = MS_MAX(1,symbol->sizex*style->scale);
380 symbol_height = MS_MAX(1,symbol->sizey*style->scale);
381 } else {
382 unsigned int unicode;
383 msUTF8ToUniChar(symbol->character, &unicode);
384 face = msGetFontFace(symbol->font, &image->map->fontset);
385 if(UNLIKELY(!face)) return MS_FAILURE;
386 unicode = msGetGlyphIndex(face,unicode);
387 glyphc = msGetGlyphByIndex(face, MS_MAX(MS_NINT(style->scale),1), unicode);
388 if(UNLIKELY(!glyphc)) return MS_FAILURE;
389 symbol_width = glyphc->metrics.maxx - glyphc->metrics.minx;
390 symbol_height = glyphc->metrics.maxy - glyphc->metrics.miny;
391 }
392 for(i=0; i<p->numlines; i++) {
393 int line_in = 0;
394 double line_length=0;
395 double current_length;
396 if(initialgap < 0) {
397 current_length = spacing/2.0; /* initial padding for each line */
398 } else {
399 current_length = initialgap; /* initial padding for each line */
400 }
401 for(j=1; j<p->line[i].numpoints; j++) {
402 double rx,ry,theta,length;
403 length = sqrt((pow((p->line[i].point[j].x - p->line[i].point[j-1].x),2) + pow((p->line[i].point[j].y - p->line[i].point[j-1].y),2)));
404 line_length += length;
405 if(length==0)continue;
406 rx = (p->line[i].point[j].x - p->line[i].point[j-1].x)/length;
407 ry = (p->line[i].point[j].y - p->line[i].point[j-1].y)/length;
408
409 if (auto_angle) {
410 theta = asin(ry);
411 if(rx < 0) {
412 theta += MS_PI;
413 } else theta = -theta;
414 style->rotation = original_rotation + theta;
415 }
416 while (current_length <= length) {
417
418 point.x = p->line[i].point[j - 1].x + current_length * rx;
419 point.y = p->line[i].point[j - 1].y + current_length * ry;
420 if(symbol->anchorpoint_x != 0.5 || symbol->anchorpoint_y != 0.5) {
421 double ox, oy;
422 ox = (0.5 - symbol->anchorpoint_x) * symbol_width;
423 oy = (0.5 - symbol->anchorpoint_y) * symbol_height;
424 if(style->rotation != 0) {
425 double sina,cosa;
426 double rox,roy;
427 sina = sin(-style->rotation);
428 cosa = cos(-style->rotation);
429 rox = ox * cosa - oy * sina;
430 roy = ox * sina + oy * cosa;
431 point.x += rox;
432 point.y += roy;
433 } else {
434 point.x += ox;
435 point.y += oy;
436 }
437 }
438
439 /* if the point is not in the map extent, skip it. (POLYLINE_NO_CLIP) */
440 if ( (point.x < -(symbol_width) || point.x > (image->width+symbol_width)) ||
441 (point.y < -(symbol_height) || point.y > (image->height+symbol_height)) ) {
442 current_length += spacing;
443 line_in=1;
444 continue;
445 }
446
447 switch (symbol->type) {
448 case MS_SYMBOL_PIXMAP:
449 ret = renderer->renderPixmapSymbol(image, point.x, point.y, symbol, style);
450 break;
451 case MS_SYMBOL_ELLIPSE:
452 ret = renderer->renderEllipseSymbol(image, point.x, point.y, symbol, style);
453 break;
454 case MS_SYMBOL_VECTOR:
455 ret = renderer->renderVectorSymbol(image, point.x, point.y, symbol, style);
456 break;
457 case MS_SYMBOL_TRUETYPE:
458 ret = drawGlyphMarker(image, face, glyphc, point.x, point.y, style->scale, style->rotation,
459 style->color, style->outlinecolor, style->outlinewidth);
460 break;
461 case (MS_SYMBOL_SVG):
462 #if defined(USE_SVG_CAIRO) || defined(USE_RSVG)
463 if (renderer->supports_svg) {
464 ret = renderer->renderSVGSymbol(image, point.x, point.y, symbol, style);
465 } else {
466 ret = msRenderRasterizedSVGSymbol(image,point.x,point.y,symbol, style);
467 }
468 #else
469 msSetError(MS_SYMERR, "SVG symbol support is not enabled.", "msImagePolylineMarkers()()");
470 ret = MS_FAILURE;
471 #endif
472 break;
473 }
474 if( ret != MS_SUCCESS)
475 return ret;
476 current_length += spacing;
477 line_in=1;
478 }
479
480 current_length -= length;
481 }
482
483 /*
484 * if we couldn't place a symbol on the line and no initialgap was
485 * specified, add one now we don't add the symbol if the line is shorter
486 * than the length of the symbol itself
487 */
488 if(initialgap < 0 && !line_in && line_length>symbol_width) {
489
490 /* total lengths of beginnning and end of current segment */
491 double before_length=0,after_length=0;
492
493 /*optimize*/
494 line_length /= 2.0;
495
496 for(j=1; j<p->line[i].numpoints; j++) {
497 double length;
498 length = sqrt((pow((p->line[i].point[j].x - p->line[i].point[j-1].x),2) + pow((p->line[i].point[j].y - p->line[i].point[j-1].y),2)));
499 after_length += length;
500 if(after_length>line_length) {
501 double rx,ry,theta;
502 /* offset where the symbol should be drawn on the current
503 * segment */
504 double offset = line_length - before_length;
505
506 rx = (p->line[i].point[j].x - p->line[i].point[j-1].x)/length;
507 ry = (p->line[i].point[j].y - p->line[i].point[j-1].y)/length;
508 if (auto_angle) {
509 theta = asin(ry);
510 if(rx < 0) {
511 theta += MS_PI;
512 } else theta = -theta;
513 style->rotation = original_rotation + theta;
514 }
515
516 point.x = p->line[i].point[j - 1].x + offset * rx;
517 point.y = p->line[i].point[j - 1].y + offset * ry;
518 switch (symbol->type) {
519 case MS_SYMBOL_PIXMAP:
520 ret = renderer->renderPixmapSymbol(image, point.x, point.y, symbol, style);
521 break;
522 case MS_SYMBOL_ELLIPSE:
523 ret = renderer->renderEllipseSymbol(image, point.x, point.y, symbol, style);
524 break;
525 case MS_SYMBOL_VECTOR:
526 ret = renderer->renderVectorSymbol(image, point.x, point.y, symbol, style);
527 break;
528 case MS_SYMBOL_TRUETYPE:
529 ret = drawGlyphMarker(image, face, glyphc, point.x, point.y, style->scale, style->rotation,
530 style->color, style->outlinecolor, style->outlinewidth);
531 break;
532 case (MS_SYMBOL_SVG):
533 #if defined(USE_SVG_CAIRO) || defined(USE_RSVG)
534 if (renderer->supports_svg) {
535 ret = renderer->renderSVGSymbol(image, point.x, point.y, symbol, style);
536 } else {
537 ret = msRenderRasterizedSVGSymbol(image,point.x,point.y,symbol, style);
538 }
539 #else
540 msSetError(MS_SYMERR, "SVG symbol support is not enabled.", "msImagePolylineMarkers()()");
541 ret = MS_FAILURE;
542 #endif
543 break;
544 }
545 break; /* we have rendered the single marker for this line */
546 }
547 before_length += length;
548 }
549 }
550
551 }
552 return ret;
553 }
554
msDrawLineSymbol(mapObj * map,imageObj * image,shapeObj * p,styleObj * style,double scalefactor)555 int msDrawLineSymbol(mapObj *map, imageObj *image, shapeObj *p,
556 styleObj *style, double scalefactor)
557 {
558 int status = MS_SUCCESS;
559 if (image) {
560 if (MS_RENDERER_PLUGIN(image->format)) {
561 rendererVTableObj *renderer = image->format->vtable;
562 symbolObj *symbol;
563 shapeObj *offsetLine = p;
564 int i;
565 double width;
566 double finalscalefactor;
567
568 if (p->numlines == 0)
569 return MS_SUCCESS;
570
571 if (style->symbol >= map->symbolset.numsymbols || style->symbol < 0)
572 return MS_SUCCESS; /* no such symbol, 0 is OK */
573
574 symbol = map->symbolset.symbol[style->symbol];
575 /* store a reference to the renderer to be used for freeing */
576 symbol->renderer = renderer;
577
578 width = style->width * scalefactor;
579 width = MS_MIN(width,style->maxwidth*image->resolutionfactor);
580 width = MS_MAX(width,style->minwidth*image->resolutionfactor);
581 if(style->width != 0) {
582 finalscalefactor = width / style->width;
583 } else {
584 finalscalefactor = 1.0;
585 }
586
587 if(style->offsety==MS_STYLE_SINGLE_SIDED_OFFSET) {
588 offsetLine = msOffsetPolyline(p,style->offsetx * finalscalefactor ,MS_STYLE_SINGLE_SIDED_OFFSET);
589 } else if(style->offsety==MS_STYLE_DOUBLE_SIDED_OFFSET) {
590 offsetLine = msOffsetPolyline(p,style->offsetx * finalscalefactor ,MS_STYLE_DOUBLE_SIDED_OFFSET);
591 } else if(style->offsetx!=0 || style->offsety!=0) {
592 offsetLine = msOffsetPolyline(p, style->offsetx * finalscalefactor,
593 style->offsety * finalscalefactor);
594 }
595 if(style->symbol == 0 || (symbol->type==MS_SYMBOL_SIMPLE)) {
596 strokeStyleObj s;
597 s.linecap = style->linecap;
598 s.linejoin = style->linejoin;
599 s.linejoinmaxsize = style->linejoinmaxsize;
600 s.width = width;
601 s.patternlength = style->patternlength;
602 for(i=0; i<s.patternlength; i++)
603 s.pattern[i] = style->pattern[i] * finalscalefactor;
604 s.patternoffset = (style->initialgap<=0) ? 0 : (style->initialgap * finalscalefactor);
605
606 if(MS_VALID_COLOR(style->color))
607 s.color = &style->color;
608 else if(MS_VALID_COLOR(style->outlinecolor))
609 s.color = &style->outlinecolor;
610 else {
611 /* msSetError(MS_MISCERR,"no color defined for line styling","msDrawLineSymbol()");
612 * not really an error */
613 status = MS_SUCCESS;
614 goto line_cleanup;
615 }
616 status = renderer->renderLine(image,offsetLine,&s);
617 } else {
618 symbolStyleObj s;
619 if(preloadSymbol(&map->symbolset, symbol, renderer) != MS_SUCCESS) {
620 status = MS_FAILURE;
621 goto line_cleanup;
622 }
623
624 INIT_SYMBOL_STYLE(s);
625 computeSymbolStyle(&s,style,symbol,scalefactor,image->resolutionfactor);
626 s.style = style;
627
628 /* compute a markerStyle and use it on the line */
629 if(style->gap<0) {
630 /* special function that treats any other symbol used as a marker, not a brush */
631 status = msImagePolylineMarkers(image,offsetLine,symbol,&s,-s.gap,
632 style->initialgap * finalscalefactor, 1);
633 } else if(style->gap>0) {
634 status = msImagePolylineMarkers(image,offsetLine,symbol,&s,s.gap,
635 style->initialgap * finalscalefactor,0);
636 } else {
637 if(renderer->renderLineTiled != NULL) {
638 int pw,ph;
639 imageObj* tile=NULL;
640 if(s.scale != 1) {
641 pw = MS_NINT(symbol->sizex * s.scale);
642 ph = MS_NINT(symbol->sizey * s.scale);
643 } else {
644 pw = symbol->sizex;
645 ph = symbol->sizey;
646 }
647 if(pw<1) pw=1;
648 if(ph<1) ph=1;
649 tile = getTile(image, symbol,&s,pw,ph,0);
650 status = renderer->renderLineTiled(image, offsetLine, tile);
651 } else {
652 msSetError(MS_RENDERERERR, "renderer does not support brushed lines", "msDrawLineSymbol()");
653 status = MS_FAILURE;
654 }
655 }
656 }
657
658 line_cleanup:
659 if(offsetLine!=p) {
660 msFreeShape(offsetLine);
661 msFree(offsetLine);
662 }
663 return status;
664 } else if( MS_RENDERER_IMAGEMAP(image->format) )
665 msDrawLineSymbolIM(map, image, p, style, scalefactor);
666 else {
667 msSetError(MS_RENDERERERR, "unsupported renderer", "msDrawShadeSymbol()");
668 status = MS_FAILURE;
669 }
670 } else {
671 status = MS_FAILURE;
672 }
673 return status;
674 }
675
msDrawShadeSymbol(mapObj * map,imageObj * image,shapeObj * p,styleObj * style,double scalefactor)676 int msDrawShadeSymbol(mapObj *map, imageObj *image, shapeObj *p, styleObj *style, double scalefactor)
677 {
678 int ret = MS_SUCCESS;
679 symbolObj *symbol;
680 if (!p)
681 return MS_SUCCESS;
682 if (p->numlines <= 0)
683 return MS_SUCCESS;
684
685 if (style->symbol >= map->symbolset.numsymbols || style->symbol < 0)
686 return MS_SUCCESS; /* no such symbol, 0 is OK */
687 symbol = map->symbolset.symbol[style->symbol];
688
689 /*
690 * if only an outlinecolor was defined, and not a color,
691 * switch to the line drawing function
692 *
693 * this behavior is kind of a mapfile hack, and must be
694 * kept for backwards compatibility
695 */
696 if (symbol->type != MS_SYMBOL_PIXMAP && symbol->type != MS_SYMBOL_SVG ) {
697 if (!MS_VALID_COLOR(style->color)) {
698 if(MS_VALID_COLOR(style->outlinecolor))
699 return msDrawLineSymbol(map, image, p, style, scalefactor);
700 else {
701 /* just do nothing if no color has been set */
702 return MS_SUCCESS;
703 }
704 }
705 }
706 if (image) {
707 if (MS_RENDERER_PLUGIN(image->format)) {
708 rendererVTableObj *renderer = image->format->vtable;
709 shapeObj *offsetPolygon = NULL;
710 /* store a reference to the renderer to be used for freeing */
711 if(style->symbol)
712 symbol->renderer = renderer;
713
714 if (style->offsetx != 0 || style->offsety != 0) {
715 if(style->offsety==MS_STYLE_SINGLE_SIDED_OFFSET) {
716 offsetPolygon = msOffsetPolyline(p, style->offsetx*scalefactor, MS_STYLE_SINGLE_SIDED_OFFSET);
717 } else if(style->offsety==MS_STYLE_DOUBLE_SIDED_OFFSET) {
718 offsetPolygon = msOffsetPolyline(p,style->offsetx * scalefactor ,MS_STYLE_DOUBLE_SIDED_OFFSET);
719 } else {
720 offsetPolygon = msOffsetPolyline(p, style->offsetx*scalefactor,style->offsety*scalefactor);
721 }
722 } else {
723 offsetPolygon=p;
724 }
725 /* simple polygon drawing, without any specific symbol.
726 * also draws an optional outline */
727 if(style->symbol == 0 || symbol->type == MS_SYMBOL_SIMPLE) {
728 ret = renderer->renderPolygon(image,offsetPolygon,&style->color);
729 if(ret != MS_SUCCESS) goto cleanup;
730 if(MS_VALID_COLOR(style->outlinecolor)) {
731 strokeStyleObj s;
732 INIT_STROKE_STYLE(s);
733 s.color = &style->outlinecolor;
734 s.color->alpha = style->color.alpha;
735 s.width = (style->width == 0)?scalefactor:style->width*scalefactor;
736 s.width = MS_MIN(s.width, style->maxwidth);
737 s.width = MS_MAX(s.width, style->minwidth);
738 ret = renderer->renderLine(image,offsetPolygon,&s);
739 }
740 goto cleanup; /*finished plain polygon*/
741 } else if(symbol->type == MS_SYMBOL_HATCH) {
742 double width, spacing;
743 double pattern[MS_MAXPATTERNLENGTH];
744 int i;
745
746 if(MS_VALID_COLOR(style->backgroundcolor)) {
747 ret = renderer->renderPolygon(image,offsetPolygon, &style->backgroundcolor);
748 if(ret != MS_SUCCESS) goto cleanup;
749 }
750 width = (style->width <= 0)?scalefactor:style->width*scalefactor;
751 width = MS_MIN(width, style->maxwidth*image->resolutionfactor);
752 width = MS_MAX(width, style->minwidth*image->resolutionfactor);
753 spacing = (style->size <= 0)?scalefactor:style->size*scalefactor;
754 spacing = MS_MIN(spacing, style->maxsize*image->resolutionfactor);
755 spacing = MS_MAX(spacing, style->minsize*image->resolutionfactor);
756
757 /* scale the pattern by the factor applied to the width */
758 for(i=0; i<style->patternlength; i++) {
759 pattern[i] = style->pattern[i]*width/style->width;
760 }
761
762 ret = msHatchPolygon(image,offsetPolygon,spacing,width,pattern,style->patternlength,style->angle, &style->color);
763 goto cleanup;
764 } else {
765 symbolStyleObj s;
766 int pw,ph;
767 imageObj *tile;
768 int seamless = 0;
769
770 if(preloadSymbol(&map->symbolset,symbol,renderer) != MS_SUCCESS) {
771 ret = MS_FAILURE;
772 goto cleanup;
773 }
774
775 INIT_SYMBOL_STYLE(s);
776 computeSymbolStyle(&s,style,symbol,scalefactor,image->resolutionfactor);
777 s.style = style;
778
779 if (!s.color && !s.outlinecolor && symbol->type != MS_SYMBOL_PIXMAP && symbol->type != MS_SYMBOL_SVG) {
780 ret = MS_SUCCESS; /* nothing to do (colors are required except for PIXMAP symbols */
781 goto cleanup;
782 }
783
784 if(s.backgroundcolor) {
785 ret = renderer->renderPolygon(image,offsetPolygon, s.backgroundcolor);
786 if(ret != MS_SUCCESS) goto cleanup;
787 }
788
789 if(s.scale != 1) {
790 if (s.gap > 0) {
791 pw = MS_MAX(MS_NINT(s.gap),symbol->sizex * s.scale);
792 ph = MS_MAX(MS_NINT(s.gap),symbol->sizey * s.scale);
793 } else {
794 pw = MS_NINT(symbol->sizex * s.scale);
795 ph = MS_NINT(symbol->sizey * s.scale);
796 }
797 } else {
798 if (s.gap > 0) {
799 pw = MS_MAX(s.gap,symbol->sizex);
800 ph = MS_MAX(s.gap,symbol->sizey);
801 } else {
802 pw = symbol->sizex;
803 ph = symbol->sizey;
804 }
805 }
806 if(pw<1) pw=1;
807 if(ph<1) ph=1;
808
809 /* if we're doing vector symbols with an antialiased pixel rendererer, we want to enable
810 * seamless mode, i.e. comute a tile that accounts for the blending of neighbouring
811 * tiles at the tile border
812 */
813 if(symbol->type == MS_SYMBOL_VECTOR && style->gap == 0 &&
814 (image->format->renderer == MS_RENDER_WITH_AGG ||
815 image->format->renderer == MS_RENDER_WITH_CAIRO_RASTER)) {
816 seamless = 1;
817 }
818 tile = getTile(image,symbol,&s,pw,ph,seamless);
819 ret = renderer->renderPolygonTiled(image,offsetPolygon, tile);
820 }
821
822 cleanup:
823 if (offsetPolygon != p) {
824 msFreeShape(offsetPolygon);
825 msFree(offsetPolygon);
826 }
827 return ret;
828 } else if( MS_RENDERER_IMAGEMAP(image->format) )
829 msDrawShadeSymbolIM(map, image, p, style, scalefactor);
830 }
831 return ret;
832 }
833
msDrawMarkerSymbol(mapObj * map,imageObj * image,pointObj * p,styleObj * style,double scalefactor)834 int msDrawMarkerSymbol(mapObj *map, imageObj *image, pointObj *p, styleObj *style,
835 double scalefactor)
836 {
837 int ret = MS_SUCCESS;
838 if (!p)
839 return MS_SUCCESS;
840 if (style->symbol >= map->symbolset.numsymbols || style->symbol <= 0)
841 return MS_SUCCESS; /* no such symbol, 0 is OK */
842
843 if (image) {
844 if(MS_RENDERER_PLUGIN(image->format)) {
845 rendererVTableObj *renderer = image->format->vtable;
846 symbolStyleObj s;
847 double p_x,p_y;
848 symbolObj *symbol = map->symbolset.symbol[style->symbol];
849 /* store a reference to the renderer to be used for freeing */
850 symbol->renderer = renderer;
851 if(preloadSymbol(&map->symbolset,symbol,renderer) != MS_SUCCESS) {
852 return MS_FAILURE;
853 }
854
855 computeSymbolStyle(&s,style,symbol,scalefactor,image->resolutionfactor);
856 s.style = style;
857 if (!s.color && !s.outlinecolor && symbol->type != MS_SYMBOL_PIXMAP &&
858 symbol->type != MS_SYMBOL_SVG) {
859 return MS_SUCCESS; // nothing to do if no color, except for pixmap symbols
860 }
861 if(s.scale == 0) {
862 return MS_SUCCESS;
863 }
864
865
866
867 /* TODO: skip the drawing of the symbol if it's smaller than a pixel ?
868 if (s.size < 1)
869 return; // size too small
870 */
871
872 p_x = p->x;
873 p_y = p->y;
874
875 if (style->polaroffsetpixel != 0 ||
876 style->polaroffsetangle != 0) {
877 double angle = style->polaroffsetangle * MS_DEG_TO_RAD;
878 p_x += (style->polaroffsetpixel * cos(-angle)) * scalefactor;
879 p_y += (style->polaroffsetpixel * sin(-angle)) * scalefactor;
880 }
881
882 p_x += style->offsetx * scalefactor;
883 p_y += style->offsety * scalefactor;
884
885 if(symbol->anchorpoint_x != 0.5 || symbol->anchorpoint_y != 0.5) {
886 double sx,sy;
887 double ox, oy;
888 if(UNLIKELY(MS_FAILURE == msGetMarkerSize(map, style, &sx, &sy, scalefactor))) {
889 return MS_FAILURE;
890 }
891 ox = (0.5 - symbol->anchorpoint_x) * sx;
892 oy = (0.5 - symbol->anchorpoint_y) * sy;
893 if(s.rotation != 0) {
894 double sina, cosa;
895 double rox,roy;
896 sina = sin(-s.rotation);
897 cosa = cos(-s.rotation);
898 rox = ox * cosa - oy * sina;
899 roy = ox * sina + oy * cosa;
900 p_x += rox;
901 p_y += roy;
902 } else {
903 p_x += ox;
904 p_y += oy;
905 }
906 }
907
908 if(renderer->use_imagecache) {
909 imageObj *tile = getTile(image, symbol, &s, -1, -1,0);
910 if(tile!=NULL)
911 return renderer->renderTile(image, tile, p_x, p_y);
912 else {
913 msSetError(MS_RENDERERERR, "problem creating cached tile", "msDrawMarkerSymbol()");
914 return MS_FAILURE;
915 }
916 }
917 switch (symbol->type) {
918 case (MS_SYMBOL_TRUETYPE): {
919 unsigned int unicode;
920 glyph_element *glyphc;
921 face_element *face = msGetFontFace(symbol->font, &map->fontset);
922 if(UNLIKELY(!face)) return MS_FAILURE;
923 msUTF8ToUniChar(symbol->character,&unicode);
924 unicode = msGetGlyphIndex(face,unicode);
925 glyphc = msGetGlyphByIndex(face, MS_MAX(MS_NINT(s.scale),1), unicode);
926 if(UNLIKELY(!glyphc)) return MS_FAILURE;
927 ret = drawGlyphMarker(image, face, glyphc, p_x, p_y, s.scale, s.rotation, s.color, s.outlinecolor, s.outlinewidth);
928 }
929 break;
930 case (MS_SYMBOL_PIXMAP): {
931 assert(symbol->pixmap_buffer);
932 ret = renderer->renderPixmapSymbol(image,p_x,p_y,symbol,&s);
933 }
934 break;
935 case (MS_SYMBOL_ELLIPSE): {
936 ret = renderer->renderEllipseSymbol(image, p_x, p_y,symbol, &s);
937 }
938 break;
939 case (MS_SYMBOL_VECTOR): {
940 ret = renderer->renderVectorSymbol(image, p_x, p_y, symbol, &s);
941 }
942 break;
943 case (MS_SYMBOL_SVG): {
944 if (renderer->supports_svg) {
945 ret = renderer->renderSVGSymbol(image, p_x, p_y, symbol, &s);
946 } else {
947 #if defined(USE_SVG_CAIRO) || defined(USE_RSVG)
948 ret = msRenderRasterizedSVGSymbol(image, p_x,p_y, symbol, &s);
949 #else
950 msSetError(MS_SYMERR, "SVG symbol support is not enabled.", "msDrawMarkerSymbol()");
951 return MS_FAILURE;
952 #endif
953 }
954 }
955 break;
956 default:
957 break;
958 }
959 return ret;
960 } else if( MS_RENDERER_IMAGEMAP(image->format) )
961 msDrawMarkerSymbolIM(map, image, p, style, scalefactor);
962
963 }
964 return ret;
965 }
966
967
msDrawLabelBounds(mapObj * map,imageObj * image,label_bounds * bnds,styleObj * style,double scalefactor)968 int msDrawLabelBounds(mapObj *map, imageObj *image, label_bounds *bnds, styleObj *style, double scalefactor)
969 {
970 /*
971 * helper function to draw label bounds, where we might have only a rectObj and not
972 * a lineObj/shapeObj
973 */
974 shapeObj shape;
975 shape.numlines = 1;
976 if(bnds->poly) {
977 shape.line = bnds->poly;
978 return msDrawShadeSymbol(map,image,&shape,style,scalefactor);
979 } else {
980 pointObj pnts1[5];
981 lineObj l;
982 l.point = pnts1;
983 l.numpoints = 5;
984 pnts1[0].x = pnts1[1].x = pnts1[4].x = bnds->bbox.minx;
985 pnts1[2].x = pnts1[3].x = bnds->bbox.maxx;
986 pnts1[0].y = pnts1[3].y = pnts1[4].y = bnds->bbox.miny;
987 pnts1[1].y = pnts1[2].y = bnds->bbox.maxy;
988 shape.line = &l; // must return from this block
989 return msDrawShadeSymbol(map,image,&shape,style,scalefactor);
990 }
991 }
992
msDrawTextSymbol(mapObj * map,imageObj * image,pointObj labelPnt,textSymbolObj * ts)993 int msDrawTextSymbol(mapObj *map, imageObj *image, pointObj labelPnt, textSymbolObj *ts)
994 {
995 rendererVTableObj *renderer = image->format->vtable;
996 colorObj *c = NULL, *oc = NULL;
997 int ow;
998 assert(ts->textpath);
999 if(!renderer->renderGlyphs) return MS_FAILURE;
1000
1001 if(!ts->textpath->absolute) {
1002 int g;
1003 double cosa,sina;
1004 double x = labelPnt.x;
1005 double y = labelPnt.y;
1006 if(ts->rotation != 0) {
1007 cosa = cos(ts->rotation);
1008 sina = sin(ts->rotation);
1009 for(g=0;g<ts->textpath->numglyphs;g++) {
1010 double ox = ts->textpath->glyphs[g].pnt.x;
1011 double oy = ts->textpath->glyphs[g].pnt.y;
1012 ts->textpath->glyphs[g].pnt.x = ox * cosa + oy * sina + x;
1013 ts->textpath->glyphs[g].pnt.y = -ox * sina + oy * cosa + y;
1014 ts->textpath->glyphs[g].rot = ts->rotation;
1015 }
1016 } else {
1017 for(g=0;g<ts->textpath->numglyphs;g++) {
1018 ts->textpath->glyphs[g].pnt.x += x;
1019 ts->textpath->glyphs[g].pnt.y += y;
1020 }
1021 }
1022 }
1023
1024 if(MS_VALID_COLOR(ts->label->shadowcolor)) {
1025 textSymbolObj *ts_shadow;
1026 int g;
1027 double ox, oy;
1028 double cosa,sina;
1029 int ret;
1030 if(ts->rotation != 0) {
1031 cosa = cos(ts->rotation);
1032 sina = sin(ts->rotation);
1033 ox = ts->scalefactor * (cosa * ts->label->shadowsizex +
1034 sina * ts->label->shadowsizey);
1035 oy = ts->scalefactor * (-sina * ts->label->shadowsizex +
1036 cosa * ts->label->shadowsizey);
1037 }
1038 else {
1039 ox = ts->scalefactor * ts->label->shadowsizex;
1040 oy = ts->scalefactor * ts->label->shadowsizey;
1041 }
1042
1043 ts_shadow = msSmallMalloc(sizeof(textSymbolObj));
1044 initTextSymbol(ts_shadow);
1045 msCopyTextSymbol(ts_shadow,ts);
1046
1047 for(g=0;g<ts_shadow->textpath->numglyphs;g++) {
1048 ts_shadow->textpath->glyphs[g].pnt.x += ox;
1049 ts_shadow->textpath->glyphs[g].pnt.y += oy;
1050 }
1051
1052 ret = renderer->renderGlyphs(image,ts_shadow->textpath,&ts->label->shadowcolor,NULL,0, MS_FALSE);
1053 freeTextSymbol(ts_shadow);
1054 msFree(ts_shadow);
1055 if( ret != MS_SUCCESS )
1056 return ret;
1057 }
1058
1059 if(MS_VALID_COLOR(ts->label->color))
1060 c = &ts->label->color;
1061 if(MS_VALID_COLOR(ts->label->outlinecolor))
1062 oc = &ts->label->outlinecolor;
1063 ow = MS_NINT((double)ts->label->outlinewidth * ((double)ts->textpath->glyph_size / (double)ts->label->size));
1064 return renderer->renderGlyphs(image,ts->textpath,c,oc,ow, MS_FALSE);
1065
1066 }
1067
1068 /************************************************************************/
1069 /* msCircleDrawLineSymbol */
1070 /* */
1071 /************************************************************************/
msCircleDrawLineSymbol(mapObj * map,imageObj * image,pointObj * p,double r,styleObj * style,double scalefactor)1072 int msCircleDrawLineSymbol(mapObj *map, imageObj *image, pointObj *p, double r, styleObj *style, double scalefactor)
1073 {
1074 shapeObj *circle;
1075 int status;
1076 if (!image) return MS_FAILURE;
1077 circle = msRasterizeArc(p->x, p->y, r, 0, 360, 0);
1078 if (!circle) return MS_FAILURE;
1079 status = msDrawLineSymbol(map, image, circle, style, scalefactor);
1080 msFreeShape(circle);
1081 msFree(circle);
1082 return status;
1083 }
1084
msCircleDrawShadeSymbol(mapObj * map,imageObj * image,pointObj * p,double r,styleObj * style,double scalefactor)1085 int msCircleDrawShadeSymbol(mapObj *map, imageObj *image, pointObj *p, double r, styleObj *style, double scalefactor)
1086 {
1087 shapeObj *circle;
1088 int status;
1089 if (!image) return MS_FAILURE;
1090 circle = msRasterizeArc(p->x, p->y, r, 0, 360, 0);
1091 if (!circle) return MS_FAILURE;
1092 status = msDrawShadeSymbol(map, image, circle, style, scalefactor);
1093 msFreeShape(circle);
1094 msFree(circle);
1095 return status;
1096 }
1097
msDrawPieSlice(mapObj * map,imageObj * image,pointObj * p,styleObj * style,double radius,double start,double end)1098 int msDrawPieSlice(mapObj *map, imageObj *image, pointObj *p, styleObj *style, double radius, double start, double end)
1099 {
1100 int status;
1101 shapeObj *circle;
1102 double center_x = p->x;
1103 double center_y = p->y;
1104 if (!image) return MS_FAILURE;
1105 if(style->offsetx>0) {
1106 center_x+=style->offsetx*cos(((-start-end)*MS_PI/360.));
1107 center_y-=style->offsetx*sin(((-start-end)*MS_PI/360.));
1108 }
1109 circle = msRasterizeArc(center_x, center_y, radius, start, end, 1);
1110 if (!circle) return MS_FAILURE;
1111 status = msDrawShadeSymbol(map, image, circle, style, 1.0);
1112 msFreeShape(circle);
1113 msFree(circle);
1114 return status;
1115 }
1116
1117 /*
1118 * RFC 49 implementation
1119 * if an outlinewidth is used:
1120 * - augment the style's width to account for the outline width
1121 * - swap the style color and outlinecolor
1122 * - draw the shape (the outline) in the first pass of the
1123 * caching mechanism
1124 */
1125
msOutlineRenderingPrepareStyle(styleObj * pStyle,mapObj * map,layerObj * layer,imageObj * image)1126 void msOutlineRenderingPrepareStyle(styleObj *pStyle, mapObj *map, layerObj *layer, imageObj *image)
1127 {
1128 colorObj tmp;
1129
1130 if (pStyle->outlinewidth > 0) {
1131 /* adapt width (must take scalefactor into account) */
1132 pStyle->width += (pStyle->outlinewidth / (layer->scalefactor/image->resolutionfactor)) * 2;
1133 pStyle->minwidth += pStyle->outlinewidth * 2;
1134 pStyle->maxwidth += pStyle->outlinewidth * 2;
1135 pStyle->size += (pStyle->outlinewidth/layer->scalefactor*(map->resolution/map->defresolution));
1136
1137 /*swap color and outlinecolor*/
1138 tmp = pStyle->color;
1139 pStyle->color = pStyle->outlinecolor;
1140 pStyle->outlinecolor = tmp;
1141 }
1142 }
1143
1144 /*
1145 * RFC 49 implementation: switch back the styleobj to its
1146 * original state, so the line fill will be drawn in the
1147 * second pass of the caching mechanism
1148 */
1149
msOutlineRenderingRestoreStyle(styleObj * pStyle,mapObj * map,layerObj * layer,imageObj * image)1150 void msOutlineRenderingRestoreStyle(styleObj *pStyle, mapObj *map, layerObj *layer, imageObj *image)
1151 {
1152 colorObj tmp;
1153
1154 if (pStyle->outlinewidth > 0) {
1155 /* reset widths to original state */
1156 pStyle->width -= (pStyle->outlinewidth / (layer->scalefactor/image->resolutionfactor)) * 2;
1157 pStyle->minwidth -= pStyle->outlinewidth * 2;
1158 pStyle->maxwidth -= pStyle->outlinewidth * 2;
1159 pStyle->size -= (pStyle->outlinewidth/layer->scalefactor*(map->resolution/map->defresolution));
1160
1161 /*reswap colors to original state*/
1162 tmp = pStyle->color;
1163 pStyle->color = pStyle->outlinecolor;
1164 pStyle->outlinecolor = tmp;
1165 }
1166 }
1167