GRASS GIS 8 Programmer's Manual  8.2.2dev(2023)-3d2c704037
symbol/read.c
Go to the documentation of this file.
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 */
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 */
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 */
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 */
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;
95  return p;
96 }
97 
98 /* add chain to part */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
220 SYMBOL *err(FILE * fp, SYMBOL * s, char *msg)
221 {
222  fclose(fp);
223  G_free(s); /* TODO: free all */
224  G_warning("%s", msg);
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  */
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], buf2[2048];
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(buf2, "Incorrect arc definition: '%s'", buf);
361  return (err(fp, symb, buf2));
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(buf2, "Unknown keyword in symbol: '%s'", buf);
445  return (err(fp, symb, buf2));
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 }
int G_getl2(char *, int, FILE *)
Gets a line of text from a file of any pedigree.
Definition: getl.c:64
#define OBJ_POLYGON
Definition: symbol/read.c:29
#define G_malloc(n)
Definition: defs/gis.h:112
#define S_POLYGON
Definition: symbol.h:16
double * sx
Definition: symbol.h:54
int g
Definition: symbol.h:25
int color
Definition: symbol.h:24
SYMBCHAIN ** chain
Definition: symbol.h:64
void read_coor(FILE *fp, SYMBEL *e)
Definition: symbol/read.c:189
#define S_STRING
Definition: symbol.h:15
SYMBOL * S_read(const char *sname)
Definition: symbol/read.c:235
SYMBCHAIN * new_chain(void)
Definition: symbol/read.c:114
void get_key_data(char *buf)
Definition: symbol/read.c:33
double fr
Definition: symbol.h:26
SYMBOL * new_symbol(void)
Definition: symbol/read.c:58
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:149
double scale
Definition: symbol.h:69
Definition: symbol.h:67
int count
Definition: symbol.h:63
double yscale
Definition: symbol.h:70
SYMBPART ** part
Definition: symbol.h:73
SYMBEL * new_arc(double x, double y, double r, double a1, double a2, int c)
Definition: symbol/read.c:173
#define OBJ_STRING
Definition: symbol/read.c:28
#define NULL
Definition: ccmath.h:32
#define x
void add_element(SYMBCHAIN *s, SYMBEL *e)
Definition: symbol/read.c:130
#define OBJ_NONE
Definition: symbol/read.c:27
double fb
Definition: symbol.h:26
int b
Definition: symbol.h:25
SYMBOL * err(FILE *fp, SYMBOL *s, char *msg)
Definition: symbol/read.c:220
double l
Definition: r_raster.c:39
struct SYMBEL::@6::@8 arc
int int G_strcasecmp(const char *, const char *)
String compare ignoring case (upper or lower)
Definition: strings.c:47
int alloc
Definition: symbol.h:72
double b
Definition: r_raster.c:39
SYMBCOLOR fcolor
Definition: symbol.h:62
void add_chain(SYMBPART *p, SYMBCHAIN *s)
Definition: symbol/read.c:99
struct SYMBEL::@6::@7 line
int type
Definition: symbol.h:32
#define S_LINE
Definition: symbol.h:11
#define S_COL_DEFAULT
Definition: symbol.h:18
SYMBCOLOR color
Definition: symbol.h:61
float g
Definition: named_colr.c:8
int count
Definition: symbol.h:72
FILE * G_fopen_old(const char *, const char *, const char *)
Open a database file for reading.
Definition: gis/open.c:253
SYMBEL * new_line(void)
Definition: symbol/read.c:142
double * sy
Definition: symbol.h:54
char * G_chop(char *)
Chop leading and trailing white spaces.
Definition: strings.c:328
int count
Definition: symbol.h:51
int type
Definition: symbol.h:60
int salloc
Definition: symbol.h:53
double fg
Definition: symbol.h:26
const char * G_find_file(const char *, char *, const char *)
Searches for a file from the mapset search list or in a specified mapset.
Definition: find_file.c:203
const char * G_gisbase(void)
Get full path name of the top level module directory.
Definition: gisbase.c:41
void G_warning(const char *,...) __attribute__((format(printf
SYMBPART * new_part(int type)
Definition: symbol/read.c:84
#define G_realloc(p, n)
Definition: defs/gis.h:114
#define S_COL_NONE
Definition: symbol.h:19
int scount
Definition: symbol.h:53
#define _(str)
Definition: glocale.h:10
int alloc
Definition: symbol.h:51
#define S_COL_DEFINED
Definition: symbol.h:20
#define OBJ_RING
Definition: symbol/read.c:30
int r
Definition: symbol.h:25
SYMBEL ** elem
Definition: symbol.h:52
int alloc
Definition: symbol.h:63
const char * name
Definition: named_colr.c:7
union SYMBEL::@6 coor
#define S_ARC
Definition: symbol.h:12
void add_part(SYMBOL *s, SYMBPART *p)
Definition: symbol/read.c:71
void add_point(SYMBEL *el, double x, double y)
Definition: symbol/read.c:156
int G_debug(int, const char *,...) __attribute__((format(printf
double xscale
Definition: symbol.h:71
double r
Definition: r_raster.c:39
void * data
Definition: rbtree.h:81
Definition: symbol.h:30