int bar(struct stat_list *dist_stats, /* list of distribution statistics */ struct Colors *colors) { struct stat_node *ptr; int draw = YES; long int bar_height; /* height, in pixels, of a histogram bar */ CELL bar_color; /* color/category number of a histogram bar */ DCELL dmax, range_dmin, range_dmax, dmin, dval; long int max_tics; /* maximum tics allowed on an axis */ long int xoffset; /* offset for x-axis */ long int yoffset; /* offset for y-axis */ long int stat_start; long int stat_finis; int text_height; int text_width; long int i, j; long int num_cats = 0; long int num_stats = 0; long int tic_every; /* spacing, in units of category value, of tics */ long int tic_unit; double t, b, l, r; double tt, tb, tl, tr; double x_line[3]; /* for border of histogram */ double y_line[3]; double x_box[5]; /* for histogram bar coordinates */ double y_box[5]; double height, width; double xscale; /* scaling factors */ double yscale; char xlabel[1024]; char ylabel[1024]; char txt[1024]; char tic_name[80]; /* get coordinates of current screen window */ D_get_src(&t, &b, &l, &r); /* create axis lines, to be drawn later */ height = b - t; width = r - l; x_line[0] = x_line[1] = l + (ORIGIN_X * width); x_line[2] = l + (XAXIS_END * width); y_line[0] = b - (YAXIS_END * height); y_line[1] = y_line[2] = b - (ORIGIN_Y * height); /* figure scaling factors and offsets */ num_cats = dist_stats->maxcat - dist_stats->mincat + 1; if (nodata) { num_cats++; dist_stats->mincat--; } xscale = ((x_line[2] - x_line[1]) / ((double)num_cats)); yscale = ((y_line[1] - y_line[0])) / dist_stats->maxstat; if (num_cats >= x_line[2] - x_line[1]) xoffset = (long int)x_line[1]; else xoffset = (long int)x_line[0] + 0.5 * xscale; /* boxes need extra space */ yoffset = (double)(y_line[1]); /* figure tic_every and tic_units for the x-axis of the bar-chart. * tic_every tells how often to place a tic-number. tic_unit tells * the unit to use in expressing tic-numbers. */ if (xscale < XTIC_DIST) { max_tics = (x_line[2] - x_line[1]) / XTIC_DIST; if (nodata) max_tics--; i = 0; if (is_fp) { Rast_get_fp_range_min_max(&fp_range, &range_dmin, &range_dmax); if (Rast_is_d_null_value(&range_dmin) || Rast_is_d_null_value(&range_dmax)) G_fatal_error("Floating point data range is empty"); if ((range_dmax - range_dmin) < 1.0) tics[i].every = 5; if ((range_dmax - range_dmin) < 110) tics[i].every = 20; /* dirrty hack */ while ((range_dmax - range_dmin) / tics[i].every > max_tics) i++; } else { while ((num_cats / tics[i].every) > max_tics) i++; } tic_every = tics[i].every; tic_unit = tics[i].unit; strcpy(tic_name, tics[i].name); } else { if (is_fp && !cat_ranges) { Rast_get_fp_range_min_max(&fp_range, &range_dmin, &range_dmax); if (Rast_is_d_null_value(&range_dmin) || Rast_is_d_null_value(&range_dmax)) G_fatal_error("Floating point data range is empty"); } tic_every = 1; tic_unit = 1; } /* X-AXIS LOOP * * loop through category range, drawing a pie-slice and a * legend bar on each iteration evenly divisible, a tic-mark * on those evenly divisible by tic_unit, and a tic_mark * number on those evenly divisible by tic_every * */ ptr = dist_stats->ptr; for (i = dist_stats->mincat; i <= dist_stats->maxcat; i++) { if (!ptr) break; draw = NO; /* figure bar color and height * * the cat number determines the color, the corresponding stat, * determines the bar height. if a stat cannot be found for the * cat, then it doesn't drow anything, before it used to draw the * box of size 0 in black. Later when the option to provide the * background color will be added , we might still draw a box in * this color. */ if (nodata && i == dist_stats->mincat) { if (dist_stats->null_stat == 0 && xscale > 1) draw = NO; else { draw = YES; Rast_set_c_null_value(&bar_color, 1); bar_height = (yoffset - yscale * (double)dist_stats->null_stat); } } else if (ptr->cat == i) { /* AH-HA!! found the stat */ if (ptr->stat == 0 && xscale > 1) draw = NO; else { draw = YES; bar_color = ptr->cat; bar_height = (yoffset - yscale * (double)ptr->stat); } if (ptr->next != NULL) ptr = ptr->next; } else { /* we have to look for the stat */ /* loop until we find it, or pass where it should be */ while (ptr->cat < i && ptr->next != NULL) ptr = ptr->next; if (ptr->cat == i) { /* AH-HA!! found the stat */ if (ptr->stat == 0 && xscale > 1) draw = NO; else { draw = YES; bar_color = ptr->cat; bar_height = (yoffset - yscale * (double)ptr->stat); } if (ptr->next != NULL) ptr = ptr->next; } else { /* stat cannot be found */ if (xscale > 1) { draw = NO; #ifdef notdef draw = YES; bar_color = D_translate_color("black"); bar_height = yoffset; /* zero */ #endif } else draw = NO; } } /* draw the bar */ if (draw == YES) { if (xscale != 1) { /* draw the bar as a box */ if (!Rast_is_c_null_value(&bar_color) && is_fp) { if (cat_ranges) Rast_get_ith_d_cat(&cats, bar_color, &dmin, &dmax); else { dmin = range_dmin + i * (range_dmax - range_dmin) / nsteps; dmax = range_dmin + (i + 1) * (range_dmax - range_dmin) / nsteps; } if (dmin != dmax) { for (j = 0; j < xscale; j++) { dval = dmin + j * (dmax - dmin) / xscale; D_d_color(dval, colors); x_box[0] = x_box[1] = xoffset + ((i - dist_stats->mincat) * xscale - 0.5 * xscale + j); x_box[2] = x_box[3] = xoffset + ((i - dist_stats->mincat) * xscale - 0.5 * xscale + j + 1); y_box[0] = y_box[3] = yoffset; y_box[1] = y_box[2] = bar_height; D_polygon_abs(x_box, y_box, 4); } } else { /* 1-color bar */ D_d_color(dmin, colors); x_box[0] = x_box[1] = xoffset + ((i - dist_stats->mincat) * xscale - 0.5 * xscale); x_box[2] = x_box[3] = xoffset + ((i - dist_stats->mincat) * xscale + 0.5 * xscale); y_box[0] = y_box[3] = yoffset; y_box[1] = y_box[2] = bar_height; D_polygon_abs(x_box, y_box, 4); } } /* fp */ else { /* 1-color bar for int data or null */ D_color((CELL) bar_color, colors); x_box[0] = x_box[1] = xoffset + ((i - dist_stats->mincat) * xscale - 0.5 * xscale); x_box[2] = x_box[3] = xoffset + ((i - dist_stats->mincat) * xscale + 0.5 * xscale); y_box[0] = y_box[3] = yoffset; y_box[1] = y_box[2] = bar_height; D_polygon_abs(x_box, y_box, 4); } } else { /* draw the bar as a line */ if (is_fp) { if (cat_ranges) Rast_get_ith_d_cat(&cats, bar_color, &dmin, &dmax); else { dmin = range_dmin + i * (range_dmax - range_dmin) / nsteps; dmax = range_dmin + (i + 1) * (range_dmax - range_dmin) / nsteps; } D_d_color(dmin, colors); } else D_color((CELL) bar_color, colors); x_box[0] = x_box[1] = xoffset + (i - dist_stats->mincat) * xscale; y_box[0] = yoffset; y_box[1] = bar_height; D_line_abs(x_box[0], y_box[0], x_box[1], y_box[1]); } } /* draw x-axis tic-marks and numbers */ /* draw tick for null and for numbers at every tic step except when there is null, don't draw tic for mincat+1 */ if (((rem((long int)i, tic_every) == 0L) || ((i == dist_stats->mincat) && nodata)) && !(nodata && i == dist_stats->mincat + 1)) { /* draw a numbered tic-mark */ D_use_color(color); D_begin(); D_move_abs(xoffset + (i - dist_stats->mincat) * xscale - 0.5 * xscale, b - ORIGIN_Y * (b - t)); D_cont_rel(0, BIG_TIC * (b - t)); D_end(); D_stroke(); if (nodata && i == dist_stats->mincat) sprintf(txt, "null"); else if (is_fp) { dmin = range_dmin + i * (range_dmax - range_dmin) / nsteps; if ((tic_every * (range_dmax - range_dmin) / nsteps) < 1.0) sprintf(txt, "%.2f", dmin / (double)tic_unit); else sprintf(txt, "%d", (int)(dmin / (double)tic_unit)); } else sprintf(txt, "%d", (int)(i / tic_unit)); text_height = (b - t) * TEXT_HEIGHT; text_width = (r - l) * TEXT_WIDTH; D_text_size(text_width, text_height); D_get_text_box(txt, &tt, &tb, &tl, &tr); while ((tr - tl) > XTIC_DIST) { text_width *= 0.75; text_height *= 0.75; D_text_size(text_width, text_height); D_get_text_box(txt, &tt, &tb, &tl, &tr); } D_pos_abs(xoffset + (i - dist_stats->mincat) * xscale - 0.5 * xscale - (tr - tl) / 2, b - XNUMS_Y * (b - t)); D_text(txt); } else if (rem(i, tic_unit) == 0.0) { /* draw a tic-mark */ D_use_color(color); D_begin(); D_move_abs(xoffset + (i - dist_stats->mincat) * xscale - 0.5 * xscale, b - ORIGIN_Y * (b - t)); D_cont_rel(0, SMALL_TIC * (b - t)); D_end(); D_stroke(); } } /* draw the x-axis label */ if (tic_unit != 1) sprintf(xlabel, "X-AXIS: Cell Values %s", tic_name); else sprintf(xlabel, "X-AXIS: Cell Values"); text_height = (b - t) * TEXT_HEIGHT; text_width = (r - l) * TEXT_WIDTH; D_text_size(text_width, text_height); D_get_text_box(xlabel, &tt, &tb, &tl, &tr); D_pos_abs(l + (r - l) / 2 - (tr - tl) / 2, b - LABEL_1 * (b - t)); D_use_color(color); D_text(xlabel); /* DRAW Y-AXIS TIC-MARKS AND NUMBERS * * first, figure tic_every and tic_units for the x-axis of the bar-chart. * tic_every tells how often to place a tic-number. tic_unit tells * the unit to use in expressing tic-numbers. */ max_tics = (long)((y_line[1] - y_line[0]) / YTIC_DIST); if (dist_stats->maxstat == dist_stats->minstat) dist_stats->minstat = 0; /* LOOKS FUNNY TO ME */ num_stats = dist_stats->maxstat - dist_stats->minstat; i = 0; while ((num_stats / tics[i].every) > max_tics) i++; tic_every = tics[i].every; tic_unit = tics[i].unit; strcpy(tic_name, tics[i].name); stat_start = tic_unit * ((long)(dist_stats->minstat / tic_unit)); stat_finis = tic_unit * ((long)(dist_stats->maxstat / tic_unit)); /* Y-AXIS LOOP * */ for (i = stat_start; i <= stat_finis; i += tic_unit) { if (rem(i, tic_every) == (float)0) { /* draw a tic-mark */ D_begin(); D_move_abs(x_line[0], yoffset - yscale * i); D_cont_rel((-(r - l) * BIG_TIC), 0); D_end(); D_stroke(); /* draw a tic-mark number */ sprintf(txt, "%d", (int)(i / tic_unit)); text_height = (b - t) * TEXT_HEIGHT; text_width = (r - l) * TEXT_WIDTH; D_text_size(text_width, text_height); D_get_text_box(txt, &tt, &tb, &tl, &tr); while ((tt - tb) > YTIC_DIST) { text_width *= 0.75; text_height *= 0.75; D_text_size(text_width, text_height); D_get_text_box(txt, &tt, &tb, &tl, &tr); } D_pos_abs(l + (r - l) * YNUMS_X - (tr - tl) / 2, yoffset - (yscale * i + 0.5 * (tt - tb))); D_text(txt); } else if (rem(i, tic_unit) == 0.0) { /* draw a tic-mark */ D_begin(); D_move_abs(x_line[0], yoffset - yscale * i); D_cont_rel(-(r - l) * SMALL_TIC, 0); D_end(); D_stroke(); } } /* draw the y-axis label */ if (tic_unit != 1) { if (type == COUNT) sprintf(ylabel, "Y-AXIS: Number of cells %s", tic_name); else sprintf(ylabel, "Y-AXIS: Area %s sq. meters", tic_name); } else { if (type == COUNT) sprintf(ylabel, "Y-AXIS: Number of cells"); else sprintf(ylabel, "Y-AXIS: Area"); } text_height = (b - t) * TEXT_HEIGHT; text_width = (r - l) * TEXT_WIDTH; D_text_size(text_width, text_height); D_get_text_box(ylabel, &tt, &tb, &tl, &tr); D_pos_abs(l + (r - l) / 2 - (tr - tl) / 2, b - LABEL_2 * (b - t)); D_use_color(color); D_text(ylabel); /* draw x and y axis lines */ D_use_color(color); D_polyline_abs(x_line, y_line, 3); return 0; }
int main(int argc, char **argv) { char *map_name; int color; int lines; int cols; struct FPRange fp_range; struct Colors colors; double ratio; DCELL dmin, dmax, dval; int cats_num; int cur_dot_row, cur_dot_col; int dots_per_line, dots_per_col; int atcat; int white, black; int atcol, atline; int count, offset; double t, b, l, r; int fp, new_colr; double x_box[5], y_box[5]; struct GModule *module; struct Option *opt1, *opt2, *opt3, *opt4; struct Flag *skip_null; /* Initialize the GIS calls */ G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("display")); G_add_keyword(_("raster")); module->description = _("Displays the color table associated with a raster map layer."); opt1 = G_define_standard_option(G_OPT_R_MAP); opt1->description = _("Name of raster map whose color table is to be displayed"); opt2 = G_define_option(); opt2->key = "color"; opt2->type = TYPE_STRING; opt2->answer = DEFAULT_BG_COLOR; opt2->gisprompt = "old_color,color,color"; opt2->description = _("Color of lines separating the colors of the color table"); opt3 = G_define_option(); opt3->key = "lines"; opt3->type = TYPE_INTEGER; opt3->options = "1-1000"; opt3->description = _("Number of lines to appear in the color table"); opt4 = G_define_option(); opt4->key = "cols"; opt4->type = TYPE_INTEGER; opt4->options = "1-1000"; opt4->description = _("Number of columns to appear in the color table"); skip_null = G_define_flag(); skip_null->key = 'n'; skip_null->description = _("Don't draw a collar showing the NULL color in FP maps"); /* Check command line */ if (G_parser(argc, argv)) exit(EXIT_FAILURE); map_name = opt1->answer; fp = Rast_map_is_fp(map_name, ""); if (opt2->answer != NULL) { new_colr = D_translate_color(opt2->answer); color = new_colr; } if (fp) lines = 1; else lines = 0; if (opt3->answer != NULL) { if (fp) G_warning(_("<%s> is floating-point; " "ignoring [lines] and drawing continuous color ramp"), map_name); else sscanf(opt3->answer, "%d", &lines); } if (fp) cols = 1; else cols = 0; if (opt4->answer) { if (fp) G_warning(_("<%s> is floating-point; " "ignoring [cols] and drawing continuous color ramp"), map_name); else sscanf(opt4->answer, "%d", &cols); } /* Make sure map is available */ if (Rast_read_colors(map_name, "", &colors) == -1) G_fatal_error(_("Color file for <%s> not available"), map_name); if (Rast_read_fp_range(map_name, "", &fp_range) == -1) G_fatal_error(_("Range file for <%s> not available"), map_name); if (D_open_driver() != 0) G_fatal_error(_("No graphics device selected. " "Use d.mon to select graphics device.")); D_setup_unity(0); D_get_src(&t, &b, &l, &r); Rast_get_fp_range_min_max(&fp_range, &dmin, &dmax); if (Rast_is_d_null_value(&dmin) || Rast_is_d_null_value(&dmax)) G_fatal_error(_("Data range is empty")); cats_num = (int)dmax - (int)dmin + 1; if (lines <= 0 && cols <= 0) { double dx, dy; dy = (double)(b - t); dx = (double)(r - l); ratio = dy / dx; cols = 1 + sqrt((dmax - dmin + 1.) / ratio); lines = 1 + cats_num / cols; } else if (lines > 0 && cols <= 0) { cols = 1 + cats_num / lines; } else if (cols > 0 && lines <= 0) { lines = 1 + cats_num / cols; } /* otherwise, accept without complaint what the user requests * It is possible that the number of lines and cols is not * sufficient for the number of categories. */ dots_per_line = (b - t) / lines; dots_per_col = (r - l) / cols; x_box[0] = 0; y_box[0] = 0; x_box[1] = 0; y_box[1] = (6 - dots_per_line); x_box[2] = (dots_per_col - 6); y_box[2] = 0; x_box[3] = 0; y_box[3] = (dots_per_line - 6); x_box[4] = (6 - dots_per_col); y_box[4] = 0; white = D_translate_color("white"); black = D_translate_color("black"); Rast_set_c_null_value(&atcat, 1); if (!fp) { for (atcol = 0; atcol < cols; atcol++) { cur_dot_row = t; cur_dot_col = l + atcol * dots_per_col; count = 0; for (atline = 0; atline < lines; atline++) { cur_dot_row += dots_per_line; /* Draw outer border box */ D_use_color(color); D_begin(); D_move_abs(cur_dot_col + 2, (cur_dot_row - 1)); D_cont_rel(0, (2 - dots_per_line)); D_cont_rel((dots_per_col - 2), 0); D_cont_rel(0, (dots_per_line - 2)); D_cont_rel((2 - dots_per_col), 0); D_end(); D_stroke(); /* Draw black box */ D_use_color(black); D_begin(); D_move_abs(cur_dot_col + 3, (cur_dot_row - 2)); D_cont_rel(0, (4 - dots_per_line)); D_cont_rel((dots_per_col - 4), 0); D_cont_rel(0, (dots_per_line - 4)); D_cont_rel((4 - dots_per_col), 0); D_end(); D_stroke(); /* Color box */ D_color((CELL) atcat, &colors); D_pos_abs(cur_dot_col + 4, (cur_dot_row - 3)); D_polygon_rel(x_box, y_box, 5); count++; /* first cat number is null value */ if (count == 1) atcat = (int)dmin; else if (++atcat > (int)dmax) break; } if (atcat > (int)dmax) break; } /* col loop */ } /* int map */ else { /*** draw continuous color ramp for fp map ***/ cur_dot_row = t + dots_per_line; cur_dot_col = l; /* Draw outer border box */ D_use_color(color); D_begin(); D_move_abs(cur_dot_col + 1, (cur_dot_row - 1)); D_cont_rel(0, (2 - dots_per_line)); D_cont_rel((dots_per_col - 2), 0); D_cont_rel(0, (dots_per_line - 2)); D_cont_rel((2 - dots_per_col), 0); D_end(); D_stroke(); /* Draw black box */ D_use_color(black); D_begin(); D_move_abs(cur_dot_col + 2, (cur_dot_row - 2)); D_cont_rel(0, (4 - dots_per_line)); D_cont_rel((dots_per_col - 4), 0); D_cont_rel(0, (dots_per_line - 4)); D_cont_rel((4 - dots_per_col), 0); D_end(); D_stroke(); /* Color ramp box */ /* get separate color for each pixel */ /* fisrt 5 pixels draw null color */ y_box[1] = -1; y_box[3] = 1; x_box[2] = (dots_per_col - 6); x_box[4] = (6 - dots_per_col); G_debug(1, "dots_per_line: %d dmin=%.2f dmax=%.2f", dots_per_line, dmin, dmax); if (skip_null->answer) offset = 1; else offset = 4; for (r = 0; r < dots_per_line - 6; r++) { if ((r <= 4) && !skip_null->answer) Rast_set_d_null_value(&dval, 1); else dval = dmin + r*(dmax - dmin) / (dots_per_line - 6 - offset); D_d_color(dval, &colors); D_pos_abs(cur_dot_col + 3, (cur_dot_row - 3) - r); D_polygon_rel(x_box, y_box, 5); } } D_save_command(G_recreate_command()); D_close_driver(); exit(EXIT_SUCCESS); }