GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-f8115df121
color_look.c
Go to the documentation of this file.
1 /*!
2  * \file lib/raster/color_look.c
3  *
4  * \brief Raster Library - Lookup array of colors
5  *
6  * (C) 1999-2009 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 USACERL and many others
13  */
14 
15 #include <math.h>
16 
17 #include <grass/gis.h>
18 #include <grass/raster.h>
19 
20 /*!
21  * \brief Lookup an array of colors
22  *
23  * Extracts colors for an array of <i>cell</i> values. The colors
24  * for the <i>n</i> values in the <i>cell</i> array are stored in
25  * the <i>red, green</i>, and <i>blue</i> arrays. The values in the
26  * <i>set</i> array will indicate if the corresponding <i>cell</i>
27  * value has a color or not (1 means it does, 0 means it does not).
28  *
29  * The programmer must allocate the <i>red, green, blue</i>, and
30  * <b>set</b> arrays to be at least dimension <i>n</i>.
31  *
32  * <b>Note:</b> The <i>red, green</i>, and <i>blue</i> intensities
33  * will be in the range 0 - 255.
34  *
35  * Modified to return a color for NULL-values.
36  *
37  * \param cell raster cell value
38  * \param[out] red red value
39  * \param[out] grn green value
40  * \param[out] blu blue value
41  * \param set array which indicates if color is set or not
42  * \param n number of values
43  * \param colors pointer to Colors structure which holds color info
44  */
45 void Rast_lookup_c_colors(const CELL *cell, unsigned char *red,
46  unsigned char *grn, unsigned char *blu,
47  unsigned char *set, int n, struct Colors *colors)
48 {
50  colors); /* make sure the lookup tables are in place */
51 
52  G_zero((char *)set, n * sizeof(unsigned char));
53 
54  /* first lookup the fixed colors */
55  Rast__lookup_colors((void *)cell, red, grn, blu, set, n, colors, 0, 0,
56  CELL_TYPE);
57 
58  /* now lookup unset colors using the modular rules */
59  Rast__lookup_colors((void *)cell, red, grn, blu, set, n, colors, 1, 0,
60  CELL_TYPE);
61 }
62 
63 /*!
64  * \brief Lookup an array of colors
65  *
66  * - If the <em>map_type</em> is CELL_TYPE, calls Rast_lookup_colors()
67  * - If the <em>map_type</em> is FCELL_TYPE, calls Rast_lookup_f_colors()
68  * - If the <em>map_type</em> is DCELL_TYPE, calls Rast_lookup_d_colors()
69  *
70  * \param raster raster cell value
71  * \param[out] red red value
72  * \param[out] grn green value
73  * \param[out] blu blue value
74  * \param set array which indicates if color is set or not
75  * \param n number of values
76  * \param colors pointer to Colors structure which holds color info
77  * \param map_type raster type (CELL, FCELL, DCELL)
78  */
79 void Rast_lookup_colors(const void *raster, unsigned char *red,
80  unsigned char *grn, unsigned char *blu,
81  unsigned char *set, int n, struct Colors *colors,
82  RASTER_MAP_TYPE map_type)
83 {
85  colors); /* make sure the lookup tables are in place */
86  /* in case of float color rules, fp_lookup table is created */
87 
88  G_zero((char *)set, n * sizeof(unsigned char));
89 
90  /* first lookup the fixed colors */
91  Rast__lookup_colors(raster, red, grn, blu, set, n, colors, 0, 0, map_type);
92 
93  /* now lookup unset colors using the modular rules */
94  Rast__lookup_colors(raster, red, grn, blu, set, n, colors, 1, 0, map_type);
95 }
96 
97 /*!
98  * \brief Lookup an array of colors (FCELL)
99  *
100  * Converts the <em>n</em> floating-point values in the <em>fcell</em>
101  * array to their <em>r,g,b</em> color components. Embedded
102  * NULL-values are handled properly as well.
103  *
104  * \param fcell raster cell value
105  * \param[out] red red value
106  * \param[out] grn green value
107  * \param[out] blu blue value
108  * \param set array which indicates if color is set or not
109  * \param n number of values
110  * \param colors pointer to Colors structure which holds color info
111  */
112 void Rast_lookup_f_colors(const FCELL *fcell, unsigned char *red,
113  unsigned char *grn, unsigned char *blu,
114  unsigned char *set, int n, struct Colors *colors)
115 {
117  colors); /* make sure the lookup tables are in place */
118  /* in case of float color rules, fp_lookup table is created */
119 
120  G_zero((char *)set, n * sizeof(unsigned char));
121 
122  /* first lookup the fixed colors */
123  Rast__lookup_colors((void *)fcell, red, grn, blu, set, n, colors, 0, 0,
124  FCELL_TYPE);
125 
126  /* now lookup unset colors using the modular rules */
127  Rast__lookup_colors((void *)fcell, red, grn, blu, set, n, colors, 1, 0,
128  FCELL_TYPE);
129 }
130 
131 /*!
132  * \brief Lookup an array of colors (DCELL)
133  *
134  * Converts the <em>n</em> double-precision values in the
135  * <em>dcell</em> array to their <em>r,g,b</em> color
136  * components. Embedded NULL-values are handled properly as well.
137  *
138  * \param dcell raster cell value
139  * \param[out] red red value
140  * \param[out] grn green value
141  * \param[out] blu blue value
142  * \param set array which indicates if color is set or not
143  * \param n number of values
144  * \param colors pointer to Colors structure which holds color info
145  */
146 void Rast_lookup_d_colors(const DCELL *dcell, unsigned char *red,
147  unsigned char *grn, unsigned char *blu,
148  unsigned char *set, int n, struct Colors *colors)
149 {
151  colors); /* make sure the lookup tables are in place */
152  /* in case of float color rules, fp_lookup table is created */
153 
154  G_zero((char *)set, n * sizeof(unsigned char));
155 
156  /* first lookup the fixed colors */
157  Rast__lookup_colors((void *)dcell, red, grn, blu, set, n, colors, 0, 0,
158  DCELL_TYPE);
159 
160  /* now lookup unset colors using the modular rules */
161  Rast__lookup_colors((void *)dcell, red, grn, blu, set, n, colors, 1, 0,
162  DCELL_TYPE);
163 }
164 
165 static int less_or_equal(double x, double y)
166 {
167  if (x <= y)
168  return 1;
169  else
170  return 0;
171 }
172 
173 static int less(double x, double y)
174 {
175  if (x < y)
176  return 1;
177  else
178  return 0;
179 }
180 
181 /*!
182  * \brief Lookup an array of colors
183  *
184  * \param raster raster cell value
185  * \param[out] red red value
186  * \param[out] grn green value
187  * \param[out] blu blue value
188  * \param set array which indicates if color is set or not
189  * \param n number of values
190  * \param colors pointer to Colors structure which holds color info
191  * \param mod
192  * \param rules_only
193  * \param data_type raster type (CELL, FCELL, DCELL)
194  */
195 void Rast__lookup_colors(const void *raster, unsigned char *red,
196  unsigned char *grn, unsigned char *blu,
197  unsigned char *set, int n, struct Colors *colors,
198  int mod, int rules_only, RASTER_MAP_TYPE data_type)
199 {
200  struct _Color_Info_ *cp;
201  struct _Color_Rule_ *rule;
202  DCELL dmin, dmax, val, dmod = 0L, shift;
203  CELL cat, min, max;
204  const void *ptr, *last_ptr = NULL;
205  int invert;
206  int found, r, g, b;
207  int cell_type;
208  int lookup, max_ind, min_ind, try;
209  int (*lower)(double, double);
210  size_t size = Rast_cell_size(data_type);
211 
212  if (mod)
213  cp = &colors->modular;
214  else
215  cp = &colors->fixed;
216 
217  /* rules_only will be true only when called by Rast__organize_colors()
218  * when building the integer lookup talbes from the rules,
219  * so do not shift, invert, use lookup table or modulate cats.
220  * these operations will happen when lookup is called by user code
221  */
222  /* we want min, max for cp, not min, max overall */
223  dmin = cp->min;
224  dmax = cp->max;
225  min = (CELL)dmin;
226  max = (CELL)dmax;
227 
228  cell_type = (data_type == CELL_TYPE);
229 
230  if (rules_only) {
231  shift = invert = lookup = mod = 0;
232  }
233  else {
234  if (mod) {
235  dmod = dmax - dmin;
236  /* for integers color table we make a gap of 1 in order
237  to make the same colors as before */
238  if (cell_type)
239  dmod += 1;
240  }
241 
242  shift = colors->shift;
243  invert = colors->invert;
244  lookup = cp->lookup.active;
245  }
246 
247  ptr = raster;
248 
249  for (; n-- > 0; ptr = G_incr_void_ptr(ptr, size), red++, grn++, blu++,
250  *set++ = found) {
251  /* if the cell is the same as last one, use the prev color values */
252  if (ptr != raster && Rast_raster_cmp(ptr, last_ptr, data_type) == 0) {
253  *red = *(red - 1);
254  *blu = *(blu - 1);
255  *grn = *(grn - 1);
256  found = *(set - 1);
257  last_ptr = ptr;
258  continue;
259  }
260  val = Rast_get_d_value(ptr, data_type);
261  /* DEBUG fprintf (stderr, "val: %.4lf\n", val); */
262  last_ptr = ptr;
263 
264  if (*set) {
265  found = 1;
266  continue;
267  }
268 
269  if (Rast_is_null_value(ptr, data_type)) {
270  /* returns integers, not unsigned chars */
271  Rast_get_null_value_color(&r, &g, &b, colors);
272  *red = r;
273  *grn = g;
274  *blu = b;
275  found = 1;
276  continue;
277  }
278 
279  if (shift && val >= dmin && val <= dmax) {
280  val += shift;
281  while (val < dmin)
282  val += dmax - dmin + 1;
283  while (val > dmax)
284  val -= dmax - dmin + 1;
285  }
286 
287  /* invert non-null data around midpoint of range [min:max] */
288  if (invert)
289  val = dmin + dmax - val;
290 
291  if (mod) {
292  if (dmod > 0) {
293  val -= dmin;
294  while (val < 0)
295  val += dmod;
296  val = val - dmod * floor(val / dmod);
297  val += dmin;
298  }
299  else
300  val = dmin;
301  }
302 
303  cat = (CELL)val;
304 
305  found = 0;
306 
307  /* for non-null integers try to look them up in lookup table */
308  /* note: lookup table exists only for integer maps, and we also must
309  check if val is really integer */
310 
311  if (lookup && ((double)cat - val == 0.)) {
312  if (cat >= min && cat <= max) {
313  cat -= min;
314  if (cp->lookup.set[cat]) {
315  *red = cp->lookup.red[cat];
316  *grn = cp->lookup.grn[cat];
317  *blu = cp->lookup.blu[cat];
318  found = 1;
319  /*DEBUG
320  fprintf (stderr, "lookup %d %.2lf %d %d %d\n\n", cat,
321  val, *red, *grn, *blu);
322  */
323  }
324  }
325  }
326 
327  if (found)
328  continue;
329 
330  /* if floating point lookup table is active, look up in there */
331  if (cp->fp_lookup.active) {
332  try = (cp->fp_lookup.nalloc - 1) / 2;
333  min_ind = 0;
334  max_ind = cp->fp_lookup.nalloc - 2;
335  while (1) {
336  /* when the rule for the interval is NULL, we exclude the end
337  points. when it exists, we include the end-points */
338  if (cp->fp_lookup.rules[try])
339  lower = less;
340  else
341  lower = less_or_equal;
342  /* DEBUG
343  fprintf (stderr, "%d %d %d %lf %lf %lf\n", min_ind, try,
344  max_ind, cp->fp_lookup.vals[try-1], val,
345  cp->fp_lookup.vals[try]);
346  */
347 
348  if (lower(cp->fp_lookup.vals[try + 1],
349  val)) { /* recurse to the second half */
350  min_ind = try + 1;
351  /* must be still < nalloc-1, since number is within the
352  * range */
353  try = (max_ind + min_ind) / 2;
354  if (min_ind > max_ind) {
355  rule = NULL;
356  break;
357  }
358  continue;
359  }
360  if (lower(val, cp->fp_lookup.vals[try])) { /* recurse to the
361  second half */
362  max_ind = try - 1;
363  /* must be still >= 0, since number is within the range */
364  try = (max_ind + min_ind) / 2;
365  if (max_ind < min_ind) {
366  rule = NULL;
367  break;
368  }
369  continue;
370  }
371  rule = cp->fp_lookup.rules[try];
372  break;
373  }
374  }
375  else {
376  /* find the [low:high] rule that applies */
377  for (rule = cp->rules; rule; rule = rule->next) {
378  /* DEBUG
379  fprintf (stderr, "%.2lf %.2lf %.2lf\n",
380  val, rule->low.value, rule->high.value);
381  */
382  if (rule->low.value <= val && val <= rule->high.value)
383  break;
384  }
385  }
386 
387  /* if found, perform linear interpolation from low to high.
388  * else set colors to colors->undef or white if undef not set
389  */
390 
391  if (rule) {
392  Rast__interpolate_color_rule(val, red, grn, blu, rule);
393  found = 1;
394  }
395  if (!found) {
396  /* otherwise use default color */
397  Rast_get_default_color(&r, &g, &b, colors);
398  *red = r;
399  *grn = g;
400  *blu = b;
401  }
402  /* DEBUG
403  if (rule)
404  fprintf (stderr, "%.2lf %d %d %d %.2lf %d %d %d \n",
405  rule->low.value , (int)rule->low.red, (int)rule->low.grn,
406  (int)rule->low.blu, rule->high.value, (int)rule->high.red,
407  (int)rule->high.grn, (int)rule->high.blu); fprintf (stderr, "rule
408  found %d %.2lf %d %d %d\n\n", cat, val, *red, *grn, *blu);
409  */
410  }
411 }
412 
413 /*!
414  \brief Interpolate color rules
415 
416  \param val raster cell value
417  \param[out] red red value
418  \param[out] grn green value
419  \param[out] blu blue value
420  \param rule pointer to _Color_Rule which holds color rules info
421  */
422 void Rast__interpolate_color_rule(DCELL val, unsigned char *red,
423  unsigned char *grn, unsigned char *blu,
424  const struct _Color_Rule_ *rule)
425 {
426  DCELL delta;
427 
428  if ((delta = rule->high.value - rule->low.value)) {
429  val -= rule->low.value;
430 
431  *red = (int)(val * (double)((int)rule->high.red - (int)rule->low.red) /
432  delta) +
433  (int)rule->low.red;
434  *grn = (int)(val * (double)((int)rule->high.grn - (int)rule->low.grn) /
435  delta) +
436  (int)rule->low.grn;
437  *blu = (int)(val * (double)((int)rule->high.blu - (int)rule->low.blu) /
438  delta) +
439  (int)rule->low.blu;
440  }
441  else {
442  *red = rule->low.red;
443  *grn = rule->low.grn;
444  *blu = rule->low.blu;
445  }
446 }
#define NULL
Definition: ccmath.h:32
void Rast__lookup_colors(const void *raster, unsigned char *red, unsigned char *grn, unsigned char *blu, unsigned char *set, int n, struct Colors *colors, int mod, int rules_only, RASTER_MAP_TYPE data_type)
Lookup an array of colors.
Definition: color_look.c:195
void Rast_lookup_f_colors(const FCELL *fcell, unsigned char *red, unsigned char *grn, unsigned char *blu, unsigned char *set, int n, struct Colors *colors)
Lookup an array of colors (FCELL)
Definition: color_look.c:112
void Rast_lookup_d_colors(const DCELL *dcell, unsigned char *red, unsigned char *grn, unsigned char *blu, unsigned char *set, int n, struct Colors *colors)
Lookup an array of colors (DCELL)
Definition: color_look.c:146
void Rast_lookup_colors(const void *raster, unsigned char *red, unsigned char *grn, unsigned char *blu, unsigned char *set, int n, struct Colors *colors, RASTER_MAP_TYPE map_type)
Lookup an array of colors.
Definition: color_look.c:79
void Rast_lookup_c_colors(const CELL *cell, unsigned char *red, unsigned char *grn, unsigned char *blu, unsigned char *set, int n, struct Colors *colors)
Lookup an array of colors.
Definition: color_look.c:45
void Rast__interpolate_color_rule(DCELL val, unsigned char *red, unsigned char *grn, unsigned char *blu, const struct _Color_Rule_ *rule)
Interpolate color rules.
Definition: color_look.c:422
void G_zero(void *, int)
Zero out a buffer, buf, of length i.
Definition: gis/zero.c:23
#define G_incr_void_ptr(ptr, size)
Definition: defs/gis.h:81
int Rast_is_null_value(const void *, RASTER_MAP_TYPE)
To check if a raster value is set to NULL.
Definition: null_val.c:176
size_t Rast_cell_size(RASTER_MAP_TYPE)
Returns size of a raster cell in bytes.
Definition: alloc_cell.c:38
void Rast__organize_colors(struct Colors *)
Definition: color_org.c:12
void Rast_get_null_value_color(int *, int *, int *, const struct Colors *)
Gets color for null value.
Definition: color_get.c:126
int Rast_raster_cmp(const void *, const void *, RASTER_MAP_TYPE)
Compares raster values.
Definition: raster/raster.c:29
DCELL Rast_get_d_value(const void *, RASTER_MAP_TYPE)
Retrieves the value of given type from pointer p (DCELL)
void Rast_get_default_color(int *, int *, int *, const struct Colors *)
Gets default color.
Definition: color_get.c:154
#define min(x, y)
Definition: draw2.c:29
#define max(x, y)
Definition: draw2.c:30
float FCELL
Definition: gis.h:627
double DCELL
Definition: gis.h:626
int CELL
Definition: gis.h:625
float g
Definition: named_colr.c:7
double b
Definition: r_raster.c:39
double r
Definition: r_raster.c:39
#define FCELL_TYPE
Definition: raster.h:12
#define DCELL_TYPE
Definition: raster.h:13
#define CELL_TYPE
Definition: raster.h:11
int RASTER_MAP_TYPE
Definition: raster.h:25
Definition: gis.h:683
struct _Color_Info_ fixed
Definition: gis.h:696
struct _Color_Info_ modular
Definition: gis.h:697
int invert
Definition: gis.h:686
DCELL shift
Definition: gis.h:685
struct _Color_Info_::@3 lookup
unsigned char * red
Definition: gis.h:664
DCELL * vals
Definition: gis.h:673
struct _Color_Info_::@4 fp_lookup
DCELL max
Definition: gis.h:680
int active
Definition: gis.h:669
unsigned char * set
Definition: gis.h:667
unsigned char * blu
Definition: gis.h:666
struct _Color_Rule_ * rules
Definition: gis.h:660
unsigned char * grn
Definition: gis.h:665
DCELL min
Definition: gis.h:680
int nalloc
Definition: gis.h:668
struct _Color_Rule_ * next
Definition: gis.h:655
struct _Color_Value_ low high
Definition: gis.h:654
unsigned char blu
Definition: gis.h:650
unsigned char red
Definition: gis.h:648
DCELL value
Definition: gis.h:647
unsigned char grn
Definition: gis.h:649
#define x