/** Re-calculates extent of a polyline. * @param pl Polyline * @param x X coordinate * @param y Y coordinate */ static void poly_recalcextent(poly* pl) { double* xs = pl->x; double* ys = pl->y; extent* e = &pl->e; int n = pl->n; int i; extent_clear(e); for (i = 0; i < n; ++i) extent_update(e, xs[i], ys[i]); }
static gboolean on_map_button_release_event(GtkWidget *widget, GdkEventButton *event, area_context_t *context) { OsmGpsMap *map = OSM_GPS_MAP(widget); osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map); if(!std::isnan(context->map.start.rlon) && !std::isnan(context->map.start.rlat)) { OsmGpsMapPoint start = context->map.start; OsmGpsMapPoint end = osm_gps_map_convert_screen_to_geographic(map, event->x, event->y); GSList *box = pos_append_rad(nullptr, start.rlat, start.rlon); box = pos_append_rad(box, end.rlat, start.rlon); box = pos_append_rad(box, end.rlat, end.rlon); box = pos_append_rad(box, start.rlat, end.rlon); box = pos_append_rad(box, start.rlat, start.rlon); osm_gps_map_add_track(map, box); if(start.rlat < end.rlat) { context->bounds.min.lat = RAD2DEG(start.rlat); context->bounds.max.lat = RAD2DEG(end.rlat); } else { context->bounds.min.lat = RAD2DEG(end.rlat); context->bounds.max.lat = RAD2DEG(start.rlat); } if(start.rlon < end.rlon) { context->bounds.min.lon = RAD2DEG(start.rlon); context->bounds.max.lon = RAD2DEG(end.rlon); } else { context->bounds.min.lon = RAD2DEG(end.rlon); context->bounds.max.lon = RAD2DEG(start.rlon); } area_main_update(context); direct_update(context); extent_update(context); context->map.start.rlon = context->map.start.rlat = NAN; } /* osm-gps-map needs this event to handle the OSD */ if(osd->check(osd, TRUE, event->x, event->y) != OSD_NONE) return FALSE; /* returning true here disables dragging in osm-gps-map */ return osm_gps_map_osd_get_state(map) == TRUE ? FALSE : TRUE; }
/** Appends a point to the tail of a polyline. * @param pl Polyline * @param x X coordinate * @param y Y coordinate */ void poly_addpoint(poly* pl, double x, double y) { if (isnan(x) || isnan(y)) gu_quit("poly_addpoint(): NaN detected"); if (pl->n == pl->nallocated) { pl->x = realloc(pl->x, pl->nallocated * sizeof(double) * 2); pl->y = realloc(pl->y, pl->nallocated * sizeof(double) * 2); pl->nallocated *= 2; } pl->x[pl->n] = x; pl->y[pl->n] = y; pl->n++; extent_update(&pl->e, x, y); }
static void callback_fetch_mm_clicked(area_context_t *context) { dbus_mm_pos_t mmpos; if(!dbus_mm_set_position(&mmpos)) { error_dlg(_("Unable to communicate with Maemo Mapper. " "You need to have Maemo Mapper installed to use this feature."), context->dialog.get()); return; } if(!mmpos.valid) { error_dlg(_("No valid position received yet. You need to " "scroll or zoom the Maemo Mapper view in order to force it to send " "its current view position to osm2go."), context->dialog.get()); return; } /* maemo mapper is fourth tab (page 3) */ if(!current_tab_is(context, "M.Mapper")) return; /* maemo mapper pos data ... */ pos_float_t center_lat = mmpos.pos.lat; pos_float_t center_lon = mmpos.pos.lon; int zoom = mmpos.zoom; if(!pos_lat_valid(center_lat) || !pos_lon_valid(center_lon)) return; double vscale = DEG2RAD(POS_EQ_RADIUS); double height = 8 * (1<<zoom) / vscale; context->bounds.min.lat = center_lat - height; context->bounds.max.lat = center_lat + height; double hscale = DEG2RAD(cos(DEG2RAD(center_lat)) * POS_EQ_RADIUS); double width = 16 * (1<<zoom) / hscale; context->bounds.min.lon = center_lon - width; context->bounds.max.lon = center_lon + width; area_main_update(context); /* also update other tabs */ direct_update(context); extent_update(context); map_update(context, false); }
static void callback_modified_direct(area_context_t *context) { /* direct is second tab (page 1) */ if(!current_tab_is(context, TAB_LABEL_DIRECT)) return; /* parse the fields from the direct entry pad */ if(unlikely(!pos_lat_get(context->direct.minlat, context->bounds.min.lat) || !pos_lon_get(context->direct.minlon, context->bounds.min.lon) || !pos_lat_get(context->direct.maxlat, context->bounds.max.lat) || !pos_lon_get(context->direct.maxlon, context->bounds.max.lon))) return; area_main_update(context); /* also adjust other views */ extent_update(context); map_update(context, false); }
/* Appends a point to the tail of a polyline. * @param pl Polyline * @param x X coordinate * @param y Y coordinate */ void poly_addpoint(poly* pl, double x, double y) { if (isnan(x) || isnan(y)) { fflush(stdout); fprintf(stderr, "error: poly_addpoint(): NaN detected\n"); exit(1); } if (pl->n == pl->nallocated) { pl->x = realloc(pl->x, pl->nallocated * sizeof(double) * 2); pl->y = realloc(pl->y, pl->nallocated * sizeof(double) * 2); pl->nallocated *= 2; } pl->x[pl->n] = x; pl->y[pl->n] = y; pl->n++; extent_update(&pl->e, x, y); }
/** Removes a point at a given position from a polyline. * @param pl Polyline * @param index Position */ void poly_deletepoint(poly* pl, int index) { double xx = pl->x[index]; double yy = pl->y[index]; extent* e = &pl->e; memmove(&pl->x[index], &pl->x[index + 1], (pl->n - index - 1) * sizeof(double)); memmove(&pl->y[index], &pl->y[index + 1], (pl->n - index - 1) * sizeof(double)); pl->n--; if (e->xmin == xx || e->xmax == xx || e->ymin == yy || e->ymax == yy) { double* x = pl->x; double* y = pl->y; int i; extent_clear(e); for (i = 0; i < pl->n; ++i) extent_update(e, x[i], y[i]); } }
/** Adds a point to a polyline at a given position. * No action for invalid index. * @param pl Polyline * @param index Index * @param x X coordinate * @param y Y coordinate */ void poly_addpointat(poly* pl, int index, double x, double y) { if (index > pl->n - 1) { poly_addpoint(pl, x, y); return; } if (pl->n == pl->nallocated) { pl->x = realloc(pl->x, pl->nallocated * sizeof(double) * 2); pl->y = realloc(pl->y, pl->nallocated * sizeof(double) * 2); pl->nallocated *= 2; } memmove(&pl->x[index + 1], &pl->x[index], (pl->n - index) * sizeof(double)); memmove(&pl->y[index + 1], &pl->x[index], (pl->n - index) * sizeof(double)); pl->x[index] = x; pl->y[index] = y; pl->n++; extent_update(&pl->e, x, y); }
bool area_edit_t::run() { GtkWidget *vbox; area_context_t context(*this, gtk_dialog_new_with_buttons(_("Area editor"), GTK_WINDOW(parent), GTK_DIALOG_MODAL, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, nullptr)); osm2go_platform::dialog_size_hint(context.dialog, osm2go_platform::MISC_DIALOG_HIGH); context.warning = gtk_dialog_add_button(context.dialog, _("Warning"), GTK_RESPONSE_HELP); gtk_button_set_image(GTK_BUTTON(context.warning), gtk_image_new_from_icon_name("dialog-warning", GTK_ICON_SIZE_BUTTON)); g_signal_connect_swapped(context.warning, "clicked", G_CALLBACK(on_area_warning_clicked), &context); /* ------------- fetch from map ------------------------ */ context.map.needs_redraw = false; context.map.widget = OSM_GPS_MAP(g_object_new(OSM_TYPE_GPS_MAP, "map-source", OSM_GPS_MAP_SOURCE_OPENSTREETMAP, "proxy-uri", g_getenv("http_proxy"), "auto-center", FALSE, "tile-cache", nullptr, nullptr)); osm_gps_map_osd_select_init(context.map.widget); g_signal_connect_swapped(context.map.widget, "configure-event", G_CALLBACK(on_map_configure), &context); g_signal_connect(context.map.widget, "button-press-event", G_CALLBACK(on_map_button_press_event), &context); g_signal_connect(context.map.widget, "motion-notify-event", G_CALLBACK(on_map_motion_notify_event), &context); g_signal_connect(context.map.widget, "button-release-event", G_CALLBACK(on_map_button_release_event), &context); /* install handler for timed updates of the gps button */ osm2go_platform::Timer timer; timer.restart(1, map_gps_update, &context); context.map.start.rlon = context.map.start.rlat = NAN; osm2go_platform::notebook_append_page(context.notebook, GTK_WIDGET(context.map.widget), _(TAB_LABEL_MAP)); /* ------------ direct min/max edit --------------- */ vbox = gtk_vbox_new(FALSE, 10); GtkTable *table = GTK_TABLE(gtk_table_new(3, 4, FALSE)); // x, y gtk_table_set_col_spacings(table, 10); gtk_table_set_row_spacings(table, 5); context.direct.minlat = pos_lat_entry_new(bounds.min.lat); table_attach(table, context.direct.minlat, 0, 0); GtkWidget *label = gtk_label_new(_("to")); table_attach(table, label, 1, 0); context.direct.maxlat = pos_lat_entry_new(bounds.max.lat); table_attach(table, context.direct.maxlat, 2, 0); context.direct.minlon = pos_lon_entry_new(bounds.min.lon); table_attach(table, context.direct.minlon, 0, 1); label = gtk_label_new(_("to")); table_attach(table, label, 1, 1); context.direct.maxlon = pos_lon_entry_new(bounds.max.lon); table_attach(table, context.direct.maxlon, 2, 1); /* setup this page */ g_signal_connect_swapped(context.direct.minlat, "changed", G_CALLBACK(callback_modified_direct), &context); g_signal_connect_swapped(context.direct.minlon, "changed", G_CALLBACK(callback_modified_direct), &context); g_signal_connect_swapped(context.direct.maxlat, "changed", G_CALLBACK(callback_modified_direct), &context); g_signal_connect_swapped(context.direct.maxlon, "changed", G_CALLBACK(callback_modified_direct), &context); /* --- hint --- */ label = gtk_label_new(_("(recommended min/max diff <0.03 degrees)")); gtk_table_attach_defaults(table, label, 0, 3, 2, 3); const GdkColor *color = osm2go_platform::invalid_text_color(); /* error label */ context.direct.error = gtk_label_new(nullptr); gtk_widget_modify_fg(context.direct.error, GTK_STATE_NORMAL, color); gtk_table_attach_defaults(table, context.direct.error, 0, 3, 3, 4); gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), FALSE, FALSE, 0); osm2go_platform::notebook_append_page(context.notebook, vbox, _(TAB_LABEL_DIRECT)); /* ------------- center/extent edit ------------------------ */ vbox = gtk_vbox_new(FALSE, 10); table = GTK_TABLE(gtk_table_new(3, 5, FALSE)); // x, y gtk_table_set_col_spacings(table, 10); gtk_table_set_row_spacings(table, 5); label = gtk_label_new(_("Center:")); gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); gtk_table_attach_defaults(table, label, 0, 1, 0, 1); context.extent.lat = pos_lat_entry_new(0.0); gtk_table_attach_defaults(table, context.extent.lat, 1, 2, 0, 1); context.extent.lon = pos_lon_entry_new(0.0); gtk_table_attach_defaults(table, context.extent.lon, 2, 3, 0, 1); gtk_table_set_row_spacing(table, 0, 10); label = gtk_label_new(_("Width:")); gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); gtk_table_attach_defaults(table, label, 0, 1, 1, 2); context.extent.width = osm2go_platform::entry_new(); gtk_table_attach_defaults(table, context.extent.width, 1, 2, 1, 2); label = gtk_label_new(_("Height:")); gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); gtk_table_attach_defaults(table, label, 0, 1, 2, 3); context.extent.height = osm2go_platform::entry_new(); gtk_table_attach_defaults(table, context.extent.height, 1, 2, 2, 3); std::vector<const char *> units(2); units[0] = _("mi"); units[1] = _("km"); context.extent.mil_km = osm2go_platform::combo_box_new(_("Unit"), units, 1); gtk_table_attach(table, context.extent.mil_km, 2, 3, 1, 3, static_cast<GtkAttachOptions>(0), static_cast<GtkAttachOptions>(0), 0, 0); /* setup this page */ extent_update(&context); /* connect signals after inital update to avoid confusion */ g_signal_connect_swapped(context.extent.lat, "changed", G_CALLBACK(callback_modified_extent), &context); g_signal_connect_swapped(context.extent.lon, "changed", G_CALLBACK(callback_modified_extent), &context); g_signal_connect_swapped(context.extent.width, "changed", G_CALLBACK(callback_modified_extent), &context); g_signal_connect_swapped(context.extent.height, "changed", G_CALLBACK(callback_modified_extent), &context); g_signal_connect_swapped(context.extent.mil_km, "changed", G_CALLBACK(callback_modified_unit), &context); /* --- hint --- */ label = gtk_label_new(_("(recommended width/height < 2km/1.25mi)")); gtk_table_attach_defaults(table, label, 0, 3, 3, 4); /* error label */ context.extent.error = gtk_label_new(nullptr); gtk_widget_modify_fg(context.extent.error, GTK_STATE_NORMAL, color); gtk_table_attach_defaults(table, context.extent.error, 0, 3, 4, 5); gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), FALSE, FALSE, 0); osm2go_platform::notebook_append_page(context.notebook, vbox, _(TAB_LABEL_EXTENT)); #ifdef HAS_MAEMO_MAPPER /* ------------- fetch from maemo mapper ------------------------ */ vbox = gtk_vbox_new(FALSE, 8); context.mmapper.fetch = osm2go_platform::button_new_with_label(_("Get from Maemo Mapper")); gtk_box_pack_start(GTK_BOX(vbox), context.mmapper.fetch, FALSE, FALSE, 0); g_signal_connect_swapped(context.mmapper.fetch, "clicked", G_CALLBACK(callback_fetch_mm_clicked), &context); /* --- hint --- */ label = gtk_label_new(_("(recommended MM zoom level < 7)")); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); osm2go_platform::notebook_append_page(context.notebook, vbox, _("M.Mapper")); #endif /* ------------------------------------------------------ */ gtk_box_pack_start(context.dialog.vbox(), context.notebook, TRUE, TRUE, 0); g_signal_connect(osm2go_platform::notebook_get_gtk_notebook(context.notebook), "switch-page", G_CALLBACK(on_page_switch), &context); gtk_widget_show_all(context.dialog.get()); area_main_update(&context); bool ok = false; int response; do { response = gtk_dialog_run(context.dialog); if(GTK_RESPONSE_ACCEPT == response) { if(area_warning(&context)) { /* copy modified values back to given storage */ bounds = context.bounds; ok = true; break; } } } while(response == GTK_RESPONSE_HELP || response == GTK_RESPONSE_ACCEPT); return ok; }