Exemplo n.º 1
0
static void draw_text(char *text, double *x, double *y, double size, char *align,
		      double rotation, char bold, int do_background, int fg_color, int bg_color)
{
    double w, h;
    double t, b, l, r;
    double c, s;
    int pt, pb, pl, pr;

    /* TODO: get text dimension */
    /* R_get_text_box() does not work with rotation and returns a little bit
     * bigger dimension than actual text size */
    if (rotation != 0.0)
	D_text_rotation(0.0);

    D_get_text_box(text, &t, &b, &l, &r);

    if (rotation != 0.0)
	D_text_rotation(rotation * 180.0 / M_PI);
    w = r - l;
    h = b - t;
    if (w > 0)
	w += 0.2 * size;
    else
	/* D_text() does not draw " ". */
	w = 0.8 * size;
    if (h > 0)
	h += 0.2 * size;
    else
	/* D_text() does not draw " ". */
	h = 0.8 * size;

    c = cos(rotation);
    s = sin(rotation);

    if (strcmp(align, "ll") != 0) {
	switch (align[0]) {
	case 'l':
	    break;
	case 'c':
	    *x += h / 2.0 * s;
	    *y += h / 2.0 * c;
	    break;
	case 'u':
	    *x += h * s;
	    *y += h * c;
	    break;
	}

	switch (align[1]) {
	case 'l':
	    break;
	case 'c':
	    *x -= w / 2.0 * c;
	    *y += w / 2.0 * s;
	    break;
	case 'r':
	    *x -= w * c;
	    *y += w * s;
	    break;
	}
    }

    if (do_background) {
 	pl = *x - size/2; /* some pixels margin for both sides */
 	pt = *y + size/2;
 	pr = *x + w + size/2;
 	pb = *y - h - size/2;
	D_use_color(bg_color);
 	D_box_abs(pl, pt, pr, pb);    /* draw the box */
 	D_use_color(fg_color); /* restore */
    }

    D_pos_abs(*x, *y);
    D_text(text);

    if (bold) {
	D_pos_abs(*x, *y + 1);
	D_text(text);
	D_pos_abs(*x + 1, *y);
	D_text(text);
    }

    *x += w * c;
    *y -= w * s;

    return;
}
Exemplo n.º 2
0
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, struct FPRange render_range)
{
    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;
	nsteps = width - 3;
    }
    else {
	max_width = width * 1.75;
	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);

    width_mult = max_width / dist_stats.maxstat;

    D_use_color(color);
    D_begin();

    ptr = dist_stats.ptr;

    if (!is_fp) {
	dy = (nsteps + 3.0) / (1 + dist_stats.maxcat - dist_stats.mincat);

	if (flip)
	    dy *= -1;

	if (dist_stats.mincat == 0)
	    y0_adjust = dy;
	else
	    y0_adjust = 0;

	if (!flip)  /* mmph */
	    y0_adjust += 0.5;
    }


    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;

	    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 */
		cell_count = ptr->stat;

		if (ptr->next != NULL)
		    ptr = ptr->next;
	    }
	    else		/* stat cannot be found */
		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;

	dx = cell_count * width_mult;

	if (is_fp) {
	    if (horiz) {
		if (flip)
		    D_move_abs(x0 + width - ystep - 1, y0 - 1);
		else
		    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 - ystep);
		else
		    D_move_abs(x0 - 1, y0 + 1 + ystep);

		D_cont_rel(-dx, 0);
	    }
	}
	else {	/* categorical */

	    if (horiz) {
		if (flip)
		    D_box_abs(x0 + width + y0_adjust + ((i - 1) * dy),
			      y0 - 1,
			      x0 + width + y0_adjust + 1 + (i * dy),
			      y0 - 1 - dx);
		else
		    D_box_abs(x0 + y0_adjust + ((i - 1) * dy),
			      y0 - 1,
			      x0 - 1 + y0_adjust + (i * dy),
			      y0 - 1 - dx);
	    }
	    else {  /* vertical */

		if (flip)
		    /* GRASS_EPSILON fudge around D_box_abs() weirdness + PNG driver */
		    D_box_abs(x0 - 1 - GRASS_EPSILON * 10,
			      y0 + height + y0_adjust + ((i - 1) * dy),
			      x0 - 1 - dx,
			      y0 + height + y0_adjust + 1 + (i * dy));
		else
		    D_box_abs(x0 - 1 - GRASS_EPSILON * 10,
			      y0 + y0_adjust + ((i - 1) * dy),
			      x0 - 1 - dx,
			      y0 + y0_adjust - 1 + (i * dy));
	    }
	}
    }

    D_close();
    D_end();
    D_stroke();
}