GRASS GIS 8 Programmer's Manual  8.2.2dev(2023)-3d2c704037
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,
46  unsigned char *red, unsigned char *grn,
47  unsigned char *blu, unsigned char *set, int n,
48  struct Colors *colors)
49 {
50  Rast__organize_colors(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,
80  unsigned char *red, unsigned char *grn,
81  unsigned char *blu, unsigned char *set, int n,
82  struct Colors *colors, RASTER_MAP_TYPE map_type)
83 {
84  Rast__organize_colors(colors); /* make sure the lookup tables are in place */
85  /* in case of float color rules, fp_lookup table is created */
86 
87  G_zero((char *)set, n * sizeof(unsigned char));
88 
89  /* first lookup the fixed colors */
90  Rast__lookup_colors(raster, red, grn, blu, set, n, colors, 0, 0,
91  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,
95  map_type);
96 }
97 
98 /*!
99  * \brief Lookup an array of colors (FCELL)
100  *
101  * Converts the <em>n</em> floating-point values in the <em>fcell</em>
102  * array to their <em>r,g,b</em> color components. Embedded
103  * NULL-values are handled properly as well.
104  *
105  * \param fcell raster cell value
106  * \param[out] red red value
107  * \param[out] grn green value
108  * \param[out] blu blue value
109  * \param set array which indicates if color is set or not
110  * \param n number of values
111  * \param colors pointer to Colors structure which holds color info
112  */
113 void Rast_lookup_f_colors(const FCELL * fcell, unsigned char *red,
114  unsigned char *grn, unsigned char *blu,
115  unsigned char *set, int n, struct Colors *colors)
116 {
117  Rast__organize_colors(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 {
150  Rast__organize_colors(colors); /* make sure the lookup tables are in place */
151  /* in case of float color rules, fp_lookup table is created */
152 
153  G_zero((char *)set, n * sizeof(unsigned char));
154 
155  /* first lookup the fixed colors */
156  Rast__lookup_colors((void *)dcell, red, grn, blu, set, n, colors, 0, 0,
157  DCELL_TYPE);
158 
159  /* now lookup unset colors using the modular rules */
160  Rast__lookup_colors((void *)dcell, red, grn, blu, set, n, colors, 1, 0,
161  DCELL_TYPE);
162 }
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)();
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;
250  ptr = G_incr_void_ptr(ptr, size),
251  red++, grn++, blu++, *set++ = found) {
252  /* if the cell is the same as last one, use the prev color values */
253  if (ptr != raster && Rast_raster_cmp(ptr, last_ptr, data_type) == 0) {
254  *red = *(red - 1);
255  *blu = *(blu - 1);
256  *grn = *(grn - 1);
257  found = *(set - 1);
258  last_ptr = ptr;
259  continue;
260  }
261  val = Rast_get_d_value(ptr, data_type);
262  /* DEBUG fprintf (stderr, "val: %.4lf\n", val); */
263  last_ptr = ptr;
264 
265  if (*set) {
266  found = 1;
267  continue;
268  }
269 
270  if (Rast_is_null_value(ptr, data_type)) {
271  /* returns integers, not unsigned chars */
272  Rast_get_null_value_color(&r, &g, &b, colors);
273  *red = r;
274  *grn = g;
275  *blu = b;
276  found = 1;
277  continue;
278  }
279 
280  if (shift && val >= dmin && val <= dmax) {
281  val += shift;
282  while (val < dmin)
283  val += dmax - dmin + 1;
284  while (val > dmax)
285  val -= dmax - dmin + 1;
286  }
287 
288  /* invert non-null data around midpoint of range [min:max] */
289  if (invert)
290  val = dmin + dmax - val;
291 
292  if (mod) {
293  if (dmod > 0) {
294  val -= dmin;
295  while (val < 0)
296  val += dmod;
297  val = val - dmod * floor(val / dmod);
298  val += dmin;
299  }
300  else
301  val = dmin;
302  }
303 
304  cat = (CELL) val;
305 
306  found = 0;
307 
308  /* for non-null integers try to look them up in lookup table */
309  /* note: lookup table exists only for integer maps, and we also must
310  check if val is really integer */
311 
312  if (lookup && ((double)cat - val == 0.)) {
313  if (cat >= min && cat <= max) {
314  cat -= min;
315  if (cp->lookup.set[cat]) {
316  *red = cp->lookup.red[cat];
317  *grn = cp->lookup.grn[cat];
318  *blu = cp->lookup.blu[cat];
319  found = 1;
320  /*DEBUG
321  fprintf (stderr, "lookup %d %.2lf %d %d %d\n\n", cat, 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 points.
337  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, max_ind,
344  cp->fp_lookup.vals[try-1],
345  val,
346  cp->fp_lookup.vals[try]);
347  */
348 
349  if (lower(cp->fp_lookup.vals[try + 1], val)) { /* recurse to the second half */
350  min_ind = try + 1;
351  /* must be still < nalloc-1, since number is within the range */
352  try = (max_ind + min_ind) / 2;
353  if (min_ind > max_ind) {
354  rule = NULL;
355  break;
356  }
357  continue;
358  }
359  if (lower(val, cp->fp_lookup.vals[try])) { /* recurse to the second half */
360  max_ind = try - 1;
361  /* must be still >= 0, since number is within the range */
362  try = (max_ind + min_ind) / 2;
363  if (max_ind < min_ind) {
364  rule = NULL;
365  break;
366  }
367  continue;
368  }
369  rule = cp->fp_lookup.rules[try];
370  break;
371  }
372  }
373  else {
374  /* find the [low:high] rule that applies */
375  for (rule = cp->rules; rule; rule = rule->next) {
376  /* DEBUG
377  fprintf (stderr, "%.2lf %.2lf %.2lf\n",
378  val, rule->low.value, rule->high.value);
379  */
380  if (rule->low.value <= val && val <= rule->high.value)
381  break;
382  }
383  }
384 
385  /* if found, perform linear interpolation from low to high.
386  * else set colors to colors->undef or white if undef not set
387  */
388 
389  if (rule) {
390  Rast__interpolate_color_rule(val, red, grn, blu, rule);
391  found = 1;
392  }
393  if (!found) {
394  /* otherwise use default color */
395  Rast_get_default_color(&r, &g, &b, colors);
396  *red = r;
397  *grn = g;
398  *blu = b;
399  }
400  /* DEBUG
401  if (rule)
402  fprintf (stderr, "%.2lf %d %d %d %.2lf %d %d %d \n", rule->low.value , (int)rule->low.red, (int)rule->low.grn, (int)rule->low.blu, rule->high.value, (int)rule->high.red, (int)rule->high.grn, (int)rule->high.blu);
403  fprintf (stderr, "rule found %d %.2lf %d %d %d\n\n", cat, val, *red, *grn, *blu);
404  */
405  }
406 }
407 
408 /*!
409  \brief Interpolate color rules
410 
411  \param val raster cell value
412  \param[out] red red value
413  \param[out] grn green value
414  \param[out] blu blue value
415  \param rule pointer to _Color_Rule which holds color rules info
416  */
417 void Rast__interpolate_color_rule(DCELL val, unsigned char *red,
418  unsigned char *grn, unsigned char *blu,
419  const struct _Color_Rule_ *rule)
420 {
421  DCELL delta;
422 
423  if ((delta = rule->high.value - rule->low.value)) {
424  val -= rule->low.value;
425 
426  *red =
427  (int)(val * (double)((int)rule->high.red - (int)rule->low.red) /
428  delta)
429  + (int)rule->low.red;
430  *grn =
431  (int)(val * (double)((int)rule->high.grn - (int)rule->low.grn) /
432  delta)
433  + (int)rule->low.grn;
434  *blu =
435  (int)(val * (double)((int)rule->high.blu - (int)rule->low.blu) /
436  delta)
437  + (int)rule->low.blu;
438  }
439  else {
440  *red = rule->low.red;
441  *grn = rule->low.grn;
442  *blu = rule->low.blu;
443  }
444 }
#define CELL_TYPE
Definition: raster.h:11
struct _Color_Info_ fixed
Definition: gis.h:690
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
unsigned char * blu
Definition: gis.h:658
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_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:113
DCELL shift
Definition: gis.h:679
unsigned char * red
Definition: gis.h:656
#define min(x, y)
Definition: draw2.c:31
double DCELL
Definition: gis.h:614
struct _Color_Value_ low high
Definition: gis.h:644
struct _Color_Rule_ * next
Definition: gis.h:645
unsigned char * grn
Definition: gis.h:657
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
#define G_incr_void_ptr(ptr, size)
Definition: defs/gis.h:100
int nalloc
Definition: gis.h:660
#define NULL
Definition: ccmath.h:32
unsigned char * set
Definition: gis.h:659
#define x
#define max(x, y)
Definition: draw2.c:32
DCELL * vals
Definition: gis.h:666
void Rast_get_default_color(int *, int *, int *, const struct Colors *)
Gets default color.
Definition: color_get.c:155
DCELL min
Definition: gis.h:673
#define DCELL_TYPE
Definition: raster.h:13
double b
Definition: r_raster.c:39
size_t Rast_cell_size(RASTER_MAP_TYPE)
Returns size of a raster cell in bytes.
Definition: alloc_cell.c:39
DCELL value
Definition: gis.h:636
void Rast_get_null_value_color(int *, int *, int *, const struct Colors *)
Gets color for null value.
Definition: color_get.c:127
float g
Definition: named_colr.c:8
float FCELL
Definition: gis.h:615
Definition: gis.h:676
int active
Definition: gis.h:661
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
int invert
Definition: gis.h:680
void G_zero(void *, int)
Zero out a buffer, buf, of length i.
Definition: gis/zero.c:23
void Rast__organize_colors(struct Colors *)
Definition: color_org.c:12
int CELL
Definition: gis.h:613
unsigned char red
Definition: gis.h:637
int RASTER_MAP_TYPE
Definition: raster.h:25
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
unsigned char blu
Definition: gis.h:639
#define FCELL_TYPE
Definition: raster.h:12
struct _Color_Info_::@3 lookup
struct _Color_Info_ modular
Definition: gis.h:691
struct _Color_Info_::@4 fp_lookup
DCELL max
Definition: gis.h:673
unsigned char grn
Definition: gis.h:638
double r
Definition: r_raster.c:39
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:417
int Rast_is_null_value(const void *, RASTER_MAP_TYPE)
To check if a raster value is set to NULL.
Definition: null_val.c:179
struct _Color_Rule_ * rules
Definition: gis.h:651