color_write.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /*!
  2. * \file raster/color_write.c
  3. *
  4. * \brief Raster Library - Write color table of raster map
  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 <string.h>
  15. #include <stdlib.h>
  16. #include <stdio.h>
  17. #include <grass/gis.h>
  18. #include <grass/glocale.h>
  19. #include <grass/raster.h>
  20. static void write_rules(FILE *, struct _Color_Rule_ *, DCELL, DCELL);
  21. static void write_new_colors(FILE *, struct Colors *);
  22. static void write_old_colors(FILE *, struct Colors *);
  23. static void forced_write_old_colors(FILE *, struct Colors *);
  24. static void format_min(char *, double);
  25. static void format_max(char *, double);
  26. /*!
  27. * \brief Write map layer color table
  28. *
  29. * The color table is written for the raster map <i>name</i> in the
  30. * specified <i>mapset</i> from the <i>colors</i> structure.
  31. *
  32. * If there is an error, -1 is returned. No diagnostic is
  33. * printed. Otherwise, 1 is returned.
  34. *
  35. * The <i>colors</i> structure must be created properly, i.e.,
  36. * Rast_init_colors() to initialize the structure and Rast_add_c_color_rule()
  37. * to set the category colors. These routines are called by
  38. * higher level routines which read or create entire color tables,
  39. * such as Rast_read_colors() or Rast_make_ramp_colors().
  40. *
  41. * <b>Note:</b> The calling sequence for this function deserves
  42. * special attention. The <i>mapset</i> parameter seems to imply that
  43. * it is possible to overwrite the color table for a raster map which
  44. * is in another mapset. However, this is not what actually
  45. * happens. It is very useful for users to create their own color
  46. * tables for raster maps in other mapsets, but without overwriting
  47. * other users' color tables for the same raster map. If <i>mapset</i>
  48. * is the current mapset, then the color file for <i>name</i> will be
  49. * overwritten by the new color table. But if <i>mapset</i> is not the
  50. * current mapset, then the color table is actually written in the
  51. * current mapset under the <tt>colr2</tt> element as:
  52. * <tt>colr2/mapset/name</tt>.
  53. *
  54. * The rules are written out using floating-point format, removing
  55. * trailing zeros (possibly producing integers). The flag marking the
  56. * colors as floating-point is <b>not</b> written.
  57. *
  58. * If the environment variable FORCE_GRASS3_COLORS is set (to anything at all)
  59. * then the output format is 3.0, even if the structure contains 4.0 rules.
  60. * This allows users to create 3.0 color files for export to sites which
  61. * don't yet have 4.0
  62. *
  63. * \param name map name
  64. * \param mapset mapset name
  65. * \param colors pointer to structure Colors which holds color info
  66. *
  67. * \return void
  68. */
  69. void Rast_write_colors(const char *name, const char *mapset,
  70. struct Colors *colors)
  71. {
  72. char element[512];
  73. char xname[GNAME_MAX], xmapset[GMAPSET_MAX];
  74. FILE *fd;
  75. if (G_name_is_fully_qualified(name, xname, xmapset)) {
  76. if (strcmp(xmapset, mapset) != 0)
  77. G_fatal_error(_("Qualified name <%s> doesn't match mapset <%s>"),
  78. name, mapset);
  79. name = xname;
  80. }
  81. /*
  82. * if mapset is current mapset, remove colr2 file (created by pre 3.0 grass)
  83. * and then write original color table
  84. * else write secondary color table
  85. */
  86. sprintf(element, "colr2/%s", mapset);
  87. if (strcmp(mapset, G_mapset()) == 0) {
  88. G_remove(element, name); /* get rid of existing colr2, if any */
  89. strcpy(element, "colr");
  90. }
  91. if (!(fd = G_fopen_new(element, name)))
  92. G_fatal_error(_("Unable to create <%s> file for map <%s>"),
  93. element, name);
  94. Rast__write_colors(fd, colors);
  95. fclose(fd);
  96. }
  97. /*!
  98. * \brief Write map layer color table
  99. *
  100. * \param fd file descriptor
  101. * \param colors pointer to Colors structure which holds color info
  102. */
  103. void Rast__write_colors(FILE * fd, struct Colors *colors)
  104. {
  105. if (getenv("FORCE_GRASS3_COLORS"))
  106. forced_write_old_colors(fd, colors);
  107. else if (colors->version < 0)
  108. write_old_colors(fd, colors);
  109. else
  110. write_new_colors(fd, colors);
  111. }
  112. static void write_new_colors(FILE * fd, struct Colors *colors)
  113. {
  114. char str1[100], str2[100];
  115. format_min(str1, (double)colors->cmin);
  116. format_max(str2, (double)colors->cmax);
  117. fprintf(fd, "%% %s %s\n", str1, str2);
  118. if (colors->shift) {
  119. sprintf(str2, "%.17g", (double)colors->shift);
  120. G_trim_decimal(str2);
  121. fprintf(fd, "shift:%s\n", str2);
  122. }
  123. if (colors->invert)
  124. fprintf(fd, "invert\n");
  125. if (colors->null_set) {
  126. fprintf(fd, "nv:%d", colors->null_red);
  127. if (colors->null_red != colors->null_grn || colors->null_red
  128. != colors->null_blu)
  129. fprintf(fd, ":%d:%d", colors->null_grn, colors->null_blu);
  130. fprintf(fd, "\n");
  131. }
  132. if (colors->undef_set) {
  133. fprintf(fd, "*:%d", colors->undef_red);
  134. if (colors->undef_red != colors->undef_grn || colors->undef_red
  135. != colors->undef_blu)
  136. fprintf(fd, ":%d:%d", colors->undef_grn, colors->undef_blu);
  137. fprintf(fd, "\n");
  138. }
  139. if (colors->modular.rules) {
  140. fprintf(fd, "%s\n", "%%");
  141. write_rules(fd, colors->modular.rules, colors->cmin, colors->cmax);
  142. fprintf(fd, "%s\n", "%%");
  143. }
  144. if (colors->fixed.rules)
  145. write_rules(fd, colors->fixed.rules, colors->cmin, colors->cmax);
  146. }
  147. /* overall min and max data values in color table */
  148. static void write_rules(FILE * fd, struct _Color_Rule_ *crules, DCELL dmin,
  149. DCELL dmax)
  150. {
  151. struct _Color_Rule_ *rule;
  152. char str[100];
  153. /* find the end of the rules list */
  154. rule = crules;
  155. while (rule->next)
  156. rule = rule->next;
  157. /* write out the rules in reverse order */
  158. for (; rule; rule = rule->prev) {
  159. if (rule->low.value == dmin)
  160. format_min(str, (double)rule->low.value);
  161. else {
  162. sprintf(str, "%.17g", (double)rule->low.value);
  163. G_trim_decimal(str);
  164. }
  165. fprintf(fd, "%s:%d", str, (int)rule->low.red);
  166. if (rule->low.red != rule->low.grn || rule->low.red != rule->low.blu)
  167. fprintf(fd, ":%d:%d", rule->low.grn, rule->low.blu);
  168. /* even if low==high, write second end when the high is dmax */
  169. if (rule->high.value == dmax || rule->low.value != rule->high.value) {
  170. if (rule->high.value == dmax)
  171. format_max(str, (double)rule->high.value);
  172. else {
  173. sprintf(str, "%.17g", (double)rule->high.value);
  174. G_trim_decimal(str);
  175. }
  176. fprintf(fd, " %s:%d", str, (int)rule->high.red);
  177. if (rule->high.red != rule->high.grn ||
  178. rule->high.red != rule->high.blu)
  179. fprintf(fd, ":%d:%d", rule->high.grn, rule->high.blu);
  180. }
  181. fprintf(fd, "\n");
  182. }
  183. }
  184. static void write_old_colors(FILE * fd, struct Colors *colors)
  185. {
  186. int i, n;
  187. fprintf(fd, "#%ld first color\n", (long)colors->fixed.min);
  188. if (colors->null_set) {
  189. fprintf(fd, "%d %d %d\n",
  190. (int)colors->null_red,
  191. (int)colors->null_grn, (int)colors->null_blu);
  192. }
  193. else
  194. fprintf(fd, "255 255 255\n"); /* white */
  195. n = colors->fixed.max - colors->fixed.min + 1;
  196. for (i = 0; i < n; i++) {
  197. fprintf(fd, "%d", (int)colors->fixed.lookup.red[i]);
  198. if (colors->fixed.lookup.red[i] != colors->fixed.lookup.grn[i]
  199. || colors->fixed.lookup.red[i] != colors->fixed.lookup.blu[i])
  200. fprintf(fd, " %d %d",
  201. (int)colors->fixed.lookup.grn[i],
  202. (int)colors->fixed.lookup.blu[i]);
  203. fprintf(fd, "\n");
  204. }
  205. }
  206. static void forced_write_old_colors(FILE * fd, struct Colors *colors)
  207. {
  208. int red, grn, blu;
  209. CELL cat;
  210. fprintf(fd, "#%ld first color\n", (long)colors->cmin);
  211. cat = 0;
  212. Rast_get_c_color(&cat, &red, &grn, &blu, colors);
  213. fprintf(fd, "%d %d %d\n", red, grn, blu);
  214. for (cat = colors->cmin; cat <= colors->cmax; cat++) {
  215. Rast_get_c_color(&cat, &red, &grn, &blu, colors);
  216. fprintf(fd, "%d", red);
  217. if (red != grn || red != blu)
  218. fprintf(fd, " %d %d", grn, blu);
  219. fprintf(fd, "\n");
  220. }
  221. }
  222. static void format_min(char *str, double dval)
  223. {
  224. double dtmp;
  225. sprintf(str, "%.17g", dval);
  226. /* Note that G_trim_decimal() does not trim e.g. 1.0000000e-20 */
  227. G_trim_decimal(str);
  228. sscanf(str, "%lf", &dtmp);
  229. if (dtmp != dval) { /* if no zeros after decimal point were trimmed */
  230. /* lower dval by GRASS_EPSILON fraction */
  231. if (dval > 0)
  232. sprintf(str, "%.17g", dval * (1 - GRASS_EPSILON));
  233. else
  234. sprintf(str, "%.17g", dval * (1 + GRASS_EPSILON));
  235. }
  236. }
  237. static void format_max(char *str, double dval)
  238. {
  239. double dtmp;
  240. sprintf(str, "%.17g", dval);
  241. /* Note that G_trim_decimal() does not trim e.g. 1.0000000e-20 */
  242. G_trim_decimal(str);
  243. sscanf(str, "%lf", &dtmp);
  244. if (dtmp != dval) { /* if no zeros after decimal point were trimmed */
  245. /* increase dval by by GRASS_EPSILON fraction */
  246. if (dval > 0)
  247. sprintf(str, "%.17g", dval * (1 + GRASS_EPSILON));
  248. else
  249. sprintf(str, "%.17g", dval * (1 - GRASS_EPSILON));
  250. }
  251. }