GRASS GIS 8 Programmer's Manual  8.2.2dev(2023)-3d2c704037
raster/color_rules.c
Go to the documentation of this file.
1 /*!
2  \file lib/raster/color_rules.c
3 
4  \brief Raster Library - Read and parse color rules file
5 
6  (C) 2007-2016 by the GRASS Development Team
7 
8  This program is free software under the GNU General Public
9  License (>=v2). Read the file COPYING that comes with GRASS
10  for details.
11 
12  \author Glynn Clements
13 */
14 
15 #include <stdio.h>
16 
17 #include <grass/gis.h>
18 #include <grass/colors.h>
19 #include <grass/raster.h>
20 #include <grass/glocale.h>
21 
22 struct rule
23 {
24  int set;
25  int r, g, b;
26  DCELL val;
27 };
28 
30 {
31  CR_OK = 0,
36 };
37 
38 /*!
39  \brief Read color rule
40 
41  The val output parameter is always an absolute value and is derived
42  from the rule and the min and max values in case the rule is in percents.
43 
44  Always only one of the norm, nval, and dflt output parameters is set
45  to non-zero value, the others are set to zero.
46 
47  The return code can be translated to an error message using
48  the Rast_parse_color_rule_error() function.
49 
50  \param min, max min & max values (used only when color rules are in percentage)
51  \param buf string with the color rule
52  \param[out] val value which the color is assigned to
53  \param[out] r,g,b color values
54  \param[out] norm set to non-zero value if the value and color are set
55  \param[out] nval set to non-zero value if rule is for null value
56  \param[out] dflt set to non-zero value if rule specifies the default color
57 
58  \returns enum rule_error values (non-zero on failure)
59 */
60 int Rast_parse_color_rule(DCELL min, DCELL max, const char *buf,
61  DCELL * val, int *r, int *g, int *b,
62  int *norm, int *nval, int *dflt)
63 {
64  char value[80], color[80];
65  double x;
66  char c;
67 
68  *norm = *nval = *dflt = 0;
69 
70  if (sscanf(buf, "%s %[^\n]", value, color) != 2)
71  return CR_ERROR_RULE_SYNTAX;
72 
73  /* we don't allow 'none' color here (ret == 2) */
74  /* G_str_to_color chops and has only 1 error state */
75  if (G_str_to_color(color, r, g, b) != 1)
76  return CR_ERROR_COLOR_SYNTAX;
77 
78  G_chop(value);
79 
80  if (G_strcasecmp(value, "default") == 0) {
81  *dflt = 1;
82  return CR_OK;
83  }
84 
85  if (G_strcasecmp(value, "nv") == 0) {
86  *nval = 1;
87  return CR_OK;
88  }
89 
90  if (sscanf(value, "%lf%c", &x, &c) == 2 && c == '%') {
91  if (x < 0 || x > 100)
92  return CR_ERROR_PERCENT;
93 
94  *val = min + (max - min) * (x / 100);
95  *norm = 1;
96  return CR_OK;
97  }
98 
99  if (sscanf(value, "%lf", val) == 1) {
100  *norm = 1;
101  return CR_OK;
102  }
103 
104  return CR_ERROR_VALUE;
105 }
106 
107 /*!
108  \brief Parse color rule
109 
110  \param code
111 
112  \return pointer to buffer with error message
113 */
114 const char *Rast_parse_color_rule_error(int code)
115 {
116  switch (code) {
117  case CR_OK:
118  return "";
120  return _("syntax error in the color rule");
122  return _("syntax error in the color format");
123 /* we no longer distinguish between these two errors
124  case CR_ERROR_RGB:
125  return _("R/G/B not in range 0-255");
126  case CR_ERROR_COLOR:
127  return _("invalid color name");
128 */
129  case CR_ERROR_PERCENT:
130  return _("percentage not in range 0-100");
131  case CR_ERROR_VALUE:
132  return _("invalid value");
133  default:
134  return _("unknown error");
135  }
136 }
137 
138 /*!
139  \brief Read color rule
140 
141  \param closure
142  \param min, max min & max values (used only when color rules are in percentage)
143  \param val value
144  \param[out] r,g,b color values
145  \param norm
146  \param nval
147  \param dflt
148 
149  \return 0 on failure
150  \return 1 on success
151 */
152 int Rast_read_color_rule(void *closure, DCELL min, DCELL max,
153  DCELL * val, int *r, int *g, int *b,
154  int *norm, int *nval, int *dflt)
155 {
156  char buf[1024];
157  FILE *fp = closure;
158  int ret;
159 
160  *norm = *nval = *dflt = 0;
161 
162  for (;;) {
163  if (!G_getl2(buf, sizeof(buf), fp))
164  return 0;
165 
166  G_strip(buf);
167  G_debug(5, "color buf = [%s]", buf);
168 
169  if (*buf == '\0')
170  continue;
171  if (*buf == '#')
172  continue;
173 
174  ret =
175  Rast_parse_color_rule(min, max, buf, val, r, g, b, norm, nval,
176  dflt);
177  if (ret == 0)
178  return 1;
179 
180  G_fatal_error(_("bad rule (%s): [%s]"),
181  Rast_parse_color_rule_error(ret), buf);
182  }
183 
184  return 0;
185 }
186 
187 /*!
188  \brief Read color rules from file
189 
190  \param[out] colors pointer to Colors structure
191  \param min, max min & max values (used only when color rules are in percentage)
192  \param read_rule pointer to read_rule_fn structure
193  \param closure
194 
195  \return 0 on failure
196  \return 1 on success
197 */
199  read_rule_fn * read_rule, void *closure)
200 {
201  struct rule *rule = NULL;
202  int nrules = 0;
203  struct rule dflt, null;
204  int set, is_null, is_dflt, r, g, b;
205  DCELL val;
206  int n;
207 
208  if (!read_rule)
209  read_rule = Rast_read_color_rule;
210 
211  Rast_init_colors(colors);
212 
213  /* initialization */
214  dflt.r = dflt.g = dflt.b = dflt.set = 0;
215  null.r = null.g = null.b = null.set = 0;
216 
217  while ((*read_rule)
218  (closure, min, max, &val, &r, &g, &b, &set, &is_null, &is_dflt)) {
219  struct rule *p = NULL;
220 
221  if (set) {
222  n = nrules++;
223  rule = G_realloc(rule, nrules * sizeof(struct rule));
224  p = &rule[n];
225  }
226  else if (is_dflt)
227  p = &dflt;
228  else if (is_null)
229  p = &null;
230 
231  if (!p)
232  G_fatal_error(_("Unknown error reading color rule"));
233 
234  p->r = r;
235  p->g = g;
236  p->b = b;
237  p->set = 1;
238  p->val = val;
239  }
240 
241  if (nrules == 0)
242  return 0;
243 
244  if (nrules == 1) {
245  const struct rule *p = &rule[0];
246 
247  Rast_set_d_color(p->val, p->r, p->g, p->b, colors);
248  }
249 
250  for (n = 1; n < nrules; n++) {
251  struct rule *lo = &rule[n - 1];
252  struct rule *hi = &rule[n];
253 
254  Rast_add_d_color_rule(&lo->val, lo->r, lo->g, lo->b,
255  &hi->val, hi->r, hi->g, hi->b, colors);
256  }
257 
258  G_free(rule);
259 
260  /* null value and default color set up, if rules are set up by user */
261  if (null.set)
262  Rast_set_null_value_color(null.r, null.g, null.b, colors);
263 
264  if (dflt.set)
265  Rast_set_default_color(dflt.r, dflt.g, dflt.b, colors);
266 
267  return 1;
268 }
269 
270 static int load_rules_file(struct Colors *colors, const char *path, DCELL min,
271  DCELL max)
272 {
273  FILE *fp;
274  int ret;
275 
276  fp = fopen(path, "r");
277 
278  if (!fp)
279  return 0;
280 
281  ret =
283  (void *)fp);
284 
285  fclose(fp);
286 
287  return ret;
288 }
289 
290 /*!
291  \brief Load color rules from file
292 
293  \param[out] colors pointer to Colors structure
294  \param path path to the color rules file
295  \param min, max min & max values (used only when color rules are in percentage)
296 
297  \return 0 on failure
298  \return 1 on success
299 */
300 int Rast_load_colors(struct Colors *colors, const char *path, CELL min,
301  CELL max)
302 {
303  return load_rules_file(colors, path, (DCELL) min, (DCELL) max);
304 }
305 
306 /*!
307  \brief Load color floating-point rules from file
308 
309  \param[out] colors pointer to Colors structure
310  \param path path to the color rules file
311  \param min, max min & max values (used only when color rules are in percentage)
312 
313  \return 0 on failure
314  \return 1 on success
315 */
316 int Rast_load_fp_colors(struct Colors *colors, const char *path, DCELL min,
317  DCELL max)
318 {
319  return load_rules_file(colors, path, min, max);
320 }
321 
322 static void load_rules_name(struct Colors *colors, const char *name,
323  DCELL min, DCELL max)
324 {
325  char path[GPATH_MAX];
326 
327  sprintf(path, "%s/etc/colors/%s", G_gisbase(), name);
328 
329  if (!load_rules_file(colors, path, min, max))
330  G_fatal_error(_("Unable to load color rules <%s>"), name);
331 }
332 
333 /*!
334  \brief Load color rules from predefined color table
335 
336  \param[out] colors pointer to Colors structure
337  \param name name of color table to load
338  \param min, max min & max values (used only when color rules are in percentage)
339 */
340 void Rast_make_colors(struct Colors *colors, const char *name, CELL min,
341  CELL max)
342 {
343  load_rules_name(colors, name, (DCELL) min, (DCELL) max);
344 }
345 
346 /*!
347  \brief Load color rules from predefined floating-point color table
348 
349  \param[out] colors pointer to Colors structure
350  \param name name of color table to load
351  \param min, max min & max values (used only when color rules are in percentage)
352 */
353 void Rast_make_fp_colors(struct Colors *colors, const char *name, DCELL min,
354  DCELL max)
355 {
356  load_rules_name(colors, name, min, max);
357 }
int G_getl2(char *, int, FILE *)
Gets a line of text from a file of any pedigree.
Definition: getl.c:64
int Rast_load_fp_colors(struct Colors *colors, const char *path, DCELL min, DCELL max)
Load color floating-point rules from file.
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void Rast_set_d_color(DCELL, int, int, int, struct Colors *)
Set a category color (DCELL)
Definition: color_set.c:60
#define min(x, y)
Definition: draw2.c:31
double DCELL
Definition: gis.h:614
int G_str_to_color(const char *, int *, int *, int *)
Parse color string and set red,green,blue.
Definition: color_str.c:112
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:149
void Rast_make_fp_colors(struct Colors *colors, const char *name, DCELL min, DCELL max)
Load color rules from predefined floating-point color table.
int Rast_read_color_rule(void *closure, DCELL min, DCELL max, DCELL *val, int *r, int *g, int *b, int *norm, int *nval, int *dflt)
Read color rule.
void G_strip(char *)
Removes all leading and trailing white space from string.
Definition: strings.c:300
int Rast_read_color_rules(struct Colors *colors, DCELL min, DCELL max, read_rule_fn *read_rule, void *closure)
Read color rules from file.
#define NULL
Definition: ccmath.h:32
#define x
#define max(x, y)
Definition: draw2.c:32
int int G_strcasecmp(const char *, const char *)
String compare ignoring case (upper or lower)
Definition: strings.c:47
double b
Definition: r_raster.c:39
rule_error
float g
Definition: named_colr.c:8
#define GPATH_MAX
Definition: gis.h:180
void Rast_set_default_color(int, int, int, struct Colors *)
Set default color value.
Definition: color_set.c:100
int Rast_load_colors(struct Colors *colors, const char *path, CELL min, CELL max)
Load color rules from file.
void Rast_set_null_value_color(int, int, int, struct Colors *)
Set color for NULL-value.
Definition: color_set.c:79
Definition: gis.h:676
char * G_chop(char *)
Chop leading and trailing white spaces.
Definition: strings.c:328
int read_rule_fn(void *, DCELL, DCELL, DCELL *, int *, int *, int *, int *, int *, int *)
Definition: defs/raster.h:232
const char * G_gisbase(void)
Get full path name of the top level module directory.
Definition: gisbase.c:41
int CELL
Definition: gis.h:613
Definition: path.h:16
#define G_realloc(p, n)
Definition: defs/gis.h:114
#define _(str)
Definition: glocale.h:10
int Rast_parse_color_rule(DCELL min, DCELL max, const char *buf, DCELL *val, int *r, int *g, int *b, int *norm, int *nval, int *dflt)
Read color rule.
void Rast_add_d_color_rule(const DCELL *, int, int, int, const DCELL *, int, int, int, struct Colors *)
Adds the floating-point color rule (DCELL version)
Definition: color_rule.c:35
const char * name
Definition: named_colr.c:7
const char * Rast_parse_color_rule_error(int code)
Parse color rule.
void Rast_init_colors(struct Colors *)
Initialize color structure.
Definition: color_init.c:25
int G_debug(int, const char *,...) __attribute__((format(printf
double r
Definition: r_raster.c:39
void Rast_make_colors(struct Colors *colors, const char *name, CELL min, CELL max)
Load color rules from predefined color table.