GRASS GIS 8 Programmer's Manual  8.5.0dev(2024)-602118adcc
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  sprintf(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  sprintf(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  sprintf(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  sprintf(buf, "Incorrect box definition: '%s'", data);
310  return (err(fp, symb, buf));
311  }
312  symb->xscale = 1 / (x2 - x);
313  symb->yscale = 1 / (y2 - y);
314  if (x2 - x > y2 - y) {
315  symb->scale = symb->xscale;
316  }
317  else {
318  symb->scale = symb->yscale;
319  }
320  }
321  else if (strcmp(key, "STRING") == 0) {
322  G_debug(4, " STRING >");
323  current = OBJ_STRING;
324  part = new_part(S_STRING);
325  add_part(symb, part);
326 
327  chain = new_chain();
328  add_chain(part, chain);
329  }
330  else if (strcmp(key, "POLYGON") == 0) {
331  G_debug(4, " POLYGON >");
332  current = OBJ_POLYGON;
333  part = new_part(S_POLYGON);
334  add_part(symb, part);
335  }
336  else if (strcmp(key, "RING") == 0) {
337  G_debug(4, " RING >");
338  current = OBJ_RING;
339  chain = new_chain();
340  add_chain(part, chain);
341  }
342  else if (strcmp(key, "LINE") == 0) {
343  G_debug(4, " LINE >");
344  elem = new_line();
345  add_element(chain, elem);
346  read_coor(fp, elem);
347  }
348  else if (strcmp(key, "ARC") == 0) {
349  G_debug(4, " ARC");
350  ret = sscanf(data, "%lf %lf %lf %lf %lf %c", &x, &y, &rad, &ang1,
351  &ang2, &clock);
352  if (ret < 5) {
353  sprintf(buf2, "Incorrect arc definition: '%s'", buf);
354  return (err(fp, symb, buf2));
355  }
356  if (ret == 6 && (clock == 'c' || clock == 'C'))
357  i = 1;
358  else
359  i = 0;
360  elem = new_arc(x, y, rad, ang1, ang2, i);
361  add_element(chain, elem);
362  }
363  else if (strcmp(key, "END") == 0) {
364  switch (current) {
365  case OBJ_STRING:
366  G_debug(4, " STRING END");
367  current = OBJ_NONE;
368  break;
369  case OBJ_POLYGON:
370  G_debug(4, " POLYGON END");
371  current = OBJ_NONE;
372  break;
373  case OBJ_RING:
374  G_debug(4, " RING END");
375  current = OBJ_POLYGON;
376  break;
377  }
378  }
379  else if (strcmp(key, "COLOR") == 0) {
380  if (G_strcasecmp(data, "NONE") == 0) {
381  part->color.color = S_COL_NONE;
382  }
383  else if (sscanf(data, "%d %d %d", &r, &g, &b) == 3) {
384  if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255)
385  G_warning(_("Incorrect symbol color: '%s', using default."),
386  buf);
387  else {
388  fr = r / 255.0;
389  fg = g / 255.0;
390  fb = b / 255.0;
391  part->color.color = S_COL_DEFINED;
392  part->color.r = r;
393  part->color.g = g;
394  part->color.b = b;
395  part->color.fr = fr;
396  part->color.fg = fg;
397  part->color.fb = fb;
398  G_debug(4, " color [%d %d %d] = [%.3f %.3f %.3f]", r, g, b,
399  fr, fg, fb);
400  }
401  }
402  else {
403  G_warning(_("Incorrect symbol color: '%s', using default."),
404  buf);
405  }
406  }
407  else if (strcmp(key, "FCOLOR") == 0) {
408  if (G_strcasecmp(data, "NONE") == 0) {
409  part->fcolor.color = S_COL_NONE;
410  }
411  else if (sscanf(data, "%d %d %d", &r, &g, &b) == 3) {
412  if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255)
413  G_warning(_("Incorrect symbol color: '%s', using default."),
414  buf);
415  else {
416  fr = r / 255.0;
417  fg = g / 255.0;
418  fb = b / 255.0;
419  part->fcolor.color = S_COL_DEFINED;
420  part->fcolor.r = r;
421  part->fcolor.g = g;
422  part->fcolor.b = b;
423  part->fcolor.fr = fr;
424  part->fcolor.fg = fg;
425  part->fcolor.fb = fb;
426  G_debug(4, " color [%d %d %d] = [%.3f %.3f %.3f]", r, g, b,
427  fr, fg, fb);
428  }
429  }
430  else {
431  G_warning(_("Incorrect symbol color: '%s', using default."),
432  buf);
433  }
434  }
435  else {
436  sprintf(buf2, "Unknown keyword in symbol: '%s'", buf);
437  return (err(fp, symb, buf2));
438  break;
439  }
440  }
441 
442  /* Debug output */
443 
444  G_debug(3, "Number of parts: %d", symb->count);
445  for (i = 0; i < symb->count; i++) {
446  part = symb->part[i];
447  G_debug(4, " Part %d: type: %d number of chains: %d", i, part->type,
448  part->count);
449  G_debug(4, " color: %d: fcolor: %d", part->color.color,
450  part->fcolor.color);
451  for (j = 0; j < part->count; j++) {
452  chain = part->chain[j];
453  G_debug(4, " Chain %d: number of elements: %d", j, chain->count);
454  for (k = 0; k < chain->count; k++) {
455  elem = chain->elem[k];
456  G_debug(4, " Element %d: type: %d", k, elem->type);
457  if (elem->type == S_LINE) {
458  G_debug(4, " Number of points %d",
459  elem->coor.line.count);
460  for (l = 0; l < elem->coor.line.count; l++) {
461  G_debug(4, " x, y: %f %f", elem->coor.line.x[l],
462  elem->coor.line.y[l]);
463  }
464  }
465  else {
466  G_debug(4, " arc r = %f", elem->coor.arc.r);
467  }
468  }
469  }
470  }
471 
472  fclose(fp);
473 
474  return symb;
475 }
#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