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