color_rules.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. /*!
  2. \file lib/raster/color_rules.c
  3. \brief Raster Library - Read and parse color rules file
  4. (C) 2007-2016 by the GRASS Development Team
  5. This program is free software under the GNU General Public
  6. License (>=v2). Read the file COPYING that comes with GRASS
  7. for details.
  8. \author Glynn Clements
  9. */
  10. #include <stdio.h>
  11. #include <grass/gis.h>
  12. #include <grass/colors.h>
  13. #include <grass/raster.h>
  14. #include <grass/glocale.h>
  15. struct rule
  16. {
  17. int set;
  18. int r, g, b;
  19. DCELL val;
  20. };
  21. enum rule_error
  22. {
  23. CR_OK = 0,
  24. CR_ERROR_RULE_SYNTAX,
  25. CR_ERROR_COLOR_SYNTAX,
  26. CR_ERROR_PERCENT,
  27. CR_ERROR_VALUE,
  28. };
  29. /*!
  30. \brief Read color rule
  31. The val output parameter is always an absolute value and is derived
  32. from the rule and the min and max values in case the rule is in percents.
  33. Always only one of the norm, nval, and dflt output parameters is set
  34. to non-zero value, the others are set to zero.
  35. The return code can be translated to an error message using
  36. the Rast_parse_color_rule_error() function.
  37. \param min, max min & max values (used only when color rules are in percentage)
  38. \param buf string with the color rule
  39. \param[out] val value which the color is assigned to
  40. \param[out] r,g,b color values
  41. \param[out] norm set to non-zero value if the value and color are set
  42. \param[out] nval set to non-zero value if rule is for null value
  43. \param[out] dflt set to non-zero value if rule specifies the default color
  44. \returns enum rule_error values (non-zero on failure)
  45. */
  46. int Rast_parse_color_rule(DCELL min, DCELL max, const char *buf,
  47. DCELL * val, int *r, int *g, int *b,
  48. int *norm, int *nval, int *dflt)
  49. {
  50. char value[80], color[80];
  51. double x;
  52. char c;
  53. *norm = *nval = *dflt = 0;
  54. if (sscanf(buf, "%s %[^\n]", value, color) != 2)
  55. return CR_ERROR_RULE_SYNTAX;
  56. /* we don't allow 'none' color here (ret == 2) */
  57. /* G_str_to_color chops and has only 1 error state */
  58. if (G_str_to_color(color, r, g, b) != 1)
  59. return CR_ERROR_COLOR_SYNTAX;
  60. G_chop(value);
  61. if (G_strcasecmp(value, "default") == 0) {
  62. *dflt = 1;
  63. return CR_OK;
  64. }
  65. if (G_strcasecmp(value, "nv") == 0) {
  66. *nval = 1;
  67. return CR_OK;
  68. }
  69. if (sscanf(value, "%lf%c", &x, &c) == 2 && c == '%') {
  70. if (x < 0 || x > 100)
  71. return CR_ERROR_PERCENT;
  72. *val = min + (max - min) * (x / 100);
  73. *norm = 1;
  74. return CR_OK;
  75. }
  76. if (sscanf(value, "%lf", val) == 1) {
  77. *norm = 1;
  78. return CR_OK;
  79. }
  80. return CR_ERROR_VALUE;
  81. }
  82. /*!
  83. \brief Parse color rule
  84. \param code
  85. \return pointer to buffer with error message
  86. */
  87. const char *Rast_parse_color_rule_error(int code)
  88. {
  89. switch (code) {
  90. case CR_OK:
  91. return "";
  92. case CR_ERROR_RULE_SYNTAX:
  93. return _("syntax error in the color rule");
  94. case CR_ERROR_COLOR_SYNTAX:
  95. return _("syntax error in the color format");
  96. /* we no longer distinguish between these two errors
  97. case CR_ERROR_RGB:
  98. return _("R/G/B not in range 0-255");
  99. case CR_ERROR_COLOR:
  100. return _("invalid color name");
  101. */
  102. case CR_ERROR_PERCENT:
  103. return _("percentage not in range 0-100");
  104. case CR_ERROR_VALUE:
  105. return _("invalid value");
  106. default:
  107. return _("unknown error");
  108. }
  109. }
  110. /*!
  111. \brief Read color rule
  112. \param closure
  113. \param min, max min & max values (used only when color rules are in percentage)
  114. \param val value
  115. \param[out] r,g,b color values
  116. \param norm
  117. \param nval
  118. \param dflt
  119. \return 0 on failure
  120. \return 1 on success
  121. */
  122. int Rast_read_color_rule(void *closure, DCELL min, DCELL max,
  123. DCELL * val, int *r, int *g, int *b,
  124. int *norm, int *nval, int *dflt)
  125. {
  126. char buf[1024];
  127. FILE *fp = closure;
  128. int ret;
  129. *norm = *nval = *dflt = 0;
  130. for (;;) {
  131. if (!G_getl2(buf, sizeof(buf), fp))
  132. return 0;
  133. G_strip(buf);
  134. G_debug(5, "color buf = [%s]", buf);
  135. if (*buf == '\0')
  136. continue;
  137. if (*buf == '#')
  138. continue;
  139. ret =
  140. Rast_parse_color_rule(min, max, buf, val, r, g, b, norm, nval,
  141. dflt);
  142. if (ret == 0)
  143. return 1;
  144. G_fatal_error(_("bad rule (%s): [%s]"),
  145. Rast_parse_color_rule_error(ret), buf);
  146. }
  147. return 0;
  148. }
  149. /*!
  150. \brief Read color rules from file
  151. \param[out] colors pointer to Colors structure
  152. \param min, max min & max values (used only when color rules are in percentage)
  153. \param read_rule pointer to read_rule_fn structure
  154. \param closure
  155. \return 0 on failure
  156. \return 1 on success
  157. */
  158. int Rast_read_color_rules(struct Colors *colors, DCELL min, DCELL max,
  159. read_rule_fn * read_rule, void *closure)
  160. {
  161. struct rule *rule = NULL;
  162. int nrules = 0;
  163. struct rule dflt, null;
  164. int set, is_null, is_dflt, r, g, b;
  165. DCELL val;
  166. int n;
  167. if (!read_rule)
  168. read_rule = Rast_read_color_rule;
  169. Rast_init_colors(colors);
  170. /* initialization */
  171. dflt.r = dflt.g = dflt.b = dflt.set = 0;
  172. null.r = null.g = null.b = null.set = 0;
  173. while ((*read_rule)
  174. (closure, min, max, &val, &r, &g, &b, &set, &is_null, &is_dflt)) {
  175. struct rule *p;
  176. if (set) {
  177. n = nrules++;
  178. rule = G_realloc(rule, nrules * sizeof(struct rule));
  179. p = &rule[n];
  180. }
  181. else if (is_dflt)
  182. p = &dflt;
  183. else if (is_null)
  184. p = &null;
  185. p->r = r;
  186. p->g = g;
  187. p->b = b;
  188. p->set = 1;
  189. p->val = val;
  190. }
  191. if (nrules == 0)
  192. return 0;
  193. if (nrules == 1) {
  194. const struct rule *p = &rule[0];
  195. Rast_set_d_color(p->val, p->r, p->g, p->b, colors);
  196. }
  197. for (n = 1; n < nrules; n++) {
  198. struct rule *lo = &rule[n - 1];
  199. struct rule *hi = &rule[n];
  200. Rast_add_d_color_rule(&lo->val, lo->r, lo->g, lo->b,
  201. &hi->val, hi->r, hi->g, hi->b, colors);
  202. }
  203. G_free(rule);
  204. /* null value and default color set up, if rules are set up by user */
  205. if (null.set)
  206. Rast_set_null_value_color(null.r, null.g, null.b, colors);
  207. if (dflt.set)
  208. Rast_set_default_color(dflt.r, dflt.g, dflt.b, colors);
  209. return 1;
  210. }
  211. static int load_rules_file(struct Colors *colors, const char *path, DCELL min,
  212. DCELL max)
  213. {
  214. FILE *fp;
  215. int ret;
  216. fp = fopen(path, "r");
  217. if (!fp)
  218. return 0;
  219. ret =
  220. Rast_read_color_rules(colors, min, max, Rast_read_color_rule,
  221. (void *)fp);
  222. fclose(fp);
  223. return ret;
  224. }
  225. /*!
  226. \brief Load color rules from file
  227. \param[out] colors pointer to Colors structure
  228. \param path path to the color rules file
  229. \param min, max min & max values (used only when color rules are in percentage)
  230. \return 0 on failure
  231. \return 1 on success
  232. */
  233. int Rast_load_colors(struct Colors *colors, const char *path, CELL min,
  234. CELL max)
  235. {
  236. return load_rules_file(colors, path, (DCELL) min, (DCELL) max);
  237. }
  238. /*!
  239. \brief Load color floating-point rules from file
  240. \param[out] colors pointer to Colors structure
  241. \param path path to the color rules file
  242. \param min, max min & max values (used only when color rules are in percentage)
  243. \return 0 on failure
  244. \return 1 on success
  245. */
  246. int Rast_load_fp_colors(struct Colors *colors, const char *path, DCELL min,
  247. DCELL max)
  248. {
  249. return load_rules_file(colors, path, min, max);
  250. }
  251. static void load_rules_name(struct Colors *colors, const char *name,
  252. DCELL min, DCELL max)
  253. {
  254. char path[GPATH_MAX];
  255. sprintf(path, "%s/etc/colors/%s", G_gisbase(), name);
  256. if (!load_rules_file(colors, path, min, max))
  257. G_fatal_error(_("Unable to load color rules <%s>"), name);
  258. }
  259. /*!
  260. \brief Load color rules from predefined color table
  261. \param[out] colors pointer to Colors structure
  262. \param name name of color table to load
  263. \param min, max min & max values (used only when color rules are in percentage)
  264. */
  265. void Rast_make_colors(struct Colors *colors, const char *name, CELL min,
  266. CELL max)
  267. {
  268. return load_rules_name(colors, name, (DCELL) min, (DCELL) max);
  269. }
  270. /*!
  271. \brief Load color rules from predefined floating-point color table
  272. \param[out] colors pointer to Colors structure
  273. \param name name of color table to load
  274. \param min, max min & max values (used only when color rules are in percentage)
  275. */
  276. void Rast_make_fp_colors(struct Colors *colors, const char *name, DCELL min,
  277. DCELL max)
  278. {
  279. return load_rules_name(colors, name, min, max);
  280. }