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