/src/MapServer/src/mapsymbol.c
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * $Id$ |
3 | | * |
4 | | * Project: MapServer |
5 | | * Purpose: symbolObj related functions. |
6 | | * Author: Steve Lime and the MapServer team. |
7 | | * |
8 | | ****************************************************************************** |
9 | | * Copyright (c) 1996-2005 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 <stdarg.h> /* variable number of function arguments support */ |
31 | | #include <time.h> /* since the parser handles time/date we need this */ |
32 | | |
33 | | #include "mapserver.h" |
34 | | #include "mapfile.h" |
35 | | #include "mapcopy.h" |
36 | | #include "mapthread.h" |
37 | | #include "fontcache.h" |
38 | | #include "mapows.h" |
39 | | |
40 | | extern int msyylex(void); /* lexer globals */ |
41 | | extern void msyyrestart(FILE *); |
42 | | extern double msyynumber; |
43 | | extern char *msyystring_buffer; |
44 | | extern int msyylineno; |
45 | | extern FILE *msyyin; |
46 | | |
47 | | extern int msyystate; |
48 | | |
49 | 19.2k | void freeImageCache(struct imageCacheObj *ic) { |
50 | 19.2k | if (ic) { |
51 | 0 | freeImageCache(ic->next); /* free any children */ |
52 | 0 | msFreeRasterBuffer(&(ic->img)); |
53 | 0 | free(ic); |
54 | 0 | } |
55 | 19.2k | return; |
56 | 19.2k | } |
57 | | |
58 | | /* |
59 | | ** msSymbolGetDefaultSize() |
60 | | ** |
61 | | ** Return the default size of a symbol. |
62 | | ** Note: The size of a symbol is the height. Everywhere in the code, the width |
63 | | ** is adjusted to the size that becomes the height. |
64 | | ** See mapgd.c // size ~ height in pixels |
65 | | */ |
66 | 0 | double msSymbolGetDefaultSize(symbolObj *s) { |
67 | 0 | double size = 1; |
68 | 0 | if (s == NULL) |
69 | 0 | return 1; |
70 | | |
71 | 0 | switch (s->type) { |
72 | 0 | case (MS_SYMBOL_TRUETYPE): |
73 | 0 | break; |
74 | 0 | case (MS_SYMBOL_PIXMAP): |
75 | 0 | assert(s->pixmap_buffer != NULL); |
76 | 0 | if (s->pixmap_buffer == NULL) |
77 | 0 | return 1; /* FIXME */ |
78 | 0 | size = (double)s->pixmap_buffer->height; |
79 | 0 | break; |
80 | 0 | case (MS_SYMBOL_SVG): |
81 | | #if defined(USE_SVG_CAIRO) || defined(USE_RSVG) |
82 | | assert(s->renderer_cache != NULL); |
83 | | size = s->sizey; |
84 | | #endif |
85 | 0 | break; |
86 | 0 | default: /* vector and ellipses, scalable */ |
87 | 0 | size = (s->sizey <= 0) ? s->sizex : s->sizey; |
88 | 0 | break; |
89 | 0 | } |
90 | | |
91 | 0 | if (size <= 0) |
92 | 0 | return 1; |
93 | | |
94 | 0 | return size; |
95 | 0 | } |
96 | | |
97 | 21.9k | void initSymbol(symbolObj *s) { |
98 | 21.9k | MS_REFCNT_INIT(s); |
99 | 21.9k | s->type = MS_SYMBOL_VECTOR; |
100 | 21.9k | s->transparent = MS_FALSE; |
101 | 21.9k | s->transparentcolor = 0; |
102 | 21.9k | s->sizex = 1; |
103 | 21.9k | s->sizey = 1; |
104 | 21.9k | s->filled = MS_FALSE; |
105 | 21.9k | s->numpoints = 0; |
106 | 21.9k | s->renderer = NULL; |
107 | 21.9k | s->renderer_free_func = NULL; |
108 | 21.9k | s->renderer_cache = NULL; |
109 | 21.9k | s->pixmap_buffer = NULL; |
110 | 21.9k | s->imagepath = NULL; |
111 | 21.9k | s->name = NULL; |
112 | 21.9k | s->inmapfile = MS_FALSE; |
113 | 21.9k | s->font = NULL; |
114 | 21.9k | s->full_pixmap_path = NULL; |
115 | 21.9k | s->character = NULL; |
116 | 21.9k | s->anchorpoint_x = s->anchorpoint_y = 0.5; |
117 | 21.9k | } |
118 | | |
119 | 21.2k | int msFreeSymbol(symbolObj *s) { |
120 | 21.2k | if (!s) |
121 | 0 | return MS_FAILURE; |
122 | 21.2k | if (MS_REFCNT_DECR_IS_NOT_ZERO(s)) { |
123 | 0 | return MS_FAILURE; |
124 | 0 | } |
125 | | |
126 | 21.2k | if (s->name) |
127 | 1.31k | free(s->name); |
128 | 21.2k | if (s->renderer_free_func) { |
129 | 0 | s->renderer_free_func(s); |
130 | 21.2k | } else { |
131 | 21.2k | if (s->renderer != NULL) { |
132 | 0 | s->renderer->freeSymbol(s); |
133 | 0 | } |
134 | 21.2k | } |
135 | 21.2k | if (s->pixmap_buffer) { |
136 | 0 | msFreeRasterBuffer(s->pixmap_buffer); |
137 | 0 | free(s->pixmap_buffer); |
138 | 0 | } |
139 | | |
140 | 21.2k | if (s->font) |
141 | 2 | free(s->font); |
142 | 21.2k | msFree(s->full_pixmap_path); |
143 | 21.2k | if (s->imagepath) |
144 | 1.31k | free(s->imagepath); |
145 | 21.2k | if (s->character) |
146 | 0 | free(s->character); |
147 | | |
148 | 21.2k | return MS_SUCCESS; |
149 | 21.2k | } |
150 | | |
151 | 704 | int loadSymbol(symbolObj *s, char *symbolpath) { |
152 | 704 | int done = MS_FALSE; |
153 | 704 | char szPath[MS_MAXPATHLEN]; |
154 | | |
155 | 704 | initSymbol(s); |
156 | | |
157 | 2.35k | for (;;) { |
158 | 2.35k | switch (msyylex()) { |
159 | 441 | case (ANCHORPOINT): |
160 | 441 | if (getDouble(&(s->anchorpoint_x), MS_NUM_CHECK_RANGE, 0, 1) == -1) { |
161 | 5 | msSetError(MS_SYMERR, "ANCHORPOINT must be between 0 and 1", |
162 | 5 | "loadSymbol()"); |
163 | 5 | return -1; |
164 | 5 | } |
165 | 436 | if (getDouble(&(s->anchorpoint_y), MS_NUM_CHECK_RANGE, 0, 1) == -1) { |
166 | 3 | msSetError(MS_SYMERR, "ANCHORPOINT must be between 0 and 1", |
167 | 3 | "loadSymbol()"); |
168 | 3 | return (-1); |
169 | 3 | } |
170 | 433 | break; |
171 | | |
172 | 433 | case (ANTIALIAS): /*ignore*/ |
173 | 0 | msyylex(); |
174 | 0 | break; |
175 | 0 | case (CHARACTER): |
176 | 0 | if (getString(&s->character) == MS_FAILURE) |
177 | 0 | return (-1); |
178 | 0 | break; |
179 | 606 | case (END): /* do some error checking */ |
180 | 606 | if ((s->type == MS_SYMBOL_SVG) && (s->imagepath == NULL)) { |
181 | 0 | msSetError(MS_SYMERR, "Symbol of type SVG has no file path specified.", |
182 | 0 | "loadSymbol()"); |
183 | 0 | return (-1); |
184 | 0 | } |
185 | 606 | if ((s->type == MS_SYMBOL_PIXMAP) && (s->full_pixmap_path == NULL)) { |
186 | 0 | msSetError(MS_SYMERR, "Symbol of type PIXMAP has no image data.", |
187 | 0 | "loadSymbol()"); |
188 | 0 | return (-1); |
189 | 0 | } |
190 | 606 | if (((s->type == MS_SYMBOL_ELLIPSE) || (s->type == MS_SYMBOL_VECTOR)) && |
191 | 606 | (s->numpoints == 0)) { |
192 | 4 | msSetError(MS_SYMERR, |
193 | 4 | "Symbol of type VECTOR or ELLIPSE has no point data.", |
194 | 4 | "loadSymbol()"); |
195 | 4 | return (-1); |
196 | 4 | } |
197 | 602 | if (s->type == MS_SYMBOL_VECTOR) { |
198 | 601 | double minx = s->points[0].x; |
199 | 601 | double miny = s->points[0].y; |
200 | | /* should only negative points be shifted? (#4116)*/ |
201 | 601 | int shiftpositive = |
202 | 601 | ((s->anchorpoint_x != 0.5) || (s->anchorpoint_y != 0.5)); |
203 | 601 | int i; |
204 | 1.37k | for (i = 1; i < s->numpoints; i++) { |
205 | 775 | if (s->points[i].x != -99 && s->points[i].y != -99) { |
206 | 500 | if (s->points[i].x < minx) |
207 | 329 | minx = s->points[i].x; |
208 | 500 | if (s->points[i].y < miny) |
209 | 111 | miny = s->points[i].y; |
210 | 500 | } |
211 | 775 | } |
212 | 601 | if (minx < 0 || miny < 0 || |
213 | 601 | (shiftpositive && (minx != 0 || miny != 0))) { |
214 | 1.45k | for (i = 0; i < s->numpoints; i++) { |
215 | 1.06k | if (s->points[i].x != -99 && s->points[i].y != -99) { |
216 | 792 | s->points[i].x -= minx; |
217 | 792 | s->points[i].y -= miny; |
218 | 792 | } |
219 | 1.06k | } |
220 | 384 | s->sizex -= minx; |
221 | 384 | s->sizey -= miny; |
222 | 384 | } |
223 | 601 | } |
224 | | |
225 | 602 | return (0); |
226 | 0 | break; |
227 | 14 | case (EOF): |
228 | 14 | msSetError(MS_EOFERR, NULL, "loadSymbol()"); |
229 | 14 | return (-1); |
230 | 0 | break; |
231 | 0 | case (FILLED): |
232 | 0 | if ((s->filled = getSymbol(2, MS_TRUE, MS_FALSE)) == -1) |
233 | 0 | return (-1); |
234 | 0 | break; |
235 | 4 | case (FONT): |
236 | 4 | if (getString(&s->font) == MS_FAILURE) |
237 | 1 | return (-1); |
238 | 3 | break; |
239 | 151 | case (IMAGE): |
240 | 151 | if (msyylex() != MS_STRING) { /* get image location from next token */ |
241 | 3 | msSetError(MS_TYPEERR, "Parsing error near (%s):(line %d)", |
242 | 3 | "loadSymbol()", msyystring_buffer, msyylineno); |
243 | 3 | return (-1); |
244 | 3 | } |
245 | 148 | msFree(s->full_pixmap_path); |
246 | 148 | s->full_pixmap_path = |
247 | 148 | msStrdup(msBuildPath(szPath, symbolpath, msyystring_buffer)); |
248 | | /* Set imagepath */ |
249 | 148 | msFree(s->imagepath); |
250 | 148 | s->imagepath = msStrdup(msyystring_buffer); |
251 | 148 | break; |
252 | 113 | case (NAME): |
253 | 113 | if (getString(&s->name) == MS_FAILURE) |
254 | 3 | return (-1); |
255 | 110 | break; |
256 | 976 | case (POINTS): |
257 | 976 | done = MS_FALSE; |
258 | 976 | s->sizex = 0; |
259 | 976 | s->sizey = 0; |
260 | 2.72k | for (;;) { |
261 | 2.72k | switch (msyylex()) { |
262 | 949 | case (END): |
263 | 949 | done = MS_TRUE; |
264 | 949 | break; |
265 | 1.75k | case (MS_NUMBER): |
266 | 1.75k | if (s->numpoints == MS_MAXVECTORPOINTS) { |
267 | 2 | msSetError(MS_SYMERR, "POINT block contains too many points.", |
268 | 2 | "loadSymbol()"); |
269 | 2 | return (-1); |
270 | 2 | } |
271 | 1.75k | s->points[s->numpoints].x = atof(msyystring_buffer); /* grab the x */ |
272 | 1.75k | if (getDouble(&(s->points[s->numpoints].y), MS_NUM_CHECK_NONE, -1, |
273 | 1.75k | -1) == -1) |
274 | 11 | return (-1); /* grab the y */ |
275 | 1.74k | if (s->points[s->numpoints].x != -99) { |
276 | 1.49k | s->sizex = MS_MAX(s->sizex, s->points[s->numpoints].x); |
277 | 1.49k | s->sizey = MS_MAX(s->sizey, s->points[s->numpoints].y); |
278 | 1.49k | } |
279 | 1.74k | s->numpoints++; |
280 | 1.74k | break; |
281 | 14 | default: |
282 | 14 | msSetError(MS_TYPEERR, "Parsing error near (%s):(line %d)", |
283 | 14 | "loadSymbol()", msyystring_buffer, msyylineno); |
284 | 14 | return (-1); |
285 | 2.72k | } |
286 | | |
287 | 2.69k | if (done == MS_TRUE) |
288 | 949 | break; |
289 | 2.69k | } |
290 | 949 | break; |
291 | 949 | case (TRANSPARENT): |
292 | 7 | s->transparent = MS_TRUE; |
293 | 7 | if (getInteger(&(s->transparentcolor), MS_NUM_CHECK_RANGE, 0, 255) == -1) |
294 | 3 | return (-1); |
295 | 4 | break; |
296 | 4 | case (TYPE): |
297 | 4 | if ((s->type = getSymbol(8, MS_SYMBOL_VECTOR, MS_SYMBOL_ELLIPSE, |
298 | 4 | MS_SYMBOL_PIXMAP, MS_SYMBOL_SIMPLE, MS_TRUETYPE, |
299 | 4 | MS_SYMBOL_HATCH, MS_SYMBOL_SVG)) == -1) |
300 | 3 | return (-1); |
301 | 1 | if (s->type == |
302 | 1 | MS_TRUETYPE) /* TrueType keyword is valid several place in map files |
303 | | and symbol files, this simplifies the lexer */ |
304 | 1 | s->type = MS_SYMBOL_TRUETYPE; |
305 | 1 | break; |
306 | 36 | default: |
307 | 36 | msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", |
308 | 36 | "loadSymbol()", msyystring_buffer, msyylineno); |
309 | 36 | return (-1); |
310 | 2.35k | } /* end switch */ |
311 | 2.35k | } /* end for */ |
312 | 0 | return done; |
313 | 704 | } |
314 | | |
315 | 0 | void writeSymbol(symbolObj *s, FILE *stream) { |
316 | 0 | int i; |
317 | |
|
318 | 0 | msIO_fprintf(stream, " SYMBOL\n"); |
319 | 0 | if (s->name != NULL) |
320 | 0 | msIO_fprintf(stream, " NAME \"%s\"\n", s->name); |
321 | |
|
322 | 0 | switch (s->type) { |
323 | 0 | case (MS_SYMBOL_HATCH): |
324 | 0 | msIO_fprintf(stream, " TYPE HATCH\n"); |
325 | 0 | break; |
326 | 0 | case (MS_SYMBOL_PIXMAP): |
327 | 0 | msIO_fprintf(stream, " TYPE PIXMAP\n"); |
328 | 0 | if (s->imagepath != NULL) |
329 | 0 | msIO_fprintf(stream, " IMAGE \"%s\"\n", s->imagepath); |
330 | 0 | if (s->anchorpoint_y != 0.5 || s->anchorpoint_x != 0.5) { |
331 | 0 | msIO_fprintf(stream, " ANCHORPOINT %g %g\n", s->anchorpoint_x, |
332 | 0 | s->anchorpoint_y); |
333 | 0 | } |
334 | 0 | msIO_fprintf(stream, " TRANSPARENT %d\n", s->transparentcolor); |
335 | 0 | break; |
336 | 0 | case (MS_SYMBOL_TRUETYPE): |
337 | 0 | msIO_fprintf(stream, " TYPE TRUETYPE\n"); |
338 | 0 | if (s->character != NULL) |
339 | 0 | msIO_fprintf(stream, " CHARACTER \"%s\"\n", s->character); |
340 | 0 | if (s->font != NULL) |
341 | 0 | msIO_fprintf(stream, " FONT \"%s\"\n", s->font); |
342 | 0 | if (s->anchorpoint_y != 0.5 || s->anchorpoint_x != 0.5) { |
343 | 0 | msIO_fprintf(stream, " ANCHORPOINT %g %g\n", s->anchorpoint_x, |
344 | 0 | s->anchorpoint_y); |
345 | 0 | } |
346 | 0 | break; |
347 | 0 | default: |
348 | 0 | if (s->type == MS_SYMBOL_ELLIPSE) |
349 | 0 | msIO_fprintf(stream, " TYPE ELLIPSE\n"); |
350 | 0 | else if (s->type == MS_SYMBOL_VECTOR) |
351 | 0 | msIO_fprintf(stream, " TYPE VECTOR\n"); |
352 | 0 | else if (s->type == MS_SYMBOL_SVG) |
353 | 0 | msIO_fprintf(stream, " TYPE SVG\n"); |
354 | 0 | else |
355 | 0 | msIO_fprintf(stream, " TYPE SIMPLE\n"); |
356 | |
|
357 | 0 | if (s->filled == MS_TRUE) |
358 | 0 | msIO_fprintf(stream, " FILLED TRUE\n"); |
359 | 0 | if (s->imagepath != NULL) |
360 | 0 | msIO_fprintf(stream, " IMAGE \"%s\"\n", s->imagepath); |
361 | 0 | if (s->anchorpoint_y != 0.5 || s->anchorpoint_x != 0.5) { |
362 | 0 | msIO_fprintf(stream, " ANCHORPOINT %g %g\n", s->anchorpoint_x, |
363 | 0 | s->anchorpoint_y); |
364 | 0 | } |
365 | | |
366 | | /* POINTS */ |
367 | 0 | if (s->numpoints != 0) { |
368 | 0 | msIO_fprintf(stream, " POINTS\n"); |
369 | 0 | for (i = 0; i < s->numpoints; i++) { |
370 | 0 | msIO_fprintf(stream, " %g %g\n", s->points[i].x, s->points[i].y); |
371 | 0 | } |
372 | 0 | msIO_fprintf(stream, " END\n"); |
373 | 0 | } |
374 | 0 | break; |
375 | 0 | } |
376 | | |
377 | 0 | msIO_fprintf(stream, " END\n\n"); |
378 | 0 | } |
379 | | |
380 | | /* |
381 | | ** Little helper function to allow us to build symbol files on-the-fly |
382 | | ** from just a file name. |
383 | | ** |
384 | | ** Returns the symbol index or -1 if it could not be added. |
385 | | */ |
386 | 1.30k | int msAddImageSymbol(symbolSetObj *symbolset, const char *filename) { |
387 | 1.30k | char szPath[MS_MAXPATHLEN]; |
388 | 1.30k | symbolObj *symbol = NULL; |
389 | 1.30k | char *extension = NULL; |
390 | 1.30k | int symbolidx; |
391 | | |
392 | 1.30k | if (!symbolset) { |
393 | 0 | msSetError(MS_SYMERR, "Symbol structure unallocated.", |
394 | 0 | "msAddImageSymbol()"); |
395 | 0 | return (-1); |
396 | 0 | } |
397 | | |
398 | 1.30k | if (!filename || strlen(filename) == 0) |
399 | 3 | return (-1); |
400 | | |
401 | | /* Allocate/init memory for new symbol if needed */ |
402 | 1.29k | if (msGrowSymbolSet(symbolset) == NULL) |
403 | 0 | return -1; |
404 | 1.29k | symbolidx = symbolset->numsymbols; |
405 | 1.29k | symbolset->numsymbols++; |
406 | 1.29k | symbol = symbolset->symbol[symbolidx]; |
407 | | |
408 | | /* check if svg checking extension otherwise assume it's a pixmap */ |
409 | 1.29k | extension = strrchr(filename, '.'); |
410 | 1.29k | if (extension == NULL) |
411 | 432 | extension = ""; |
412 | 1.29k | if (strncasecmp(extension, ".svg", 4) == 0) { |
413 | 294 | symbol->type = MS_SYMBOL_SVG; |
414 | 1.00k | } else { |
415 | 1.00k | symbol->type = MS_SYMBOL_PIXMAP; |
416 | 1.00k | } |
417 | | |
418 | | #ifdef USE_CURL |
419 | | if (strncasecmp(filename, "http", 4) == 0) { |
420 | | char *tmpfullfilename = NULL; |
421 | | char *tmpfilename = NULL; |
422 | | char *tmppath = NULL; |
423 | | int status = 0; |
424 | | char szPath[MS_MAXPATHLEN]; |
425 | | int bCheckLocalCache = MS_TRUE; |
426 | | |
427 | | tmppath = msTmpPath(NULL, NULL, NULL); |
428 | | if (tmppath) { |
429 | | tmpfilename = msEncodeUrl(filename); |
430 | | tmpfullfilename = msBuildPath(szPath, tmppath, tmpfilename); |
431 | | if (tmpfullfilename) { |
432 | | /*use the url for now as a caching mechanism*/ |
433 | | if (msHTTPGetFile(filename, tmpfullfilename, &status, -1, |
434 | | bCheckLocalCache, 0, |
435 | | 1024 * 1024 /* 1 MegaByte */) == MS_SUCCESS) { |
436 | | symbol->imagepath = msStrdup(tmpfullfilename); |
437 | | symbol->full_pixmap_path = msStrdup(tmpfullfilename); |
438 | | } else { |
439 | | unlink(tmpfullfilename); |
440 | | msFree(tmpfilename); |
441 | | msFree(tmppath); |
442 | | return -1; |
443 | | } |
444 | | } |
445 | | msFree(tmpfilename); |
446 | | msFree(tmppath); |
447 | | } |
448 | | } |
449 | | #endif |
450 | | /*if the http did not work, allow it to be treated as a file*/ |
451 | 1.29k | if (!symbol->full_pixmap_path) { |
452 | 1.29k | if (symbolset->map) { |
453 | 1.29k | symbol->full_pixmap_path = |
454 | 1.29k | msStrdup(msBuildPath(szPath, symbolset->map->mappath, filename)); |
455 | 1.29k | } else { |
456 | 0 | symbol->full_pixmap_path = msStrdup(msBuildPath(szPath, NULL, filename)); |
457 | 0 | } |
458 | 1.29k | symbol->imagepath = msStrdup(filename); |
459 | 1.29k | } |
460 | 1.29k | symbol->name = msStrdup(filename); |
461 | 1.29k | return symbolidx; |
462 | 1.29k | } |
463 | | |
464 | 19.2k | int msFreeSymbolSet(symbolSetObj *symbolset) { |
465 | 19.2k | int i; |
466 | | |
467 | 19.2k | freeImageCache(symbolset->imagecache); |
468 | 40.4k | for (i = 0; i < symbolset->numsymbols; i++) { |
469 | 21.1k | if (symbolset->symbol[i] != NULL) { |
470 | 21.1k | if (msFreeSymbol((symbolset->symbol[i])) == MS_SUCCESS) { |
471 | 21.1k | msFree(symbolset->symbol[i]); |
472 | 21.1k | symbolset->symbol[i] = NULL; |
473 | 21.1k | } |
474 | 21.1k | } |
475 | 21.1k | } |
476 | 19.2k | msFree(symbolset->symbol); |
477 | | |
478 | | /* no need to deal with fontset, it's a pointer */ |
479 | 19.2k | return MS_SUCCESS; |
480 | 19.2k | } |
481 | | |
482 | 19.2k | void msInitSymbolSet(symbolSetObj *symbolset) { |
483 | 19.2k | symbolset->filename = NULL; |
484 | | |
485 | 19.2k | symbolset->imagecache = NULL; |
486 | 19.2k | symbolset->imagecachesize = 0; /* 0 symbols in the cache */ |
487 | | |
488 | 19.2k | symbolset->fontset = NULL; |
489 | 19.2k | symbolset->map = NULL; |
490 | | |
491 | 19.2k | symbolset->numsymbols = 0; |
492 | 19.2k | symbolset->maxsymbols = 0; |
493 | 19.2k | symbolset->symbol = NULL; |
494 | | |
495 | | /* Alloc symbol[] array and ensure there is at least 1 symbol: |
496 | | * symbol 0 which is the default symbol with all default params. |
497 | | */ |
498 | 19.2k | symbolObj *symbol = msGrowSymbolSet(symbolset); |
499 | 19.2k | if (symbol == NULL) |
500 | 0 | return; /* alloc failed */ |
501 | 19.2k | symbol->type = MS_SYMBOL_ELLIPSE; |
502 | 19.2k | symbol->filled = MS_TRUE; |
503 | 19.2k | symbol->numpoints = 1; |
504 | 19.2k | symbol->points[0].x = 1; |
505 | 19.2k | symbol->points[0].y = 1; |
506 | | |
507 | | /* Just increment numsymbols to reserve symbol 0. |
508 | | * initSymbol() has already been called |
509 | | */ |
510 | 19.2k | symbolset->numsymbols = 1; |
511 | 19.2k | } |
512 | | |
513 | | /* |
514 | | ** Ensure there is at least one free entry in the symbol array of this |
515 | | ** symbolSetObj. Grow the allocated symbol[] array if necessary and |
516 | | ** allocate a new symbol for symbol[numsymbols] if there is not already one |
517 | | ** and call initSymbol() on it. |
518 | | ** |
519 | | ** This function is safe to use for the initial allocation of the symbol[] |
520 | | ** array as well (i.e. when maxsymbols==0 and symbol==NULL) |
521 | | ** |
522 | | ** Returns a reference to the new symbolObj on success, NULL on error. |
523 | | */ |
524 | 21.2k | symbolObj *msGrowSymbolSet(symbolSetObj *symbolset) { |
525 | | /* Do we need to increase the size of symbol[] by MS_SYMBOL_ALLOCSIZE? */ |
526 | 21.2k | if (symbolset->numsymbols == symbolset->maxsymbols) { |
527 | 19.2k | int i; |
528 | 19.2k | if (symbolset->maxsymbols == 0) { |
529 | | /* Initial allocation of array */ |
530 | 19.2k | symbolset->maxsymbols += MS_SYMBOL_ALLOCSIZE; |
531 | 19.2k | symbolset->numsymbols = 0; |
532 | 19.2k | symbolset->symbol = |
533 | 19.2k | (symbolObj **)malloc(symbolset->maxsymbols * sizeof(symbolObj *)); |
534 | 19.2k | } else { |
535 | | /* realloc existing array */ |
536 | 1 | symbolset->maxsymbols += MS_SYMBOL_ALLOCSIZE; |
537 | 1 | symbolset->symbol = (symbolObj **)realloc( |
538 | 1 | symbolset->symbol, symbolset->maxsymbols * sizeof(symbolObj *)); |
539 | 1 | } |
540 | | |
541 | 19.2k | if (symbolset->symbol == NULL) { |
542 | 0 | msSetError(MS_MEMERR, "Failed to allocate memory for symbol array.", |
543 | 0 | "msGrowSymbolSet()"); |
544 | 0 | return NULL; |
545 | 0 | } |
546 | | |
547 | 1.25M | for (i = symbolset->numsymbols; i < symbolset->maxsymbols; i++) |
548 | 1.23M | symbolset->symbol[i] = NULL; |
549 | 19.2k | } |
550 | | |
551 | 21.2k | if (symbolset->symbol[symbolset->numsymbols] == NULL) { |
552 | 21.2k | symbolset->symbol[symbolset->numsymbols] = |
553 | 21.2k | (symbolObj *)malloc(sizeof(symbolObj)); |
554 | 21.2k | if (symbolset->symbol[symbolset->numsymbols] == NULL) { |
555 | 0 | msSetError(MS_MEMERR, "Failed to allocate memory for a symbolObj", |
556 | 0 | "msGrowSymbolSet()"); |
557 | 0 | return NULL; |
558 | 0 | } |
559 | 21.2k | } |
560 | | |
561 | | /* Always call initSymbol() even if we didn't allocate a new symbolObj |
562 | | * Since it's possible to dynamically remove/reuse symbols */ |
563 | 21.2k | initSymbol(symbolset->symbol[symbolset->numsymbols]); |
564 | | |
565 | 21.2k | return symbolset->symbol[symbolset->numsymbols]; |
566 | 21.2k | } |
567 | | |
568 | | /* --------------------------------------------------------------------------- |
569 | | msLoadSymbolSet and loadSymbolSet |
570 | | |
571 | | msLoadSymbolSet wraps calls to loadSymbolSet with mutex acquisition and |
572 | | release. It should be used everywhere outside the mapfile loading |
573 | | phase of an application. loadSymbolSet should only be used when a mutex |
574 | | exists. It does not check for existence of a mutex! |
575 | | |
576 | | See bug 339 for more details -- SG. |
577 | | ------------------------------------------------------------------------ */ |
578 | | |
579 | 0 | int msLoadSymbolSet(symbolSetObj *symbolset, mapObj *map) { |
580 | 0 | int retval = MS_FAILURE; |
581 | |
|
582 | 0 | msAcquireLock(TLOCK_PARSER); |
583 | 0 | retval = loadSymbolSet(symbolset, map); |
584 | 0 | msReleaseLock(TLOCK_PARSER); |
585 | |
|
586 | 0 | return retval; |
587 | 0 | } |
588 | | |
589 | 1.83k | int loadSymbolSet(symbolSetObj *symbolset, mapObj *map) { |
590 | 1.83k | int status = 1; |
591 | 1.83k | char szPath[MS_MAXPATHLEN], *pszSymbolPath = NULL; |
592 | | |
593 | 1.83k | int foundSymbolSetToken = MS_FALSE; |
594 | 1.83k | int symbolSetLevel = 0; |
595 | 1.83k | int token; |
596 | | |
597 | 1.83k | if (!symbolset) { |
598 | 0 | msSetError(MS_SYMERR, "Symbol structure unallocated.", "loadSymbolSet()"); |
599 | 0 | return (-1); |
600 | 0 | } |
601 | | |
602 | 1.83k | symbolset->map = (mapObj *)map; |
603 | | |
604 | 1.83k | if (!symbolset->filename) |
605 | 1.82k | return (0); |
606 | | |
607 | | /* |
608 | | ** Open the file |
609 | | */ |
610 | 9 | if ((msyyin = fopen( |
611 | 9 | msBuildPath(szPath, symbolset->map->mappath, symbolset->filename), |
612 | 9 | "r")) == NULL) { |
613 | 6 | msSetError(MS_IOERR, "(%s)", "loadSymbolSet()", symbolset->filename); |
614 | 6 | return (-1); |
615 | 6 | } |
616 | | |
617 | 3 | pszSymbolPath = msGetPath(szPath); |
618 | | |
619 | 3 | msyystate = MS_TOKENIZE_FILE; /* restore lexer state to INITIAL, and do return |
620 | | comments */ |
621 | 3 | msyylex(); /* sets things up, but doesn't process any tokens */ |
622 | | |
623 | 3 | msyylineno = 0; /* reset line counter */ |
624 | 3 | msyyrestart(msyyin); /* flush the scanner - there's a better way but this |
625 | | works for now */ |
626 | | |
627 | | /* |
628 | | ** Read the symbol file |
629 | | */ |
630 | 3 | for (;;) { |
631 | 3 | token = msyylex(); |
632 | | |
633 | 3 | if (!foundSymbolSetToken && token != SYMBOLSET) { |
634 | 3 | msSetError(MS_IDENTERR, |
635 | 3 | "First token must be SYMBOLSET, this doesn't look like a " |
636 | 3 | "symbol file.", |
637 | 3 | "msLoadSymbolSet()"); |
638 | 3 | status = -1; |
639 | 3 | break; |
640 | 3 | } |
641 | | |
642 | 0 | switch (token) { |
643 | 0 | case (END): |
644 | 0 | if (--symbolSetLevel < 0) { |
645 | 0 | msSetError( |
646 | 0 | MS_IDENTERR, |
647 | 0 | "END token found outside SYMBOLSET context. When nesting multiple " |
648 | 0 | "SYMBOLSETs, make sure the SYMBOLSET/END pairs match.", |
649 | 0 | "msLoadSymbolSet()"); |
650 | 0 | status = -1; |
651 | 0 | } |
652 | 0 | break; |
653 | 0 | case (EOF): |
654 | 0 | status = 0; |
655 | 0 | break; |
656 | 0 | case (SYMBOL): |
657 | | /* Allocate/init memory for new symbol if needed */ |
658 | 0 | if (symbolSetLevel == 0) { |
659 | 0 | msSetError( |
660 | 0 | MS_IDENTERR, |
661 | 0 | "SYMBOL token found outside SYMBOLSET context. When nesting " |
662 | 0 | "multiple SYMBOLSETs, make sure the SYMBOLSET/END pairs match.", |
663 | 0 | "msLoadSymbolSet()"); |
664 | 0 | status = -1; |
665 | 0 | } else if (msGrowSymbolSet(symbolset) == NULL) { |
666 | 0 | status = -1; |
667 | 0 | } else if ((loadSymbol((symbolset->symbol[symbolset->numsymbols]), |
668 | 0 | pszSymbolPath) == -1)) |
669 | 0 | status = -1; |
670 | 0 | else |
671 | 0 | symbolset->numsymbols++; |
672 | 0 | break; |
673 | 0 | case (SYMBOLSET): |
674 | 0 | foundSymbolSetToken = MS_TRUE; |
675 | 0 | symbolSetLevel++; |
676 | 0 | break; |
677 | 0 | default: |
678 | 0 | msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", |
679 | 0 | "loadSymbolSet()", msyystring_buffer, msyylineno); |
680 | 0 | status = -1; |
681 | 0 | } /* end switch */ |
682 | | |
683 | 0 | if (status != 1) |
684 | 0 | break; |
685 | 0 | } /* end for */ |
686 | | |
687 | 3 | fclose(msyyin); |
688 | 3 | msyyin = NULL; |
689 | 3 | free(pszSymbolPath); |
690 | 3 | return (status); |
691 | 3 | } |
692 | | |
693 | | int msGetCharacterSize(mapObj *map, const char *font, int size, |
694 | 0 | const char *character, rectObj *r) { |
695 | 0 | unsigned int unicode, codepoint; |
696 | 0 | glyph_element *glyph; |
697 | 0 | face_element *face = msGetFontFace(font, &map->fontset); |
698 | 0 | if (MS_UNLIKELY(!face)) |
699 | 0 | return MS_FAILURE; |
700 | 0 | msUTF8ToUniChar(character, &unicode); |
701 | 0 | codepoint = msGetGlyphIndex(face, unicode); |
702 | 0 | glyph = msGetGlyphByIndex(face, size, codepoint); |
703 | 0 | if (MS_UNLIKELY(!glyph)) |
704 | 0 | return MS_FAILURE; |
705 | 0 | r->minx = glyph->metrics.minx; |
706 | 0 | r->maxx = glyph->metrics.maxx; |
707 | 0 | r->miny = -glyph->metrics.maxy; |
708 | 0 | r->maxy = -glyph->metrics.miny; |
709 | 0 | return MS_SUCCESS; |
710 | 0 | } |
711 | | |
712 | | /* |
713 | | ** Returns the size, in pixels, of a marker symbol defined by a specific style |
714 | | *and scalefactor. Used for annotation |
715 | | ** layer collision avoidance. A marker is made up of a number of styles so the |
716 | | *calling code must either do the looping |
717 | | ** itself or call this function for the bottom style which should be the |
718 | | *largest. |
719 | | */ |
720 | | int msGetMarkerSize(mapObj *map, styleObj *style, double *width, double *height, |
721 | 0 | double scalefactor) { |
722 | 0 | int size; |
723 | 0 | symbolObj *symbol; |
724 | 0 | *width = *height = 0; /* set a starting value */ |
725 | |
|
726 | 0 | if (style->symbol > map->symbolset.numsymbols || style->symbol < 0) |
727 | 0 | return (MS_FAILURE); /* no such symbol, 0 is OK */ |
728 | | |
729 | 0 | if (style->symbol == 0) { /* single point */ |
730 | 0 | *width = 1; |
731 | 0 | *height = 1; |
732 | 0 | return (MS_SUCCESS); |
733 | 0 | } |
734 | | |
735 | 0 | symbol = map->symbolset.symbol[style->symbol]; |
736 | 0 | if (symbol->type == MS_SYMBOL_PIXMAP && !symbol->pixmap_buffer) { |
737 | 0 | if (MS_SUCCESS != msPreloadImageSymbol(MS_MAP_RENDERER(map), symbol)) |
738 | 0 | return MS_FAILURE; |
739 | 0 | } |
740 | 0 | if (symbol->type == MS_SYMBOL_SVG && !symbol->renderer_cache) { |
741 | | #if defined(USE_SVG_CAIRO) || defined(USE_RSVG) |
742 | | if (MS_SUCCESS != msPreloadSVGSymbol(symbol)) |
743 | | return MS_FAILURE; |
744 | | #else |
745 | 0 | msSetError(MS_SYMERR, "SVG symbol support is not enabled.", |
746 | 0 | "msGetMarkerSize()"); |
747 | 0 | return MS_FAILURE; |
748 | 0 | #endif |
749 | 0 | } |
750 | 0 | if (style->size == -1) { |
751 | 0 | size = (msSymbolGetDefaultSize(symbol) * scalefactor); |
752 | 0 | } else |
753 | 0 | size = (style->size * scalefactor); |
754 | 0 | size = MS_MAX(size, style->minsize); |
755 | 0 | size = MS_MIN(size, style->maxsize); |
756 | |
|
757 | 0 | switch (symbol->type) { |
758 | | |
759 | 0 | case (MS_SYMBOL_TRUETYPE): { |
760 | 0 | rectObj gbounds; |
761 | 0 | if (MS_UNLIKELY(MS_FAILURE == msGetCharacterSize(map, symbol->font, size, |
762 | 0 | symbol->character, |
763 | 0 | &gbounds))) |
764 | 0 | return MS_FAILURE; |
765 | | |
766 | 0 | *width = MS_MAX(*width, (gbounds.maxx - gbounds.minx)); |
767 | 0 | *height = MS_MAX(*height, (gbounds.maxy - gbounds.miny)); |
768 | 0 | } |
769 | | |
770 | 0 | break; |
771 | | |
772 | 0 | case (MS_SYMBOL_PIXMAP): |
773 | 0 | if (size == 1) { |
774 | 0 | *width = MS_MAX(*width, symbol->pixmap_buffer->width); |
775 | 0 | *height = MS_MAX(*height, symbol->pixmap_buffer->height); |
776 | 0 | } else { |
777 | 0 | *width = MS_MAX(*width, |
778 | 0 | (((double)size / (double)symbol->pixmap_buffer->height) * |
779 | 0 | symbol->pixmap_buffer->width)); |
780 | 0 | *height = MS_MAX(*height, size); |
781 | 0 | } |
782 | 0 | break; |
783 | 0 | default: /* vector and ellipses, scalable */ |
784 | 0 | if (style->size > 0) { |
785 | 0 | *width = MS_MAX(*width, ((size / symbol->sizey) * symbol->sizex)); |
786 | 0 | *height = MS_MAX(*height, size); |
787 | 0 | } else { /* use symbol defaults */ |
788 | 0 | *width = MS_MAX(*width, symbol->sizex); |
789 | 0 | *height = MS_MAX(*height, symbol->sizey); |
790 | 0 | } |
791 | 0 | break; |
792 | 0 | } |
793 | | |
794 | 0 | return (MS_SUCCESS); |
795 | 0 | } |
796 | | |
797 | | /* |
798 | | * Add a default new symbol. If the symbol name exists |
799 | | * return the id of the symbol. |
800 | | */ |
801 | 0 | int msAddNewSymbol(mapObj *map, const char *name) { |
802 | 0 | int i = 0; |
803 | |
|
804 | 0 | if (!map || !name) |
805 | 0 | return -1; |
806 | | |
807 | 0 | i = msGetSymbolIndex(&map->symbolset, name, MS_TRUE); |
808 | 0 | if (i >= 0) |
809 | 0 | return i; |
810 | | |
811 | | /* Allocate memory for new symbol if needed */ |
812 | 0 | if (msGrowSymbolSet(&(map->symbolset)) == NULL) |
813 | 0 | return -1; |
814 | | |
815 | 0 | i = map->symbolset.numsymbols; |
816 | 0 | map->symbolset.symbol[i]->name = msStrdup(name); |
817 | |
|
818 | 0 | map->symbolset.numsymbols++; |
819 | |
|
820 | 0 | return i; |
821 | 0 | } |
822 | | |
823 | | /* msAppendSymbol and msRemoveSymbol are part of the work to resolve |
824 | | * MapServer bug 579. |
825 | | * http://mapserver.gis.umn.edu/bugs/show_bug.cgi?id=579 */ |
826 | | |
827 | 0 | int msAppendSymbol(symbolSetObj *symbolset, symbolObj *symbol) { |
828 | | /* Allocate memory for new symbol if needed */ |
829 | 0 | if (msGrowSymbolSet(symbolset) == NULL) |
830 | 0 | return -1; |
831 | | |
832 | | /* we need to free the symbolObj that was already allocated as we are |
833 | | going to replace it with the provided symbolObj*. Not the most efficient |
834 | | technique, but this function should be rarely called, and in any case only |
835 | | by mapscript. Another option could be to use msCopySymbol(), in which case |
836 | | the call to MS_REFCNT_INCR(symbol) should be removed.*/ |
837 | 0 | if (symbolset->symbol[symbolset->numsymbols]) { |
838 | 0 | msFreeSymbol(symbolset->symbol[symbolset->numsymbols]); |
839 | 0 | msFree(symbolset->symbol[symbolset->numsymbols]); |
840 | 0 | } |
841 | 0 | symbolset->symbol[symbolset->numsymbols] = symbol; |
842 | 0 | MS_REFCNT_INCR(symbol); |
843 | 0 | return symbolset->numsymbols++; |
844 | 0 | } |
845 | | |
846 | 0 | symbolObj *msRemoveSymbol(symbolSetObj *symbolset, int nSymbolIndex) { |
847 | 0 | int i; |
848 | 0 | symbolObj *symbol; |
849 | 0 | if (symbolset->numsymbols == 1) { |
850 | 0 | msSetError(MS_CHILDERR, "Cannot remove a symbolset's sole symbol", |
851 | 0 | "removeSymbol()"); |
852 | 0 | return NULL; |
853 | 0 | } else if (nSymbolIndex < 0 || nSymbolIndex >= symbolset->numsymbols) { |
854 | 0 | msSetError(MS_CHILDERR, "Cannot remove symbol, invalid nSymbolIndex %d", |
855 | 0 | "removeSymbol()", nSymbolIndex); |
856 | 0 | return NULL; |
857 | 0 | } else { |
858 | 0 | symbol = symbolset->symbol[nSymbolIndex]; |
859 | 0 | for (i = nSymbolIndex + 1; i < symbolset->numsymbols; i++) { |
860 | 0 | symbolset->symbol[i - 1] = symbolset->symbol[i]; |
861 | 0 | } |
862 | 0 | symbolset->symbol[i - 1] = NULL; |
863 | 0 | symbolset->numsymbols--; |
864 | 0 | MS_REFCNT_DECR(symbol); |
865 | | /* update symbol references in the map */ |
866 | 0 | if (symbolset->map) { |
867 | 0 | int l, c, s, lb; |
868 | 0 | layerObj *layer; |
869 | 0 | classObj *cl; |
870 | 0 | styleObj *style; |
871 | 0 | labelObj *label; |
872 | 0 | for (l = 0; l < symbolset->map->numlayers; l++) { |
873 | 0 | layer = GET_LAYER(symbolset->map, l); |
874 | 0 | for (c = 0; c < layer->numclasses; c++) { |
875 | 0 | cl = layer->class[c]; |
876 | 0 | for (s = 0; s < cl->numstyles; s++) { |
877 | 0 | style = cl->styles[s]; |
878 | 0 | if (style->symbol >= nSymbolIndex) |
879 | 0 | --style->symbol; |
880 | 0 | } |
881 | 0 | for (lb = 0; lb < cl->numlabels; lb++) { |
882 | 0 | label = cl->labels[lb]; |
883 | 0 | for (s = 0; s < label->numstyles; s++) { |
884 | 0 | style = label->styles[s]; |
885 | 0 | if (style->symbol >= nSymbolIndex) |
886 | 0 | --style->symbol; |
887 | 0 | } |
888 | 0 | } |
889 | 0 | } |
890 | 0 | } |
891 | | /* Update symbol references in labelcache */ |
892 | 0 | for (c = 0; c < MS_MAX_LABEL_PRIORITY; c++) { |
893 | 0 | labelCacheSlotObj *cacheslot = &(symbolset->map->labelcache.slots[c]); |
894 | 0 | for (l = 0; l < cacheslot->numlabels; l++) { |
895 | 0 | labelCacheMemberObj *cachePtr = &(cacheslot->labels[l]); |
896 | 0 | for (lb = 0; lb < cachePtr->numtextsymbols; lb++) { |
897 | 0 | label = cachePtr->textsymbols[lb]->label; |
898 | 0 | for (s = 0; s < label->numstyles; s++) { |
899 | 0 | style = label->styles[s]; |
900 | 0 | if (style->symbol >= nSymbolIndex) |
901 | 0 | --style->symbol; |
902 | 0 | } |
903 | 0 | } |
904 | 0 | } |
905 | 0 | } |
906 | 0 | } |
907 | 0 | return symbol; |
908 | 0 | } |
909 | 0 | } |
910 | | |
911 | 0 | int msSaveSymbolSetStream(symbolSetObj *symbolset, FILE *stream) { |
912 | 0 | int i; |
913 | 0 | if (!symbolset || !stream) { |
914 | 0 | msSetError(MS_SYMERR, "Cannot save symbolset.", "msSaveSymbolSetStream()"); |
915 | 0 | return MS_FAILURE; |
916 | 0 | } |
917 | | /* Don't ever write out the default symbol at index 0 */ |
918 | 0 | for (i = 1; i < symbolset->numsymbols; i++) { |
919 | 0 | if (!symbolset->symbol[i]->inmapfile) |
920 | 0 | writeSymbol((symbolset->symbol[i]), stream); |
921 | 0 | } |
922 | 0 | return MS_SUCCESS; |
923 | 0 | } |
924 | | |
925 | 0 | int msSaveSymbolSet(symbolSetObj *symbolset, const char *filename) { |
926 | 0 | FILE *stream; |
927 | 0 | int retval; |
928 | 0 | if (!filename || strlen(filename) == 0) { |
929 | 0 | msSetError(MS_SYMERR, "Invalid filename.", "msSaveSymbolSet()"); |
930 | 0 | return MS_FAILURE; |
931 | 0 | } |
932 | 0 | stream = fopen(filename, "w"); |
933 | 0 | if (stream) { |
934 | 0 | fprintf(stream, "SYMBOLSET\n"); |
935 | 0 | retval = msSaveSymbolSetStream(symbolset, stream); |
936 | 0 | fprintf(stream, "END\n"); |
937 | 0 | fclose(stream); |
938 | 0 | } else { |
939 | 0 | msSetError(MS_SYMERR, "Could not write to %s", "msSaveSymbolSet()", |
940 | 0 | filename); |
941 | 0 | retval = MS_FAILURE; |
942 | 0 | } |
943 | 0 | return retval; |
944 | 0 | } |
945 | | |
946 | 0 | int msLoadImageSymbol(symbolObj *symbol, const char *filename) { |
947 | 0 | msFree(symbol->full_pixmap_path); |
948 | 0 | symbol->full_pixmap_path = msStrdup(filename); |
949 | 0 | return MS_SUCCESS; |
950 | 0 | } |
951 | | |
952 | 0 | int msPreloadImageSymbol(rendererVTableObj *renderer, symbolObj *symbol) { |
953 | 0 | if (symbol->pixmap_buffer && symbol->renderer == renderer) |
954 | 0 | return MS_SUCCESS; |
955 | 0 | if (symbol->pixmap_buffer) { /* other renderer was used, start again */ |
956 | 0 | msFreeRasterBuffer(symbol->pixmap_buffer); |
957 | 0 | } else { |
958 | 0 | symbol->pixmap_buffer = |
959 | 0 | (rasterBufferObj *)calloc(1, sizeof(rasterBufferObj)); |
960 | 0 | } |
961 | 0 | if (MS_SUCCESS != renderer->loadImageFromFile(symbol->full_pixmap_path, |
962 | 0 | symbol->pixmap_buffer)) { |
963 | | /* Free pixmap_buffer already allocated */ |
964 | 0 | free(symbol->pixmap_buffer); |
965 | 0 | symbol->pixmap_buffer = NULL; |
966 | 0 | return MS_FAILURE; |
967 | 0 | } |
968 | 0 | symbol->renderer = renderer; |
969 | 0 | symbol->sizex = symbol->pixmap_buffer->width; |
970 | 0 | symbol->sizey = symbol->pixmap_buffer->height; |
971 | 0 | return MS_SUCCESS; |
972 | 0 | } |
973 | | |
974 | | /*********************************************************************** |
975 | | * msCopySymbol() * |
976 | | * * |
977 | | * Copy a symbolObj, using mapfile.c:initSymbol(), msCopyPoint() * |
978 | | * gdImageCreate(), gdImageCopy() * |
979 | | **********************************************************************/ |
980 | | |
981 | 0 | int msCopySymbol(symbolObj *dst, const symbolObj *src, mapObj *map) { |
982 | 0 | int i; |
983 | |
|
984 | 0 | initSymbol(dst); |
985 | |
|
986 | 0 | MS_COPYSTRING(dst->name, src->name); |
987 | 0 | MS_COPYSTELEM(type); |
988 | 0 | MS_COPYSTELEM(inmapfile); |
989 | | |
990 | | /* map is a special case */ |
991 | 0 | dst->map = map; |
992 | |
|
993 | 0 | MS_COPYSTELEM(sizex); |
994 | 0 | MS_COPYSTELEM(sizey); |
995 | 0 | MS_COPYSTELEM(anchorpoint_x); |
996 | 0 | MS_COPYSTELEM(anchorpoint_y); |
997 | |
|
998 | 0 | for (i = 0; i < src->numpoints; i++) { |
999 | 0 | MS_COPYPOINT(&(dst->points[i]), &(src->points[i])); |
1000 | 0 | } |
1001 | |
|
1002 | 0 | MS_COPYSTELEM(numpoints); |
1003 | 0 | MS_COPYSTELEM(filled); |
1004 | |
|
1005 | 0 | MS_COPYSTRING(dst->imagepath, src->imagepath); |
1006 | 0 | MS_COPYSTELEM(transparent); |
1007 | 0 | MS_COPYSTELEM(transparentcolor); |
1008 | 0 | MS_COPYSTRING(dst->character, src->character); |
1009 | 0 | MS_COPYSTRING(dst->font, src->font); |
1010 | 0 | MS_COPYSTRING(dst->full_pixmap_path, src->full_pixmap_path); |
1011 | |
|
1012 | 0 | return (MS_SUCCESS); |
1013 | 0 | } |
1014 | | |
1015 | | /*********************************************************************** |
1016 | | * msCopySymbolSet() * |
1017 | | * * |
1018 | | * Copy a symbolSetObj using msCopyFontSet(), msCopySymbol() * |
1019 | | **********************************************************************/ |
1020 | | |
1021 | 0 | int msCopySymbolSet(symbolSetObj *dst, const symbolSetObj *src, mapObj *map) { |
1022 | 0 | int i, return_value; |
1023 | |
|
1024 | 0 | MS_COPYSTRING(dst->filename, src->filename); |
1025 | |
|
1026 | 0 | dst->map = map; |
1027 | 0 | dst->fontset = &(map->fontset); |
1028 | | |
1029 | | /* Copy child symbols */ |
1030 | 0 | for (i = 0; i < src->numsymbols; i++) { |
1031 | 0 | if (msGrowSymbolSet(dst) == NULL) |
1032 | 0 | return MS_FAILURE; |
1033 | 0 | return_value = msCopySymbol(dst->symbol[i], src->symbol[i], map); |
1034 | 0 | if (return_value != MS_SUCCESS) { |
1035 | 0 | msSetError(MS_MEMERR, "Failed to copy symbol.", "msCopySymbolSet()"); |
1036 | 0 | return (MS_FAILURE); |
1037 | 0 | } |
1038 | 0 | dst->numsymbols++; |
1039 | 0 | } |
1040 | | |
1041 | | /* MS_COPYSTELEM(imagecachesize); */ |
1042 | | |
1043 | | /* I have a feeling that the code below is not quite right - Sean */ |
1044 | | /*copyProperty(&(dst->imagecache), &(src->imagecache), |
1045 | | sizeof(struct imageCacheObj)); |
1046 | | */ |
1047 | | |
1048 | 0 | dst->imagecachesize = 0; /* since we are not copying the cache set the cache |
1049 | | to NUNLL and the size to 0 (bug 1521) */ |
1050 | 0 | dst->imagecache = NULL; |
1051 | |
|
1052 | 0 | return (MS_SUCCESS); |
1053 | 0 | } |
1054 | | |
1055 | | static void get_bbox(pointObj *poiList, int numpoints, double *minx, |
1056 | 0 | double *miny, double *maxx, double *maxy) { |
1057 | 0 | int j; |
1058 | |
|
1059 | 0 | *minx = *maxx = poiList[0].x; |
1060 | 0 | *miny = *maxy = poiList[0].y; |
1061 | 0 | for (j = 1; j < numpoints; j++) { |
1062 | 0 | if ((poiList[j].x == -99.0) || (poiList[j].y == -99.0)) |
1063 | 0 | continue; |
1064 | 0 | *minx = MS_MIN(*minx, poiList[j].x); |
1065 | 0 | *maxx = MS_MAX(*maxx, poiList[j].x); |
1066 | 0 | *miny = MS_MIN(*miny, poiList[j].y); |
1067 | 0 | *maxy = MS_MAX(*maxy, poiList[j].y); |
1068 | 0 | } |
1069 | |
|
1070 | 0 | return; |
1071 | 0 | } |
1072 | | |
1073 | | /* |
1074 | | ** msRotateSymbol - Clockwise rotation of a symbol definition. Contributed |
1075 | | ** by MapMedia, with clean up by SDL. Currently only type VECTOR and PIXMAP |
1076 | | ** symbols are handled. |
1077 | | */ |
1078 | 0 | symbolObj *msRotateVectorSymbol(symbolObj *symbol, double angle) { |
1079 | 0 | double angle_rad = 0.0; |
1080 | 0 | double cos_a, sin_a; |
1081 | 0 | double minx = 0.0, miny = 0.0, maxx = 0.0, maxy = 0.0; |
1082 | 0 | symbolObj *newSymbol = NULL; |
1083 | 0 | double dp_x, dp_y, xcor, ycor; |
1084 | 0 | double TOL = 0.00000000001; |
1085 | 0 | int i; |
1086 | | |
1087 | | /* assert(symbol->type == MS_SYMBOL_VECTOR); */ |
1088 | |
|
1089 | 0 | newSymbol = (symbolObj *)malloc(sizeof(symbolObj)); |
1090 | 0 | msCopySymbol( |
1091 | 0 | newSymbol, symbol, |
1092 | 0 | NULL); /* TODO: do we really want to do this for all symbol types? */ |
1093 | |
|
1094 | 0 | angle_rad = (MS_DEG_TO_RAD * angle); |
1095 | |
|
1096 | 0 | sin_a = sin(angle_rad); |
1097 | 0 | cos_a = cos(angle_rad); |
1098 | |
|
1099 | 0 | dp_x = symbol->sizex * .5; /* get the shift vector at 0,0 */ |
1100 | 0 | dp_y = symbol->sizey * .5; |
1101 | | |
1102 | | /* center at 0,0 and rotate; then move back */ |
1103 | 0 | for (i = 0; i < symbol->numpoints; i++) { |
1104 | | /* don't rotate PENUP commands (TODO: should use a constant here) */ |
1105 | 0 | if ((symbol->points[i].x == -99.0) && (symbol->points[i].y == -99.0)) { |
1106 | 0 | newSymbol->points[i].x = -99.0; |
1107 | 0 | newSymbol->points[i].y = -99.0; |
1108 | 0 | continue; |
1109 | 0 | } |
1110 | | |
1111 | 0 | newSymbol->points[i].x = dp_x + ((symbol->points[i].x - dp_x) * cos_a - |
1112 | 0 | (symbol->points[i].y - dp_y) * sin_a); |
1113 | 0 | newSymbol->points[i].y = dp_y + ((symbol->points[i].x - dp_x) * sin_a + |
1114 | 0 | (symbol->points[i].y - dp_y) * cos_a); |
1115 | 0 | } |
1116 | | |
1117 | | /* get the new bbox of the symbol, because we need it to get the new |
1118 | | * dimensions of the new symbol */ |
1119 | 0 | get_bbox(newSymbol->points, newSymbol->numpoints, &minx, &miny, &maxx, &maxy); |
1120 | 0 | if ((fabs(minx) > TOL) || (fabs(miny) > TOL)) { |
1121 | 0 | xcor = |
1122 | 0 | minx * -1.0; /* symbols always start at 0,0 so get the shift vector */ |
1123 | 0 | ycor = miny * -1.0; |
1124 | 0 | for (i = 0; i < newSymbol->numpoints; i++) { |
1125 | 0 | if ((newSymbol->points[i].x == -99.0) && |
1126 | 0 | (newSymbol->points[i].y == -99.0)) |
1127 | 0 | continue; |
1128 | 0 | newSymbol->points[i].x = newSymbol->points[i].x + xcor; |
1129 | 0 | newSymbol->points[i].y = newSymbol->points[i].y + ycor; |
1130 | 0 | } |
1131 | | |
1132 | | /* update the bbox to get the final dimension values for the symbol */ |
1133 | 0 | get_bbox(newSymbol->points, newSymbol->numpoints, &minx, &miny, &maxx, |
1134 | 0 | &maxy); |
1135 | 0 | } |
1136 | |
|
1137 | 0 | newSymbol->sizex = maxx; |
1138 | 0 | newSymbol->sizey = maxy; |
1139 | 0 | return newSymbol; |
1140 | 0 | } |