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"
40 #include "vikmapslayer.h"
43 static VikLayerParamData image_default ( void )
45 VikLayerParamData data;
46 data.s = g_strdup ("");
51 VikLayerParam georef_layer_params[] = {
52 { VIK_LAYER_GEOREF, "image", VIK_LAYER_PARAM_STRING, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
53 { VIK_LAYER_GEOREF, "corner_easting", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
54 { VIK_LAYER_GEOREF, "corner_northing", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
55 { VIK_LAYER_GEOREF, "mpp_easting", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
56 { VIK_LAYER_GEOREF, "mpp_northing", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
57 { VIK_LAYER_GEOREF, "corner_zone", VIK_LAYER_PARAM_UINT, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
58 { VIK_LAYER_GEOREF, "corner_letter_as_int", VIK_LAYER_PARAM_UINT, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
59 { VIK_LAYER_GEOREF, "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
73 static const gchar* georef_layer_tooltip ( VikGeorefLayer *vgl );
74 static void georef_layer_marshall( VikGeorefLayer *vgl, guint8 **data, gint *len );
75 static VikGeorefLayer *georef_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
76 static gboolean georef_layer_set_param ( VikGeorefLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
77 static VikLayerParamData georef_layer_get_param ( VikGeorefLayer *vgl, guint16 id, gboolean is_file_operation );
78 static VikGeorefLayer *georef_layer_new ( VikViewport *vvp );
79 static VikGeorefLayer *georef_layer_create ( VikViewport *vp );
80 static void georef_layer_free ( VikGeorefLayer *vgl );
81 static gboolean georef_layer_properties ( VikGeorefLayer *vgl, gpointer vp );
82 static void georef_layer_draw ( VikGeorefLayer *vgl, VikViewport *vp );
83 static void georef_layer_add_menu_items ( VikGeorefLayer *vgl, GtkMenu *menu, gpointer vlp );
84 static void georef_layer_set_image ( VikGeorefLayer *vgl, const gchar *image );
85 static gboolean georef_layer_dialog ( VikGeorefLayer *vgl, gpointer vp, GtkWindow *w );
86 static void georef_layer_load_image ( VikGeorefLayer *vgl, VikViewport *vp, gboolean from_file );
89 static gpointer georef_layer_move_create ( VikWindow *vw, VikViewport *vvp);
90 static gboolean georef_layer_move_release ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
91 static gboolean georef_layer_move_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
92 static gpointer georef_layer_zoom_create ( VikWindow *vw, VikViewport *vvp);
93 static gboolean georef_layer_zoom_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
95 // See comment in viktrwlayer.c for advice on values used
96 static VikToolInterface georef_tools[] = {
97 { { "GeorefMoveMap", "vik-icon-Georef Move Map", N_("_Georef Move Map"), NULL, N_("Georef Move Map"), 0 },
98 (VikToolConstructorFunc) georef_layer_move_create, NULL, NULL, NULL,
99 (VikToolMouseFunc) georef_layer_move_press, NULL, (VikToolMouseFunc) georef_layer_move_release,
100 (VikToolKeyFunc) NULL,
102 GDK_CURSOR_IS_PIXMAP, &cursor_geomove_pixbuf, NULL },
104 { { "GeorefZoomTool", "vik-icon-Georef Zoom Tool", N_("Georef Z_oom Tool"), NULL, N_("Georef Zoom Tool"), 0 },
105 (VikToolConstructorFunc) georef_layer_zoom_create, NULL, NULL, NULL,
106 (VikToolMouseFunc) georef_layer_zoom_press, NULL, NULL,
107 (VikToolKeyFunc) NULL,
109 GDK_CURSOR_IS_PIXMAP, &cursor_geozoom_pixbuf, NULL },
112 VikLayerInterface vik_georef_layer_interface = {
116 &vikgeoreflayer_pixbuf, /*icon */
119 sizeof(georef_tools) / sizeof(VikToolInterface),
128 (VikLayerFuncCreate) georef_layer_create,
129 (VikLayerFuncRealize) NULL,
130 (VikLayerFuncPostRead) georef_layer_load_image,
131 (VikLayerFuncFree) georef_layer_free,
133 (VikLayerFuncProperties) georef_layer_properties,
134 (VikLayerFuncDraw) georef_layer_draw,
135 (VikLayerFuncChangeCoordMode) NULL,
137 (VikLayerFuncGetTimestamp) NULL,
139 (VikLayerFuncSetMenuItemsSelection) NULL,
140 (VikLayerFuncGetMenuItemsSelection) NULL,
142 (VikLayerFuncAddMenuItems) georef_layer_add_menu_items,
143 (VikLayerFuncSublayerAddMenuItems) NULL,
145 (VikLayerFuncSublayerRenameRequest) NULL,
146 (VikLayerFuncSublayerToggleVisible) NULL,
147 (VikLayerFuncSublayerTooltip) NULL,
148 (VikLayerFuncLayerTooltip) georef_layer_tooltip,
149 (VikLayerFuncLayerSelected) NULL,
151 (VikLayerFuncMarshall) georef_layer_marshall,
152 (VikLayerFuncUnmarshall) georef_layer_unmarshall,
154 (VikLayerFuncSetParam) georef_layer_set_param,
155 (VikLayerFuncGetParam) georef_layer_get_param,
156 (VikLayerFuncChangeParam) NULL,
158 (VikLayerFuncReadFileData) NULL,
159 (VikLayerFuncWriteFileData) NULL,
161 (VikLayerFuncDeleteItem) NULL,
162 (VikLayerFuncCutItem) NULL,
163 (VikLayerFuncCopyItem) NULL,
164 (VikLayerFuncPasteItem) NULL,
165 (VikLayerFuncFreeCopiedItem) NULL,
166 (VikLayerFuncDragDropRequest) NULL,
168 (VikLayerFuncSelectClick) NULL,
169 (VikLayerFuncSelectMove) NULL,
170 (VikLayerFuncSelectRelease) NULL,
171 (VikLayerFuncSelectedViewportMenu) NULL,
178 GtkWidget *ce_spin; // top left
179 GtkWidget *cn_spin; // "
180 GtkWidget *utm_zone_spin;
181 GtkWidget *utm_letter_entry;
183 GtkWidget *lat_tl_spin;
184 GtkWidget *lon_tl_spin;
185 GtkWidget *lat_br_spin;
186 GtkWidget *lon_br_spin;
189 GtkWidget *imageentry;
190 } changeable_widgets;
192 struct _VikGeorefLayer {
198 struct UTM corner; // Top Left
199 gdouble mpp_easting, mpp_northing;
200 struct LatLon ll_br; // Bottom Right
204 guint32 scaled_width, scaled_height;
206 gint click_x, click_y;
207 changeable_widgets cw;
210 static VikLayerParam io_prefs[] = {
211 { 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,
212 N_("Automatically attempt to read associated world file of a new image for a GeoRef layer"), NULL, NULL, NULL}
215 void vik_georef_layer_init (void)
217 VikLayerParamData tmp;
219 a_preferences_register(&io_prefs[0], tmp, VIKING_PREFERENCES_IO_GROUP_KEY);
222 GType vik_georef_layer_get_type ()
224 static GType vgl_type = 0;
228 static const GTypeInfo vgl_info =
230 sizeof (VikGeorefLayerClass),
231 NULL, /* base_init */
232 NULL, /* base_finalize */
233 NULL, /* class init */
234 NULL, /* class_finalize */
235 NULL, /* class_data */
236 sizeof (VikGeorefLayer),
238 NULL /* instance init */
240 vgl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikGeorefLayer", &vgl_info, 0 );
246 static const gchar* georef_layer_tooltip ( VikGeorefLayer *vgl )
251 static void georef_layer_marshall( VikGeorefLayer *vgl, guint8 **data, gint *len )
253 vik_layer_marshall_params ( VIK_LAYER(vgl), data, len );
256 static VikGeorefLayer *georef_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
258 VikGeorefLayer *rv = georef_layer_new ( vvp );
259 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
261 georef_layer_load_image ( rv, vvp, TRUE );
266 static gboolean georef_layer_set_param ( VikGeorefLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
270 case PARAM_IMAGE: georef_layer_set_image ( vgl, data.s ); break;
271 case PARAM_CN: vgl->corner.northing = data.d; break;
272 case PARAM_CE: vgl->corner.easting = data.d; break;
273 case PARAM_MN: vgl->mpp_northing = data.d; break;
274 case PARAM_ME: vgl->mpp_easting = data.d; break;
275 case PARAM_CZ: if ( data.u <= 60 ) vgl->corner.zone = data.u; break;
276 case PARAM_CL: if ( data.u >= 65 || data.u <= 90 ) vgl->corner.letter = data.u; break;
277 case PARAM_AA: if ( data.u <= 255 ) vgl->alpha = data.u; break;
283 static void create_image_file ( VikGeorefLayer *vgl )
285 // Create in .viking-maps
286 gchar *filename = g_strconcat ( maps_layer_default_dir(), vik_layer_get_name(VIK_LAYER(vgl)), ".jpg", NULL );
287 GError *error = NULL;
288 gdk_pixbuf_save ( vgl->pixbuf, filename, "jpeg", &error, NULL );
290 g_warning ( "%s", error->message );
291 g_error_free ( error );
294 vgl->image = g_strdup ( filename );
299 static VikLayerParamData georef_layer_get_param ( VikGeorefLayer *vgl, guint16 id, gboolean is_file_operation )
301 VikLayerParamData rv;
305 gboolean set = FALSE;
306 if ( is_file_operation ) {
307 if ( vgl->pixbuf && !vgl->image ) {
308 // Force creation of image file
309 create_image_file ( vgl );
311 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
312 gchar *cwd = g_get_current_dir();
314 rv.s = file_GetRelativeFilename ( cwd, vgl->image );
315 if ( !rv.s ) rv.s = "";
321 rv.s = vgl->image ? vgl->image : "";
324 case PARAM_CN: rv.d = vgl->corner.northing; break;
325 case PARAM_CE: rv.d = vgl->corner.easting; break;
326 case PARAM_MN: rv.d = vgl->mpp_northing; break;
327 case PARAM_ME: rv.d = vgl->mpp_easting; break;
328 case PARAM_CZ: rv.u = vgl->corner.zone; break;
329 case PARAM_CL: rv.u = vgl->corner.letter; break;
330 case PARAM_AA: rv.u = vgl->alpha; break;
336 static VikGeorefLayer *georef_layer_new ( VikViewport *vvp )
338 VikGeorefLayer *vgl = VIK_GEOREF_LAYER ( g_object_new ( VIK_GEOREF_LAYER_TYPE, NULL ) );
339 vik_layer_set_type ( VIK_LAYER(vgl), VIK_LAYER_GEOREF );
341 // Since GeoRef layer doesn't use uibuilder
342 // initializing this way won't do anything yet..
343 vik_layer_set_defaults ( VIK_LAYER(vgl), vvp );
345 // Make these defaults based on the current view
346 vgl->mpp_northing = vik_viewport_get_ympp ( vvp );
347 vgl->mpp_easting = vik_viewport_get_xmpp ( vvp );
348 vik_coord_to_utm ( vik_viewport_get_center ( vvp ), &(vgl->corner) );
355 vgl->scaled_width = 0;
356 vgl->scaled_height = 0;
357 vgl->ll_br.lat = 0.0;
358 vgl->ll_br.lon = 0.0;
364 * Return mpp for the given coords, coord mode and image size.
366 static void georef_layer_mpp_from_coords ( VikCoordMode mode, struct LatLon ll_tl, struct LatLon ll_br, guint width, guint height, gdouble *xmpp, gdouble *ympp )
369 ll_tr.lat = ll_tl.lat;
370 ll_tr.lon = ll_br.lon;
373 ll_bl.lat = ll_br.lat;
374 ll_bl.lon = ll_tl.lon;
376 // UTM mode should be exact MPP
377 gdouble factor = 1.0;
378 if ( mode == VIK_COORD_LATLON ) {
379 // NB the 1.193 - is at the Equator.
380 // http://wiki.openstreetmap.org/wiki/Zoom_levels
382 // Convert from actual image MPP to Viking 'pixelfact'
383 gdouble mid_lat = (ll_bl.lat + ll_tr.lat ) / 2.0;
384 // Protect against div by zero (but shouldn't have 90 degrees for mid latitude...)
385 if ( fabs(mid_lat) < 89.9 )
386 factor = cos(DEG2RAD(mid_lat)) * 1.193;
389 gdouble diffx = a_coords_latlon_diff ( &ll_tl, &ll_tr );
390 *xmpp = (diffx / width) / factor;
392 gdouble diffy = a_coords_latlon_diff ( &ll_tl, &ll_bl );
393 *ympp = (diffy / height) / factor;
396 static void georef_layer_draw ( VikGeorefLayer *vgl, VikViewport *vp )
400 gdouble xmpp = vik_viewport_get_xmpp(vp), ympp = vik_viewport_get_ympp(vp);
401 GdkPixbuf *pixbuf = vgl->pixbuf;
402 guint layer_width = vgl->width;
403 guint layer_height = vgl->height;
405 guint width = vik_viewport_get_width(vp), height = vik_viewport_get_height(vp);
407 VikCoord corner_coord;
408 vik_coord_load_from_utm ( &corner_coord, vik_viewport_get_coord_mode(vp), &(vgl->corner) );
409 vik_viewport_coord_to_screen ( vp, &corner_coord, &x, &y );
411 /* mark to scale the pixbuf if it doesn't match our dimensions */
412 gboolean scale = FALSE;
413 if ( xmpp != vgl->mpp_easting || ympp != vgl->mpp_northing )
416 layer_width = round(vgl->width * vgl->mpp_easting / xmpp);
417 layer_height = round(vgl->height * vgl->mpp_northing / ympp);
420 // If image not in viewport bounds - no need to draw it (or bother with any scaling)
421 if ( (x < 0 || x < width) && (y < 0 || y < height) && x+layer_width > 0 && y+layer_height > 0 ) {
425 /* rescale if necessary */
426 if (layer_width == vgl->scaled_width && layer_height == vgl->scaled_height && vgl->scaled != NULL)
427 pixbuf = vgl->scaled;
430 pixbuf = gdk_pixbuf_scale_simple(
437 if (vgl->scaled != NULL)
438 g_object_unref(vgl->scaled);
440 vgl->scaled = pixbuf;
441 vgl->scaled_width = layer_width;
442 vgl->scaled_height = layer_height;
445 vik_viewport_draw_pixbuf ( vp, pixbuf, 0, 0, x, y, layer_width, layer_height ); /* todo: draw only what we need to. */
450 static void georef_layer_free ( VikGeorefLayer *vgl )
452 if ( vgl->image != NULL )
453 g_free ( vgl->image );
454 if ( vgl->scaled != NULL )
455 g_object_unref ( vgl->scaled );
458 static VikGeorefLayer *georef_layer_create ( VikViewport *vp )
460 return georef_layer_new ( vp );
463 static gboolean georef_layer_properties ( VikGeorefLayer *vgl, gpointer vp )
465 return georef_layer_dialog ( vgl, vp, VIK_GTK_WINDOW_FROM_WIDGET(vp) );
468 static void georef_layer_load_image ( VikGeorefLayer *vgl, VikViewport *vp, gboolean from_file )
471 if ( vgl->image == NULL )
475 g_object_unref ( G_OBJECT(vgl->pixbuf) );
478 g_object_unref ( G_OBJECT(vgl->scaled) );
482 vgl->pixbuf = gdk_pixbuf_new_from_file ( vgl->image, &gx );
487 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(vp), _("Couldn't open image file: %s"), gx->message );
492 vgl->width = gdk_pixbuf_get_width ( vgl->pixbuf );
493 vgl->height = gdk_pixbuf_get_height ( vgl->pixbuf );
495 if ( vgl->pixbuf && vgl->alpha < 255 )
496 vgl->pixbuf = ui_pixbuf_set_alpha ( vgl->pixbuf, vgl->alpha );
498 /* should find length and width here too */
501 static void georef_layer_set_image ( VikGeorefLayer *vgl, const gchar *image )
504 g_free ( vgl->image );
507 g_object_unref ( vgl->scaled );
513 if ( g_strcmp0 (image, "") != 0 )
514 vgl->image = vu_get_canonical_filename ( VIK_LAYER(vgl), image );
516 vgl->image = g_strdup (image);
519 // Only positive values allowed here
520 static void gdouble2spinwidget ( GtkWidget *widget, gdouble val )
522 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(widget), val > 0 ? val : -val );
525 static void set_widget_values ( changeable_widgets *cw, gdouble values[4] )
527 gdouble2spinwidget ( cw->x_spin, values[0] );
528 gdouble2spinwidget ( cw->y_spin, values[1] );
529 gdouble2spinwidget ( cw->ce_spin, values[2] );
530 gdouble2spinwidget ( cw->cn_spin, values[3] );
533 static gboolean world_file_read_line ( FILE *ff, gdouble *value, gboolean use_value )
535 gboolean answer = TRUE; // Success
537 if ( !fgets ( buffer, 1024, ff ) ) {
540 if ( answer && use_value )
541 *value = g_strtod ( buffer, NULL );
547 * http://en.wikipedia.org/wiki/World_file
549 * Note world files do not define the units and nor are the units standardized :(
550 * Currently Viking only supports:
551 * x&y scale as meters per pixel
552 * x&y coords as UTM eastings and northings respectively
554 static gint world_file_read_file ( const gchar* filename, gdouble values[4] )
556 g_debug ("%s - trying world file %s", __FUNCTION__, filename);
558 FILE *f = g_fopen ( filename, "r" );
562 gint answer = 2; // Not enough info read yet
563 // **We do not handle 'skew' values ATM - normally they are a value of 0 anyway to align with the UTM grid
564 if ( world_file_read_line ( f, &values[0], TRUE ) // x scale
565 && world_file_read_line ( f, NULL, FALSE ) // Ignore value in y-skew line**
566 && world_file_read_line ( f, NULL, FALSE ) // Ignore value in x-skew line**
567 && world_file_read_line ( f, &values[1], TRUE ) // y scale
568 && world_file_read_line ( f, &values[2], TRUE ) // x-coordinate of the upper left pixel
569 && world_file_read_line ( f, &values[3], TRUE ) // y-coordinate of the upper left pixel
573 g_debug ("%s - %s - world file read success", __FUNCTION__, filename);
581 static void georef_layer_dialog_load ( changeable_widgets *cw )
583 GtkWidget *file_selector = gtk_file_chooser_dialog_new (_("Choose World file"),
585 GTK_FILE_CHOOSER_ACTION_OPEN,
586 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
587 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
590 if ( gtk_dialog_run ( GTK_DIALOG ( file_selector ) ) == GTK_RESPONSE_ACCEPT )
593 gint answer = world_file_read_file ( gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_selector)), values );
595 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(cw->x_spin), _("The World file you requested could not be opened for reading.") );
596 else if ( answer == 2 )
597 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(cw->x_spin), _("Unexpected end of file reading World file.") );
599 // NB answer should == 0 for success
600 set_widget_values ( cw, values );
603 gtk_widget_destroy ( file_selector );
606 static void georef_layer_export_params ( gpointer *pass_along[2] )
608 VikGeorefLayer *vgl = VIK_GEOREF_LAYER(pass_along[0]);
609 GtkWidget *file_selector = gtk_file_chooser_dialog_new (_("Choose World file"),
611 GTK_FILE_CHOOSER_ACTION_SAVE,
612 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
613 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
615 if ( gtk_dialog_run ( GTK_DIALOG ( file_selector ) ) == GTK_RESPONSE_ACCEPT )
617 FILE *f = g_fopen ( gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER(file_selector) ), "w" );
619 gtk_widget_destroy ( file_selector );
622 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(pass_along[0]), _("The file you requested could not be opened for writing.") );
627 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 );
633 gtk_widget_destroy ( file_selector );
637 * Auto attempt to read the world file associated with the image used for the georef
638 * Based on simple file name conventions
639 * Only attempted if the preference is on.
641 static void maybe_read_world_file ( VikFileEntry *vfe, gpointer user_data )
643 if ( a_preferences_get (VIKING_PREFERENCES_IO_NAMESPACE "georef_auto_read_world_file")->b ) {
644 const gchar* filename = vik_file_entry_get_filename(VIK_FILE_ENTRY(vfe));
646 if ( filename && user_data ) {
648 changeable_widgets *cw = user_data;
650 gboolean upper = g_ascii_isupper (filename[strlen(filename)-1]);
651 gchar* filew = g_strconcat ( filename, (upper ? "W" : "w") , NULL );
653 if ( world_file_read_file ( filew, values ) == 0 ) {
654 set_widget_values ( cw, values );
657 if ( strlen(filename) > 3 ) {
658 gchar* file0 = g_strndup ( filename, strlen(filename)-2 );
659 gchar* file1 = g_strdup_printf ( "%s%c%c", file0, filename[strlen(filename)-1], (upper ? 'W' : 'w') );
660 if ( world_file_read_file ( file1, values ) == 0 ) {
661 set_widget_values ( cw, values );
672 static struct LatLon get_ll_tl (VikGeorefLayer *vgl)
675 ll_tl.lat = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.lat_tl_spin) );
676 ll_tl.lon = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.lon_tl_spin) );
680 static struct LatLon get_ll_br (VikGeorefLayer *vgl)
683 ll_br.lat = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.lat_br_spin) );
684 ll_br.lon = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.lon_br_spin) );
688 // Align displayed UTM values with displayed Lat/Lon values
689 static void align_utm2ll (VikGeorefLayer *vgl)
691 struct LatLon ll_tl = get_ll_tl (vgl);
694 a_coords_latlon_to_utm ( &ll_tl, &utm );
695 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.ce_spin), utm.easting );
696 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.cn_spin), utm.northing );
699 tmp_letter[0] = utm.letter;
700 tmp_letter[1] = '\0';
701 gtk_entry_set_text ( GTK_ENTRY(vgl->cw.utm_letter_entry), tmp_letter );
703 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.utm_zone_spin), utm.zone );
706 // Align displayed Lat/Lon values with displayed UTM values
707 static void align_ll2utm (VikGeorefLayer *vgl)
710 const gchar *letter = gtk_entry_get_text ( GTK_ENTRY(vgl->cw.utm_letter_entry) );
712 corner.letter = toupper(*letter);
713 corner.zone = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(vgl->cw.utm_zone_spin) );
714 corner.easting = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.ce_spin) );
715 corner.northing = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.cn_spin) );
718 a_coords_utm_to_latlon ( &corner, &ll );
719 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.lat_tl_spin), ll.lat );
720 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.lon_tl_spin), ll.lon );
724 * Align coordinates between tabs as the user may have changed the values
725 * Use this before acting on the user input
726 * This is easier then trying to use the 'value-changed' signal for each individual coordinate
727 * especiallly since it tends to end up in an infinite loop continually updating each other.
729 static void align_coords ( VikGeorefLayer *vgl )
731 if (gtk_notebook_get_current_page(GTK_NOTEBOOK(vgl->cw.tabs)) == 0)
732 align_ll2utm ( vgl );
734 align_utm2ll ( vgl );
737 static void switch_tab (GtkNotebook *notebook, gpointer tab, guint tab_num, gpointer user_data)
739 VikGeorefLayer *vgl = user_data;
749 static void check_br_is_good_or_msg_user ( VikGeorefLayer *vgl )
751 // if a 'blank' ll value that's alright
752 if ( vgl->ll_br.lat == 0.0 && vgl->ll_br.lon == 0.0 )
755 struct LatLon ll_tl = get_ll_tl (vgl);
756 if ( ll_tl.lat < vgl->ll_br.lat || ll_tl.lon > vgl->ll_br.lon )
757 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vgl), _("Lower right corner values may not be consistent with upper right values") );
763 static void calculate_mpp_from_coords ( GtkWidget *ww, VikGeorefLayer *vgl )
765 const gchar* filename = vik_file_entry_get_filename(VIK_FILE_ENTRY(vgl->cw.imageentry));
770 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( filename, &gx );
772 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(ww), _("Couldn't open image file: %s"), gx->message );
777 guint width = gdk_pixbuf_get_width ( pixbuf );
778 guint height = gdk_pixbuf_get_height ( pixbuf );
780 if ( width == 0 || height == 0 ) {
781 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(ww), _("Invalid image size: %s"), filename);
784 align_coords ( vgl );
786 struct LatLon ll_tl = get_ll_tl (vgl);
787 struct LatLon ll_br = get_ll_br (vgl);
790 georef_layer_mpp_from_coords ( VIK_COORD_LATLON, ll_tl, ll_br, width, height, &xmpp, &ympp );
792 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.x_spin), xmpp );
793 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.y_spin), ympp );
795 check_br_is_good_or_msg_user ( vgl );
798 g_object_unref ( G_OBJECT(pixbuf) );
801 #define VIK_SETTINGS_GEOREF_TAB "georef_coordinate_tab"
803 /* returns TRUE if OK was pressed. */
804 static gboolean georef_layer_dialog ( VikGeorefLayer *vgl, gpointer vp, GtkWindow *w )
806 GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Layer Properties"),
808 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
814 /* Default to reject as user really needs to specify map file first */
815 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_REJECT );
816 GtkWidget *response_w = NULL;
817 #if GTK_CHECK_VERSION (2, 20, 0)
818 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_REJECT );
820 GtkWidget *table, *wfp_hbox, *wfp_label, *wfp_button, *ce_label, *cn_label, *xlabel, *ylabel, *imagelabel;
821 changeable_widgets cw;
823 GtkBox *dgbox = GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog)));
824 table = gtk_table_new ( 4, 2, FALSE );
825 gtk_box_pack_start ( dgbox, table, TRUE, TRUE, 0 );
827 wfp_hbox = gtk_hbox_new ( FALSE, 0 );
828 wfp_label = gtk_label_new ( _("World File Parameters:") );
829 wfp_button = gtk_button_new_with_label ( _("Load From File...") );
831 gtk_box_pack_start ( GTK_BOX(wfp_hbox), wfp_label, TRUE, TRUE, 0 );
832 gtk_box_pack_start ( GTK_BOX(wfp_hbox), wfp_button, FALSE, FALSE, 3 );
834 ce_label = gtk_label_new ( _("Corner pixel easting:") );
835 cw.ce_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, 0.0, 1500000.0, 1, 5, 0 ), 1, 4 );
836 gtk_widget_set_tooltip_text ( GTK_WIDGET(cw.ce_spin), _("the UTM \"easting\" value of the upper-left corner pixel of the map") );
838 cn_label = gtk_label_new ( _("Corner pixel northing:") );
839 cw.cn_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, 0.0, 9000000.0, 1, 5, 0 ), 1, 4 );
840 gtk_widget_set_tooltip_text ( GTK_WIDGET(cw.cn_spin), _("the UTM \"northing\" value of the upper-left corner pixel of the map") );
842 xlabel = gtk_label_new ( _("X (easting) scale (mpp): "));
843 ylabel = gtk_label_new ( _("Y (northing) scale (mpp): "));
845 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 );
846 gtk_widget_set_tooltip_text ( GTK_WIDGET(cw.x_spin), _("the scale of the map in the X direction (meters per pixel)") );
847 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 );
848 gtk_widget_set_tooltip_text ( GTK_WIDGET(cw.y_spin), _("the scale of the map in the Y direction (meters per pixel)") );
850 imagelabel = gtk_label_new ( _("Map Image:") );
851 cw.imageentry = vik_file_entry_new (GTK_FILE_CHOOSER_ACTION_OPEN, VF_FILTER_IMAGE, maybe_read_world_file, &cw);
853 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.ce_spin), vgl->corner.easting );
854 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.cn_spin), vgl->corner.northing );
855 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.x_spin), vgl->mpp_easting );
856 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.y_spin), vgl->mpp_northing );
858 vik_file_entry_set_filename ( VIK_FILE_ENTRY(cw.imageentry), vgl->image );
860 gtk_table_attach_defaults ( GTK_TABLE(table), imagelabel, 0, 1, 0, 1 );
861 gtk_table_attach_defaults ( GTK_TABLE(table), cw.imageentry, 1, 2, 0, 1 );
862 gtk_table_attach_defaults ( GTK_TABLE(table), wfp_hbox, 0, 2, 1, 2 );
863 gtk_table_attach_defaults ( GTK_TABLE(table), xlabel, 0, 1, 2, 3 );
864 gtk_table_attach_defaults ( GTK_TABLE(table), cw.x_spin, 1, 2, 2, 3 );
865 gtk_table_attach_defaults ( GTK_TABLE(table), ylabel, 0, 1, 3, 4 );
866 gtk_table_attach_defaults ( GTK_TABLE(table), cw.y_spin, 1, 2, 3, 4 );
868 cw.tabs = gtk_notebook_new();
869 GtkWidget *table_utm = gtk_table_new ( 3, 2, FALSE );
871 gtk_table_attach_defaults ( GTK_TABLE(table_utm), ce_label, 0, 1, 0, 1 );
872 gtk_table_attach_defaults ( GTK_TABLE(table_utm), cw.ce_spin, 1, 2, 0, 1 );
873 gtk_table_attach_defaults ( GTK_TABLE(table_utm), cn_label, 0, 1, 1, 2 );
874 gtk_table_attach_defaults ( GTK_TABLE(table_utm), cw.cn_spin, 1, 2, 1, 2 );
876 GtkWidget *utm_hbox = gtk_hbox_new ( FALSE, 0 );
877 cw.utm_zone_spin = gtk_spin_button_new ((GtkAdjustment*)gtk_adjustment_new( vgl->corner.zone, 1, 60, 1, 5, 0 ), 1, 0 );
878 gtk_box_pack_start ( GTK_BOX(utm_hbox), gtk_label_new(_("Zone:")), TRUE, TRUE, 0 );
879 gtk_box_pack_start ( GTK_BOX(utm_hbox), cw.utm_zone_spin, TRUE, TRUE, 0 );
880 gtk_box_pack_start ( GTK_BOX(utm_hbox), gtk_label_new(_("Letter:")), TRUE, TRUE, 0 );
881 cw.utm_letter_entry = gtk_entry_new ();
882 gtk_entry_set_max_length ( GTK_ENTRY(cw.utm_letter_entry), 1 );
883 gtk_entry_set_width_chars ( GTK_ENTRY(cw.utm_letter_entry), 2 );
885 tmp_letter[0] = vgl->corner.letter;
886 tmp_letter[1] = '\0';
887 gtk_entry_set_text ( GTK_ENTRY(cw.utm_letter_entry), tmp_letter );
888 gtk_box_pack_start ( GTK_BOX(utm_hbox), cw.utm_letter_entry, TRUE, TRUE, 0 );
890 gtk_table_attach_defaults ( GTK_TABLE(table_utm), utm_hbox, 0, 2, 2, 3 );
893 GtkWidget *table_ll = gtk_table_new ( 5, 2, FALSE );
895 GtkWidget *lat_tl_label = gtk_label_new ( _("Upper left latitude:") );
896 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 );
897 GtkWidget *lon_tl_label = gtk_label_new ( _("Upper left longitude:") );
898 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 );
899 GtkWidget *lat_br_label = gtk_label_new ( _("Lower right latitude:") );
900 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 );
901 GtkWidget *lon_br_label = gtk_label_new ( _("Lower right longitude:") );
902 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 );
904 gtk_table_attach_defaults ( GTK_TABLE(table_ll), lat_tl_label, 0, 1, 0, 1 );
905 gtk_table_attach_defaults ( GTK_TABLE(table_ll), cw.lat_tl_spin, 1, 2, 0, 1 );
906 gtk_table_attach_defaults ( GTK_TABLE(table_ll), lon_tl_label, 0, 1, 1, 2 );
907 gtk_table_attach_defaults ( GTK_TABLE(table_ll), cw.lon_tl_spin, 1, 2, 1, 2 );
908 gtk_table_attach_defaults ( GTK_TABLE(table_ll), lat_br_label, 0, 1, 2, 3 );
909 gtk_table_attach_defaults ( GTK_TABLE(table_ll), cw.lat_br_spin, 1, 2, 2, 3 );
910 gtk_table_attach_defaults ( GTK_TABLE(table_ll), lon_br_label, 0, 1, 3, 4 );
911 gtk_table_attach_defaults ( GTK_TABLE(table_ll), cw.lon_br_spin, 1, 2, 3, 4 );
913 GtkWidget *calc_mpp_button = gtk_button_new_with_label ( _("Calculate MPP values from coordinates") );
914 gtk_widget_set_tooltip_text ( calc_mpp_button, _("Enter all corner coordinates before calculating the MPP values from the image size") );
915 gtk_table_attach_defaults ( GTK_TABLE(table_ll), calc_mpp_button, 0, 2, 4, 5 );
918 vik_coord_load_from_utm (&vc, VIK_COORD_LATLON, &(vgl->corner));
919 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.lat_tl_spin), vc.north_south );
920 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.lon_tl_spin), vc.east_west );
921 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.lat_br_spin), vgl->ll_br.lat );
922 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.lon_br_spin), vgl->ll_br.lon );
924 gtk_notebook_append_page(GTK_NOTEBOOK(cw.tabs), GTK_WIDGET(table_utm), gtk_label_new(_("UTM")));
925 gtk_notebook_append_page(GTK_NOTEBOOK(cw.tabs), GTK_WIDGET(table_ll), gtk_label_new(_("Latitude/Longitude")));
926 gtk_box_pack_start ( dgbox, cw.tabs, TRUE, TRUE, 0 );
928 GtkWidget *alpha_hbox = gtk_hbox_new ( FALSE, 0 );
929 // GTK3 => GtkWidget *alpha_scale = gtk_scale_new_with_range ( GTK_ORIENTATION_HORIZONTAL, 0, 255, 1 );
930 GtkWidget *alpha_scale = gtk_hscale_new_with_range ( 0, 255, 1 );
931 gtk_scale_set_digits ( GTK_SCALE(alpha_scale), 0 );
932 gtk_range_set_value ( GTK_RANGE(alpha_scale), vgl->alpha );
933 gtk_box_pack_start ( GTK_BOX(alpha_hbox), gtk_label_new(_("Alpha:")), TRUE, TRUE, 0 );
934 gtk_box_pack_start ( GTK_BOX(alpha_hbox), alpha_scale, TRUE, TRUE, 0 );
935 gtk_box_pack_start ( dgbox, alpha_hbox, TRUE, TRUE, 0 );
939 g_signal_connect ( G_OBJECT(vgl->cw.tabs), "switch-page", G_CALLBACK(switch_tab), vgl );
940 g_signal_connect ( G_OBJECT(calc_mpp_button), "clicked", G_CALLBACK(calculate_mpp_from_coords), vgl );
942 g_signal_connect_swapped ( G_OBJECT(wfp_button), "clicked", G_CALLBACK(georef_layer_dialog_load), &cw );
945 gtk_widget_grab_focus ( response_w );
947 gtk_widget_show_all ( dialog );
949 // Remember setting the notebook page must be done after the widget is visible.
951 if ( a_settings_get_integer ( VIK_SETTINGS_GEOREF_TAB, &page_num ) )
952 if ( page_num < 0 || page_num > 1 )
954 gtk_notebook_set_current_page ( GTK_NOTEBOOK(cw.tabs), page_num );
956 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
958 align_coords ( vgl );
960 vgl->corner.easting = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cw.ce_spin) );
961 vgl->corner.northing = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cw.cn_spin) );
962 vgl->corner.zone = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(cw.utm_zone_spin) );
963 const gchar *letter = gtk_entry_get_text ( GTK_ENTRY(cw.utm_letter_entry) );
965 vgl->corner.letter = toupper(*letter);
966 vgl->mpp_easting = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cw.x_spin) );
967 vgl->mpp_northing = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cw.y_spin) );
968 vgl->ll_br = get_ll_br (vgl);
969 check_br_is_good_or_msg_user ( vgl );
970 // TODO check if image has changed otherwise no need to regenerate pixbuf
973 if ( g_strcmp0 (vgl->image, vik_file_entry_get_filename(VIK_FILE_ENTRY(cw.imageentry)) ) != 0 )
975 georef_layer_set_image ( vgl, vik_file_entry_get_filename(VIK_FILE_ENTRY(cw.imageentry)) );
976 georef_layer_load_image ( vgl, VIK_VIEWPORT(vp), FALSE );
980 vgl->alpha = (guint8) gtk_range_get_value ( GTK_RANGE(alpha_scale) );
981 if ( vgl->pixbuf && vgl->alpha < 255 )
982 vgl->pixbuf = ui_pixbuf_set_alpha ( vgl->pixbuf, vgl->alpha );
983 if ( vgl->scaled && vgl->alpha < 255 )
984 vgl->scaled = ui_pixbuf_set_alpha ( vgl->scaled, vgl->alpha );
986 a_settings_set_integer ( VIK_SETTINGS_GEOREF_TAB, gtk_notebook_get_current_page(GTK_NOTEBOOK(cw.tabs)) );
988 gtk_widget_destroy ( GTK_WIDGET(dialog) );
991 gtk_widget_destroy ( GTK_WIDGET(dialog) );
995 static void georef_layer_zoom_to_fit ( gpointer vgl_vlp[2] )
997 vik_viewport_set_xmpp ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1])), VIK_GEOREF_LAYER(vgl_vlp[0])->mpp_easting );
998 vik_viewport_set_ympp ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1])), VIK_GEOREF_LAYER(vgl_vlp[0])->mpp_northing );
999 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vgl_vlp[1]) );
1002 static void georef_layer_goto_center ( gpointer vgl_vlp[2] )
1004 VikGeorefLayer *vgl = VIK_GEOREF_LAYER ( vgl_vlp[0] );
1005 VikViewport *vp = vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1]));
1009 vik_coord_to_utm ( vik_viewport_get_center ( vp ), &utm );
1011 utm.easting = vgl->corner.easting + (vgl->width * vgl->mpp_easting / 2); /* only an approximation */
1012 utm.northing = vgl->corner.northing - (vgl->height * vgl->mpp_northing / 2);
1014 vik_coord_load_from_utm ( &coord, vik_viewport_get_coord_mode ( vp ), &utm );
1015 vik_viewport_set_center_coord ( vp, &coord, TRUE );
1017 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vgl_vlp[1]) );
1020 static void georef_layer_add_menu_items ( VikGeorefLayer *vgl, GtkMenu *menu, gpointer vlp )
1022 static gpointer pass_along[2];
1024 pass_along[0] = vgl;
1025 pass_along[1] = vlp;
1027 item = gtk_menu_item_new();
1028 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1029 gtk_widget_show ( item );
1031 /* Now with icons */
1032 item = gtk_image_menu_item_new_with_mnemonic ( _("_Zoom to Fit Map") );
1033 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
1034 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_zoom_to_fit), pass_along );
1035 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1036 gtk_widget_show ( item );
1038 item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto Map Center") );
1039 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
1040 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_goto_center), pass_along );
1041 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1042 gtk_widget_show ( item );
1044 item = gtk_image_menu_item_new_with_mnemonic ( _("_Export to World File") );
1045 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_HARDDISK, GTK_ICON_SIZE_MENU) );
1046 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_export_params), pass_along );
1047 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1048 gtk_widget_show ( item );
1052 static gpointer georef_layer_move_create ( VikWindow *vw, VikViewport *vvp)
1057 static gboolean georef_layer_move_release ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
1059 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
1062 if ( vgl->click_x != -1 )
1064 vgl->corner.easting += (event->x - vgl->click_x) * vik_viewport_get_xmpp (vvp);
1065 vgl->corner.northing -= (event->y - vgl->click_y) * vik_viewport_get_ympp (vvp);
1066 vik_layer_emit_update ( VIK_LAYER(vgl) );
1069 return FALSE; /* I didn't move anything on this layer! */
1072 static gpointer georef_layer_zoom_create ( VikWindow *vw, VikViewport *vvp)
1077 static gboolean georef_layer_zoom_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
1079 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
1081 if ( event->button == 1 )
1083 if ( vgl->mpp_easting < (VIK_VIEWPORT_MAX_ZOOM / 1.05) && vgl->mpp_northing < (VIK_VIEWPORT_MAX_ZOOM / 1.05) )
1085 vgl->mpp_easting *= 1.01;
1086 vgl->mpp_northing *= 1.01;
1091 if ( vgl->mpp_easting > (VIK_VIEWPORT_MIN_ZOOM * 1.05) && vgl->mpp_northing > (VIK_VIEWPORT_MIN_ZOOM * 1.05) )
1093 vgl->mpp_easting /= 1.01;
1094 vgl->mpp_northing /= 1.01;
1097 vik_viewport_set_xmpp ( vvp, vgl->mpp_easting );
1098 vik_viewport_set_ympp ( vvp, vgl->mpp_northing );
1099 vik_layer_emit_update ( VIK_LAYER(vgl) );
1103 static gboolean georef_layer_move_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
1105 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
1107 vgl->click_x = event->x;
1108 vgl->click_y = event->y;
1112 static void goto_center_ll ( VikViewport *vp,
1113 struct LatLon ll_tl,
1114 struct LatLon ll_br )
1117 struct LatLon ll_center;
1119 ll_center.lat = (ll_tl.lat + ll_br.lat) / 2.0;
1120 ll_center.lon = (ll_tl.lon + ll_br.lon) / 2.0;
1122 vik_coord_load_from_latlon ( &vc_center, vik_viewport_get_coord_mode (vp), &ll_center );
1123 vik_viewport_set_center_coord ( vp, &vc_center, TRUE );
1129 VikGeorefLayer *vik_georef_layer_create ( VikViewport *vp,
1130 VikLayersPanel *vlp,
1134 VikCoord *coord_br )
1136 VikGeorefLayer *vgl = georef_layer_new ( vp );
1137 vik_layer_rename ( VIK_LAYER(vgl), name );
1139 vgl->pixbuf = pixbuf;
1141 vik_coord_to_utm ( coord_tl, &(vgl->corner) );
1142 vik_coord_to_latlon ( coord_br, &(vgl->ll_br) );
1144 if ( vgl->pixbuf ) {
1145 vgl->width = gdk_pixbuf_get_width ( vgl->pixbuf );
1146 vgl->height = gdk_pixbuf_get_height ( vgl->pixbuf );
1148 if ( vgl->width > 0 && vgl->height > 0 ) {
1150 struct LatLon ll_tl;
1151 vik_coord_to_latlon ( coord_tl, &ll_tl);
1152 struct LatLon ll_br;
1153 vik_coord_to_latlon ( coord_br, &ll_br);
1155 VikCoordMode mode = vik_viewport_get_coord_mode (vp);
1158 georef_layer_mpp_from_coords ( mode, ll_tl, ll_br, vgl->width, vgl->height, &xmpp, &ympp );
1159 vgl->mpp_easting = xmpp;
1160 vgl->mpp_northing = ympp;
1162 goto_center_ll ( vp, ll_tl, ll_br);
1163 // Set best zoom level
1164 struct LatLon maxmin[2] = { ll_tl, ll_br };
1165 vu_zoom_to_show_latlons ( vik_viewport_get_coord_mode(vp), vp, maxmin );
1172 georef_layer_free ( vgl );