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