1 /****************************************************************************
2 *
3 * MODULE:       Symbol library
4 *
5 * AUTHOR(S):    Radim Blazek
6 *
7 * PURPOSE:      Read symbol from a file to internal structure
8 *
9 * COPYRIGHT:    (C) 2001 by the GRASS Development Team
10 *
11 *               This program is free software under the GNU General Public
12 *   	    	License (>=v2). Read the file COPYING that comes with GRASS
13 *   	    	for details.
14 *
15 *****************************************************************************/
16 
17 #include <stdlib.h>
18 #include <string.h>
19 #include <dirent.h>
20 #include <grass/gis.h>
21 #include <grass/symbol.h>
22 #include <grass/glocale.h>
23 
24 static char key[100], data[500];
25 
26 /* Define currently processed part */
27 #define OBJ_NONE    0
28 #define OBJ_STRING  1
29 #define OBJ_POLYGON 2
30 #define OBJ_RING    3
31 
32 /* stores input to key an data */
get_key_data(char * buf)33 void get_key_data(char *buf)
34 {
35     char *p;
36 
37     G_debug(3, "  get_key_data(): %s", buf);
38 
39     data[0] = '\0';
40 
41     strcpy(key, buf);
42     p = strchr(key, ' ');
43     if (p == NULL)
44 	return;
45 
46     p[0] = '\0';
47 
48     p++;
49     if (strlen(p) > 0) {
50 	strcpy(data, p);
51 	G_chop(data);
52     }
53     G_debug(3, "  key = %s data = %s", key, data);
54 }
55 
56 /* --- SYMBOL --- */
57 /* create new empty symbol */
new_symbol(void)58 SYMBOL *new_symbol(void)
59 {
60     SYMBOL *p;
61 
62     p = (SYMBOL *) G_malloc(sizeof(SYMBOL));
63     p->scale = 1.0;
64     p->count = 0;
65     p->alloc = 0;
66     p->part = NULL;
67     return p;
68 }
69 
70 /* add part to symbol */
add_part(SYMBOL * s,SYMBPART * p)71 void add_part(SYMBOL * s, SYMBPART * p)
72 {
73     if (s->count == s->alloc) {
74 	s->alloc += 10;
75 	s->part =
76 	    (SYMBPART **) G_realloc(s->part, s->alloc * sizeof(SYMBPART *));
77     }
78     s->part[s->count] = p;
79     s->count++;
80 }
81 
82 /* --- PART --- */
83 /* create new empty part */
new_part(int type)84 SYMBPART *new_part(int type)
85 {
86     SYMBPART *p;
87 
88     p = (SYMBPART *) G_malloc(sizeof(SYMBPART));
89     p->type = type;
90     p->count = 0;
91     p->alloc = 0;
92     p->chain = NULL;
93     p->color.color = S_COL_DEFAULT;
94     p->fcolor.color = S_COL_DEFAULT;
95     return p;
96 }
97 
98 /* add chain to part */
add_chain(SYMBPART * p,SYMBCHAIN * s)99 void add_chain(SYMBPART * p, SYMBCHAIN * s)
100 {
101     if (p->count == p->alloc) {
102 	p->alloc += 10;
103 	p->chain =
104 	    (SYMBCHAIN **) G_realloc(p->chain,
105 				     p->alloc * sizeof(SYMBCHAIN *));
106     }
107     p->chain[p->count] = s;
108     p->count++;
109 }
110 
111 
112 /* --- CHAIN --- */
113 /* create new empty chain */
new_chain(void)114 SYMBCHAIN *new_chain(void)
115 {
116     SYMBCHAIN *p;
117 
118     p = (SYMBCHAIN *) G_malloc(sizeof(SYMBCHAIN));
119     p->count = 0;
120     p->alloc = 0;
121     p->elem = NULL;
122     p->scount = 0;
123     p->salloc = 0;
124     p->sx = NULL;
125     p->sy = NULL;
126     return p;
127 }
128 
129 /* add element to chain */
add_element(SYMBCHAIN * s,SYMBEL * e)130 void add_element(SYMBCHAIN * s, SYMBEL * e)
131 {
132     if (s->count == s->alloc) {
133 	s->alloc += 10;
134 	s->elem = (SYMBEL **) G_realloc(s->elem, s->alloc * sizeof(SYMBEL *));
135     }
136     s->elem[s->count] = e;
137     s->count++;
138 }
139 
140 /* --- ELEMENT --- */
141 /* create new empty line */
new_line(void)142 SYMBEL *new_line(void)
143 {
144     SYMBEL *p;
145 
146     p = (SYMBEL *) G_malloc(sizeof(SYMBEL));
147     p->type = S_LINE;
148     p->coor.line.count = 0;
149     p->coor.line.alloc = 0;
150     p->coor.line.x = NULL;
151     p->coor.line.y = NULL;
152     return p;
153 }
154 
155 /* add point to line */
add_point(SYMBEL * el,double x,double y)156 void add_point(SYMBEL * el, double x, double y)
157 {
158     if (el->coor.line.count == el->coor.line.alloc) {
159 	el->coor.line.alloc += 10;
160 	el->coor.line.x =
161 	    (double *)G_realloc(el->coor.line.x,
162 				el->coor.line.alloc * sizeof(double));
163 	el->coor.line.y =
164 	    (double *)G_realloc(el->coor.line.y,
165 				el->coor.line.alloc * sizeof(double));
166     }
167     el->coor.line.x[el->coor.line.count] = x;
168     el->coor.line.y[el->coor.line.count] = y;
169     el->coor.line.count++;
170 }
171 
172 /* create new arc */
new_arc(double x,double y,double r,double a1,double a2,int c)173 SYMBEL *new_arc(double x, double y, double r, double a1, double a2, int c)
174 {
175     SYMBEL *p;
176 
177     p = (SYMBEL *) G_malloc(sizeof(SYMBEL));
178     p->type = S_ARC;
179     p->coor.arc.clock = c;
180     p->coor.arc.x = x;
181     p->coor.arc.y = y;
182     p->coor.arc.r = r;
183     p->coor.arc.a1 = a1;
184     p->coor.arc.a2 = a2;
185     return p;
186 }
187 
188 /* read line coordinates */
read_coor(FILE * fp,SYMBEL * e)189 void read_coor(FILE * fp, SYMBEL * e)
190 {
191     char buf[501];
192     double x, y;
193 
194     G_debug(5, "    read_coor()");
195 
196     while (G_getl2(buf, 500, fp) != 0) {
197 	G_chop(buf);
198 
199 	/* skip empty and comment lines */
200 	if ((buf[0] == '#') || (buf[0] == '\0'))
201 	    continue;
202 
203 	get_key_data(buf);
204 
205 	if (strcmp(key, "END") == 0) {
206 	    G_debug(5, "    LINE END");
207 	    return;
208 	}
209 
210 	if (sscanf(buf, "%lf %lf", &x, &y) != 2) {
211 	    G_warning(_("Cannot read symbol line coordinates: %s"), buf);
212 	    return;
213 	}
214 	G_debug(5, "      x = %f y = %f", x, y);
215 	add_point(e, x, y);
216     }
217 }
218 
219 /* close file free symbol, print message, return NULL */
err(FILE * fp,SYMBOL * s,char * msg)220 SYMBOL *err(FILE * fp, SYMBOL * s, char *msg)
221 {
222     fclose(fp);
223     G_free(s);			/* TODO: free all */
224     G_warning(msg, "%s");
225     return NULL;
226 }
227 
228 /*
229  *  Read symbol specified by name.
230  *  Name: group/name | group/name@mapset
231  *        (later add syntax to prefer symbol from GISBASE)
232  *  S_read() searches first in mapsets (standard GRASS search) and
233  *   then in GISBASE/etc/symbol/
234  */
S_read(const char * sname)235 SYMBOL *S_read(const char *sname)
236 {
237     int i, j, k, l;
238     FILE *fp;
239     char group[500], name[500], buf[2001];
240     const char *ms;
241     char *c;
242     double x, y, x2, y2, rad, ang1, ang2;
243     int r, g, b;
244     double fr, fg, fb;
245     int ret;
246     char clock;
247     SYMBOL *symb;
248     int current;		/* current part_type */
249     SYMBPART *part;		/* current part */
250     SYMBCHAIN *chain;		/* current chain */
251     SYMBEL *elem;		/* current element */
252 
253     G_debug(3, "S_read(): sname = %s", sname);
254 
255     /* Find file */
256     /* Get group and name */
257     strcpy(group, sname);
258     c = strchr(group, '/');
259     if (c == NULL) {
260 	G_warning(_("Incorrect symbol name: '%s' (should be: group/name or group/name@mapset)"),
261 		  sname);
262 	return NULL;
263     }
264     c[0] = '\0';
265 
266     c++;
267     strcpy(name, c);
268 
269     G_debug(3, "  group: '%s' name: '%s'", group, name);
270 
271     /* Search in mapsets */
272     sprintf(buf, "symbol/%s", group);
273     ms = G_find_file(buf, name, NULL);
274 
275     if (ms != NULL) {		/* Found in mapsets */
276 	fp = G_fopen_old(buf, name, ms);
277     }
278     else {			/* Search in GISBASE */
279 	sprintf(buf, "%s/etc/symbol/%s", G_gisbase(), sname);
280 	fp = fopen(buf, "r");
281     }
282 
283     if (fp == NULL) {
284 	G_warning(_("Cannot find/open symbol: '%s'"), sname);
285 	return NULL;
286     }
287 
288     /* create new symbol */
289     symb = new_symbol();
290 
291     current = OBJ_NONE;		/* no part */
292 
293     /* read file */
294     while (G_getl2(buf, 2000, fp) != 0) {
295 	G_chop(buf);
296 	G_debug(3, "  BUF: [%s]", buf);
297 
298 	/* skip empty and comment lines */
299 	if ((buf[0] == '#') || (buf[0] == '\0'))
300 	    continue;
301 
302 	get_key_data(buf);
303 
304 	if (strcmp(key, "VERSION") == 0) {
305 	    if (strcmp(data, "1.0") != 0) {
306 		sprintf(buf, "Wrong symbol version: '%s'", data);
307 		return (err(fp, symb, buf));
308 	    }
309 	}
310 	else if (strcmp(key, "BOX") == 0) {
311 	    if (sscanf(data, "%lf %lf %lf %lf", &x, &y, &x2, &y2) != 4) {
312 		sprintf(buf, "Incorrect box definition: '%s'", data);
313 		return (err(fp, symb, buf));
314 	    }
315 	    symb->xscale = 1 / (x2 - x);
316 	    symb->yscale = 1 / (y2 - y);
317 	    if (x2 - x > y2 - y) {
318 		symb->scale = symb->xscale;
319 	    }
320 	    else {
321 		symb->scale = symb->yscale;
322 	    }
323 	}
324 	else if (strcmp(key, "STRING") == 0) {
325 	    G_debug(4, "  STRING >");
326 	    current = OBJ_STRING;
327 	    part = new_part(S_STRING);
328 	    add_part(symb, part);
329 
330 	    chain = new_chain();
331 	    add_chain(part, chain);
332 	}
333 	else if (strcmp(key, "POLYGON") == 0) {
334 	    G_debug(4, "  POLYGON >");
335 	    current = OBJ_POLYGON;
336 	    part = new_part(S_POLYGON);
337 	    add_part(symb, part);
338 
339 	}
340 	else if (strcmp(key, "RING") == 0) {
341 	    G_debug(4, "  RING >");
342 	    current = OBJ_RING;
343 	    chain = new_chain();
344 	    add_chain(part, chain);
345 
346 	}
347 	else if (strcmp(key, "LINE") == 0) {
348 	    G_debug(4, "    LINE >");
349 	    elem = new_line();
350 	    add_element(chain, elem);
351 	    read_coor(fp, elem);
352 
353 	}
354 	else if (strcmp(key, "ARC") == 0) {
355 	    G_debug(4, "    ARC");
356 	    ret =
357 		sscanf(data, "%lf %lf %lf %lf %lf %c", &x, &y, &rad, &ang1,
358 		       &ang2, &clock);
359 	    if (ret < 5) {
360 		sprintf(buf, "Incorrect arc definition: '%s'", buf);
361 		return (err(fp, symb, buf));
362 	    }
363 	    if (ret == 6 && (clock == 'c' || clock == 'C'))
364 		i = 1;
365 	    else
366 		i = 0;
367 	    elem = new_arc(x, y, rad, ang1, ang2, i);
368 	    add_element(chain, elem);
369 
370 	}
371 	else if (strcmp(key, "END") == 0) {
372 	    switch (current) {
373 	    case OBJ_STRING:
374 		G_debug(4, "  STRING END");
375 		current = OBJ_NONE;
376 		break;
377 	    case OBJ_POLYGON:
378 		G_debug(4, "  POLYGON END");
379 		current = OBJ_NONE;
380 		break;
381 	    case OBJ_RING:
382 		G_debug(4, "  RING END");
383 		current = OBJ_POLYGON;
384 		break;
385 	    }
386 	}
387 	else if (strcmp(key, "COLOR") == 0) {
388 	    if (G_strcasecmp(data, "NONE") == 0) {
389 		part->color.color = S_COL_NONE;
390 	    }
391 	    else if (sscanf(data, "%d %d %d", &r, &g, &b) == 3) {
392 		if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255)
393 		    G_warning(_("Incorrect symbol color: '%s', using default."),
394 			      buf);
395 		else {
396 		    fr = r / 255.0;
397 		    fg = g / 255.0;
398 		    fb = b / 255.0;
399 		    part->color.color = S_COL_DEFINED;
400 		    part->color.r = r;
401 		    part->color.g = g;
402 		    part->color.b = b;
403 		    part->color.fr = fr;
404 		    part->color.fg = fg;
405 		    part->color.fb = fb;
406 		    G_debug(4, "  color [%d %d %d] = [%.3f %.3f %.3f]", r, g,
407 			    b, fr, fg, fb);
408 		}
409 	    }
410 	    else {
411 		G_warning(_("Incorrect symbol color: '%s', using default."),
412 			  buf);
413 	    }
414 	}
415 	else if (strcmp(key, "FCOLOR") == 0) {
416 	    if (G_strcasecmp(data, "NONE") == 0) {
417 		part->fcolor.color = S_COL_NONE;
418 	    }
419 	    else if (sscanf(data, "%d %d %d", &r, &g, &b) == 3) {
420 		if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255)
421 		    G_warning(_("Incorrect symbol color: '%s', using default."),
422 			      buf);
423 		else {
424 		    fr = r / 255.0;
425 		    fg = g / 255.0;
426 		    fb = b / 255.0;
427 		    part->fcolor.color = S_COL_DEFINED;
428 		    part->fcolor.r = r;
429 		    part->fcolor.g = g;
430 		    part->fcolor.b = b;
431 		    part->fcolor.fr = fr;
432 		    part->fcolor.fg = fg;
433 		    part->fcolor.fb = fb;
434 		    G_debug(4, "  color [%d %d %d] = [%.3f %.3f %.3f]", r, g,
435 			    b, fr, fg, fb);
436 		}
437 	    }
438 	    else {
439 		G_warning(_("Incorrect symbol color: '%s', using default."),
440 			  buf);
441 	    }
442 	}
443 	else {
444 	    sprintf(buf, "Unknown keyword in symbol: '%s'", buf);
445 	    return (err(fp, symb, buf));
446 	    break;
447 	}
448     }
449 
450     /* Debug output */
451 
452     G_debug(3, "Number of parts: %d", symb->count);
453     for (i = 0; i < symb->count; i++) {
454 	part = symb->part[i];
455 	G_debug(4, "  Part %d: type: %d number of chains: %d", i, part->type,
456 		part->count);
457 	G_debug(4, "           color: %d: fcolor: %d", part->color.color,
458 		part->fcolor.color);
459 	for (j = 0; j < part->count; j++) {
460 	    chain = part->chain[j];
461 	    G_debug(4, "    Chain %d: number of elements: %d", j,
462 		    chain->count);
463 	    for (k = 0; k < chain->count; k++) {
464 		elem = chain->elem[k];
465 		G_debug(4, "      Element %d: type: %d", k, elem->type);
466 		if (elem->type == S_LINE) {
467 		    G_debug(4, "        Number of points %d",
468 			    elem->coor.line.count);
469 		    for (l = 0; l < elem->coor.line.count; l++) {
470 			G_debug(4, "        x, y: %f %f",
471 				elem->coor.line.x[l], elem->coor.line.y[l]);
472 		    }
473 		}
474 		else {
475 		    G_debug(4, "        arc r = %f", elem->coor.arc.r);
476 		}
477 	    }
478 	}
479     }
480 
481     fclose(fp);
482 
483     return symb;
484 }
485