/* * Since this function is used for every drawn trackpoint - it can get called alot * Thus x & y position factors are calculated once on zoom changes, * avoiding the need to do it here all the time. * For good measure the half width and height values are also pre calculated too. */ void vik_viewport_coord_to_screen ( VikViewport *vvp, const VikCoord *coord, int *x, int *y ) { static VikCoord tmp; g_return_if_fail ( vvp != NULL ); if ( coord->mode != vvp->coord_mode ) { g_warning ( "Have to convert in vik_viewport_coord_to_screen! This should never happen!"); vik_coord_copy_convert ( coord, vvp->coord_mode, &tmp ); coord = &tmp; } if ( vvp->coord_mode == VIK_COORD_UTM ) { struct UTM *center = (struct UTM *) &(vvp->center); struct UTM *utm = (struct UTM *) coord; if ( center->zone != utm->zone && vvp->one_utm_zone ) { *x = *y = VIK_VIEWPORT_UTM_WRONG_ZONE; return; } *x = ( (utm->easting - center->easting) / vvp->xmpp ) + (vvp->width_2) - (center->zone - utm->zone ) * vvp->utm_zone_width / vvp->xmpp; *y = (vvp->height_2) - ( (utm->northing - center->northing) / vvp->ympp ); } else if ( vvp->coord_mode == VIK_COORD_LATLON ) { struct LatLon *center = (struct LatLon *) &(vvp->center); struct LatLon *ll = (struct LatLon *) coord; double xx,yy; if ( vvp->drawmode == VIK_VIEWPORT_DRAWMODE_LATLON ) { *x = vvp->width_2 + ( MERCATOR_FACTOR(vvp->xmpp) * (ll->lon - center->lon) ); *y = vvp->height_2 + ( MERCATOR_FACTOR(vvp->ympp) * (center->lat - ll->lat) ); } else if ( vvp->drawmode == VIK_VIEWPORT_DRAWMODE_EXPEDIA ) { calcxy ( &xx, &yy, center->lon, center->lat, ll->lon, ll->lat, vvp->xmpp * ALTI_TO_MPP, vvp->ympp * ALTI_TO_MPP, vvp->width_2, vvp->height_2 ); *x = xx; *y = yy; } else if ( vvp->drawmode == VIK_VIEWPORT_DRAWMODE_MERCATOR ) { *x = vvp->width_2 + ( MERCATOR_FACTOR(vvp->xmpp) * (ll->lon - center->lon) ); *y = vvp->height_2 + ( MERCATOR_FACTOR(vvp->ympp) * ( MERCLAT(center->lat) - MERCLAT(ll->lat) ) ); } } }
/* * Draw a grid over the map */ void draw_grid (GtkWidget * widget) { int count; gdouble step, step_pow10; gdouble lat, lon; gdouble lat_ul, lon_ul; gdouble lat_ll, lon_ll; gdouble lat_ur, lon_ur; gdouble lat_lr, lon_lr; gdouble lat_min, lon_min; gdouble lat_max, lon_max; gchar precision[10]; gint iteration_count =0; if ( mydebug >50 ) fprintf(stderr , "draw_grid()\n"); // calculate the start and stop for lat/lon according to the displayed section calcxytopos (0, 0, &lat_ul, &lon_ul, current.zoom); calcxytopos (0, gui_status.mapview_y, &lat_ll, &lon_ll, current.zoom); calcxytopos (gui_status.mapview_x, 0, &lat_ur, &lon_ur, current.zoom); calcxytopos (gui_status.mapview_x, gui_status.mapview_y, &lat_lr, &lon_lr, current.zoom); // add more lines as the scale increases // Calculate distance between grid lines step = (gdouble) current.mapscale / 2000000.0 / current.zoom; /* round step to one sig. digit */ step_pow10= floor( log10(step) ); // add -1 for 2 sig digits, -2 for 3, etc. /* FIXME: use round(x) instead of floor(x+0.5) ??? */ // step = pow(10, step_pow10) * round(step * pow(10, -1 * step_pow10)); step = pow(10, step_pow10) * floor(0.5+ (step * pow(10, -1 * step_pow10))); /* TODO: respect user's prefered DMS style; round and display accordingly: DDD.DDDDD, DDD MM.MMMM, DDD MM SS.SSSS TODO: round on "nice numbers": deg, min, sec: 30, 15, 10, 5, 2, 1 decimal deg: .5, .25, .1, .05, 0.02, 0.1 see SourceForge wish #2375742 for some sample GPL'd code to do that (from GRASS GIS's ps/ps.map/ps_fclrtbl.c#L162) */ if (step != step || step == 0) { fprintf(stderr, "?? draw_grid(): distance step is %f, " "mapscale is 1:%ld\n", step, current.mapscale); return; } do { if (step >= 1) g_snprintf (precision, sizeof (precision), "%%.0f"); else if (step >= .1) g_snprintf (precision, sizeof (precision), "%%.1f"); else if (step >= .01) g_snprintf (precision, sizeof (precision), "%%.2f"); else if (step >= .001) g_snprintf (precision, sizeof (precision), "%%.3f"); else if (step >= .0001) g_snprintf (precision, sizeof (precision), "%%.4f"); else g_snprintf (precision, sizeof (precision), "%%.5f"); if (current.mapscale / current.zoom < 50000000) { lat_min = min (lat_ll, lat_ul) - step; lat_max = max (lat_lr, lat_ur) + step; lon_min = min (lon_ll, lon_ul) - step; lon_max = max (lon_lr, lon_ur) + step; } else { lat_min = -90; lat_max = 90; lon_min = -180; lon_max = 180; } lat_min = floor (lat_min / step) * step; lon_min = floor (lon_min / step) * step; if ( mydebug > 20 ) printf ("Draw Grid: (%.2f,%.2f) - (%.2f,%.2f) Step %f for Ef.Scale %ld Zoom %d\n", lat_min, lon_min, lat_max, lon_max, step, current.mapscale/current.zoom, current.zoom); if ( mydebug > 40 ) { printf ("Draw Grid: (%.2f) Iterations for lat\n", (lat_max-lat_min)/step); printf ("Draw Grid: (%.2f) Iterations for lon\n", (lon_max-lon_min)/step); } // limit number of grid iterations to between 20 and 45 iterations iteration_count = ((lat_max-lat_min)/step) * ((lon_max-lon_min)/step); if ( iteration_count > 45 ) step = step * 2; else if ( iteration_count < 20 ) step = step / 3.; } while ( iteration_count > 45 || iteration_count < 20 ); // Loop over desired lat/lon count = 0; for (lon = lon_min; lon <= lon_max; lon = lon + step) { for (lat = lat_min; lat <= lat_max; lat = lat + step) { gint posxdest11, posydest11; gint posxdest12, posydest12; gint posxdest21, posydest21; gint posxdest22, posydest22; gint posxdist, posydist; gchar str[200]; count++; calcxy (&posxdest11, &posydest11, lon, max(-90,lat) , current.zoom); calcxy (&posxdest12, &posydest12, lon, min( 90,lat + step), current.zoom); calcxy (&posxdest21, &posydest21, lon + step, max(-90,lat), current.zoom); calcxy (&posxdest22, &posydest22, lon + step, min( 90,lat + step), current.zoom); if (((posxdest11 >= 0) && (posxdest11 < gui_status.mapview_x) && (posydest11 >= 0) && (posydest11 < gui_status.mapview_y)) || ((posxdest22 >= 0) && (posxdest22 < gui_status.mapview_x) && (posydest22 >= 0) && (posydest22 < gui_status.mapview_y)) || ((posxdest21 >= 0) && (posxdest21 < gui_status.mapview_x) && (posydest21 >= 0) && (posydest21 < gui_status.mapview_y)) || ((posxdest12 >= 0) && (posxdest12 < gui_status.mapview_x) && (posydest12 >= 0) && (posydest12 < gui_status.mapview_y))) { // TODO: add linethickness 2 for Mayor Lines // Set Drawing Mode gdk_gc_set_function (kontext_map, GDK_XOR); gdk_gc_set_foreground (kontext_map, &colors.darkgrey); gdk_gc_set_line_attributes (kontext_map, 1, GDK_LINE_SOLID, 0, 0); gdk_draw_line (drawable, kontext_map, posxdest11, posydest11, posxdest21, posydest21); gdk_draw_line (drawable, kontext_map, posxdest11, posydest11, posxdest12, posydest12); // Text lon g_snprintf (str, sizeof (str), precision, lon); posxdist = (posxdest12 - posxdest11) / 4; posydist = (posydest12 - posydest11) / 4; draw_grid_text (widget, posxdest11 + posxdist, posydest11 + posydist, str); // Text lat g_snprintf (str, sizeof (str), precision, lat); posxdist = (posxdest21 - posxdest11) / 4; posydist = (posydest21 - posydest11) / 4; draw_grid_text (widget, posxdest11 + posxdist, posydest11 + posydist-5, str); } } } if ( mydebug > 30 ) printf ("draw_grid loops: %d\n", count); }
/* **************************************************************************** * draw lines showing the route */ void draw_route (void) { GdkSegment *route_seg; gint destpos_x, destpos_y, curpos_x, curpos_y; gint i, j; gint t = 0; gchar t_routept[5]; GtkTreeIter iter_route; gdouble t_lon, t_lat; if (route.items < 1) return; i = (route.items + 5); route_seg = g_new0 (GdkSegment, i); if (local_config.use_database) { /* poi mode */ g_snprintf (t_routept, sizeof (t_routept), "%d", (route.pointer)); gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (route_list_tree), &iter_route, t_routept); calcxy (&curpos_x, &curpos_y, coords.current_lon, coords.current_lat, current.zoom); (route_seg)->x1 = curpos_x; (route_seg)->y1 = curpos_y; do { gtk_tree_model_get (GTK_TREE_MODEL (route_list_tree), &iter_route, ROUTE_LON, &t_lon, ROUTE_LAT, &t_lat, -1); if (t != 0) { (route_seg + t)->x1 = (route_seg + t - 1)->x2; (route_seg + t)->y1 = (route_seg + t - 1)->y2; } calcxy (&destpos_x, &destpos_y, t_lon, t_lat, current.zoom); (route_seg + t)->x2 = destpos_x; (route_seg + t)->y2 = destpos_y; t++; } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (route_list_tree), &iter_route)); } else { /* waypoints mode */ /* start beginning with actual route.pointer */ for (j = route.pointer; j < route.items; j++) { /* start drawing with current_pos */ if (j == route.pointer) { calcxy (&curpos_x, &curpos_y, coords.current_lon, coords.current_lat, current.zoom); (route_seg + t)->x1 = curpos_x; (route_seg + t)->y1 = curpos_y; } else { (route_seg + t)->x1 = (route_seg + t - 1)->x2; (route_seg + t)->y1 = (route_seg + t - 1)->y2; } calcxy (&destpos_x, &destpos_y, (routelist + j)->lon, (routelist + j)->lat, current.zoom); (route_seg + t)->x2 = destpos_x; (route_seg + t)->y2 = destpos_y; t++; } } gdk_gc_set_foreground (kontext_map, &colors.route); gdk_gc_set_background (kontext_map, &colors.white); gdk_gc_set_line_attributes (kontext_map, 4, GDK_LINE_ON_OFF_DASH, 0, 0); gdk_gc_set_dashes (kontext_map, 0, (gpointer) linestyles[local_config.style_route], 4); gdk_gc_set_function (kontext_map, GDK_COPY); gdk_draw_segments (drawable, kontext_map, (GdkSegment *) route_seg, t); g_free (route_seg); }