|
@@ -9,18 +9,26 @@
|
|
|
|
|
|
#include <grass/gis.h>
|
|
|
#include <grass/display.h>
|
|
|
+#include <grass/raster.h>
|
|
|
+#include <grass/glocale.h>
|
|
|
#include "local_proto.h"
|
|
|
|
|
|
void draw_histogram(const char *map_name, int x0, int y0, int width,
|
|
|
int height, int color, int flip, int horiz,
|
|
|
- int map_type, int is_fp)
|
|
|
+ int map_type, int is_fp, struct FPRange render_range)
|
|
|
{
|
|
|
- int i, nsteps;
|
|
|
- long cell_count;
|
|
|
+ int i, nsteps, ystep;
|
|
|
+ long cell_count = 0;
|
|
|
double max_width, width_mult, dx;
|
|
|
double dy, y0_adjust; /* only needed for CELL maps */
|
|
|
struct stat_list dist_stats;
|
|
|
struct stat_node *ptr;
|
|
|
+ struct Range range;
|
|
|
+ struct FPRange fprange;
|
|
|
+ CELL c_map_min, c_map_max;
|
|
|
+ DCELL d_map_min, d_map_max;
|
|
|
+ double map_min, map_max, map_range, user_range;
|
|
|
+ double crop_min_perc = 0.0, crop_max_perc = 1.0, pad_min_perc = 0.0;
|
|
|
|
|
|
if (horiz) {
|
|
|
max_width = height * 1.75;
|
|
@@ -31,6 +39,78 @@ void draw_histogram(const char *map_name, int x0, int y0, int width,
|
|
|
nsteps = height - 3;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ if (render_range.first_time) {
|
|
|
+ /* user specified range, can be either larger
|
|
|
+ or smaller than actual map's range */
|
|
|
+
|
|
|
+ if (is_fp) {
|
|
|
+ Rast_read_fp_range(map_name, "", &fprange);
|
|
|
+ Rast_get_fp_range_min_max(&fprange, &d_map_min, &d_map_max);
|
|
|
+ map_min = (double)d_map_min;
|
|
|
+ map_max = (double)d_map_max;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ Rast_read_range(map_name, "", &range);
|
|
|
+ Rast_get_range_min_max(&range, &c_map_min, &c_map_max);
|
|
|
+ map_min = (double)c_map_min;
|
|
|
+ map_max = (double)c_map_max;
|
|
|
+ }
|
|
|
+
|
|
|
+ map_range = map_max - map_min;
|
|
|
+ user_range = render_range.max - render_range.min;
|
|
|
+
|
|
|
+ if (horiz)
|
|
|
+ nsteps = (int)(0.5 + (map_range * (width - 3) / user_range));
|
|
|
+ else
|
|
|
+ nsteps = (int)(0.5 + (map_range * (height - 3) / user_range));
|
|
|
+
|
|
|
+ G_debug(1, "number of steps for r.stats = %d, height-3=%d width-3=%d",
|
|
|
+ nsteps, height - 3, width - 3);
|
|
|
+
|
|
|
+ /* need to know the % of the MAP range where user range starts and stops.
|
|
|
+ * note that MAP range can be fully inside user range, in which case
|
|
|
+ * keep 0-100% aka 0,nsteps, i.e. the step number in the nsteps range */
|
|
|
+
|
|
|
+ if (render_range.min > map_min) {
|
|
|
+ crop_min_perc = (render_range.min - map_min) / map_range;
|
|
|
+ G_debug(3, "min: %.02f vs. %.02f (%.02f) ... %.02f%%",
|
|
|
+ render_range.min, map_min, map_range, 100 * crop_min_perc);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (render_range.max > map_max) {
|
|
|
+ crop_max_perc = 1.0 - ((render_range.max - map_max) / user_range);
|
|
|
+ G_debug(3, "max: %.02f vs. %.02f (%.02f) ... %.02f%%",
|
|
|
+ map_max, render_range.max, map_range, 100 * crop_max_perc);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (render_range.min < map_min) {
|
|
|
+ pad_min_perc = (map_min - render_range.min) / user_range;
|
|
|
+ G_debug(3, "Min: %.02f vs. %.02f (%.02f) ... %.02f%%",
|
|
|
+ map_min, render_range.min, user_range, 100 * pad_min_perc);
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef amplify_gain
|
|
|
+ /* proportion of nsteps to width, use as mult factor to boost the 1.75x
|
|
|
+ when spread out over more nsteps than we are displaying */
|
|
|
+ G_debug(0, "max_width was: %.2f (nsteps=%d)", max_width, nsteps);
|
|
|
+
|
|
|
+ if (nsteps > ((horiz ? width : height) - 3.0))
|
|
|
+ max_width *= nsteps / ((horiz ? width : height) - 3.0);
|
|
|
+
|
|
|
+ G_debug(0, "max_width now: %.2f", max_width);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /* TODO */
|
|
|
+ if (!is_fp && render_range.first_time) {
|
|
|
+ G_warning(_("Histogram constrained by range not yet implemented for "
|
|
|
+ "categorical rasters"));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
/* get the distribution statistics */
|
|
|
get_stats(map_name, &dist_stats, nsteps, map_type);
|
|
|
|
|
@@ -56,10 +136,39 @@ void draw_histogram(const char *map_name, int x0, int y0, int width,
|
|
|
y0_adjust += 0.5;
|
|
|
}
|
|
|
|
|
|
- for (i = dist_stats.mincat; i <= dist_stats.maxcat; i++) {
|
|
|
+
|
|
|
+ G_debug(3, "mincat=%ld maxcat=%ld", dist_stats.mincat, dist_stats.maxcat);
|
|
|
+
|
|
|
+ for (i = dist_stats.mincat, ystep = 0; i <= dist_stats.maxcat; i++) {
|
|
|
if (!ptr)
|
|
|
break;
|
|
|
|
|
|
+ /* jump out if user range cuts things shorter than the map's native range */
|
|
|
+ if ((horiz && ystep > width - 4) || (!horiz && ystep > height - 4))
|
|
|
+ break;
|
|
|
+
|
|
|
+ /* jump out if user range goes beyond max of map data */
|
|
|
+ if (((double)ystep / ((horiz ? width : height) - 3.0)) > crop_max_perc)
|
|
|
+ break;
|
|
|
+/* TODO if (!is_fp && i > render_range.max)
|
|
|
+ break;
|
|
|
+*/
|
|
|
+ /* haven't made it to the min of the user range yet */
|
|
|
+ if (((double)i / nsteps) < crop_min_perc) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* now it's ok advance the plotter position */
|
|
|
+ ystep++;
|
|
|
+
|
|
|
+ /* if user range is below the minimum real map value, we need to pad out the space */
|
|
|
+ if (render_range.first_time && render_range.min < map_min) {
|
|
|
+ if ( ((double)ystep / ((horiz ? width : height) - 3.0)) < pad_min_perc) {
|
|
|
+ i--;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if (ptr->cat == i) { /* AH-HA!! found the stat */
|
|
|
cell_count = ptr->stat;
|
|
|
|
|
@@ -78,9 +187,12 @@ void draw_histogram(const char *map_name, int x0, int y0, int width,
|
|
|
ptr = ptr->next;
|
|
|
}
|
|
|
else /* stat cannot be found */
|
|
|
- G_debug(4, "No matching stat found, i=%d", i);
|
|
|
+ G_debug(5, "No matching stat found, i=%d", i);
|
|
|
}
|
|
|
|
|
|
+ G_debug(5, "i=%d ptr->cat=%ld cell_count=%ld", i, ptr->cat,
|
|
|
+ cell_count);
|
|
|
+
|
|
|
if (!cell_count)
|
|
|
continue;
|
|
|
|
|
@@ -89,17 +201,17 @@ void draw_histogram(const char *map_name, int x0, int y0, int width,
|
|
|
if (is_fp) {
|
|
|
if (horiz) {
|
|
|
if (flip)
|
|
|
- D_move_abs(x0 + width - i - 1, y0 - 1);
|
|
|
+ D_move_abs(x0 + width - ystep - 1, y0 - 1);
|
|
|
else
|
|
|
- D_move_abs(x0 + i + 1, y0 - 1);
|
|
|
+ D_move_abs(x0 + ystep + 1, y0 - 1);
|
|
|
|
|
|
D_cont_rel(0, -dx);
|
|
|
}
|
|
|
else { /* vertical */
|
|
|
if (flip)
|
|
|
- D_move_abs(x0 - 1, y0 - 1 + height - i);
|
|
|
+ D_move_abs(x0 - 1, y0 - 1 + height - ystep);
|
|
|
else
|
|
|
- D_move_abs(x0 - 1, y0 + 1 + i);
|
|
|
+ D_move_abs(x0 - 1, y0 + 1 + ystep);
|
|
|
|
|
|
D_cont_rel(-dx, 0);
|
|
|
}
|