浏览代码

r.colors: add offset and scale (#954)

adding offset and scale enables r.colors to add e.g. the celsius rules to a map with units = Kelvin * 50
Markus Metz 4 年之前
父节点
当前提交
9bbd20df7d
共有 5 个文件被更改,包括 254 次插入111 次删除
  1. 52 5
      raster/r.colors/edit_colors.c
  2. 3 1
      raster/r.colors/local_proto.h
  3. 7 0
      raster/r.colors/r.colors.html
  4. 81 1
      raster/r.colors/rules.c
  5. 111 104
      raster/r.colors/stats.c

+ 52 - 5
raster/r.colors/edit_colors.c

@@ -59,13 +59,16 @@ int edit_colors(int argc, char **argv, int type, const char *maptype,
     struct GModule *module;
     struct GModule *module;
     struct maps_info input_maps;
     struct maps_info input_maps;
     int stat = -1;
     int stat = -1;
+    int do_scale, rule_is_percent;
+    double scale, offset;
 
 
     struct {
     struct {
         struct Flag *r, *w, *l, *d, *g, *a, *n, *e;
         struct Flag *r, *w, *l, *d, *g, *a, *n, *e;
     } flag; 
     } flag; 
 
 
     struct {
     struct {
-        struct Option *maps, *colr, *rast, *volume, *rules, *file;
+        struct Option *maps, *colr, *rast, *volume, *rules, *file,
+		      *scale, *offset;
     } opt;
     } opt;
     
     
     G_gisinit(argv[0]);
     G_gisinit(argv[0]);
@@ -127,6 +130,24 @@ int edit_colors(int argc, char **argv, int type, const char *maptype,
     opt.rules->description = _("\"-\" to read rules from stdin");
     opt.rules->description = _("\"-\" to read rules from stdin");
     opt.rules->guisection = _("Define");
     opt.rules->guisection = _("Define");
 
 
+    opt.offset = G_define_option();
+    opt.offset->key = "offset";
+    opt.offset->type = TYPE_DOUBLE;
+    opt.offset->required = NO;
+    opt.offset->answer = "0";
+    opt.offset->label = _("Offset for color rule values");
+    opt.offset->description = _("New value = (old value + offset) * scale");
+    opt.offset->guisection = _("Define");
+
+    opt.scale = G_define_option();
+    opt.scale->key = "scale";
+    opt.scale->type = TYPE_DOUBLE;
+    opt.scale->required = NO;
+    opt.scale->answer = "1";
+    opt.scale->label = _("Scale for color rule values");
+    opt.scale->description = _("New value = (old value + offset) * scale");
+    opt.scale->guisection = _("Define");
+
     flag.r = G_define_flag();
     flag.r = G_define_flag();
     flag.r->key = 'r';
     flag.r->key = 'r';
     flag.r->description = _("Remove existing color table");
     flag.r->description = _("Remove existing color table");
@@ -199,6 +220,9 @@ int edit_colors(int argc, char **argv, int type, const char *maptype,
     rules = opt.rules->answer;
     rules = opt.rules->answer;
     file = opt.file->answer;
     file = opt.file->answer;
 
 
+    offset = atof(opt.offset->answer);
+    scale = atof(opt.scale->answer);
+
     if (opt.rast->answer)
     if (opt.rast->answer)
         cmap = opt.rast->answer;
         cmap = opt.rast->answer;
     if (opt.volume->answer)
     if (opt.volume->answer)
@@ -360,7 +384,7 @@ int edit_colors(int argc, char **argv, int type, const char *maptype,
 	}
 	}
 
 
 	if (i > 0) {
 	if (i > 0) {
-	    if(has_fcell_type && has_cell_type) {
+	    if (has_fcell_type && has_cell_type) {
 		G_fatal_error("Input maps must have the same cell type. "
 		G_fatal_error("Input maps must have the same cell type. "
 				"Mixing of integer and floating point maps is not supported.");
 				"Mixing of integer and floating point maps is not supported.");
 	    }
 	    }
@@ -381,9 +405,12 @@ int edit_colors(int argc, char **argv, int type, const char *maptype,
 	}
 	}
     }
     }
 
 
+    rule_is_percent = 0;
+    do_scale = 0;
     if (is_from_stdin) {
     if (is_from_stdin) {
-        if (!read_color_rules(stdin, &colors, min, max, has_fcell_type))
+        if (!read_color_rules(stdin, &colors, min, max, has_fcell_type, &rule_is_percent))
             exit(EXIT_FAILURE);
             exit(EXIT_FAILURE);
+	do_scale = 1;
     }
     }
     else if (style) {
     else if (style) {
         /* 
         /* 
@@ -409,13 +436,27 @@ int edit_colors(int argc, char **argv, int type, const char *maptype,
             Rast_make_histogram_log_colors(&colors, &statf, (CELL) min,
             Rast_make_histogram_log_colors(&colors, &statf, (CELL) min,
                                            (CELL) max);
                                            (CELL) max);
         }
         }
-	else if (G_find_color_rule(style))
+	else if (G_find_color_rule(style)) {
+	    char path[GPATH_MAX];
+
             Rast_make_fp_colors(&colors, style, min, max);
             Rast_make_fp_colors(&colors, style, min, max);
+
+	    /* check if this style is a percentage style */
+            /* don't bother with native dirsep as not needed for backwards compatibility */
+            G_snprintf(path, GPATH_MAX, "%s/etc/colors/%s", G_gisbase(), style);
+	    rule_is_percent = check_percent_rule(path);
+	    do_scale = 1;
+	}
         else
         else
             G_fatal_error(_("Unknown color request '%s'"), style);
             G_fatal_error(_("Unknown color request '%s'"), style);
     }
     }
     else if (rules) {
     else if (rules) {
-        if (!Rast_load_fp_colors(&colors, rules, min, max)) {
+	do_scale = 1;
+	/* check if these rules are percentage rules */
+        if (Rast_load_fp_colors(&colors, rules, min, max)) {
+	    rule_is_percent = check_percent_rule(rules);
+	}
+	else {
             /* for backwards compatibility try as std name; remove for GRASS 7 */
             /* for backwards compatibility try as std name; remove for GRASS 7 */
             char path[GPATH_MAX];
             char path[GPATH_MAX];
 
 
@@ -424,6 +465,7 @@ int edit_colors(int argc, char **argv, int type, const char *maptype,
 
 
             if (!Rast_load_fp_colors(&colors, path, min, max))
             if (!Rast_load_fp_colors(&colors, path, min, max))
                 G_fatal_error(_("Unable to load rules file <%s>"), rules);
                 G_fatal_error(_("Unable to load rules file <%s>"), rules);
+	    rule_is_percent = check_percent_rule(path);
         }
         }
     }
     }
     else {
     else {
@@ -449,6 +491,11 @@ int edit_colors(int argc, char **argv, int type, const char *maptype,
     if (has_fcell_type)
     if (has_fcell_type)
         Rast_mark_colors_as_fp(&colors);
         Rast_mark_colors_as_fp(&colors);
 
 
+    if (do_scale && !rule_is_percent && (offset != 0 || scale != 1)) {
+	rescale_colors(&colors_tmp, &colors, offset, scale);
+	colors = colors_tmp;
+    }
+
     if (flag.n->answer)
     if (flag.n->answer)
         Rast_invert_colors(&colors);
         Rast_invert_colors(&colors);
 
 

+ 3 - 1
raster/r.colors/local_proto.h

@@ -47,6 +47,8 @@ void get_fp_stats(struct maps_info *, struct FP_stats *statf,
 int edit_colors(int, char **, int, const char *, const char*);
 int edit_colors(int, char **, int, const char *, const char*);
 
 
 /* rules.c */
 /* rules.c */
-int read_color_rules(FILE *, struct Colors *, DCELL, DCELL, int);
+int read_color_rules(FILE *, struct Colors *, DCELL, DCELL, int, int *);
+int check_percent_rule(const char *);
+void rescale_colors(struct Colors *, struct Colors *, double, double);
 
 
 #endif /* __LOCAL_PROTO_H__ */
 #endif /* __LOCAL_PROTO_H__ */

+ 7 - 0
raster/r.colors/r.colors.html

@@ -38,6 +38,13 @@ solution.
 
 
 <p>The <b>-e</b> and <b>-g</b> flags are not mutually exclusive.
 <p>The <b>-e</b> and <b>-g</b> flags are not mutually exclusive.
 
 
+<p><b>offset</b> and <b>scale</b> modify color rules to match the
+values of a raster map using the formula <em>new_value = (old_value +
+offset) x scale</em>. For example, if the units of a raster map are
+Kelvin x 50, the color rules <em>celsius</em> can be applied with
+<em>offset=273.15</em> and <em>scale=50</em>.
+
+
 <p>If the user specifies the <b>-w</b> flag, the current color table file for
 <p>If the user specifies the <b>-w</b> flag, the current color table file for
 the input map will not be overwritten. This means that the color table is
 the input map will not be overwritten. This means that the color table is
 created only if the <i>map</i> does not already have a color table. If this
 created only if the <i>map</i> does not already have a color table. If this

+ 81 - 1
raster/r.colors/rules.c

@@ -30,8 +30,10 @@ static int read_rule(void *, DCELL, DCELL, DCELL *, int *, int *, int *,
 static void badrule(int, const char *, int);
 static void badrule(int, const char *, int);
 static int show_colors(FILE *);
 static int show_colors(FILE *);
 
 
+static int rule_is_percent = 0;
+
 int read_color_rules(FILE * fp, struct Colors *colors, DCELL min, DCELL max,
 int read_color_rules(FILE * fp, struct Colors *colors, DCELL min, DCELL max,
-		     int is_fp)
+		     int is_fp, int *is_percent)
 {
 {
     DCELL rulemin, rulemax;
     DCELL rulemin, rulemax;
 
 
@@ -64,9 +66,78 @@ int read_color_rules(FILE * fp, struct Colors *colors, DCELL min, DCELL max,
 	G_warning(_("Your color rules do not cover the whole range of data!\n (rules %f to %f but data %f to %f)"),
 	G_warning(_("Your color rules do not cover the whole range of data!\n (rules %f to %f but data %f to %f)"),
 		  rulemin, rulemax, min, max);
 		  rulemin, rulemax, min, max);
 
 
+    *is_percent = rule_is_percent;
+
     return 1;
     return 1;
 }
 }
 
 
+int check_percent_rule(const char *path)
+{
+    FILE *fp;
+    char buf[1024];
+
+    fp = fopen(path, "r");
+    if (!fp)
+	G_fatal_error(_("Unable to open color rule"));
+
+    rule_is_percent = 0;
+    while (G_getl2(buf, sizeof(buf), fp)) {
+	char value[80], color[80];
+	double x;
+	char c;
+
+	G_strip(buf);
+
+	if (*buf == '\0')
+	    continue;
+	if (*buf == '#')
+	    continue;
+
+	if (sscanf(buf, "%s %[^\n]", value, color) != 2)
+	    continue;
+
+	if (sscanf(value, "%lf%c", &x, &c) == 2 && c == '%') {
+	    rule_is_percent = 1;
+	    break;
+	}
+    }
+    fclose(fp);
+
+    return rule_is_percent;
+}
+
+void rescale_colors(struct Colors *colors_tmp, struct Colors *colors,
+                    double offset, double scale)
+{
+    int i, rcount;
+    unsigned char r1, g1, b1, r2, g2, b2;
+    int red, grn, blu;
+    DCELL dmin, dmax;
+
+    Rast_init_colors(colors_tmp);
+
+    Rast_get_default_color(&red, &grn, &blu, colors);
+    Rast_set_default_color(red, grn, blu, colors_tmp);
+
+    Rast_get_null_value_color(&red, &grn, &blu, colors);
+    Rast_set_null_value_color(red, grn, blu, colors_tmp);
+
+    rcount = Rast_colors_count(colors);
+    for (i = 0; i < rcount; i++) {
+
+	Rast_get_fp_color_rule(&dmin, &r1, &g1, &b1,
+			       &dmax, &r2, &g2, &b2,
+			       colors, i);
+
+	dmin = (dmin + offset) * scale;
+	dmax = (dmax + offset) * scale;
+
+	Rast_add_d_color_rule(&dmin, r1, g1, b1,
+			      &dmax, r2, g2, b2, colors_tmp);
+
+    }
+}
+
 static int read_rule(void *closure, DCELL min, DCELL max,
 static int read_rule(void *closure, DCELL min, DCELL max,
 		     DCELL * val, int *r, int *g, int *b,
 		     DCELL * val, int *r, int *g, int *b,
 		     int *norm, int *nval, int *dflt)
 		     int *norm, int *nval, int *dflt)
@@ -79,6 +150,9 @@ static int read_rule(void *closure, DCELL min, DCELL max,
     for (;;) {
     for (;;) {
 	char buf[1024];
 	char buf[1024];
 	int ret, i;
 	int ret, i;
+	char value[80], color[80];
+	double x;
+	char c;
 
 
 	if (tty)
 	if (tty)
 	    fprintf(stderr, "> ");
 	    fprintf(stderr, "> ");
@@ -113,6 +187,12 @@ static int read_rule(void *closure, DCELL min, DCELL max,
 	    continue;
 	    continue;
 	}
 	}
 
 
+	if (sscanf(buf, "%s %[^\n]", value, color) == 2) {
+	    if (sscanf(value, "%lf%c", &x, &c) == 2 && c == '%') {
+		rule_is_percent = 1;
+	    }
+	}
+
 	ret =
 	ret =
 	    Rast_parse_color_rule(min, max, buf, val, r, g, b, norm, nval, dflt);
 	    Rast_parse_color_rule(min, max, buf, val, r, g, b, norm, nval, dflt);
 	if (ret == 0)
 	if (ret == 0)

+ 111 - 104
raster/r.colors/stats.c

@@ -21,7 +21,8 @@
 #include <stdlib.h>
 #include <stdlib.h>
 #include "local_proto.h"
 #include "local_proto.h"
 
 
-int get_stats(struct maps_info *input_maps, struct Cell_stats *statf) {
+int get_stats(struct maps_info *input_maps, struct Cell_stats *statf)
+{
     CELL *cell;
     CELL *cell;
     int row, nrows, ncols;
     int row, nrows, ncols;
     int fd;
     int fd;
@@ -29,25 +30,25 @@ int get_stats(struct maps_info *input_maps, struct Cell_stats *statf) {
 
 
     Rast_init_cell_stats(statf);
     Rast_init_cell_stats(statf);
 
 
-    for(i = 0; i < input_maps->num; i++) {
-		fd = Rast_open_old(input_maps->names[i], input_maps->mapsets[i]);
+    for (i = 0; i < input_maps->num; i++) {
+	fd = Rast_open_old(input_maps->names[i], input_maps->mapsets[i]);
 
 
-	    cell = Rast_allocate_c_buf();
-	    nrows = Rast_window_rows();
-	    ncols = Rast_window_cols();
+	cell = Rast_allocate_c_buf();
+	nrows = Rast_window_rows();
+	ncols = Rast_window_cols();
 
 
-		G_verbose_message(_("(%i/%i) Reading raster map <%s>..."),
-				i + 1, input_maps->num,
-				G_fully_qualified_name(input_maps->names[i], input_maps->mapsets[i]));
+	G_verbose_message(_("(%i/%i) Reading raster map <%s>..."),
+			i + 1, input_maps->num,
+			G_fully_qualified_name(input_maps->names[i], input_maps->mapsets[i]));
 
 
-		for (row = 0; row < nrows; row++) {
-			G_percent(row, nrows, 2);
-			Rast_get_c_row(fd, cell, row);
-			Rast_update_cell_stats(cell, ncols, statf);
-		}
-		G_percent(row, nrows, 2);
-		Rast_close(fd);
-	    G_free(cell);
+	for (row = 0; row < nrows; row++) {
+	    G_percent(row, nrows, 2);
+	    Rast_get_c_row(fd, cell, row);
+	    Rast_update_cell_stats(cell, ncols, statf);
+	}
+	G_percent(nrows, nrows, 2);
+	Rast_close(fd);
+	G_free(cell);
     }
     }
 
 
     return 1;
     return 1;
@@ -55,7 +56,8 @@ int get_stats(struct maps_info *input_maps, struct Cell_stats *statf) {
 
 
 void get_fp_stats(struct maps_info *input_maps,
 void get_fp_stats(struct maps_info *input_maps,
         struct FP_stats *statf,
         struct FP_stats *statf,
-        DCELL min, DCELL max, int geometric, int geom_abs, int type) {
+        DCELL min, DCELL max, int geometric, int geom_abs, int type)
+{
     DCELL *dcell = NULL;
     DCELL *dcell = NULL;
     int row, col, depth, nrows, ncols, ndepths = 1;
     int row, col, depth, nrows, ncols, ndepths = 1;
     int fd;
     int fd;
@@ -64,108 +66,113 @@ void get_fp_stats(struct maps_info *input_maps,
     char *mapset;
     char *mapset;
     RASTER3D_Map *map3d = NULL;
     RASTER3D_Map *map3d = NULL;
 
 
-	statf->geometric = geometric;
-	statf->geom_abs = geom_abs;
-	statf->flip = 0;
+    statf->geometric = geometric;
+    statf->geom_abs = geom_abs;
+    statf->flip = 0;
 
 
-	if (statf->geometric) {
-		if (min * max < 0)
-			G_fatal_error(_("Unable to use logarithmic scaling if range includes zero"));
+    if (statf->geometric) {
+	if (min * max < 0)
+	    G_fatal_error(_("Unable to use logarithmic scaling if range includes zero"));
 
 
-		if (min < 0) {
-			statf->flip = 1;
-			min = -min;
-			max = -max;
-		}
-		min = log(min);
-		max = log(max);
+	if (min < 0) {
+	    statf->flip = 1;
+	    min = -min;
+	    max = -max;
 	}
 	}
+	min = log(min);
+	max = log(max);
+    }
+
+    if (statf->geom_abs) {
+	double a = log(fabs(min) + 1);
+	double b = log(fabs(max) + 1);
+	int has_zero = min * max < 0;
+
+	min = a < b ? a : b;
+	max = a > b ? a : b;
+	if (has_zero)
+	    min = 0;
+    }
+
+    statf->count = 1000;
+    statf->min = min;
+    statf->max = max;
+    statf->stats = G_calloc(statf->count + 1, sizeof (unsigned long));
+    statf->total = 0;
+
+    /* Loop over all input maps */
+    for(i = 0; i < input_maps->num; i++) {
+	name = input_maps->names[i];
+	mapset = input_maps->mapsets[i];
 
 
-	if (statf->geom_abs) {
-		double a = log(fabs(min) + 1);
-		double b = log(fabs(max) + 1);
-		int has_zero = min * max < 0;
-		min = a < b ? a : b;
-		max = a > b ? a : b;
-		if (has_zero)
-			min = 0;
+	fd = -1;
+	if (type == RASTER_TYPE) {
+	    fd = Rast_open_old(name, mapset);
+	    dcell = Rast_allocate_d_buf();
+	    nrows = Rast_window_rows();
+	    ncols = Rast_window_cols();
 	}
 	}
+	else {
+	    /* Initiate the default settings */
+	    Rast3d_init_defaults();
 
 
-	statf->count = 1000;
-	statf->min = min;
-	statf->max = max;
-	statf->stats = G_calloc(statf->count + 1, sizeof (unsigned long));
-	statf->total = 0;
-
-	/* Loop over all input maps */
-	for(i = 0; i < input_maps->num; i++) {
-		name = input_maps->names[i];
-		mapset = input_maps->mapsets[i];
-
-		if (type == RASTER_TYPE) {
-			fd = Rast_open_old(name, mapset);
-			dcell = Rast_allocate_d_buf();
-			nrows = Rast_window_rows();
-			ncols = Rast_window_cols();
-		} else {
-			/* Initiate the default settings */
-			Rast3d_init_defaults();
-
-			map3d = Rast3d_open_cell_old(name, mapset, RASTER3D_DEFAULT_WINDOW,
-					RASTER3D_TILE_SAME_AS_FILE, RASTER3D_USE_CACHE_DEFAULT);
-
-			if (map3d == NULL)
-				Rast3d_fatal_error(_("Error opening 3d raster map"));
-
-			nrows = map3d->window.rows;
-			ncols = map3d->window.cols;
-			ndepths = map3d->window.depths;
-		}
+	    map3d = Rast3d_open_cell_old(name, mapset, RASTER3D_DEFAULT_WINDOW,
+			    RASTER3D_TILE_SAME_AS_FILE, RASTER3D_USE_CACHE_DEFAULT);
 
 
-		G_verbose_message(_("(%i/%i) Reading map <%s>..."), i, input_maps->num,
-				G_fully_qualified_name(name, mapset));
+	    if (map3d == NULL)
+		Rast3d_fatal_error(_("Error opening 3d raster map"));
 
 
-		for (depth = 0; depth < ndepths; depth++) {
-			for (row = 0; row < nrows; row++) {
-				G_percent(row, nrows, 2);
+	    nrows = map3d->window.rows;
+	    ncols = map3d->window.cols;
+	    ndepths = map3d->window.depths;
+	}
 
 
-				if (type == RASTER_TYPE)
-					Rast_get_d_row(fd, dcell, row);
+	G_verbose_message(_("(%i/%i) Reading map <%s>..."), i, input_maps->num,
+			G_fully_qualified_name(name, mapset));
 
 
-				for (col = 0; col < ncols; col++) {
-					DCELL x;
-					int j;
+	for (depth = 0; depth < ndepths; depth++) {
+	    for (row = 0; row < nrows; row++) {
+		G_percent(row, nrows, 2);
 
 
-					if (type == RASTER_TYPE)
-						x = dcell[col];
-					else
-						x = Rast3d_get_double(map3d, col, row, depth);
+		if (type == RASTER_TYPE)
+		    Rast_get_d_row(fd, dcell, row);
 
 
-					if (Rast_is_d_null_value(&x))
-						continue;
+		for (col = 0; col < ncols; col++) {
+		    DCELL x;
+		    int j;
 
 
-					if (statf->flip)
-						x = -x;
-					if (statf->geometric)
-						x = log(x);
-					if (statf->geom_abs)
-						x = log(fabs(x) + 1);
+		    if (type == RASTER_TYPE)
+			x = dcell[col];
+		    else
+			x = Rast3d_get_double(map3d, col, row, depth);
 
 
-					j = (int) floor(statf->count * (x - statf->min) / (statf->max - statf->min));
-					statf->stats[j]++;
-					statf->total++;
-				}
-			}
-		}
+		    if (Rast_is_d_null_value(&x))
+			continue;
 
 
-		G_percent(row, nrows, 2);
+		    if (statf->flip)
+			x = -x;
+		    if (statf->geometric)
+			x = log(x);
+		    if (statf->geom_abs)
+			x = log(fabs(x) + 1);
 
 
-		if (type == RASTER_TYPE) {
-			Rast_close(fd);
-		if(dcell)
-				G_free(dcell);
-		} else {
-			Rast3d_close(map3d);
+		    j = (int) floor(statf->count * (x - statf->min) / (statf->max - statf->min));
+		    statf->stats[j]++;
+		    statf->total++;
 		}
 		}
+	    }
+	}
+
+	G_percent(nrows, nrows, 2);
+
+	if (type == RASTER_TYPE) {
+	    Rast_close(fd);
+	if(dcell)
+	    G_free(dcell);
+	}
+	else {
+	    Rast3d_close(map3d);
+	    map3d = NULL;
 	}
 	}
+    }
 }
 }