2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5 * Copyright (c) 2014, Rob Norris <rw_norris@hotmail.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include <glib/gstdio.h>
31 #include <glib/gi18n.h>
38 #include "preferences.h"
39 #include "icons/icons.h"
41 static VikLayerParamData image_default ( void )
43 VikLayerParamData data;
44 data.s = g_strdup ("");
49 VikLayerParam georef_layer_params[] = {
50 { VIK_LAYER_GEOREF, "image", VIK_LAYER_PARAM_STRING, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
51 { VIK_LAYER_GEOREF, "corner_easting", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
52 { VIK_LAYER_GEOREF, "corner_northing", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
53 { VIK_LAYER_GEOREF, "mpp_easting", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
54 { VIK_LAYER_GEOREF, "mpp_northing", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
55 { VIK_LAYER_GEOREF, "corner_zone", VIK_LAYER_PARAM_UINT, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
56 { VIK_LAYER_GEOREF, "corner_letter_as_int", VIK_LAYER_PARAM_UINT, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
57 { VIK_LAYER_GEOREF, "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
71 static const gchar* georef_layer_tooltip ( VikGeorefLayer *vgl );
72 static void georef_layer_marshall( VikGeorefLayer *vgl, guint8 **data, gint *len );
73 static VikGeorefLayer *georef_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
74 static gboolean georef_layer_set_param ( VikGeorefLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
75 static VikLayerParamData georef_layer_get_param ( VikGeorefLayer *vgl, guint16 id, gboolean is_file_operation );
76 static VikGeorefLayer *georef_layer_new ( VikViewport *vvp );
77 static VikGeorefLayer *georef_layer_create ( VikViewport *vp );
78 static void georef_layer_free ( VikGeorefLayer *vgl );
79 static gboolean georef_layer_properties ( VikGeorefLayer *vgl, gpointer vp );
80 static void georef_layer_draw ( VikGeorefLayer *vgl, VikViewport *vp );
81 static void georef_layer_add_menu_items ( VikGeorefLayer *vgl, GtkMenu *menu, gpointer vlp );
82 static void georef_layer_set_image ( VikGeorefLayer *vgl, const gchar *image );
83 static gboolean georef_layer_dialog ( VikGeorefLayer *vgl, gpointer vp, GtkWindow *w );
84 static void georef_layer_load_image ( VikGeorefLayer *vgl, VikViewport *vp, gboolean from_file );
87 static gpointer georef_layer_move_create ( VikWindow *vw, VikViewport *vvp);
88 static gboolean georef_layer_move_release ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
89 static gboolean georef_layer_move_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
90 static gpointer georef_layer_zoom_create ( VikWindow *vw, VikViewport *vvp);
91 static gboolean georef_layer_zoom_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
93 // See comment in viktrwlayer.c for advice on values used
94 static VikToolInterface georef_tools[] = {
95 { { "GeorefMoveMap", "vik-icon-Georef Move Map", N_("_Georef Move Map"), NULL, N_("Georef Move Map"), 0 },
96 (VikToolConstructorFunc) georef_layer_move_create, NULL, NULL, NULL,
97 (VikToolMouseFunc) georef_layer_move_press, NULL, (VikToolMouseFunc) georef_layer_move_release,
98 (VikToolKeyFunc) NULL,
100 GDK_CURSOR_IS_PIXMAP, &cursor_geomove_pixbuf, NULL },
102 { { "GeorefZoomTool", "vik-icon-Georef Zoom Tool", N_("Georef Z_oom Tool"), NULL, N_("Georef Zoom Tool"), 0 },
103 (VikToolConstructorFunc) georef_layer_zoom_create, NULL, NULL, NULL,
104 (VikToolMouseFunc) georef_layer_zoom_press, NULL, NULL,
105 (VikToolKeyFunc) NULL,
107 GDK_CURSOR_IS_PIXMAP, &cursor_geozoom_pixbuf, NULL },
110 VikLayerInterface vik_georef_layer_interface = {
114 &vikgeoreflayer_pixbuf, /*icon */
117 sizeof(georef_tools) / sizeof(VikToolInterface),
126 (VikLayerFuncCreate) georef_layer_create,
127 (VikLayerFuncRealize) NULL,
128 (VikLayerFuncPostRead) georef_layer_load_image,
129 (VikLayerFuncFree) georef_layer_free,
131 (VikLayerFuncProperties) georef_layer_properties,
132 (VikLayerFuncDraw) georef_layer_draw,
133 (VikLayerFuncChangeCoordMode) NULL,
135 (VikLayerFuncGetTimestamp) NULL,
137 (VikLayerFuncSetMenuItemsSelection) NULL,
138 (VikLayerFuncGetMenuItemsSelection) NULL,
140 (VikLayerFuncAddMenuItems) georef_layer_add_menu_items,
141 (VikLayerFuncSublayerAddMenuItems) NULL,
143 (VikLayerFuncSublayerRenameRequest) NULL,
144 (VikLayerFuncSublayerToggleVisible) NULL,
145 (VikLayerFuncSublayerTooltip) NULL,
146 (VikLayerFuncLayerTooltip) georef_layer_tooltip,
147 (VikLayerFuncLayerSelected) NULL,
149 (VikLayerFuncMarshall) georef_layer_marshall,
150 (VikLayerFuncUnmarshall) georef_layer_unmarshall,
152 (VikLayerFuncSetParam) georef_layer_set_param,
153 (VikLayerFuncGetParam) georef_layer_get_param,
154 (VikLayerFuncChangeParam) NULL,
156 (VikLayerFuncReadFileData) NULL,
157 (VikLayerFuncWriteFileData) NULL,
159 (VikLayerFuncDeleteItem) NULL,
160 (VikLayerFuncCutItem) NULL,
161 (VikLayerFuncCopyItem) NULL,
162 (VikLayerFuncPasteItem) NULL,
163 (VikLayerFuncFreeCopiedItem) NULL,
164 (VikLayerFuncDragDropRequest) NULL,
166 (VikLayerFuncSelectClick) NULL,
167 (VikLayerFuncSelectMove) NULL,
168 (VikLayerFuncSelectRelease) NULL,
169 (VikLayerFuncSelectedViewportMenu) NULL,
176 GtkWidget *ce_spin; // top left
177 GtkWidget *cn_spin; // "
178 GtkWidget *utm_zone_spin;
179 GtkWidget *utm_letter_entry;
181 GtkWidget *lat_tl_spin;
182 GtkWidget *lon_tl_spin;
183 GtkWidget *lat_br_spin;
184 GtkWidget *lon_br_spin;
187 GtkWidget *imageentry;
188 } changeable_widgets;
190 struct _VikGeorefLayer {
196 struct UTM corner; // Top Left
197 gdouble mpp_easting, mpp_northing;
198 struct LatLon ll_br; // Bottom Right
202 guint32 scaled_width, scaled_height;
204 gint click_x, click_y;
205 changeable_widgets cw;
208 static VikLayerParam io_prefs[] = {
209 { VIK_LAYER_NUM_TYPES, VIKING_PREFERENCES_IO_NAMESPACE "georef_auto_read_world_file", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Auto Read World Files:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
210 N_("Automatically attempt to read associated world file of a new image for a GeoRef layer"), NULL, NULL, NULL}
213 void vik_georef_layer_init (void)
215 VikLayerParamData tmp;
217 a_preferences_register(&io_prefs[0], tmp, VIKING_PREFERENCES_IO_GROUP_KEY);
220 GType vik_georef_layer_get_type ()
222 static GType vgl_type = 0;
226 static const GTypeInfo vgl_info =
228 sizeof (VikGeorefLayerClass),
229 NULL, /* base_init */
230 NULL, /* base_finalize */
231 NULL, /* class init */
232 NULL, /* class_finalize */
233 NULL, /* class_data */
234 sizeof (VikGeorefLayer),
236 NULL /* instance init */
238 vgl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikGeorefLayer", &vgl_info, 0 );
244 static const gchar* georef_layer_tooltip ( VikGeorefLayer *vgl )
249 static void georef_layer_marshall( VikGeorefLayer *vgl, guint8 **data, gint *len )
251 vik_layer_marshall_params ( VIK_LAYER(vgl), data, len );
254 static VikGeorefLayer *georef_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
256 VikGeorefLayer *rv = georef_layer_new ( vvp );
257 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
259 georef_layer_load_image ( rv, vvp, TRUE );
264 static gboolean georef_layer_set_param ( VikGeorefLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
268 case PARAM_IMAGE: georef_layer_set_image ( vgl, data.s ); break;
269 case PARAM_CN: vgl->corner.northing = data.d; break;
270 case PARAM_CE: vgl->corner.easting = data.d; break;
271 case PARAM_MN: vgl->mpp_northing = data.d; break;
272 case PARAM_ME: vgl->mpp_easting = data.d; break;
273 case PARAM_CZ: if ( data.u <= 60 ) vgl->corner.zone = data.u; break;
274 case PARAM_CL: if ( data.u >= 65 || data.u <= 90 ) vgl->corner.letter = data.u; break;
275 case PARAM_AA: if ( data.u <= 255 ) vgl->alpha = data.u; break;
281 static VikLayerParamData georef_layer_get_param ( VikGeorefLayer *vgl, guint16 id, gboolean is_file_operation )
283 VikLayerParamData rv;
287 gboolean set = FALSE;
288 if ( is_file_operation ) {
289 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
290 gchar *cwd = g_get_current_dir();
292 rv.s = file_GetRelativeFilename ( cwd, vgl->image );
293 if ( !rv.s ) rv.s = "";
299 rv.s = vgl->image ? vgl->image : "";
302 case PARAM_CN: rv.d = vgl->corner.northing; break;
303 case PARAM_CE: rv.d = vgl->corner.easting; break;
304 case PARAM_MN: rv.d = vgl->mpp_northing; break;
305 case PARAM_ME: rv.d = vgl->mpp_easting; break;
306 case PARAM_CZ: rv.u = vgl->corner.zone; break;
307 case PARAM_CL: rv.u = vgl->corner.letter; break;
308 case PARAM_AA: rv.u = vgl->alpha; break;
314 static VikGeorefLayer *georef_layer_new ( VikViewport *vvp )
316 VikGeorefLayer *vgl = VIK_GEOREF_LAYER ( g_object_new ( VIK_GEOREF_LAYER_TYPE, NULL ) );
317 vik_layer_set_type ( VIK_LAYER(vgl), VIK_LAYER_GEOREF );
319 // Since GeoRef layer doesn't use uibuilder
320 // initializing this way won't do anything yet..
321 vik_layer_set_defaults ( VIK_LAYER(vgl), vvp );
323 // Make these defaults based on the current view
324 vgl->mpp_northing = vik_viewport_get_ympp ( vvp );
325 vgl->mpp_easting = vik_viewport_get_xmpp ( vvp );
326 vik_coord_to_utm ( vik_viewport_get_center ( vvp ), &(vgl->corner) );
333 vgl->scaled_width = 0;
334 vgl->scaled_height = 0;
335 vgl->ll_br.lat = 0.0;
336 vgl->ll_br.lon = 0.0;
341 static void georef_layer_draw ( VikGeorefLayer *vgl, VikViewport *vp )
345 gdouble xmpp = vik_viewport_get_xmpp(vp), ympp = vik_viewport_get_ympp(vp);
346 GdkPixbuf *pixbuf = vgl->pixbuf;
347 guint layer_width = vgl->width;
348 guint layer_height = vgl->height;
350 guint width = vik_viewport_get_width(vp), height = vik_viewport_get_height(vp);
352 VikCoord corner_coord;
353 vik_coord_load_from_utm ( &corner_coord, vik_viewport_get_coord_mode(vp), &(vgl->corner) );
354 vik_viewport_coord_to_screen ( vp, &corner_coord, &x, &y );
356 /* mark to scale the pixbuf if it doesn't match our dimensions */
357 gboolean scale = FALSE;
358 if ( xmpp != vgl->mpp_easting || ympp != vgl->mpp_northing )
361 layer_width = round(vgl->width * vgl->mpp_easting / xmpp);
362 layer_height = round(vgl->height * vgl->mpp_northing / ympp);
365 // If image not in viewport bounds - no need to draw it (or bother with any scaling)
366 if ( (x < 0 || x < width) && (y < 0 || y < height) && x+layer_width > 0 && y+layer_height > 0 ) {
370 /* rescale if necessary */
371 if (layer_width == vgl->scaled_width && layer_height == vgl->scaled_height && vgl->scaled != NULL)
372 pixbuf = vgl->scaled;
375 pixbuf = gdk_pixbuf_scale_simple(
382 if (vgl->scaled != NULL)
383 g_object_unref(vgl->scaled);
385 vgl->scaled = pixbuf;
386 vgl->scaled_width = layer_width;
387 vgl->scaled_height = layer_height;
390 vik_viewport_draw_pixbuf ( vp, pixbuf, 0, 0, x, y, layer_width, layer_height ); /* todo: draw only what we need to. */
395 static void georef_layer_free ( VikGeorefLayer *vgl )
397 if ( vgl->image != NULL )
398 g_free ( vgl->image );
399 if ( vgl->scaled != NULL )
400 g_object_unref ( vgl->scaled );
403 static VikGeorefLayer *georef_layer_create ( VikViewport *vp )
405 return georef_layer_new ( vp );
408 static gboolean georef_layer_properties ( VikGeorefLayer *vgl, gpointer vp )
410 return georef_layer_dialog ( vgl, vp, VIK_GTK_WINDOW_FROM_WIDGET(vp) );
413 static void georef_layer_load_image ( VikGeorefLayer *vgl, VikViewport *vp, gboolean from_file )
416 if ( vgl->image == NULL )
420 g_object_unref ( G_OBJECT(vgl->pixbuf) );
423 g_object_unref ( G_OBJECT(vgl->scaled) );
427 vgl->pixbuf = gdk_pixbuf_new_from_file ( vgl->image, &gx );
432 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(vp), _("Couldn't open image file: %s"), gx->message );
437 vgl->width = gdk_pixbuf_get_width ( vgl->pixbuf );
438 vgl->height = gdk_pixbuf_get_height ( vgl->pixbuf );
440 if ( vgl->pixbuf && vgl->alpha < 255 )
441 vgl->pixbuf = ui_pixbuf_set_alpha ( vgl->pixbuf, vgl->alpha );
443 /* should find length and width here too */
446 static void georef_layer_set_image ( VikGeorefLayer *vgl, const gchar *image )
449 g_free ( vgl->image );
452 g_object_unref ( vgl->scaled );
458 if ( g_strcmp0 (image, "") != 0 )
459 vgl->image = vu_get_canonical_filename ( VIK_LAYER(vgl), image );
461 vgl->image = g_strdup (image);
464 // Only positive values allowed here
465 static void gdouble2spinwidget ( GtkWidget *widget, gdouble val )
467 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(widget), val > 0 ? val : -val );
470 static void set_widget_values ( changeable_widgets *cw, gdouble values[4] )
472 gdouble2spinwidget ( cw->x_spin, values[0] );
473 gdouble2spinwidget ( cw->y_spin, values[1] );
474 gdouble2spinwidget ( cw->ce_spin, values[2] );
475 gdouble2spinwidget ( cw->cn_spin, values[3] );
478 static gboolean world_file_read_line ( FILE *ff, gdouble *value, gboolean use_value )
480 gboolean answer = TRUE; // Success
482 if ( !fgets ( buffer, 1024, ff ) ) {
485 if ( answer && use_value )
486 *value = g_strtod ( buffer, NULL );
492 * http://en.wikipedia.org/wiki/World_file
494 * Note world files do not define the units and nor are the units standardized :(
495 * Currently Viking only supports:
496 * x&y scale as meters per pixel
497 * x&y coords as UTM eastings and northings respectively
499 static gint world_file_read_file ( const gchar* filename, gdouble values[4] )
501 g_debug ("%s - trying world file %s", __FUNCTION__, filename);
503 FILE *f = g_fopen ( filename, "r" );
507 gint answer = 2; // Not enough info read yet
508 // **We do not handle 'skew' values ATM - normally they are a value of 0 anyway to align with the UTM grid
509 if ( world_file_read_line ( f, &values[0], TRUE ) // x scale
510 && world_file_read_line ( f, NULL, FALSE ) // Ignore value in y-skew line**
511 && world_file_read_line ( f, NULL, FALSE ) // Ignore value in x-skew line**
512 && world_file_read_line ( f, &values[1], TRUE ) // y scale
513 && world_file_read_line ( f, &values[2], TRUE ) // x-coordinate of the upper left pixel
514 && world_file_read_line ( f, &values[3], TRUE ) // y-coordinate of the upper left pixel
518 g_debug ("%s - %s - world file read success", __FUNCTION__, filename);
526 static void georef_layer_dialog_load ( changeable_widgets *cw )
528 GtkWidget *file_selector = gtk_file_chooser_dialog_new (_("Choose World file"),
530 GTK_FILE_CHOOSER_ACTION_OPEN,
531 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
532 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
535 if ( gtk_dialog_run ( GTK_DIALOG ( file_selector ) ) == GTK_RESPONSE_ACCEPT )
538 gint answer = world_file_read_file ( gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_selector)), values );
540 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(cw->x_spin), _("The World file you requested could not be opened for reading.") );
541 else if ( answer == 2 )
542 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(cw->x_spin), _("Unexpected end of file reading World file.") );
544 // NB answer should == 0 for success
545 set_widget_values ( cw, values );
548 gtk_widget_destroy ( file_selector );
551 static void georef_layer_export_params ( gpointer *pass_along[2] )
553 VikGeorefLayer *vgl = VIK_GEOREF_LAYER(pass_along[0]);
554 GtkWidget *file_selector = gtk_file_chooser_dialog_new (_("Choose World file"),
556 GTK_FILE_CHOOSER_ACTION_SAVE,
557 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
558 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
560 if ( gtk_dialog_run ( GTK_DIALOG ( file_selector ) ) == GTK_RESPONSE_ACCEPT )
562 FILE *f = g_fopen ( gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER(file_selector) ), "w" );
564 gtk_widget_destroy ( file_selector );
567 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(pass_along[0]), _("The file you requested could not be opened for writing.") );
572 fprintf ( f, "%f\n%f\n%f\n%f\n%f\n%f\n", vgl->mpp_easting, vgl->mpp_northing, 0.0, 0.0, vgl->corner.easting, vgl->corner.northing );
578 gtk_widget_destroy ( file_selector );
582 * Auto attempt to read the world file associated with the image used for the georef
583 * Based on simple file name conventions
584 * Only attempted if the preference is on.
586 static void maybe_read_world_file ( VikFileEntry *vfe, gpointer user_data )
588 if ( a_preferences_get (VIKING_PREFERENCES_IO_NAMESPACE "georef_auto_read_world_file")->b ) {
589 const gchar* filename = vik_file_entry_get_filename(VIK_FILE_ENTRY(vfe));
591 if ( filename && user_data ) {
593 changeable_widgets *cw = user_data;
595 gboolean upper = g_ascii_isupper (filename[strlen(filename)-1]);
596 gchar* filew = g_strconcat ( filename, (upper ? "W" : "w") , NULL );
598 if ( world_file_read_file ( filew, values ) == 0 ) {
599 set_widget_values ( cw, values );
602 if ( strlen(filename) > 3 ) {
603 gchar* file0 = g_strndup ( filename, strlen(filename)-2 );
604 gchar* file1 = g_strdup_printf ( "%s%c%c", file0, filename[strlen(filename)-1], (upper ? 'W' : 'w') );
605 if ( world_file_read_file ( file1, values ) == 0 ) {
606 set_widget_values ( cw, values );
617 static struct LatLon get_ll_tl (VikGeorefLayer *vgl)
620 ll_tl.lat = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.lat_tl_spin) );
621 ll_tl.lon = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.lon_tl_spin) );
625 static struct LatLon get_ll_br (VikGeorefLayer *vgl)
628 ll_br.lat = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.lat_br_spin) );
629 ll_br.lon = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.lon_br_spin) );
633 // Align displayed UTM values with displayed Lat/Lon values
634 static void align_utm2ll (VikGeorefLayer *vgl)
636 struct LatLon ll_tl = get_ll_tl (vgl);
639 a_coords_latlon_to_utm ( &ll_tl, &utm );
640 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.ce_spin), utm.easting );
641 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.cn_spin), utm.northing );
644 tmp_letter[0] = utm.letter;
645 tmp_letter[1] = '\0';
646 gtk_entry_set_text ( GTK_ENTRY(vgl->cw.utm_letter_entry), tmp_letter );
648 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.utm_zone_spin), utm.zone );
651 // Align displayed Lat/Lon values with displayed UTM values
652 static void align_ll2utm (VikGeorefLayer *vgl)
655 const gchar *letter = gtk_entry_get_text ( GTK_ENTRY(vgl->cw.utm_letter_entry) );
657 corner.letter = toupper(*letter);
658 corner.zone = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(vgl->cw.utm_zone_spin) );
659 corner.easting = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.ce_spin) );
660 corner.northing = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.cn_spin) );
663 a_coords_utm_to_latlon ( &corner, &ll );
664 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.lat_tl_spin), ll.lat );
665 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.lon_tl_spin), ll.lon );
669 * Align coordinates between tabs as the user may have changed the values
670 * Use this before acting on the user input
671 * This is easier then trying to use the 'value-changed' signal for each individual coordinate
672 * especiallly since it tends to end up in an infinite loop continually updating each other.
674 static void align_coords ( VikGeorefLayer *vgl )
676 if (gtk_notebook_get_current_page(GTK_NOTEBOOK(vgl->cw.tabs)) == 0)
677 align_ll2utm ( vgl );
679 align_utm2ll ( vgl );
682 static void switch_tab (GtkNotebook *notebook, gpointer tab, guint tab_num, gpointer user_data)
684 VikGeorefLayer *vgl = user_data;
694 static void check_br_is_good_or_msg_user ( VikGeorefLayer *vgl )
696 // if a 'blank' ll value that's alright
697 if ( vgl->ll_br.lat == 0.0 && vgl->ll_br.lon == 0.0 )
700 struct LatLon ll_tl = get_ll_tl (vgl);
701 if ( ll_tl.lat < vgl->ll_br.lat || ll_tl.lon > vgl->ll_br.lon )
702 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vgl), _("Lower right corner values may not be consistent with upper right values") );
708 static void calculate_mpp_from_coords ( GtkWidget *ww, VikGeorefLayer *vgl )
710 const gchar* filename = vik_file_entry_get_filename(VIK_FILE_ENTRY(vgl->cw.imageentry));
715 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( filename, &gx );
717 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(ww), _("Couldn't open image file: %s"), gx->message );
722 guint width = gdk_pixbuf_get_width ( pixbuf );
723 guint height = gdk_pixbuf_get_height ( pixbuf );
725 if ( width == 0 || height == 0 ) {
726 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(ww), _("Invalid image size: %s"), filename);
729 align_coords ( vgl );
731 struct LatLon ll_tl = get_ll_tl (vgl);
732 struct LatLon ll_br = get_ll_br (vgl);
735 ll_tr.lat = ll_tl.lat;
736 ll_tr.lon = ll_br.lon;
739 ll_bl.lat = ll_br.lat;
740 ll_bl.lon = ll_tl.lon;
742 gdouble diffx = a_coords_latlon_diff ( &ll_tl, &ll_tr );
743 gdouble xmpp = diffx / width;
745 gdouble diffy = a_coords_latlon_diff ( &ll_tl, &ll_bl );
746 gdouble ympp = diffy / height;
748 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.x_spin), xmpp );
749 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.y_spin), ympp );
751 check_br_is_good_or_msg_user ( vgl );
754 g_object_unref ( G_OBJECT(pixbuf) );
757 #define VIK_SETTINGS_GEOREF_TAB "georef_coordinate_tab"
759 /* returns TRUE if OK was pressed. */
760 static gboolean georef_layer_dialog ( VikGeorefLayer *vgl, gpointer vp, GtkWindow *w )
762 GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Layer Properties"),
764 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
770 /* Default to reject as user really needs to specify map file first */
771 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_REJECT );
772 GtkWidget *response_w = NULL;
773 #if GTK_CHECK_VERSION (2, 20, 0)
774 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_REJECT );
776 GtkWidget *table, *wfp_hbox, *wfp_label, *wfp_button, *ce_label, *cn_label, *xlabel, *ylabel, *imagelabel;
777 changeable_widgets cw;
779 GtkBox *dgbox = GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog)));
780 table = gtk_table_new ( 4, 2, FALSE );
781 gtk_box_pack_start ( dgbox, table, TRUE, TRUE, 0 );
783 wfp_hbox = gtk_hbox_new ( FALSE, 0 );
784 wfp_label = gtk_label_new ( _("World File Parameters:") );
785 wfp_button = gtk_button_new_with_label ( _("Load From File...") );
787 gtk_box_pack_start ( GTK_BOX(wfp_hbox), wfp_label, TRUE, TRUE, 0 );
788 gtk_box_pack_start ( GTK_BOX(wfp_hbox), wfp_button, FALSE, FALSE, 3 );
790 ce_label = gtk_label_new ( _("Corner pixel easting:") );
791 cw.ce_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, 0.0, 1500000.0, 1, 5, 0 ), 1, 4 );
792 gtk_widget_set_tooltip_text ( GTK_WIDGET(cw.ce_spin), _("the UTM \"easting\" value of the upper-left corner pixel of the map") );
794 cn_label = gtk_label_new ( _("Corner pixel northing:") );
795 cw.cn_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, 0.0, 9000000.0, 1, 5, 0 ), 1, 4 );
796 gtk_widget_set_tooltip_text ( GTK_WIDGET(cw.cn_spin), _("the UTM \"northing\" value of the upper-left corner pixel of the map") );
798 xlabel = gtk_label_new ( _("X (easting) scale (mpp): "));
799 ylabel = gtk_label_new ( _("Y (northing) scale (mpp): "));
801 cw.x_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, VIK_VIEWPORT_MIN_ZOOM, VIK_VIEWPORT_MAX_ZOOM, 1, 5, 0 ), 1, 8 );
802 gtk_widget_set_tooltip_text ( GTK_WIDGET(cw.x_spin), _("the scale of the map in the X direction (meters per pixel)") );
803 cw.y_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, VIK_VIEWPORT_MIN_ZOOM, VIK_VIEWPORT_MAX_ZOOM, 1, 5, 0 ), 1, 8 );
804 gtk_widget_set_tooltip_text ( GTK_WIDGET(cw.y_spin), _("the scale of the map in the Y direction (meters per pixel)") );
806 imagelabel = gtk_label_new ( _("Map Image:") );
807 cw.imageentry = vik_file_entry_new (GTK_FILE_CHOOSER_ACTION_OPEN, VF_FILTER_IMAGE, maybe_read_world_file, &cw);
809 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.ce_spin), vgl->corner.easting );
810 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.cn_spin), vgl->corner.northing );
811 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.x_spin), vgl->mpp_easting );
812 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.y_spin), vgl->mpp_northing );
814 vik_file_entry_set_filename ( VIK_FILE_ENTRY(cw.imageentry), vgl->image );
816 gtk_table_attach_defaults ( GTK_TABLE(table), imagelabel, 0, 1, 0, 1 );
817 gtk_table_attach_defaults ( GTK_TABLE(table), cw.imageentry, 1, 2, 0, 1 );
818 gtk_table_attach_defaults ( GTK_TABLE(table), wfp_hbox, 0, 2, 1, 2 );
819 gtk_table_attach_defaults ( GTK_TABLE(table), xlabel, 0, 1, 2, 3 );
820 gtk_table_attach_defaults ( GTK_TABLE(table), cw.x_spin, 1, 2, 2, 3 );
821 gtk_table_attach_defaults ( GTK_TABLE(table), ylabel, 0, 1, 3, 4 );
822 gtk_table_attach_defaults ( GTK_TABLE(table), cw.y_spin, 1, 2, 3, 4 );
824 cw.tabs = gtk_notebook_new();
825 GtkWidget *table_utm = gtk_table_new ( 3, 2, FALSE );
827 gtk_table_attach_defaults ( GTK_TABLE(table_utm), ce_label, 0, 1, 0, 1 );
828 gtk_table_attach_defaults ( GTK_TABLE(table_utm), cw.ce_spin, 1, 2, 0, 1 );
829 gtk_table_attach_defaults ( GTK_TABLE(table_utm), cn_label, 0, 1, 1, 2 );
830 gtk_table_attach_defaults ( GTK_TABLE(table_utm), cw.cn_spin, 1, 2, 1, 2 );
832 GtkWidget *utm_hbox = gtk_hbox_new ( FALSE, 0 );
833 cw.utm_zone_spin = gtk_spin_button_new ((GtkAdjustment*)gtk_adjustment_new( vgl->corner.zone, 1, 60, 1, 5, 0 ), 1, 0 );
834 gtk_box_pack_start ( GTK_BOX(utm_hbox), gtk_label_new(_("Zone:")), TRUE, TRUE, 0 );
835 gtk_box_pack_start ( GTK_BOX(utm_hbox), cw.utm_zone_spin, TRUE, TRUE, 0 );
836 gtk_box_pack_start ( GTK_BOX(utm_hbox), gtk_label_new(_("Letter:")), TRUE, TRUE, 0 );
837 cw.utm_letter_entry = gtk_entry_new ();
838 gtk_entry_set_max_length ( GTK_ENTRY(cw.utm_letter_entry), 1 );
839 gtk_entry_set_width_chars ( GTK_ENTRY(cw.utm_letter_entry), 2 );
841 tmp_letter[0] = vgl->corner.letter;
842 tmp_letter[1] = '\0';
843 gtk_entry_set_text ( GTK_ENTRY(cw.utm_letter_entry), tmp_letter );
844 gtk_box_pack_start ( GTK_BOX(utm_hbox), cw.utm_letter_entry, TRUE, TRUE, 0 );
846 gtk_table_attach_defaults ( GTK_TABLE(table_utm), utm_hbox, 0, 2, 2, 3 );
849 GtkWidget *table_ll = gtk_table_new ( 5, 2, FALSE );
851 GtkWidget *lat_tl_label = gtk_label_new ( _("Upper left latitude:") );
852 cw.lat_tl_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new (0.0,-90,90.0,0.05,0.1,0), 0.1, 6 );
853 GtkWidget *lon_tl_label = gtk_label_new ( _("Upper left longitude:") );
854 cw.lon_tl_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new (0.0,-180,180.0,0.05,0.1,0), 0.1, 6 );
855 GtkWidget *lat_br_label = gtk_label_new ( _("Lower right latitude:") );
856 cw.lat_br_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new (0.0,-90,90.0,0.05,0.1,0), 0.1, 6 );
857 GtkWidget *lon_br_label = gtk_label_new ( _("Lower right longitude:") );
858 cw.lon_br_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new (0.0,-180.0,180.0,0.05,0.1,0), 0.1, 6 );
860 gtk_table_attach_defaults ( GTK_TABLE(table_ll), lat_tl_label, 0, 1, 0, 1 );
861 gtk_table_attach_defaults ( GTK_TABLE(table_ll), cw.lat_tl_spin, 1, 2, 0, 1 );
862 gtk_table_attach_defaults ( GTK_TABLE(table_ll), lon_tl_label, 0, 1, 1, 2 );
863 gtk_table_attach_defaults ( GTK_TABLE(table_ll), cw.lon_tl_spin, 1, 2, 1, 2 );
864 gtk_table_attach_defaults ( GTK_TABLE(table_ll), lat_br_label, 0, 1, 2, 3 );
865 gtk_table_attach_defaults ( GTK_TABLE(table_ll), cw.lat_br_spin, 1, 2, 2, 3 );
866 gtk_table_attach_defaults ( GTK_TABLE(table_ll), lon_br_label, 0, 1, 3, 4 );
867 gtk_table_attach_defaults ( GTK_TABLE(table_ll), cw.lon_br_spin, 1, 2, 3, 4 );
869 GtkWidget *calc_mpp_button = gtk_button_new_with_label ( _("Calculate MPP values from coordinates") );
870 gtk_widget_set_tooltip_text ( calc_mpp_button, _("Enter all corner coordinates before calculating the MPP values from the image size") );
871 gtk_table_attach_defaults ( GTK_TABLE(table_ll), calc_mpp_button, 0, 2, 4, 5 );
874 vik_coord_load_from_utm (&vc, VIK_COORD_LATLON, &(vgl->corner));
875 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.lat_tl_spin), vc.north_south );
876 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.lon_tl_spin), vc.east_west );
877 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.lat_br_spin), vgl->ll_br.lat );
878 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.lon_br_spin), vgl->ll_br.lon );
880 gtk_notebook_append_page(GTK_NOTEBOOK(cw.tabs), GTK_WIDGET(table_utm), gtk_label_new(_("UTM")));
881 gtk_notebook_append_page(GTK_NOTEBOOK(cw.tabs), GTK_WIDGET(table_ll), gtk_label_new(_("Latitude/Longitude")));
882 gtk_box_pack_start ( dgbox, cw.tabs, TRUE, TRUE, 0 );
884 GtkWidget *alpha_hbox = gtk_hbox_new ( FALSE, 0 );
885 // GTK3 => GtkWidget *alpha_scale = gtk_scale_new_with_range ( GTK_ORIENTATION_HORIZONTAL, 0, 255, 1 );
886 GtkWidget *alpha_scale = gtk_hscale_new_with_range ( 0, 255, 1 );
887 gtk_scale_set_digits ( GTK_SCALE(alpha_scale), 0 );
888 gtk_range_set_value ( GTK_RANGE(alpha_scale), vgl->alpha );
889 gtk_box_pack_start ( GTK_BOX(alpha_hbox), gtk_label_new(_("Alpha:")), TRUE, TRUE, 0 );
890 gtk_box_pack_start ( GTK_BOX(alpha_hbox), alpha_scale, TRUE, TRUE, 0 );
891 gtk_box_pack_start ( dgbox, alpha_hbox, TRUE, TRUE, 0 );
895 g_signal_connect ( G_OBJECT(vgl->cw.tabs), "switch-page", G_CALLBACK(switch_tab), vgl );
896 g_signal_connect ( G_OBJECT(calc_mpp_button), "clicked", G_CALLBACK(calculate_mpp_from_coords), vgl );
898 g_signal_connect_swapped ( G_OBJECT(wfp_button), "clicked", G_CALLBACK(georef_layer_dialog_load), &cw );
901 gtk_widget_grab_focus ( response_w );
903 gtk_widget_show_all ( dialog );
905 // Remember setting the notebook page must be done after the widget is visible.
907 if ( a_settings_get_integer ( VIK_SETTINGS_GEOREF_TAB, &page_num ) )
908 if ( page_num < 0 || page_num > 1 )
910 gtk_notebook_set_current_page ( GTK_NOTEBOOK(cw.tabs), page_num );
912 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
914 align_coords ( vgl );
916 vgl->corner.easting = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cw.ce_spin) );
917 vgl->corner.northing = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cw.cn_spin) );
918 vgl->corner.zone = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(cw.utm_zone_spin) );
919 const gchar *letter = gtk_entry_get_text ( GTK_ENTRY(cw.utm_letter_entry) );
921 vgl->corner.letter = toupper(*letter);
922 vgl->mpp_easting = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cw.x_spin) );
923 vgl->mpp_northing = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cw.y_spin) );
924 vgl->ll_br = get_ll_br (vgl);
925 check_br_is_good_or_msg_user ( vgl );
926 if ( g_strcmp0 (vgl->image, vik_file_entry_get_filename(VIK_FILE_ENTRY(cw.imageentry)) ) != 0 )
928 georef_layer_set_image ( vgl, vik_file_entry_get_filename(VIK_FILE_ENTRY(cw.imageentry)) );
929 georef_layer_load_image ( vgl, VIK_VIEWPORT(vp), FALSE );
932 vgl->alpha = (guint8) gtk_range_get_value ( GTK_RANGE(alpha_scale) );
933 if ( vgl->pixbuf && vgl->alpha < 255 )
934 vgl->pixbuf = ui_pixbuf_set_alpha ( vgl->pixbuf, vgl->alpha );
935 if ( vgl->scaled && vgl->alpha < 255 )
936 vgl->scaled = ui_pixbuf_set_alpha ( vgl->scaled, vgl->alpha );
938 a_settings_set_integer ( VIK_SETTINGS_GEOREF_TAB, gtk_notebook_get_current_page(GTK_NOTEBOOK(cw.tabs)) );
940 gtk_widget_destroy ( GTK_WIDGET(dialog) );
943 gtk_widget_destroy ( GTK_WIDGET(dialog) );
947 static void georef_layer_zoom_to_fit ( gpointer vgl_vlp[2] )
949 vik_viewport_set_xmpp ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1])), VIK_GEOREF_LAYER(vgl_vlp[0])->mpp_easting );
950 vik_viewport_set_ympp ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1])), VIK_GEOREF_LAYER(vgl_vlp[0])->mpp_northing );
951 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vgl_vlp[1]) );
954 static void georef_layer_goto_center ( gpointer vgl_vlp[2] )
956 VikGeorefLayer *vgl = VIK_GEOREF_LAYER ( vgl_vlp[0] );
957 VikViewport *vp = vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1]));
961 vik_coord_to_utm ( vik_viewport_get_center ( vp ), &utm );
963 utm.easting = vgl->corner.easting + (vgl->width * vgl->mpp_easting / 2); /* only an approximation */
964 utm.northing = vgl->corner.northing - (vgl->height * vgl->mpp_northing / 2);
966 vik_coord_load_from_utm ( &coord, vik_viewport_get_coord_mode ( vp ), &utm );
967 vik_viewport_set_center_coord ( vp, &coord, TRUE );
969 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vgl_vlp[1]) );
972 static void georef_layer_add_menu_items ( VikGeorefLayer *vgl, GtkMenu *menu, gpointer vlp )
974 static gpointer pass_along[2];
979 item = gtk_menu_item_new();
980 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
981 gtk_widget_show ( item );
984 item = gtk_image_menu_item_new_with_mnemonic ( _("_Zoom to Fit Map") );
985 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
986 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_zoom_to_fit), pass_along );
987 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
988 gtk_widget_show ( item );
990 item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto Map Center") );
991 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
992 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_goto_center), pass_along );
993 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
994 gtk_widget_show ( item );
996 item = gtk_image_menu_item_new_with_mnemonic ( _("_Export to World File") );
997 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_HARDDISK, GTK_ICON_SIZE_MENU) );
998 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_export_params), pass_along );
999 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1000 gtk_widget_show ( item );
1004 static gpointer georef_layer_move_create ( VikWindow *vw, VikViewport *vvp)
1009 static gboolean georef_layer_move_release ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
1011 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
1014 if ( vgl->click_x != -1 )
1016 vgl->corner.easting += (event->x - vgl->click_x) * vik_viewport_get_xmpp (vvp);
1017 vgl->corner.northing -= (event->y - vgl->click_y) * vik_viewport_get_ympp (vvp);
1018 vik_layer_emit_update ( VIK_LAYER(vgl) );
1021 return FALSE; /* I didn't move anything on this layer! */
1024 static gpointer georef_layer_zoom_create ( VikWindow *vw, VikViewport *vvp)
1029 static gboolean georef_layer_zoom_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
1031 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
1033 if ( event->button == 1 )
1035 if ( vgl->mpp_easting < (VIK_VIEWPORT_MAX_ZOOM / 1.05) && vgl->mpp_northing < (VIK_VIEWPORT_MAX_ZOOM / 1.05) )
1037 vgl->mpp_easting *= 1.01;
1038 vgl->mpp_northing *= 1.01;
1043 if ( vgl->mpp_easting > (VIK_VIEWPORT_MIN_ZOOM * 1.05) && vgl->mpp_northing > (VIK_VIEWPORT_MIN_ZOOM * 1.05) )
1045 vgl->mpp_easting /= 1.01;
1046 vgl->mpp_northing /= 1.01;
1049 vik_viewport_set_xmpp ( vvp, vgl->mpp_easting );
1050 vik_viewport_set_ympp ( vvp, vgl->mpp_northing );
1051 vik_layer_emit_update ( VIK_LAYER(vgl) );
1055 static gboolean georef_layer_move_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
1057 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
1059 vgl->click_x = event->x;
1060 vgl->click_y = event->y;