1124 lines
32 KiB
C
1124 lines
32 KiB
C
/*
|
|
* mappix-trackedit.c
|
|
*
|
|
* Copyright (C) 2006 Nils Faerber <nils.faerber@kernelconcepts.de>
|
|
*
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#include "mappix.h"
|
|
#include "geo-dist.h"
|
|
#include "geo-tools.h"
|
|
|
|
|
|
/*
|
|
* takes head of a track
|
|
* returns number of data points in a track
|
|
*/
|
|
static gint
|
|
track_get_number_of_points(track_head *track)
|
|
{
|
|
GList *lp;
|
|
gint pcount=0;
|
|
|
|
lp = track->track;
|
|
while ((lp = g_list_next(lp))) {
|
|
pcount++;
|
|
}
|
|
|
|
return pcount;
|
|
}
|
|
|
|
|
|
/*
|
|
* takes head of a track
|
|
* returns total length of a track in meters
|
|
*/
|
|
double
|
|
track_get_length(track_head *track)
|
|
{
|
|
gdouble plat, plong;
|
|
gdouble olat, olong;
|
|
trackdata *tdata;
|
|
GList *lp;
|
|
double dist=0.;
|
|
double tdist=0.;
|
|
|
|
lp = track->track;
|
|
tdata = (trackdata *)lp->data;
|
|
unit2latlon(tdata->unitx, tdata->unity, olat, olong);
|
|
while ((lp = g_list_next(lp))) {
|
|
tdata = (trackdata *)lp->data;
|
|
unit2latlon(tdata->unitx, tdata->unity, plat, plong);
|
|
dist = dist_ell(olat, olong, plat, plong, WGS84);
|
|
if (!isnan(dist)) {
|
|
tdist += dist;
|
|
}
|
|
olat = plat;
|
|
olong = plong;
|
|
}
|
|
tdist *= NAUTICAL_MILE;
|
|
|
|
return tdist;
|
|
}
|
|
|
|
|
|
/*
|
|
* takes head of a track
|
|
* returns mean distance between two data points in meters
|
|
*/
|
|
double
|
|
track_get_mean_pointdistance(track_head *track)
|
|
{
|
|
gdouble dist;
|
|
gint pcount;
|
|
gdouble mdist;
|
|
|
|
dist = track_get_length(track);
|
|
pcount = track_get_number_of_points(track);
|
|
mdist = (dist / (double)pcount) * 1000.;
|
|
// fprintf(stderr, "total data points in track = %d\ntotal tracklength = %lf km\nmean distance = %lf m\n", pcount, tdist, mdist);
|
|
|
|
return mdist;
|
|
}
|
|
|
|
|
|
void
|
|
track_add_new_to_main(mapwin *Mapper, track_head *track)
|
|
{
|
|
GtkListStore *store;
|
|
GtkTreeIter iter;
|
|
|
|
g_list_foreach(track->track, track_find_minmax, track);
|
|
Mapper->tracklist = g_list_prepend(Mapper->tracklist, track);
|
|
store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(Mapper->track_treeview)));
|
|
gtk_list_store_append (store, &iter);
|
|
if (g_str_has_suffix(track->name, ".gpx"))
|
|
track->name[strlen(track->name)-4] = 0;
|
|
gtk_list_store_set (store, &iter, 0, track->show, 1, g_path_get_basename(track->name), 2, track, -1);
|
|
}
|
|
|
|
|
|
/* calculate distance from point to next point,
|
|
* if actual distance > dist then create new track:
|
|
* cut old track at current position,
|
|
* end old track here,
|
|
* start new track at next point
|
|
*/
|
|
static int
|
|
do_auto_split_track(mapwin *Mapper, track_head *track, gint dist)
|
|
{
|
|
gdouble olat, olong;
|
|
gdouble plat, plong;
|
|
trackdata *tdata;
|
|
GList *lp;
|
|
gint pcount=0;
|
|
double pdist=0.;
|
|
track_head *split_track;
|
|
trackdata *split_track_data;
|
|
|
|
lp = track->track;
|
|
tdata = (trackdata *)lp->data;
|
|
unit2latlon(tdata->unitx, tdata->unity, olat, olong);
|
|
|
|
split_track = (track_head *)malloc(sizeof(track_head));
|
|
split_track->name = g_strdup_printf("%s-%03d", track->name, pcount);
|
|
split_track->type = track->type;
|
|
split_track->show = TRUE;
|
|
split_track->track = NULL;
|
|
split_track->xmin = WORLD_SIZE_UNITS;
|
|
split_track->ymin = WORLD_SIZE_UNITS;
|
|
split_track->xmax = 0;
|
|
split_track->ymax = 0;
|
|
|
|
while ((lp = g_list_next(lp))) {
|
|
tdata = (trackdata *)lp->data;
|
|
split_track_data = (trackdata *)malloc(sizeof(trackdata));
|
|
memcpy(split_track_data, tdata, sizeof(trackdata));
|
|
unit2latlon(tdata->unitx, tdata->unity, plat, plong);
|
|
pdist = dist_ell(olat, olong, plat, plong, WGS84);
|
|
pdist *= NAUTICAL_MILE * 1000.;
|
|
if (pdist > dist) {
|
|
pcount++;
|
|
track_add_new_to_main(Mapper, split_track);
|
|
|
|
split_track = (track_head *)malloc(sizeof(track_head));
|
|
split_track->name = g_strdup_printf("%s-%03d", track->name, pcount);
|
|
split_track->type = track->type;
|
|
split_track->show = TRUE;
|
|
split_track->track = NULL;
|
|
split_track->xmin = WORLD_SIZE_UNITS;
|
|
split_track->ymin = WORLD_SIZE_UNITS;
|
|
split_track->xmax = 0;
|
|
split_track->ymax = 0;
|
|
split_track->track = g_list_prepend(split_track->track, split_track_data);
|
|
} else {
|
|
split_track->track = g_list_prepend(split_track->track, split_track_data);
|
|
}
|
|
olat = plat;
|
|
olong = plong;
|
|
}
|
|
track_add_new_to_main(Mapper, split_track);
|
|
// fprintf(stderr, "would split into %d new tracks\n", pcount);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void
|
|
track_find_minmax(gpointer data, gpointer user_data)
|
|
{
|
|
trackdata *tdata = (trackdata *)data;
|
|
track_head *ntrack = (track_head *)user_data;
|
|
|
|
if (tdata->unitx > ntrack->xmax)
|
|
ntrack->xmax = tdata->unitx;
|
|
if (tdata->unitx < ntrack->xmin)
|
|
ntrack->xmin = tdata->unitx;
|
|
if (tdata->unity > ntrack->ymax)
|
|
ntrack->ymax = tdata->unity;
|
|
if (tdata->unity < ntrack->ymin)
|
|
ntrack->ymin = tdata->unity;
|
|
}
|
|
|
|
|
|
gboolean
|
|
get_selected_track (GtkTreeModel **tree_model, GtkTreeIter *iter, mapwin *Mapper)
|
|
{
|
|
GtkTreeSelection *tree_selection;
|
|
GtkWidget *dialog;
|
|
|
|
tree_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(Mapper->track_treeview));
|
|
if (!gtk_tree_selection_get_selected(tree_selection, tree_model, iter)) {
|
|
// gtk_widget_destroy(dialog);
|
|
dialog = gtk_message_dialog_new(GTK_WINDOW(gtk_widget_get_toplevel(Mapper->mainwin)),
|
|
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_MESSAGE_ERROR,
|
|
GTK_BUTTONS_OK,
|
|
"%s", "No track selected,\nselect a track first.");
|
|
gtk_dialog_run(GTK_DIALOG(dialog));
|
|
gtk_widget_hide (dialog);
|
|
gtk_widget_destroy (dialog);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static gint
|
|
do_auto_split_dialog(mapwin *Mapper, track_head **track, guint *dist)
|
|
{
|
|
GtkWidget *dialog;
|
|
GtkWidget *hbox;
|
|
GtkWidget *stock;
|
|
GtkWidget *table;
|
|
GtkWidget *spinb_split_dist;
|
|
GtkWidget *label;
|
|
GtkWidget *w;
|
|
gint result;
|
|
GtkTreeModel *tree_model;
|
|
GtkTreeIter iter;
|
|
gchar *tname;
|
|
track_head *trackh;
|
|
gdouble mean_dist;
|
|
|
|
if (!get_selected_track(&tree_model, &iter, Mapper))
|
|
return -1;
|
|
|
|
dialog = gtk_dialog_new_with_buttons("Auto Split Track", GTK_WINDOW(gtk_widget_get_toplevel(Mapper->mainwin)),
|
|
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_STOCK_OK,
|
|
GTK_RESPONSE_ACCEPT,
|
|
GTK_STOCK_CANCEL,
|
|
GTK_RESPONSE_REJECT,
|
|
NULL);
|
|
|
|
hbox = gtk_hbox_new (FALSE, 8);
|
|
gtk_container_set_border_width (GTK_CONTAINER (hbox), 8);
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, FALSE, FALSE, 0);
|
|
|
|
stock = gtk_image_new_from_stock (GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
|
|
gtk_box_pack_start (GTK_BOX (hbox), stock, FALSE, FALSE, 0);
|
|
|
|
table = gtk_table_new (2, 4, FALSE);
|
|
gtk_table_set_row_spacings (GTK_TABLE (table), 4);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 4);
|
|
gtk_table_set_homogeneous(GTK_TABLE (table), FALSE);
|
|
gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0);
|
|
|
|
label = gtk_label_new ("Track to split");
|
|
gtk_table_attach_defaults (GTK_TABLE (table),
|
|
label,
|
|
0, 1, 0, 1);
|
|
w = gtk_entry_new();
|
|
gtk_table_attach_defaults (GTK_TABLE (table), w, 1, 2, 0, 1);
|
|
gtk_entry_set_editable(GTK_ENTRY(w), FALSE);
|
|
|
|
gtk_tree_model_get(tree_model, &iter, 1, &tname, 2, &trackh, -1);
|
|
gtk_entry_set_text(GTK_ENTRY(w), tname);
|
|
gtk_entry_set_max_length(GTK_ENTRY(w), strlen(tname) + 1);
|
|
gtk_entry_set_width_chars(GTK_ENTRY(w), strlen(tname) + 1);
|
|
|
|
mean_dist = track_get_mean_pointdistance(trackh);
|
|
|
|
label = gtk_label_new ("Split Distance (m)\n(default: mean distance)");
|
|
gtk_table_attach_defaults (GTK_TABLE (table),
|
|
label,
|
|
0, 1, 1, 2);
|
|
|
|
spinb_split_dist = gtk_spin_button_new_with_range(0, 9999999, 1);
|
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinb_split_dist), mean_dist);
|
|
gtk_table_attach_defaults (GTK_TABLE (table), spinb_split_dist, 1, 2, 1, 2);
|
|
|
|
gtk_widget_show_all (hbox);
|
|
|
|
result = gtk_dialog_run (GTK_DIALOG (dialog));
|
|
gtk_widget_hide (dialog);
|
|
|
|
switch (result) {
|
|
case GTK_RESPONSE_ACCEPT:
|
|
*dist = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spinb_split_dist));
|
|
*track = trackh;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
gtk_widget_destroy (dialog);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
void
|
|
on_auto_split (GtkButton *widget, gpointer user_data)
|
|
{
|
|
mapwin *Mapper = (mapwin *)user_data;
|
|
track_head *track;
|
|
guint dist;
|
|
gint result;
|
|
|
|
track = NULL;
|
|
dist = 0;
|
|
result = do_auto_split_dialog(Mapper, &track, &dist);
|
|
if (result == -1 || result == GTK_RESPONSE_REJECT)
|
|
return;
|
|
// fprintf(stderr, "split: track '%s' if dist > %dm\n", track->name, dist);
|
|
do_auto_split_track(Mapper, track, dist);
|
|
}
|
|
|
|
|
|
/* split the selected track at the selected postion
|
|
* into one new track and the rest of the other
|
|
* split-point will be duplicated, original track will be preserved
|
|
*/
|
|
void
|
|
on_split_track (GtkToolButton *widget, gpointer user_data)
|
|
{
|
|
mapwin *Mapper = (mapwin *)user_data;
|
|
track_head *track;
|
|
GtkTreeModel *tree_model;
|
|
GtkTreeIter iter;
|
|
gchar *tname;
|
|
trackdata *tdata;
|
|
GList *lp;
|
|
gint pcount=0;
|
|
track_head *split_track;
|
|
trackdata *split_track_data;
|
|
|
|
|
|
if (!get_selected_track(&tree_model, &iter, Mapper))
|
|
return;
|
|
gtk_tree_model_get(tree_model, &iter, 1, &tname, 2, &track, -1);
|
|
|
|
lp = track->track;
|
|
while ((lp = g_list_next(lp))) {
|
|
tdata = (trackdata *)lp->data;
|
|
if (tdata->selected)
|
|
break;
|
|
}
|
|
if (!lp) {
|
|
GtkWidget *dialog;
|
|
|
|
dialog = gtk_message_dialog_new(GTK_WINDOW(gtk_widget_get_toplevel(Mapper->mainwin)),
|
|
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_MESSAGE_ERROR,
|
|
GTK_BUTTONS_OK,
|
|
"%s", "No selected split-point,\non selected track.");
|
|
gtk_dialog_run(GTK_DIALOG(dialog));
|
|
gtk_widget_hide (dialog);
|
|
gtk_widget_destroy (dialog);
|
|
|
|
return;
|
|
}
|
|
|
|
lp = track->track;
|
|
tdata = (trackdata *)lp->data;
|
|
|
|
split_track = (track_head *)malloc(sizeof(track_head));
|
|
split_track->name = g_strdup_printf("%s-%03d", track->name, pcount);
|
|
split_track->type = track->type;
|
|
split_track->show = TRUE;
|
|
split_track->track = NULL;
|
|
split_track->xmin = WORLD_SIZE_UNITS;
|
|
split_track->ymin = WORLD_SIZE_UNITS;
|
|
split_track->xmax = 0;
|
|
split_track->ymax = 0;
|
|
|
|
while ((lp = g_list_next(lp))) {
|
|
tdata = (trackdata *)lp->data;
|
|
split_track_data = (trackdata *)malloc(sizeof(trackdata));
|
|
memcpy(split_track_data, tdata, sizeof(trackdata));
|
|
if (tdata->selected) {
|
|
tdata->selected = FALSE;
|
|
pcount++;
|
|
split_track->track = g_list_prepend(split_track->track, split_track_data);
|
|
track_add_new_to_main(Mapper, split_track);
|
|
|
|
split_track = (track_head *)malloc(sizeof(track_head));
|
|
split_track->name = g_strdup_printf("%s-%03d", track->name, pcount);
|
|
split_track->type = track->type;
|
|
split_track->show = TRUE;
|
|
split_track->track = NULL;
|
|
split_track->xmin = WORLD_SIZE_UNITS;
|
|
split_track->ymin = WORLD_SIZE_UNITS;
|
|
split_track->xmax = 0;
|
|
split_track->ymax = 0;
|
|
split_track_data = (trackdata *)malloc(sizeof(trackdata));
|
|
memcpy(split_track_data, tdata, sizeof(trackdata));
|
|
split_track->track = g_list_prepend(split_track->track, split_track_data);
|
|
} else {
|
|
split_track->track = g_list_prepend(split_track->track, split_track_data);
|
|
}
|
|
}
|
|
track_add_new_to_main(Mapper, split_track);
|
|
// fprintf(stderr, "would split into %d new tracks\n", pcount);
|
|
}
|
|
|
|
|
|
static void
|
|
delete_track_data(gpointer data, gpointer user_data)
|
|
{
|
|
trackdata *tdata = (trackdata *)data;
|
|
|
|
g_free(tdata);
|
|
}
|
|
|
|
|
|
/* the calculated distance is not at all exact but serves
|
|
* the purpose for greater, lower comparison
|
|
*/
|
|
static inline guint
|
|
dist_point_to_point(gint x1, gint y1, gint x2, gint y2)
|
|
{
|
|
guint dist;
|
|
|
|
dist = ABS((gint)x2-(gint)x1) + ABS((gint)y2-(gint)y1);
|
|
|
|
return dist;
|
|
}
|
|
|
|
|
|
void
|
|
do_select_trackpoint(gint sx, gint sy, gpointer user_data)
|
|
{
|
|
mapwin *Mapper = (mapwin *)user_data;
|
|
GList *tracks, *track;
|
|
track_head *trackh;
|
|
trackdata *tdata, *least_tdata;
|
|
guint dist, least_dist;
|
|
gint x,y;
|
|
|
|
/* find nearest trackpoint to pointer */
|
|
least_dist = WORLD_SIZE_UNITS;
|
|
least_tdata = NULL;
|
|
if (Mapper->tracklist != NULL) {
|
|
for (tracks=Mapper->tracklist; tracks; tracks=g_list_next(tracks)) {
|
|
trackh = (track_head *)tracks->data;
|
|
if (trackh->show) {
|
|
if (trackh->xmax < Mapper->xoffset ||
|
|
trackh->ymax < Mapper->yoffset ||
|
|
trackh->xmin > (Mapper->xoffset + (Mapper->canvas_x / Mapper->scale)) ||
|
|
trackh->ymin > (Mapper->yoffset + (Mapper->canvas_y / Mapper->scale))) {
|
|
// fprintf(stderr, "not drawing track '%s'\n", trackh->name);
|
|
} else {
|
|
/* now search in this track */
|
|
for (track=trackh->track; track; track=g_list_next(track)) {
|
|
tdata = (trackdata *)track->data;
|
|
dist = dist_point_to_point(sx, sy, tdata->unitx, tdata->unity);
|
|
if (dist < least_dist) {
|
|
least_dist = dist;
|
|
least_tdata = tdata;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (least_tdata != NULL) {
|
|
least_tdata->selected = ! least_tdata->selected;
|
|
// draw_tracks(Mapper);
|
|
x = (least_tdata->unitx - Mapper->xoffset) * Mapper->scale;
|
|
y = (least_tdata->unity - Mapper->yoffset) * Mapper->scale;
|
|
draw_marker(x, y, Mapper->marker_size, Mapper->marker_type | (least_tdata->selected ? MARKER_SELECTED : 0), Mapper);
|
|
gtk_widget_queue_draw(Mapper->drawarea);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
do_trackpoint_region_select(gint sx1, gint sy1, guint sx2, guint sy2, gpointer user_data)
|
|
{
|
|
mapwin *Mapper = (mapwin *)user_data;
|
|
GList *tracks, *track;
|
|
track_head *trackh;
|
|
trackdata *tdata;
|
|
gint x,y;
|
|
|
|
if (sx1 > sx2) {
|
|
x=sx1;
|
|
sx1=sx2;
|
|
sx2=x;
|
|
}
|
|
if (sy1 > sy2) {
|
|
y=sy1;
|
|
sy1=sy2;
|
|
sy2=y;
|
|
}
|
|
/* find trackpoints in boundary box */
|
|
if (Mapper->tracklist != NULL) {
|
|
for (tracks=Mapper->tracklist; tracks; tracks=g_list_next(tracks)) {
|
|
trackh = (track_head *)tracks->data;
|
|
if (trackh->show) {
|
|
if (trackh->xmax < Mapper->xoffset ||
|
|
trackh->ymax < Mapper->yoffset ||
|
|
trackh->xmin > (Mapper->xoffset + (Mapper->canvas_x / Mapper->scale)) ||
|
|
trackh->ymin > (Mapper->yoffset + (Mapper->canvas_y / Mapper->scale))) {
|
|
// fprintf(stderr, "not drawing track '%s'\n", trackh->name);
|
|
} else {
|
|
/* now search in this track */
|
|
for (track=trackh->track; track; track=g_list_next(track)) {
|
|
tdata = (trackdata *)track->data;
|
|
if (tdata->unitx >= sx1 && tdata->unitx <= sx2 &&
|
|
tdata->unity >= sy1 && tdata->unity <= sy2) {
|
|
tdata->selected = ! tdata->selected;
|
|
x = (tdata->unitx - Mapper->xoffset) * Mapper->scale;
|
|
y = (tdata->unity - Mapper->yoffset) * Mapper->scale;
|
|
/*XXX*/ draw_marker(x, y, Mapper->marker_size, Mapper->marker_type | (tdata->selected ? MARKER_SELECTED : 0), Mapper);
|
|
gtk_widget_queue_draw(Mapper->drawarea);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
do_move_trackpoint(gint sx, gint sy, gint ex, gint ey, gpointer user_data)
|
|
{
|
|
mapwin *Mapper = (mapwin *)user_data;
|
|
gint moffset_x, moffset_y;
|
|
GList *tracks, *track;
|
|
track_head *trackh;
|
|
trackdata *tdata;
|
|
|
|
moffset_x = ex - sx;
|
|
moffset_y = ey - sy;
|
|
|
|
if (Mapper->tracklist != NULL) {
|
|
for (tracks=Mapper->tracklist; tracks; tracks=g_list_next(tracks)) {
|
|
trackh = (track_head *)tracks->data;
|
|
if (trackh->show) {
|
|
if (trackh->xmax < Mapper->xoffset ||
|
|
trackh->ymax < Mapper->yoffset ||
|
|
trackh->xmin > (Mapper->xoffset + (Mapper->canvas_x / Mapper->scale)) ||
|
|
trackh->ymin > (Mapper->yoffset + (Mapper->canvas_y / Mapper->scale))) {
|
|
// fprintf(stderr, "not drawing track '%s'\n", trackh->name);
|
|
} else {
|
|
/* now search in this track */
|
|
for (track=trackh->track; track; track=g_list_next(track)) {
|
|
tdata = (trackdata *)track->data;
|
|
if (tdata->selected) {
|
|
tdata->unitx += moffset_x;
|
|
tdata->unity += moffset_y;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
draw_tracks(Mapper);
|
|
|
|
}
|
|
|
|
|
|
void
|
|
on_select_trackpoint_cb(GtkToolButton *toolbutton, gpointer user_data)
|
|
{
|
|
mapwin *Mapper = (mapwin *)user_data;
|
|
|
|
Mapper->toolmode = MAPPIX_TOOL_SELECT_TRACKPOINT;
|
|
}
|
|
|
|
|
|
void
|
|
on_select_region_cb(GtkToolButton *toolbutton, gpointer user_data)
|
|
{
|
|
mapwin *Mapper = (mapwin *)user_data;
|
|
|
|
Mapper->toolmode = MAPPIX_TOOL_SELECT_REGION;
|
|
}
|
|
|
|
|
|
void
|
|
on_move_trackpoint_cb(GtkToolButton *toolbutton, gpointer user_data)
|
|
{
|
|
mapwin *Mapper = (mapwin *)user_data;
|
|
|
|
Mapper->toolmode = MAPPIX_TOOL_MOVE_TRACKPOINT;
|
|
}
|
|
|
|
|
|
void
|
|
on_track_delete(GtkToolButton *toolbutton, gpointer user_data)
|
|
{
|
|
mapwin *Mapper = (mapwin *)user_data;
|
|
GtkWidget *dialog;
|
|
GtkTreeModel *tree_model;
|
|
GtkTreeIter iter;
|
|
track_head *trackh;
|
|
gchar *tname;
|
|
gint res;
|
|
|
|
if (!get_selected_track(&tree_model, &iter, Mapper))
|
|
return;
|
|
gtk_tree_model_get(tree_model, &iter, 1, &tname, 2, &trackh, -1);
|
|
|
|
dialog = gtk_message_dialog_new(GTK_WINDOW(gtk_widget_get_toplevel(Mapper->mainwin)),
|
|
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_MESSAGE_QUESTION,
|
|
GTK_BUTTONS_YES_NO,
|
|
"Are you sure you want to delete track\n%s", tname);
|
|
res = gtk_dialog_run(GTK_DIALOG(dialog));
|
|
gtk_widget_hide (dialog);
|
|
gtk_widget_destroy (dialog);
|
|
if (res != GTK_RESPONSE_YES) {
|
|
return;
|
|
}
|
|
// fprintf(stderr, "would delete %s\n", tname);
|
|
gtk_list_store_remove(GTK_LIST_STORE(tree_model), &iter);
|
|
g_list_foreach(trackh->track, delete_track_data, NULL);
|
|
g_list_free(trackh->track);
|
|
Mapper->tracklist = g_list_remove(Mapper->tracklist, trackh);
|
|
do_redraw(Mapper);
|
|
}
|
|
|
|
|
|
static void
|
|
track_delete_selected_nodes(track_head *trackh)
|
|
{
|
|
GList *track;
|
|
trackdata *tdata;
|
|
|
|
for (track=trackh->track; track; track=g_list_next(track)) {
|
|
tdata = (trackdata *)track->data;
|
|
if (tdata->selected) {
|
|
//track = g_list_remove(track, tdata);
|
|
g_free(track->data);
|
|
trackh->track = g_list_delete_link(trackh->track, track);
|
|
track=trackh->track;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
on_delete_nodes_cb(GtkToolButton *toolbutton, gpointer user_data)
|
|
{
|
|
mapwin *Mapper = (mapwin *)user_data;
|
|
GList *tracks; //, *track;
|
|
track_head *trackh;
|
|
// trackdata *tdata;
|
|
|
|
if (Mapper->tracklist != NULL) {
|
|
for (tracks=Mapper->tracklist; tracks; tracks=g_list_next(tracks)) {
|
|
trackh = (track_head *)tracks->data;
|
|
if (trackh->show) {
|
|
if (trackh->xmax < Mapper->xoffset ||
|
|
trackh->ymax < Mapper->yoffset ||
|
|
trackh->xmin > (Mapper->xoffset + (Mapper->canvas_x / Mapper->scale)) ||
|
|
trackh->ymin > (Mapper->yoffset + (Mapper->canvas_y / Mapper->scale))) {
|
|
// fprintf(stderr, "not drawing track '%s'\n", trackh->name);
|
|
} else {
|
|
/* now search in this track */
|
|
track_delete_selected_nodes(trackh);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
do_redraw(Mapper);
|
|
}
|
|
|
|
|
|
/* calculate distance from point to next point,
|
|
* if actual distance > dist then create new track:
|
|
* cut old track at current position,
|
|
* end old track here,
|
|
* start new track at next point
|
|
*/
|
|
static int
|
|
do_thin_track(mapwin *Mapper, track_head *track, gint dist)
|
|
{
|
|
double olat, olong;
|
|
double plat, plong;
|
|
trackdata *tdata;
|
|
GList *lp;
|
|
double pdist=0.;
|
|
track_head *split_track;
|
|
trackdata *split_track_data;
|
|
gint pkept, pskip;
|
|
GtkWidget *dialog;
|
|
|
|
lp = track->track;
|
|
tdata = (trackdata *)lp->data;
|
|
|
|
split_track = (track_head *)malloc(sizeof(track_head));
|
|
split_track->name = g_strdup_printf("%s-thin-%d", track->name, dist);
|
|
split_track->show = TRUE;
|
|
split_track->track = NULL;
|
|
split_track->xmin = WORLD_SIZE_UNITS;
|
|
split_track->ymin = WORLD_SIZE_UNITS;
|
|
split_track->xmax = 0;
|
|
split_track->ymax = 0;
|
|
|
|
pkept=0;
|
|
pskip=0;
|
|
|
|
split_track_data = (trackdata *)malloc(sizeof(trackdata));
|
|
memcpy(split_track_data, tdata, sizeof(trackdata));
|
|
split_track->track = g_list_prepend(split_track->track, split_track_data);
|
|
unit2latlon(tdata->unitx, tdata->unity, olat, olong);
|
|
lp = g_list_next(lp);
|
|
while ((lp = g_list_next(lp))) {
|
|
tdata = (trackdata *)lp->data;
|
|
unit2latlon(tdata->unitx, tdata->unity, plat, plong);
|
|
pdist = dist_ell(olat, olong, plat, plong, WGS84);
|
|
pdist *= NAUTICAL_MILE * 1000.;
|
|
if (pdist > dist) {
|
|
split_track_data = (trackdata *)malloc(sizeof(trackdata));
|
|
memcpy(split_track_data, tdata, sizeof(trackdata));
|
|
split_track->track = g_list_prepend(split_track->track, split_track_data);
|
|
olat = plat;
|
|
olong = plong;
|
|
pkept++;
|
|
} else
|
|
pskip++;
|
|
}
|
|
track_add_new_to_main(Mapper, split_track);
|
|
// fprintf(stderr, "would split into %d new tracks\n", pcount);
|
|
// g_message("kept %d points, skipped %d points", pkept, pskip);
|
|
dialog = gtk_message_dialog_new(GTK_WINDOW(gtk_widget_get_toplevel(Mapper->mainwin)), GTK_DIALOG_MODAL| GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "Kept %d points,\nskipped %d points", pkept, pskip);
|
|
gtk_dialog_run(GTK_DIALOG(dialog));
|
|
gtk_widget_hide(dialog);
|
|
gtk_widget_destroy(dialog);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static gint
|
|
do_auto_thin_dialog(mapwin *Mapper, track_head **track, gint *dist)
|
|
{
|
|
GtkWidget *dialog;
|
|
GtkWidget *hbox;
|
|
GtkWidget *stock;
|
|
GtkWidget *table;
|
|
GtkWidget *spinb_split_dist;
|
|
GtkWidget *label;
|
|
GtkWidget *w;
|
|
gint result;
|
|
GtkTreeModel *tree_model;
|
|
GtkTreeIter iter;
|
|
gchar *tname;
|
|
track_head *trackh;
|
|
gdouble mean_dist;
|
|
|
|
if (!get_selected_track(&tree_model, &iter, Mapper))
|
|
return -1;
|
|
gtk_tree_model_get(tree_model, &iter, 1, &tname, 2, &trackh, -1);
|
|
|
|
dialog = gtk_dialog_new_with_buttons("Auto Thin Track", GTK_WINDOW(gtk_widget_get_toplevel(Mapper->mainwin)),
|
|
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_STOCK_OK,
|
|
GTK_RESPONSE_ACCEPT,
|
|
GTK_STOCK_CANCEL,
|
|
GTK_RESPONSE_REJECT,
|
|
NULL);
|
|
|
|
hbox = gtk_hbox_new (FALSE, 8);
|
|
gtk_container_set_border_width (GTK_CONTAINER (hbox), 8);
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, FALSE, FALSE, 0);
|
|
|
|
stock = gtk_image_new_from_stock (GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
|
|
gtk_box_pack_start (GTK_BOX (hbox), stock, FALSE, FALSE, 0);
|
|
|
|
table = gtk_table_new (2, 4, FALSE);
|
|
gtk_table_set_row_spacings (GTK_TABLE (table), 4);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 4);
|
|
gtk_table_set_homogeneous(GTK_TABLE (table), FALSE);
|
|
gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0);
|
|
|
|
label = gtk_label_new ("Track to thin-out");
|
|
gtk_table_attach_defaults (GTK_TABLE (table),
|
|
label,
|
|
0, 1, 0, 1);
|
|
w = gtk_entry_new();
|
|
gtk_table_attach_defaults (GTK_TABLE (table), w, 1, 2, 0, 1);
|
|
gtk_entry_set_editable(GTK_ENTRY(w), FALSE);
|
|
|
|
//gtk_combo_box_append_text(GTK_COMBO_BOX(track_combo), tname);
|
|
gtk_entry_set_text(GTK_ENTRY(w), tname);
|
|
gtk_entry_set_max_length(GTK_ENTRY(w), strlen(tname) + 1);
|
|
gtk_entry_set_width_chars(GTK_ENTRY(w), strlen(tname) + 1);
|
|
|
|
mean_dist = track_get_mean_pointdistance(trackh);
|
|
|
|
label = gtk_label_new ("Minimum Distance (m)\n(default: mean distance)");
|
|
gtk_table_attach_defaults (GTK_TABLE (table),
|
|
label,
|
|
0, 1, 1, 2);
|
|
|
|
spinb_split_dist = gtk_spin_button_new_with_range(0, 9999, 1);
|
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinb_split_dist), mean_dist);
|
|
gtk_table_attach_defaults (GTK_TABLE (table), spinb_split_dist, 1, 2, 1, 2);
|
|
|
|
gtk_widget_show_all (hbox);
|
|
|
|
result = gtk_dialog_run (GTK_DIALOG (dialog));
|
|
gtk_widget_hide (dialog);
|
|
|
|
switch (result) {
|
|
case GTK_RESPONSE_ACCEPT:
|
|
*dist = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spinb_split_dist));
|
|
*track = trackh;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
gtk_widget_destroy (dialog);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
void
|
|
on_auto_thin (GtkButton *widget, gpointer user_data)
|
|
{
|
|
mapwin *Mapper = (mapwin *)user_data;
|
|
track_head *track;
|
|
gint dist;
|
|
gint result;
|
|
|
|
track = NULL;
|
|
dist = 0;
|
|
result = do_auto_thin_dialog(Mapper, &track, &dist);
|
|
if (result == -1 || result == GTK_RESPONSE_REJECT)
|
|
return;
|
|
// fprintf(stderr, "split: track '%s' if dist > %dm\n", track->name, dist);
|
|
do_thin_track(Mapper, track, dist);
|
|
}
|
|
|
|
|
|
void
|
|
on_properties_track (GtkButton *widget, gpointer user_data)
|
|
{
|
|
mapwin *Mapper = (mapwin *)user_data;
|
|
GtkWidget *dialog, *hbox, *stock, *table, *label, *entry_name, *entry_type;
|
|
GtkTreeModel *tree_model;
|
|
GtkTreeIter iter;
|
|
track_head *trackh;
|
|
gchar *tname;
|
|
const gchar *tmp_name;
|
|
gint result;
|
|
|
|
if (!get_selected_track(&tree_model, &iter, Mapper))
|
|
return;
|
|
gtk_tree_model_get(tree_model, &iter, 1, &tname, 2, &trackh, -1);
|
|
|
|
dialog = gtk_dialog_new_with_buttons("Rename track", GTK_WINDOW(gtk_widget_get_toplevel(Mapper->mainwin)),
|
|
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_STOCK_OK,
|
|
GTK_RESPONSE_ACCEPT,
|
|
GTK_STOCK_CANCEL,
|
|
GTK_RESPONSE_REJECT,
|
|
NULL);
|
|
|
|
hbox = gtk_hbox_new (FALSE, 8);
|
|
gtk_container_set_border_width (GTK_CONTAINER (hbox), 8);
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, FALSE, FALSE, 0);
|
|
|
|
stock = gtk_image_new_from_stock (GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
|
|
gtk_box_pack_start (GTK_BOX (hbox), stock, FALSE, FALSE, 0);
|
|
|
|
table = gtk_table_new (3, 4, FALSE);
|
|
gtk_table_set_row_spacings (GTK_TABLE (table), 4);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 4);
|
|
gtk_table_set_homogeneous(GTK_TABLE (table), FALSE);
|
|
gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0);
|
|
|
|
label = gtk_label_new ("Track name");
|
|
gtk_table_attach_defaults (GTK_TABLE (table),
|
|
label,
|
|
0, 1, 0, 1);
|
|
// track_combo = gtk_combo_box_new_text();
|
|
entry_name = gtk_entry_new();
|
|
gtk_entry_set_text(GTK_ENTRY(entry_name), tname);
|
|
gtk_entry_set_editable(GTK_ENTRY(entry_name), TRUE);
|
|
gtk_table_attach_defaults (GTK_TABLE (table), entry_name, 1, 2, 0, 1);
|
|
|
|
label = gtk_label_new ("Track type");
|
|
gtk_table_attach_defaults (GTK_TABLE (table),
|
|
label,
|
|
0, 1, 1, 2);
|
|
// track_combo = gtk_combo_box_new_text();
|
|
entry_type = gtk_combo_box_new_text();
|
|
gtk_combo_box_append_text (GTK_COMBO_BOX(entry_type), "Unknown");
|
|
gtk_combo_box_append_text (GTK_COMBO_BOX(entry_type), "Outline / Border");
|
|
gtk_combo_box_append_text (GTK_COMBO_BOX(entry_type), "River");
|
|
gtk_combo_box_append_text (GTK_COMBO_BOX(entry_type), "Footpath");
|
|
gtk_combo_box_append_text (GTK_COMBO_BOX(entry_type), "Agricultural");
|
|
gtk_combo_box_append_text (GTK_COMBO_BOX(entry_type), "City");
|
|
gtk_combo_box_append_text (GTK_COMBO_BOX(entry_type), "Urban");
|
|
gtk_combo_box_append_text (GTK_COMBO_BOX(entry_type), "Motorway");
|
|
gtk_combo_box_append_text (GTK_COMBO_BOX(entry_type), "Highway");
|
|
gtk_combo_box_set_active (GTK_COMBO_BOX(entry_type), trackh->type);
|
|
gtk_table_attach_defaults (GTK_TABLE (table), entry_type, 1, 2, 1, 2);
|
|
|
|
gtk_widget_show_all (hbox);
|
|
|
|
result = gtk_dialog_run (GTK_DIALOG (dialog));
|
|
gtk_widget_hide (dialog);
|
|
|
|
switch (result) {
|
|
case GTK_RESPONSE_ACCEPT:
|
|
tmp_name = gtk_entry_get_text(GTK_ENTRY(entry_name));
|
|
g_free(trackh->name);
|
|
trackh->name = g_strdup(tmp_name);
|
|
gtk_list_store_set(GTK_LIST_STORE(tree_model), &iter, 1, trackh->name, -1);
|
|
if (trackh->type != gtk_combo_box_get_active(GTK_COMBO_BOX(entry_type))) {
|
|
trackh->type = gtk_combo_box_get_active(GTK_COMBO_BOX(entry_type));
|
|
draw_tracks(Mapper);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
gtk_widget_destroy (dialog);
|
|
}
|
|
|
|
|
|
/*
|
|
* Simplify a track by judging the angle variation between trackpoints
|
|
* takes head of a track, minimum angle difference, main Mapper struct
|
|
* does not return a value
|
|
*
|
|
* Idea of operation:
|
|
* We do not need to record trackpoints which are "lineary" aligned on a track.
|
|
* That means if the direction of a track section does not change by more than a
|
|
* minimum angle we assume that the previous direction continues and we can drop
|
|
* the current trackpoint.
|
|
* Assume four consequent trackpoints A, B, C and D.
|
|
* We calculate the angle of the track between points A and B.
|
|
* We do the same for the angle between points B and C.
|
|
* If the difference of the angles is less than min_angle we assume only a minimal change
|
|
* and ignore (delete) point B. Next we calculate the angles from A to C and C to D and do
|
|
* the same comparison, etc.
|
|
* If the angle is greater than min_angle then we have a certain "twist" in direction and
|
|
* the trackpoint should be kept, i.e. we move the triple forward one point and calculate
|
|
* the next angles from B to C and C to D, etc.
|
|
* The result will pretty well take care of curves and even light circles while eliminating
|
|
* quite useless points from almost straight lines.
|
|
* Good results can be expected for angle differences around 1.0 degree.
|
|
*/
|
|
void
|
|
track_calc_angles(track_head *track, gdouble min_angle, mapwin *Mapper)
|
|
{
|
|
GtkWidget *dialog;
|
|
trackdata *tdata1;
|
|
trackdata *tdata2;
|
|
trackdata *tdata3;
|
|
GList *lp1, *lp2,*lp3;
|
|
gdouble angle1=0.;
|
|
gdouble angle2=0.;
|
|
gdouble angle_diff;
|
|
gint dx1, dy1;
|
|
gint dx2, dy2;
|
|
gint pkept=0, pskipped=0;
|
|
|
|
lp1 = track->track;
|
|
lp2 = g_list_next(lp1);
|
|
if (!lp2)
|
|
return;
|
|
lp3 = g_list_next(lp2);
|
|
if (!lp3)
|
|
return;
|
|
while (lp3) {
|
|
tdata1 = (trackdata *)lp1->data;
|
|
tdata2 = (trackdata *)lp2->data;
|
|
tdata3 = (trackdata *)lp3->data;
|
|
|
|
dx1 = tdata1->unitx - tdata2->unitx;
|
|
dy1 = tdata1->unity - tdata2->unity;
|
|
|
|
dx2 = tdata2->unitx - tdata3->unitx;
|
|
dy2 = tdata2->unity - tdata3->unity;
|
|
|
|
angle1 = atan2((gdouble)dx1, (gdouble)dy1);
|
|
angle2 = atan2((gdouble)dx2, (gdouble)dy2);
|
|
|
|
angle_diff = angle1 - angle2;
|
|
|
|
if (fabs(angle_diff) < min_angle) {
|
|
/* OK, zap point 2 ! */
|
|
tdata2->selected = TRUE;
|
|
lp2 = g_list_next(lp2);
|
|
lp3 = g_list_next(lp3);
|
|
pskipped++;
|
|
} else {
|
|
do {
|
|
lp1 = g_list_next(lp1);
|
|
if (lp1)
|
|
tdata1 = (trackdata *)lp1->data;
|
|
} while (lp1 && tdata1->selected);
|
|
lp2 = g_list_next(lp1);
|
|
if (!lp2)
|
|
break;
|
|
lp3 = g_list_next(lp2);
|
|
if (!lp3)
|
|
break;
|
|
pkept++;
|
|
}
|
|
}
|
|
track_delete_selected_nodes(track);
|
|
draw_tracks(Mapper);
|
|
dialog = gtk_message_dialog_new(GTK_WINDOW(gtk_widget_get_toplevel(Mapper->mainwin)), GTK_DIALOG_MODAL| GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "Kept %d points,\nskipped %d points", pkept, pskipped);
|
|
gtk_dialog_run(GTK_DIALOG(dialog));
|
|
gtk_widget_hide(dialog);
|
|
gtk_widget_destroy(dialog);
|
|
}
|
|
|
|
|
|
void
|
|
on_track_angle_simplify (GtkButton *widget, gpointer user_data)
|
|
{
|
|
mapwin *Mapper = (mapwin *)user_data;
|
|
GtkWidget *dialog, *hbox, *stock, *table, *label, *spinb_angle;
|
|
GtkTreeModel *tree_model;
|
|
GtkTreeIter iter;
|
|
track_head *trackh;
|
|
gchar *tname;
|
|
gdouble min_angle;
|
|
gint result;
|
|
|
|
if (!get_selected_track(&tree_model, &iter, Mapper))
|
|
return;
|
|
|
|
gtk_tree_model_get(tree_model, &iter, 1, &tname, 2, &trackh, -1);
|
|
|
|
dialog = gtk_dialog_new_with_buttons("Angle Simplify", GTK_WINDOW(gtk_widget_get_toplevel(Mapper->mainwin)),
|
|
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_STOCK_OK,
|
|
GTK_RESPONSE_ACCEPT,
|
|
GTK_STOCK_CANCEL,
|
|
GTK_RESPONSE_REJECT,
|
|
NULL);
|
|
|
|
hbox = gtk_hbox_new (FALSE, 8);
|
|
gtk_container_set_border_width (GTK_CONTAINER (hbox), 8);
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, FALSE, FALSE, 0);
|
|
|
|
stock = gtk_image_new_from_stock (GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
|
|
gtk_box_pack_start (GTK_BOX (hbox), stock, FALSE, FALSE, 0);
|
|
|
|
table = gtk_table_new (2, 4, FALSE);
|
|
gtk_table_set_row_spacings (GTK_TABLE (table), 4);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 4);
|
|
gtk_table_set_homogeneous(GTK_TABLE (table), FALSE);
|
|
gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0);
|
|
|
|
label = gtk_label_new ("Minimum angle (degree)");
|
|
gtk_table_attach_defaults (GTK_TABLE (table),
|
|
label,
|
|
0, 1, 0, 1);
|
|
|
|
spinb_angle = gtk_spin_button_new_with_range(0, 2 * M_PI, .01);
|
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinb_angle), 4.0);
|
|
gtk_table_attach_defaults (GTK_TABLE (table), spinb_angle, 1, 2, 0, 1);
|
|
|
|
gtk_widget_show_all (hbox);
|
|
|
|
result = gtk_dialog_run (GTK_DIALOG (dialog));
|
|
gtk_widget_hide (dialog);
|
|
|
|
switch (result) {
|
|
case GTK_RESPONSE_ACCEPT:
|
|
min_angle = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spinb_angle));
|
|
min_angle = ((2. * M_PI) / 360.) * min_angle;
|
|
track_calc_angles(trackh, min_angle, Mapper);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
gtk_widget_destroy (dialog);
|
|
}
|
|
|
|
|
|
void
|
|
on_track_length(GtkWidget *widget, gpointer user_data)
|
|
{
|
|
mapwin *Mapper = (mapwin *)user_data;
|
|
GtkWidget *dialog;
|
|
GtkTreeModel *tree_model;
|
|
GtkTreeIter iter;
|
|
gchar *tname;
|
|
track_head *trackh;
|
|
double length=0.;
|
|
|
|
if (!get_selected_track(&tree_model, &iter, Mapper))
|
|
return;
|
|
|
|
gtk_tree_model_get(tree_model, &iter, 1, &tname, 2, &trackh, -1);
|
|
length = track_get_length(trackh);
|
|
|
|
// gtk_widget_destroy(dialog);
|
|
dialog = gtk_message_dialog_new(GTK_WINDOW(gtk_widget_get_toplevel(Mapper->mainwin)),
|
|
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_MESSAGE_INFO,
|
|
GTK_BUTTONS_OK,
|
|
"Track '%s' length is\n %lfkm", tname, length);
|
|
gtk_dialog_run(GTK_DIALOG(dialog));
|
|
gtk_widget_hide (dialog);
|
|
gtk_widget_destroy (dialog);
|
|
}
|
|
|