color_look.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. /*!
  2. * \file raster/color_lookup.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. #include <math.h>
  15. #include <grass/gis.h>
  16. #include <grass/raster.h>
  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. */
  42. void Rast_lookup_c_colors(const CELL * cell,
  43. unsigned char *red, unsigned char *grn,
  44. unsigned char *blu, unsigned char *set, int n,
  45. struct Colors *colors)
  46. {
  47. Rast__organize_colors(colors); /* make sure the lookup tables are in place */
  48. G_zero((char *)set, n * sizeof(unsigned char));
  49. /* first lookup the fixed colors */
  50. Rast__lookup_colors((void *)cell, red, grn, blu, set, n, colors, 0, 0,
  51. CELL_TYPE);
  52. /* now lookup unset colors using the modular rules */
  53. Rast__lookup_colors((void *)cell, red, grn, blu, set, n, colors, 1, 0,
  54. CELL_TYPE);
  55. }
  56. /*!
  57. * \brief Lookup an array of colors
  58. *
  59. * - If the <em>map_type</em> is CELL_TYPE, calls Rast_lookup_colors()
  60. * - If the <em>map_type</em> is FCELL_TYPE, calls Rast_lookup_f_colors()
  61. * - If the <em>map_type</em> is DCELL_TYPE, calls Rast_lookup_d_colors()
  62. *
  63. * \param raster raster cell value
  64. * \param[out] red red value
  65. * \param[out] grn green value
  66. * \param[out] blu blue value
  67. * \param set array which indicates if color is set or not
  68. * \param n number of values
  69. * \param colors pointer to Colors structure which holds color info
  70. * \param map_type raster type (CELL, FCELL, DCELL)
  71. */
  72. void Rast_lookup_colors(const void *raster,
  73. unsigned char *red, unsigned char *grn,
  74. unsigned char *blu, unsigned char *set, int n,
  75. struct Colors *colors, RASTER_MAP_TYPE map_type)
  76. {
  77. Rast__organize_colors(colors); /* make sure the lookup tables are in place */
  78. /* in case of float color rules, fp_lookup table is created */
  79. G_zero((char *)set, n * sizeof(unsigned char));
  80. /* first lookup the fixed colors */
  81. Rast__lookup_colors(raster, red, grn, blu, set, n, colors, 0, 0,
  82. map_type);
  83. /* now lookup unset colors using the modular rules */
  84. Rast__lookup_colors(raster, red, grn, blu, set, n, colors, 1, 0,
  85. map_type);
  86. }
  87. /*!
  88. * \brief Lookup an array of colors (FCELL)
  89. *
  90. * Converts the <em>n</em> floating-point values in the <em>fcell</em>
  91. * array to their <em>r,g,b</em> color components. Embedded
  92. * NULL-values are handled properly as well.
  93. *
  94. * \param fcell raster cell value
  95. * \param[out] red red value
  96. * \param[out] grn green value
  97. * \param[out] blu blue value
  98. * \param set array which indicates if color is set or not
  99. * \param n number of values
  100. * \param colors pointer to Colors structure which holds color info
  101. */
  102. void Rast_lookup_f_colors(const FCELL * fcell, unsigned char *red,
  103. unsigned char *grn, unsigned char *blu,
  104. unsigned char *set, int n, struct Colors *colors)
  105. {
  106. Rast__organize_colors(colors); /* make sure the lookup tables are in place */
  107. /* in case of float color rules, fp_lookup table is created */
  108. G_zero((char *)set, n * sizeof(unsigned char));
  109. /* first lookup the fixed colors */
  110. Rast__lookup_colors((void *)fcell, red, grn, blu, set, n, colors, 0, 0,
  111. FCELL_TYPE);
  112. /* now lookup unset colors using the modular rules */
  113. Rast__lookup_colors((void *)fcell, red, grn, blu, set, n, colors, 1, 0,
  114. FCELL_TYPE);
  115. }
  116. /*!
  117. * \brief Lookup an array of colors (DCELL)
  118. *
  119. * Converts the <em>n</em> double-precision values in the
  120. * <em>dcell</em> array to their <em>r,g,b</em> color
  121. * components. Embedded NULL-values are handled properly as well.
  122. *
  123. * \param dcell raster cell value
  124. * \param[out] red red value
  125. * \param[out] grn green value
  126. * \param[out] blu blue value
  127. * \param set array which indicates if color is set or not
  128. * \param n number of values
  129. * \param colors pointer to Colors structure which holds color info
  130. */
  131. void Rast_lookup_d_colors(const DCELL * dcell, unsigned char *red,
  132. unsigned char *grn, unsigned char *blu,
  133. unsigned char *set, int n, struct Colors *colors)
  134. {
  135. Rast__organize_colors(colors); /* make sure the lookup tables are in place */
  136. /* in case of float color rules, fp_lookup table is created */
  137. G_zero((char *)set, n * sizeof(unsigned char));
  138. /* first lookup the fixed colors */
  139. Rast__lookup_colors((void *)dcell, red, grn, blu, set, n, colors, 0, 0,
  140. DCELL_TYPE);
  141. /* now lookup unset colors using the modular rules */
  142. Rast__lookup_colors((void *)dcell, red, grn, blu, set, n, colors, 1, 0,
  143. DCELL_TYPE);
  144. }
  145. static int less_or_equal(double x, double y)
  146. {
  147. if (x <= y)
  148. return 1;
  149. else
  150. return 0;
  151. }
  152. static int less(double x, double y)
  153. {
  154. if (x < y)
  155. return 1;
  156. else
  157. return 0;
  158. }
  159. /*!
  160. * \brief Lookup an array of colors
  161. *
  162. * \param raster raster cell value
  163. * \param[out] red red value
  164. * \param[out] grn green value
  165. * \param[out] blu blue value
  166. * \param set array which indicates if color is set or not
  167. * \param n number of values
  168. * \param colors pointer to Colors structure which holds color info
  169. * \param mod
  170. * \param rules_only
  171. * \param data_type raster type (CELL, FCELL, DCELL)
  172. */
  173. void Rast__lookup_colors(const void *raster, unsigned char *red,
  174. unsigned char *grn, unsigned char *blu,
  175. unsigned char *set, int n, struct Colors *colors,
  176. int mod, int rules_only, RASTER_MAP_TYPE data_type)
  177. {
  178. struct _Color_Info_ *cp;
  179. struct _Color_Rule_ *rule;
  180. DCELL dmin, dmax, val, dmod = 0L, shift;
  181. CELL cat, min, max;
  182. const void *ptr, *last_ptr = NULL;
  183. int invert;
  184. int found, r, g, b;
  185. int cell_type;
  186. int lookup, max_ind, min_ind, try;
  187. int (*lower)();
  188. size_t size = Rast_cell_size(data_type);
  189. if (mod)
  190. cp = &colors->modular;
  191. else
  192. cp = &colors->fixed;
  193. /* rules_only will be true only when called by Rast__organize_colors()
  194. * when building the integer lookup talbes from the rules,
  195. * so do not shift, invert, use lookup table or modulate cats.
  196. * these operations will happen when lookup is called by user code
  197. */
  198. /* we want min, max for cp, not min, max overall */
  199. dmin = cp->min;
  200. dmax = cp->max;
  201. min = (CELL) dmin;
  202. max = (CELL) dmax + 1;
  203. cell_type = (data_type == CELL_TYPE);
  204. if (rules_only) {
  205. shift = invert = lookup = mod = 0;
  206. }
  207. else {
  208. if (mod) {
  209. dmod = dmax - dmin;
  210. /* for integers color table we make a gap of 1 in order
  211. to make the same colors as before */
  212. if (cell_type)
  213. dmod += 1;
  214. }
  215. shift = colors->shift;
  216. invert = colors->invert;
  217. lookup = cp->lookup.active;
  218. }
  219. ptr = raster;
  220. for (; n-- > 0;
  221. ptr = G_incr_void_ptr(ptr, size),
  222. red++, grn++, blu++, *set++ = found) {
  223. /* if the cell is the same as last one, use the prev color values */
  224. if (ptr != raster && Rast_raster_cmp(ptr, last_ptr, data_type) == 0) {
  225. *red = *(red - 1);
  226. *blu = *(blu - 1);
  227. *grn = *(grn - 1);
  228. found = *(set - 1);
  229. last_ptr = ptr;
  230. continue;
  231. }
  232. val = Rast_get_d_value(ptr, data_type);
  233. /* DEBUG fprintf (stderr, "val: %.4lf\n", val); */
  234. last_ptr = ptr;
  235. if (*set) {
  236. found = 1;
  237. continue;
  238. }
  239. if (Rast_is_null_value(ptr, data_type)) {
  240. /* returns integers, not unsigned chars */
  241. Rast_get_null_value_color(&r, &g, &b, colors);
  242. *red = r;
  243. *grn = g;
  244. *blu = b;
  245. found = 1;
  246. continue;
  247. }
  248. if (shift && val >= dmin && val <= dmax) {
  249. val += shift;
  250. while (val < dmin)
  251. val += dmax - dmin + 1;
  252. while (val > dmax)
  253. val -= dmax - dmin + 1;
  254. }
  255. /* invert non-null data around midpoint of range [min:max] */
  256. if (invert)
  257. val = dmin + dmax - val;
  258. if (mod) {
  259. if (dmod > 0) {
  260. val -= dmin;
  261. while (val < 0)
  262. val += dmod;
  263. val = val - dmod * floor(val / dmod);
  264. val += dmin;
  265. }
  266. else
  267. val = dmin;
  268. }
  269. cat = (CELL) val;
  270. found = 0;
  271. /* for non-null integers try to look them up in lookup table */
  272. /* note: lookup table exists only for integer maps, and we also must
  273. check if val is really integer */
  274. if (lookup && ((double)cat - val == 0.)) {
  275. if (cat >= min && cat <= max) {
  276. cat -= min;
  277. if (cp->lookup.set[cat]) {
  278. *red = cp->lookup.red[cat];
  279. *grn = cp->lookup.grn[cat];
  280. *blu = cp->lookup.blu[cat];
  281. found = 1;
  282. /*DEBUG
  283. fprintf (stderr, "lookup %d %.2lf %d %d %d\n\n", cat, val, *red, *grn, *blu);
  284. */
  285. }
  286. }
  287. }
  288. if (found)
  289. continue;
  290. /* if floating point lookup table is active, look up in there */
  291. if (cp->fp_lookup.active) {
  292. try = (cp->fp_lookup.nalloc - 1) / 2;
  293. min_ind = 0;
  294. max_ind = cp->fp_lookup.nalloc - 2;
  295. while (1) {
  296. /* when the rule for the interval is NULL, we exclude the end points.
  297. when it exists, we include the end-points */
  298. if (cp->fp_lookup.rules[try])
  299. lower = less;
  300. else
  301. lower = less_or_equal;
  302. /* DEBUG
  303. fprintf (stderr, "%d %d %d %lf %lf %lf\n", min_ind, try, max_ind,
  304. cp->fp_lookup.vals[try-1],
  305. val,
  306. cp->fp_lookup.vals[try]);
  307. */
  308. if (lower(cp->fp_lookup.vals[try + 1], val)) { /* recurse to the second half */
  309. min_ind = try + 1;
  310. /* must be still < nalloc-1, since number is within the range */
  311. try = (max_ind + min_ind) / 2;
  312. if (min_ind > max_ind) {
  313. rule = NULL;
  314. break;
  315. }
  316. continue;
  317. }
  318. if (lower(val, cp->fp_lookup.vals[try])) { /* recurse to the second half */
  319. max_ind = try - 1;
  320. /* must be still >= 0, since number is within the range */
  321. try = (max_ind + min_ind) / 2;
  322. if (max_ind < min_ind) {
  323. rule = NULL;
  324. break;
  325. }
  326. continue;
  327. }
  328. rule = cp->fp_lookup.rules[try];
  329. break;
  330. }
  331. }
  332. else {
  333. /* find the [low:high] rule that applies */
  334. for (rule = cp->rules; rule; rule = rule->next) {
  335. /* DEBUG
  336. fprintf (stderr, "%.2lf %.2lf %.2lf\n",
  337. val, rule->low.value, rule->high.value);
  338. */
  339. if (rule->low.value <= val && val <= rule->high.value)
  340. break;
  341. }
  342. }
  343. /* if found, perform linear interpolation from low to high.
  344. * else set colors to colors->undef or white if undef not set
  345. */
  346. if (rule) {
  347. Rast__interpolate_color_rule(val, red, grn, blu, rule);
  348. found = 1;
  349. }
  350. if (!found) {
  351. /* otherwise use default color */
  352. Rast_get_default_color(&r, &g, &b, colors);
  353. *red = r;
  354. *grn = g;
  355. *blu = b;
  356. }
  357. /* DEBUG
  358. if (rule)
  359. 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);
  360. fprintf (stderr, "rule found %d %.2lf %d %d %d\n\n", cat, val, *red, *grn, *blu);
  361. */
  362. }
  363. }
  364. /*!
  365. \brief Interpolate color rules
  366. \param val raster cell value
  367. \param[out] red red value
  368. \param[out] grn green value
  369. \param[out] blu blue value
  370. \param rule pointer to _Color_Rule which holds color rules info
  371. */
  372. void Rast__interpolate_color_rule(DCELL val, unsigned char *red,
  373. unsigned char *grn, unsigned char *blu,
  374. const struct _Color_Rule_ *rule)
  375. {
  376. DCELL delta;
  377. if ((delta = rule->high.value - rule->low.value)) {
  378. val -= rule->low.value;
  379. *red =
  380. (int)(val * (double)((int)rule->high.red - (int)rule->low.red) /
  381. delta)
  382. + (int)rule->low.red;
  383. *grn =
  384. (int)(val * (double)((int)rule->high.grn - (int)rule->low.grn) /
  385. delta)
  386. + (int)rule->low.grn;
  387. *blu =
  388. (int)(val * (double)((int)rule->high.blu - (int)rule->low.blu) /
  389. delta)
  390. + (int)rule->low.blu;
  391. }
  392. else {
  393. *red = rule->low.red;
  394. *grn = rule->low.grn;
  395. *blu = rule->low.blu;
  396. }
  397. }