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 */
Rast_lookup_c_colors(const CELL * cell,unsigned char * red,unsigned char * grn,unsigned char * blu,unsigned char * set,int n,struct Colors * colors)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 */
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)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 */
Rast_lookup_f_colors(const FCELL * fcell,unsigned char * red,unsigned char * grn,unsigned char * blu,unsigned char * set,int n,struct Colors * colors)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 */
Rast_lookup_d_colors(const DCELL * dcell,unsigned char * red,unsigned char * grn,unsigned char * blu,unsigned char * set,int n,struct Colors * colors)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
less_or_equal(double x,double y)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
less(double x,double y)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 */
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)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 */
Rast__interpolate_color_rule(DCELL val,unsigned char * red,unsigned char * grn,unsigned char * blu,const struct _Color_Rule_ * rule)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 }
445