--- trunk/src/osm-gps-map-osd-classic.c 2009/09/07 13:20:37 98 +++ trunk/src/osm-gps-map-osd-classic.c 2009/09/09 11:50:50 103 @@ -25,10 +25,11 @@ /* OSD_DIAMETER */ /* OSD_X, OSD_Y */ -#define OSD_SCALE - -#define OSD_SCALE_W 100 -#define OSD_SCALE_H 20 +#ifndef OSD_SCALE_FONT_SIZE +#define OSD_SCALE_FONT_SIZE 12 +#endif +#define OSD_SCALE_W (10*OSD_SCALE_FONT_SIZE) +#define OSD_SCALE_H (5*OSD_SCALE_FONT_SIZE/2) #ifndef USE_CAIRO #error "OSD control display lacks a non-cairo implementation!" @@ -46,6 +47,7 @@ #ifdef OSD_SCALE cairo_surface_t *scale; + int scale_zoom; #endif #ifdef OSD_SOURCE_SEL @@ -451,7 +453,6 @@ int w = OSD_S_W, h = OSD_S_H; if(priv->expanded) { - /* ... and right of it the waypoint id */ cairo_text_extents_t extents; /* determine content size */ @@ -728,31 +729,137 @@ cairo_line_to (cr, x + Z_RIGHT + Z_LEN, y + Z_MID); } -static float pixel2m(OsmGpsMap *map, int pixel) { - return pixel*osm_gps_map_get_scale(OSM_GPS_MAP(map)); -} +/* various parameters used to create the scale */ +#define OSD_SCALE_H2 (OSD_SCALE_H/2) +#define OSD_SCALE_TICK (2*OSD_SCALE_FONT_SIZE/3) +#define OSD_SCALE_M (OSD_SCALE_H2 - OSD_SCALE_TICK) +#define OSD_SCALE_I (OSD_SCALE_H2 + OSD_SCALE_TICK) +#define OSD_SCALE_FD (OSD_SCALE_FONT_SIZE/4) static void osd_render_scale(osm_gps_map_osd_t *osd) { osd_priv_t *priv = (osd_priv_t*)osd->priv; + /* this only needs to be rendered if the zoom has changed */ + gint zoom; + g_object_get(OSM_GPS_MAP(osd->widget), "zoom", &zoom, NULL); + if(zoom == priv->scale_zoom) + return; + + priv->scale_zoom = zoom; + + float m_per_pix = osm_gps_map_get_scale(OSM_GPS_MAP(osd->widget)); + /* first fill with transparency */ cairo_t *cr = cairo_create(priv->scale); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - // cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.0); - cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.2); + cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.0); + // pink for testing: cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.2); cairo_paint(cr); cairo_set_operator(cr, CAIRO_OPERATOR_OVER); /* determine the size of the scale width in meters */ - float width = pixel2m(OSM_GPS_MAP(osd->widget), OSD_SCALE_W); - printf("width = %f meters\n", width); - + float width = (OSD_SCALE_W-OSD_SCALE_FONT_SIZE/6) * m_per_pix; + /* scale this to useful values */ int exp = logf(width)*M_LOG10E; int mant = width/pow(10,exp); - printf("mant = %d, exp = %d \n", mant, exp); + int width_metric = mant * pow(10,exp); + char *dist_str = NULL; + if(width_metric<1000) + dist_str = g_strdup_printf("%u m", width_metric); + else + dist_str = g_strdup_printf("%u km", width_metric/1000); + width_metric /= m_per_pix; + + /* and now the hard part: scale for useful imperial values :-( */ + /* try to convert to feet, 1ft == 0.3048 m */ + width /= 0.3048; + float imp_scale = 0.3048; + char *dist_imp_unit = "ft"; + + if(width >= 100) { + /* 1yd == 3 feet */ + width /= 3.0; + imp_scale *= 3.0; + dist_imp_unit = "yd"; + + if(width >= 1760.0) { + /* 1mi == 1760 yd */ + width /= 1760.0; + imp_scale *= 1760.0; + dist_imp_unit = "mi"; + } + } + + /* also convert this to full tens/hundreds */ + exp = logf(width)*M_LOG10E; + mant = width/pow(10,exp); + int width_imp = mant * pow(10,exp); + char *dist_str_imp = g_strdup_printf("%u %s", width_imp, dist_imp_unit); + + /* convert back to pixels */ + width_imp *= imp_scale; + width_imp /= m_per_pix; + + cairo_select_font_face (cr, "Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_BOLD); + cairo_set_font_size (cr, OSD_SCALE_FONT_SIZE); + cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0); + + cairo_text_extents_t extents; + cairo_text_extents (cr, dist_str, &extents); + + cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); + cairo_set_line_width (cr, OSD_SCALE_FONT_SIZE/6); + cairo_move_to (cr, 2*OSD_SCALE_FD, OSD_SCALE_H2-OSD_SCALE_FD); + cairo_text_path (cr, dist_str); + cairo_stroke (cr); + cairo_move_to (cr, 2*OSD_SCALE_FD, + OSD_SCALE_H2+OSD_SCALE_FD + extents.height); + cairo_text_path (cr, dist_str_imp); + cairo_stroke (cr); + + cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); + cairo_move_to (cr, 2*OSD_SCALE_FD, OSD_SCALE_H2-OSD_SCALE_FD); + cairo_show_text (cr, dist_str); + cairo_move_to (cr, 2*OSD_SCALE_FD, + OSD_SCALE_H2+OSD_SCALE_FD + extents.height); + cairo_show_text (cr, dist_str_imp); + + g_free(dist_str); + g_free(dist_str_imp); + + /* draw white line */ + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0); + cairo_set_line_width (cr, OSD_SCALE_FONT_SIZE/3); + cairo_move_to (cr, OSD_SCALE_FONT_SIZE/6, OSD_SCALE_M); + cairo_rel_line_to (cr, 0, OSD_SCALE_TICK); + cairo_rel_line_to (cr, width_metric, 0); + cairo_rel_line_to (cr, 0, -OSD_SCALE_TICK); + cairo_stroke(cr); + cairo_move_to (cr, OSD_SCALE_FONT_SIZE/6, OSD_SCALE_I); + cairo_rel_line_to (cr, 0, -OSD_SCALE_TICK); + cairo_rel_line_to (cr, width_imp, 0); + cairo_rel_line_to (cr, 0, +OSD_SCALE_TICK); + cairo_stroke(cr); + + /* draw black line */ + cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0); + cairo_set_line_width (cr, OSD_SCALE_FONT_SIZE/6); + cairo_move_to (cr, OSD_SCALE_FONT_SIZE/6, OSD_SCALE_M); + cairo_rel_line_to (cr, 0, OSD_SCALE_TICK); + cairo_rel_line_to (cr, width_metric, 0); + cairo_rel_line_to (cr, 0, -OSD_SCALE_TICK); + cairo_stroke(cr); + cairo_move_to (cr, OSD_SCALE_FONT_SIZE/6, OSD_SCALE_I); + cairo_rel_line_to (cr, 0, -OSD_SCALE_TICK); + cairo_rel_line_to (cr, width_imp, 0); + cairo_rel_line_to (cr, 0, +OSD_SCALE_TICK); + cairo_stroke(cr); cairo_destroy(cr); } @@ -873,6 +980,7 @@ priv->scale = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, OSD_SCALE_W, OSD_SCALE_H); + priv->scale_zoom = -1; #endif /* ... and render it */