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
29 #include <glib/gstdio.h>
30 #include <glib/gi18n.h>
37 #include "preferences.h"
38 #include "icons/icons.h"
39 #include "vikmapslayer.h"
42 static VikLayerParamData image_default ( void )
44 VikLayerParamData data;
45 data.s = g_strdup ("");
50 VikLayerParam georef_layer_params[] = {
51 { VIK_LAYER_GEOREF, "image", VIK_LAYER_PARAM_STRING, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
52 { VIK_LAYER_GEOREF, "corner_easting", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
53 { VIK_LAYER_GEOREF, "corner_northing", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
54 { VIK_LAYER_GEOREF, "mpp_easting", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
55 { VIK_LAYER_GEOREF, "mpp_northing", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
56 { VIK_LAYER_GEOREF, "corner_zone", VIK_LAYER_PARAM_UINT, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
57 { VIK_LAYER_GEOREF, "corner_letter_as_int", VIK_LAYER_PARAM_UINT, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
58 { VIK_LAYER_GEOREF, "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
72 static const gchar* georef_layer_tooltip ( VikGeorefLayer *vgl );
73 static void georef_layer_marshall( VikGeorefLayer *vgl, guint8 **data, gint *len );
74 static VikGeorefLayer *georef_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
75 static gboolean georef_layer_set_param ( VikGeorefLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
76 static VikLayerParamData georef_layer_get_param ( VikGeorefLayer *vgl, guint16 id, gboolean is_file_operation );
77 static VikGeorefLayer *georef_layer_new ( VikViewport *vvp );
78 static VikGeorefLayer *georef_layer_create ( VikViewport *vp );
79 static void georef_layer_free ( VikGeorefLayer *vgl );
80 static gboolean georef_layer_properties ( VikGeorefLayer *vgl, gpointer vp );
81 static void georef_layer_draw ( VikGeorefLayer *vgl, VikViewport *vp );
82 static void georef_layer_add_menu_items ( VikGeorefLayer *vgl, GtkMenu *menu, gpointer vlp );
83 static void georef_layer_set_image ( VikGeorefLayer *vgl, const gchar *image );
84 static gboolean georef_layer_dialog ( VikGeorefLayer *vgl, gpointer vp, GtkWindow *w );
85 static void georef_layer_load_image ( VikGeorefLayer *vgl, VikViewport *vp, gboolean from_file );
88 static gpointer georef_layer_move_create ( VikWindow *vw, VikViewport *vvp);
89 static gboolean georef_layer_move_release ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
90 static gboolean georef_layer_move_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
91 static gpointer georef_layer_zoom_create ( VikWindow *vw, VikViewport *vvp);
92 static gboolean georef_layer_zoom_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
94 // See comment in viktrwlayer.c for advice on values used
95 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 { &geozoom_18_pixbuf,
105 { "GeorefZoomTool", "vik-icon-Georef Zoom Tool", N_("Georef Z_oom Tool"), NULL, N_("Georef Zoom Tool"), 0 },
106 (VikToolConstructorFunc) georef_layer_zoom_create, NULL, NULL, NULL,
107 (VikToolMouseFunc) georef_layer_zoom_press, NULL, NULL,
108 (VikToolKeyFunc) NULL,
110 GDK_CURSOR_IS_PIXMAP, &cursor_geozoom_pixbuf, NULL },
113 VikLayerInterface vik_georef_layer_interface = {
117 &vikgeoreflayer_pixbuf, /*icon */
120 sizeof(georef_tools) / sizeof(VikToolInterface),
129 (VikLayerFuncCreate) georef_layer_create,
130 (VikLayerFuncRealize) NULL,
131 (VikLayerFuncPostRead) georef_layer_load_image,
132 (VikLayerFuncFree) georef_layer_free,
134 (VikLayerFuncProperties) georef_layer_properties,
135 (VikLayerFuncDraw) georef_layer_draw,
136 (VikLayerFuncChangeCoordMode) NULL,
138 (VikLayerFuncGetTimestamp) NULL,
140 (VikLayerFuncSetMenuItemsSelection) NULL,
141 (VikLayerFuncGetMenuItemsSelection) NULL,
143 (VikLayerFuncAddMenuItems) georef_layer_add_menu_items,
144 (VikLayerFuncSublayerAddMenuItems) NULL,
146 (VikLayerFuncSublayerRenameRequest) NULL,
147 (VikLayerFuncSublayerToggleVisible) NULL,
148 (VikLayerFuncSublayerTooltip) NULL,
149 (VikLayerFuncLayerTooltip) georef_layer_tooltip,
150 (VikLayerFuncLayerSelected) NULL,
152 (VikLayerFuncMarshall) georef_layer_marshall,
153 (VikLayerFuncUnmarshall) georef_layer_unmarshall,
155 (VikLayerFuncSetParam) georef_layer_set_param,
156 (VikLayerFuncGetParam) georef_layer_get_param,
157 (VikLayerFuncChangeParam) NULL,
159 (VikLayerFuncReadFileData) NULL,
160 (VikLayerFuncWriteFileData) NULL,
162 (VikLayerFuncDeleteItem) NULL,
163 (VikLayerFuncCutItem) NULL,
164 (VikLayerFuncCopyItem) NULL,
165 (VikLayerFuncPasteItem) NULL,
166 (VikLayerFuncFreeCopiedItem) NULL,
167 (VikLayerFuncDragDropRequest) NULL,
169 (VikLayerFuncSelectClick) NULL,
170 (VikLayerFuncSelectMove) NULL,
171 (VikLayerFuncSelectRelease) NULL,
172 (VikLayerFuncSelectedViewportMenu) NULL,
179 GtkWidget *ce_spin; // top left
180 GtkWidget *cn_spin; // "
181 GtkWidget *utm_zone_spin;
182 GtkWidget *utm_letter_entry;
184 GtkWidget *lat_tl_spin;
185 GtkWidget *lon_tl_spin;
186 GtkWidget *lat_br_spin;
187 GtkWidget *lon_br_spin;
190 GtkWidget *imageentry;
191 } changeable_widgets;
193 struct _VikGeorefLayer {
199 struct UTM corner; // Top Left
200 gdouble mpp_easting, mpp_northing;
201 struct LatLon ll_br; // Bottom Right
205 guint32 scaled_width, scaled_height;
207 gint click_x, click_y;
208 changeable_widgets cw;
211 static VikLayerParam io_prefs[] = {
212 { 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,
213 N_("Automatically attempt to read associated world file of a new image for a GeoRef layer"), NULL, NULL, NULL}
216 void vik_georef_layer_init (void)
218 VikLayerParamData tmp;
220 a_preferences_register(&io_prefs[0], tmp, VIKING_PREFERENCES_IO_GROUP_KEY);
223 GType vik_georef_layer_get_type ()
225 static GType vgl_type = 0;
229 static const GTypeInfo vgl_info =
231 sizeof (VikGeorefLayerClass),
232 NULL, /* base_init */
233 NULL, /* base_finalize */
234 NULL, /* class init */
235 NULL, /* class_finalize */
236 NULL, /* class_data */
237 sizeof (VikGeorefLayer),
239 NULL /* instance init */
241 vgl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikGeorefLayer", &vgl_info, 0 );
247 static const gchar* georef_layer_tooltip ( VikGeorefLayer *vgl )
252 static void georef_layer_marshall( VikGeorefLayer *vgl, guint8 **data, gint *len )
254 vik_layer_marshall_params ( VIK_LAYER(vgl), data, len );
257 static VikGeorefLayer *georef_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
259 VikGeorefLayer *rv = georef_layer_new ( vvp );
260 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
262 georef_layer_load_image ( rv, vvp, TRUE );
267 static gboolean georef_layer_set_param ( VikGeorefLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
271 case PARAM_IMAGE: georef_layer_set_image ( vgl, data.s ); break;
272 case PARAM_CN: vgl->corner.northing = data.d; break;
273 case PARAM_CE: vgl->corner.easting = data.d; break;
274 case PARAM_MN: vgl->mpp_northing = data.d; break;
275 case PARAM_ME: vgl->mpp_easting = data.d; break;
276 case PARAM_CZ: if ( data.u <= 60 ) vgl->corner.zone = data.u; break;
277 case PARAM_CL: if ( data.u >= 65 || data.u <= 90 ) vgl->corner.letter = data.u; break;
278 case PARAM_AA: if ( data.u <= 255 ) vgl->alpha = data.u; break;
284 static void create_image_file ( VikGeorefLayer *vgl )
286 // Create in .viking-maps
287 gchar *filename = g_strconcat ( maps_layer_default_dir(), vik_layer_get_name(VIK_LAYER(vgl)), ".jpg", NULL );
288 GError *error = NULL;
289 gdk_pixbuf_save ( vgl->pixbuf, filename, "jpeg", &error, NULL );
291 g_warning ( "%s", error->message );
292 g_error_free ( error );
295 vgl->image = g_strdup ( filename );
300 static VikLayerParamData georef_layer_get_param ( VikGeorefLayer *vgl, guint16 id, gboolean is_file_operation )
302 VikLayerParamData rv;
306 gboolean set = FALSE;
307 if ( is_file_operation ) {
308 if ( vgl->pixbuf && !vgl->image ) {
309 // Force creation of image file
310 create_image_file ( vgl );
312 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
313 gchar *cwd = g_get_current_dir();
315 rv.s = file_GetRelativeFilename ( cwd, vgl->image );
316 if ( !rv.s ) rv.s = "";
322 rv.s = vgl->image ? vgl->image : "";
325 case PARAM_CN: rv.d = vgl->corner.northing; break;
326 case PARAM_CE: rv.d = vgl->corner.easting; break;
327 case PARAM_MN: rv.d = vgl->mpp_northing; break;
328 case PARAM_ME: rv.d = vgl->mpp_easting; break;
329 case PARAM_CZ: rv.u = vgl->corner.zone; break;
330 case PARAM_CL: rv.u = vgl->corner.letter; break;
331 case PARAM_AA: rv.u = vgl->alpha; break;
337 static VikGeorefLayer *georef_layer_new ( VikViewport *vvp )
339 VikGeorefLayer *vgl = VIK_GEOREF_LAYER ( g_object_new ( VIK_GEOREF_LAYER_TYPE, NULL ) );
340 vik_layer_set_type ( VIK_LAYER(vgl), VIK_LAYER_GEOREF );
342 // Since GeoRef layer doesn't use uibuilder
343 // initializing this way won't do anything yet..
344 vik_layer_set_defaults ( VIK_LAYER(vgl), vvp );
346 // Make these defaults based on the current view
347 vgl->mpp_northing = vik_viewport_get_ympp ( vvp );
348 vgl->mpp_easting = vik_viewport_get_xmpp ( vvp );
349 vik_coord_to_utm ( vik_viewport_get_center ( vvp ), &(vgl->corner) );
356 vgl->scaled_width = 0;
357 vgl->scaled_height = 0;
358 vgl->ll_br.lat = 0.0;
359 vgl->ll_br.lon = 0.0;
365 * Return mpp for the given coords, coord mode and image size.
367 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 )
370 ll_tr.lat = ll_tl.lat;
371 ll_tr.lon = ll_br.lon;
374 ll_bl.lat = ll_br.lat;
375 ll_bl.lon = ll_tl.lon;
377 // UTM mode should be exact MPP
378 gdouble factor = 1.0;
379 if ( mode == VIK_COORD_LATLON ) {
380 // NB the 1.193 - is at the Equator.
381 // http://wiki.openstreetmap.org/wiki/Zoom_levels
383 // Convert from actual image MPP to Viking 'pixelfact'
384 gdouble mid_lat = (ll_bl.lat + ll_tr.lat ) / 2.0;
385 // Protect against div by zero (but shouldn't have 90 degrees for mid latitude...)
386 if ( fabs(mid_lat) < 89.9 )
387 factor = cos(DEG2RAD(mid_lat)) * 1.193;
390 gdouble diffx = a_coords_latlon_diff ( &ll_tl, &ll_tr );
391 *xmpp = (diffx / width) / factor;
393 gdouble diffy = a_coords_latlon_diff ( &ll_tl, &ll_bl );
394 *ympp = (diffy / height) / factor;
397 static void georef_layer_draw ( VikGeorefLayer *vgl, VikViewport *vp )
401 gdouble xmpp = vik_viewport_get_xmpp(vp), ympp = vik_viewport_get_ympp(vp);
402 GdkPixbuf *pixbuf = vgl->pixbuf;
403 guint layer_width = vgl->width;
404 guint layer_height = vgl->height;
406 guint width = vik_viewport_get_width(vp), height = vik_viewport_get_height(vp);
408 VikCoord corner_coord;
409 vik_coord_load_from_utm ( &corner_coord, vik_viewport_get_coord_mode(vp), &(vgl->corner) );
410 vik_viewport_coord_to_screen ( vp, &corner_coord, &x, &y );
412 /* mark to scale the pixbuf if it doesn't match our dimensions */
413 gboolean scale = FALSE;
414 if ( xmpp != vgl->mpp_easting || ympp != vgl->mpp_northing )
417 layer_width = round(vgl->width * vgl->mpp_easting / xmpp);
418 layer_height = round(vgl->height * vgl->mpp_northing / ympp);
421 // If image not in viewport bounds - no need to draw it (or bother with any scaling)
422 if ( (x < 0 || x < width) && (y < 0 || y < height) && x+layer_width > 0 && y+layer_height > 0 ) {
426 /* rescale if necessary */
427 if (layer_width == vgl->scaled_width && layer_height == vgl->scaled_height && vgl->scaled != NULL)
428 pixbuf = vgl->scaled;
431 pixbuf = gdk_pixbuf_scale_simple(
438 if (vgl->scaled != NULL)
439 g_object_unref(vgl->scaled);
441 vgl->scaled = pixbuf;
442 vgl->scaled_width = layer_width;
443 vgl->scaled_height = layer_height;
446 vik_viewport_draw_pixbuf ( vp, pixbuf, 0, 0, x, y, layer_width, layer_height ); /* todo: draw only what we need to. */
451 static void georef_layer_free ( VikGeorefLayer *vgl )
453 if ( vgl->image != NULL )
454 g_free ( vgl->image );
455 if ( vgl->scaled != NULL )
456 g_object_unref ( vgl->scaled );
459 static VikGeorefLayer *georef_layer_create ( VikViewport *vp )
461 return georef_layer_new ( vp );
464 static gboolean georef_layer_properties ( VikGeorefLayer *vgl, gpointer vp )
466 return georef_layer_dialog ( vgl, vp, VIK_GTK_WINDOW_FROM_WIDGET(vp) );
469 static void georef_layer_load_image ( VikGeorefLayer *vgl, VikViewport *vp, gboolean from_file )
472 if ( vgl->image == NULL )
476 g_object_unref ( G_OBJECT(vgl->pixbuf) );
479 g_object_unref ( G_OBJECT(vgl->scaled) );
483 vgl->pixbuf = gdk_pixbuf_new_from_file ( vgl->image, &gx );
488 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(vp), _("Couldn't open image file: %s"), gx->message );
493 vgl->width = gdk_pixbuf_get_width ( vgl->pixbuf );
494 vgl->height = gdk_pixbuf_get_height ( vgl->pixbuf );
496 if ( vgl->pixbuf && vgl->alpha <= 255 )
497 vgl->pixbuf = ui_pixbuf_set_alpha ( vgl->pixbuf, vgl->alpha );
499 /* should find length and width here too */
502 static void georef_layer_set_image ( VikGeorefLayer *vgl, const gchar *image )
505 g_free ( vgl->image );
508 g_object_unref ( vgl->scaled );
514 if ( g_strcmp0 (image, "") != 0 )
515 vgl->image = vu_get_canonical_filename ( VIK_LAYER(vgl), image );
517 vgl->image = g_strdup (image);
520 // Only positive values allowed here
521 static void gdouble2spinwidget ( GtkWidget *widget, gdouble val )
523 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(widget), val > 0 ? val : -val );
526 static void set_widget_values ( changeable_widgets *cw, gdouble values[4] )
528 gdouble2spinwidget ( cw->x_spin, values[0] );
529 gdouble2spinwidget ( cw->y_spin, values[1] );
530 gdouble2spinwidget ( cw->ce_spin, values[2] );
531 gdouble2spinwidget ( cw->cn_spin, values[3] );
534 static gboolean world_file_read_line ( FILE *ff, gdouble *value, gboolean use_value )
536 gboolean answer = TRUE; // Success
538 if ( !fgets ( buffer, 1024, ff ) ) {
541 if ( answer && use_value )
542 *value = g_strtod ( buffer, NULL );
548 * http://en.wikipedia.org/wiki/World_file
550 * Note world files do not define the units and nor are the units standardized :(
551 * Currently Viking only supports:
552 * x&y scale as meters per pixel
553 * x&y coords as UTM eastings and northings respectively
555 static gint world_file_read_file ( const gchar* filename, gdouble values[4] )
557 g_debug ("%s - trying world file %s", __FUNCTION__, filename);
559 FILE *f = g_fopen ( filename, "r" );
563 gint answer = 2; // Not enough info read yet
564 // **We do not handle 'skew' values ATM - normally they are a value of 0 anyway to align with the UTM grid
565 if ( world_file_read_line ( f, &values[0], TRUE ) // x scale
566 && world_file_read_line ( f, NULL, FALSE ) // Ignore value in y-skew line**
567 && world_file_read_line ( f, NULL, FALSE ) // Ignore value in x-skew line**
568 && world_file_read_line ( f, &values[1], TRUE ) // y scale
569 && world_file_read_line ( f, &values[2], TRUE ) // x-coordinate of the upper left pixel
570 && world_file_read_line ( f, &values[3], TRUE ) // y-coordinate of the upper left pixel
574 g_debug ("%s - %s - world file read success", __FUNCTION__, filename);
582 static void georef_layer_dialog_load ( changeable_widgets *cw )
584 GtkWidget *file_selector = gtk_file_chooser_dialog_new (_("Choose World file"),
586 GTK_FILE_CHOOSER_ACTION_OPEN,
587 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
588 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
591 if ( gtk_dialog_run ( GTK_DIALOG ( file_selector ) ) == GTK_RESPONSE_ACCEPT )
594 gint answer = world_file_read_file ( gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_selector)), values );
596 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(cw->x_spin), _("The World file you requested could not be opened for reading.") );
597 else if ( answer == 2 )
598 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(cw->x_spin), _("Unexpected end of file reading World file.") );
600 // NB answer should == 0 for success
601 set_widget_values ( cw, values );
604 gtk_widget_destroy ( file_selector );
607 static void georef_layer_export_params ( gpointer *pass_along[2] )
609 VikGeorefLayer *vgl = VIK_GEOREF_LAYER(pass_along[0]);
610 GtkWidget *file_selector = gtk_file_chooser_dialog_new (_("Choose World file"),
612 GTK_FILE_CHOOSER_ACTION_SAVE,
613 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
614 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
616 if ( gtk_dialog_run ( GTK_DIALOG ( file_selector ) ) == GTK_RESPONSE_ACCEPT )
618 FILE *f = g_fopen ( gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER(file_selector) ), "w" );
620 gtk_widget_destroy ( file_selector );
623 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(pass_along[0]), _("The file you requested could not be opened for writing.") );
628 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 );
634 gtk_widget_destroy ( file_selector );
638 * Auto attempt to read the world file associated with the image used for the georef
639 * Based on simple file name conventions
640 * Only attempted if the preference is on.
642 static void maybe_read_world_file ( VikFileEntry *vfe, gpointer user_data )
644 if ( a_preferences_get (VIKING_PREFERENCES_IO_NAMESPACE "georef_auto_read_world_file")->b ) {
645 const gchar* filename = vik_file_entry_get_filename(VIK_FILE_ENTRY(vfe));
647 if ( filename && user_data ) {
649 changeable_widgets *cw = user_data;
651 gboolean upper = g_ascii_isupper (filename[strlen(filename)-1]);
652 gchar* filew = g_strconcat ( filename, (upper ? "W" : "w") , NULL );
654 if ( world_file_read_file ( filew, values ) == 0 ) {
655 set_widget_values ( cw, values );
658 if ( strlen(filename) > 3 ) {
659 gchar* file0 = g_strndup ( filename, strlen(filename)-2 );
660 gchar* file1 = g_strdup_printf ( "%s%c%c", file0, filename[strlen(filename)-1], (upper ? 'W' : 'w') );
661 if ( world_file_read_file ( file1, values ) == 0 ) {
662 set_widget_values ( cw, values );
673 static struct LatLon get_ll_tl (VikGeorefLayer *vgl)
676 ll_tl.lat = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.lat_tl_spin) );
677 ll_tl.lon = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.lon_tl_spin) );
681 static struct LatLon get_ll_br (VikGeorefLayer *vgl)
684 ll_br.lat = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.lat_br_spin) );
685 ll_br.lon = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.lon_br_spin) );
689 // Align displayed UTM values with displayed Lat/Lon values
690 static void align_utm2ll (VikGeorefLayer *vgl)
692 struct LatLon ll_tl = get_ll_tl (vgl);
695 a_coords_latlon_to_utm ( &ll_tl, &utm );
696 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.ce_spin), utm.easting );
697 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.cn_spin), utm.northing );
700 tmp_letter[0] = utm.letter;
701 tmp_letter[1] = '\0';
702 gtk_entry_set_text ( GTK_ENTRY(vgl->cw.utm_letter_entry), tmp_letter );
704 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.utm_zone_spin), utm.zone );
707 // Align displayed Lat/Lon values with displayed UTM values
708 static void align_ll2utm (VikGeorefLayer *vgl)
711 const gchar *letter = gtk_entry_get_text ( GTK_ENTRY(vgl->cw.utm_letter_entry) );
713 corner.letter = toupper(*letter);
714 corner.zone = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(vgl->cw.utm_zone_spin) );
715 corner.easting = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.ce_spin) );
716 corner.northing = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.cn_spin) );
719 a_coords_utm_to_latlon ( &corner, &ll );
720 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.lat_tl_spin), ll.lat );
721 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.lon_tl_spin), ll.lon );
725 * Align coordinates between tabs as the user may have changed the values
726 * Use this before acting on the user input
727 * This is easier then trying to use the 'value-changed' signal for each individual coordinate
728 * especiallly since it tends to end up in an infinite loop continually updating each other.
730 static void align_coords ( VikGeorefLayer *vgl )
732 if (gtk_notebook_get_current_page(GTK_NOTEBOOK(vgl->cw.tabs)) == 0)
733 align_ll2utm ( vgl );
735 align_utm2ll ( vgl );
738 static void switch_tab (GtkNotebook *notebook, gpointer tab, guint tab_num, gpointer user_data)
740 VikGeorefLayer *vgl = user_data;
750 static void check_br_is_good_or_msg_user ( VikGeorefLayer *vgl )
752 // if a 'blank' ll value that's alright
753 if ( vgl->ll_br.lat == 0.0 && vgl->ll_br.lon == 0.0 )
756 struct LatLon ll_tl = get_ll_tl (vgl);
757 if ( ll_tl.lat < vgl->ll_br.lat || ll_tl.lon > vgl->ll_br.lon )
758 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vgl), _("Lower right corner values may not be consistent with upper right values") );
764 static void calculate_mpp_from_coords ( GtkWidget *ww, VikGeorefLayer *vgl )
766 const gchar* filename = vik_file_entry_get_filename(VIK_FILE_ENTRY(vgl->cw.imageentry));
771 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( filename, &gx );
773 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(ww), _("Couldn't open image file: %s"), gx->message );
778 guint width = gdk_pixbuf_get_width ( pixbuf );
779 guint height = gdk_pixbuf_get_height ( pixbuf );
781 if ( width == 0 || height == 0 ) {
782 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(ww), _("Invalid image size: %s"), filename);
785 align_coords ( vgl );
787 struct LatLon ll_tl = get_ll_tl (vgl);
788 struct LatLon ll_br = get_ll_br (vgl);
791 georef_layer_mpp_from_coords ( VIK_COORD_LATLON, ll_tl, ll_br, width, height, &xmpp, &ympp );
793 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.x_spin), xmpp );
794 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.y_spin), ympp );
796 check_br_is_good_or_msg_user ( vgl );
799 g_object_unref ( G_OBJECT(pixbuf) );
802 #define VIK_SETTINGS_GEOREF_TAB "georef_coordinate_tab"
804 /* returns TRUE if OK was pressed. */
805 static gboolean georef_layer_dialog ( VikGeorefLayer *vgl, gpointer vp, GtkWindow *w )
807 GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Layer Properties"),
809 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
815 /* Default to reject as user really needs to specify map file first */
816 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_REJECT );
817 GtkWidget *response_w = NULL;
818 #if GTK_CHECK_VERSION (2, 20, 0)
819 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_REJECT );
821 GtkWidget *table, *wfp_hbox, *wfp_label, *wfp_button, *ce_label, *cn_label, *xlabel, *ylabel, *imagelabel;
822 changeable_widgets cw;
824 GtkBox *dgbox = GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog)));
825 table = gtk_table_new ( 4, 2, FALSE );
826 gtk_box_pack_start ( dgbox, table, TRUE, TRUE, 0 );
828 wfp_hbox = gtk_hbox_new ( FALSE, 0 );
829 wfp_label = gtk_label_new ( _("World File Parameters:") );
830 wfp_button = gtk_button_new_with_label ( _("Load From File...") );
832 gtk_box_pack_start ( GTK_BOX(wfp_hbox), wfp_label, TRUE, TRUE, 0 );
833 gtk_box_pack_start ( GTK_BOX(wfp_hbox), wfp_button, FALSE, FALSE, 3 );
835 ce_label = gtk_label_new ( _("Corner pixel easting:") );
836 cw.ce_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, 0.0, 1500000.0, 1, 5, 0 ), 1, 4 );
837 gtk_widget_set_tooltip_text ( GTK_WIDGET(cw.ce_spin), _("the UTM \"easting\" value of the upper-left corner pixel of the map") );
839 cn_label = gtk_label_new ( _("Corner pixel northing:") );
840 cw.cn_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, 0.0, 9000000.0, 1, 5, 0 ), 1, 4 );
841 gtk_widget_set_tooltip_text ( GTK_WIDGET(cw.cn_spin), _("the UTM \"northing\" value of the upper-left corner pixel of the map") );
843 xlabel = gtk_label_new ( _("X (easting) scale (mpp): "));
844 ylabel = gtk_label_new ( _("Y (northing) scale (mpp): "));
846 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 );
847 gtk_widget_set_tooltip_text ( GTK_WIDGET(cw.x_spin), _("the scale of the map in the X direction (meters per pixel)") );
848 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 );
849 gtk_widget_set_tooltip_text ( GTK_WIDGET(cw.y_spin), _("the scale of the map in the Y direction (meters per pixel)") );
851 imagelabel = gtk_label_new ( _("Map Image:") );
852 cw.imageentry = vik_file_entry_new (GTK_FILE_CHOOSER_ACTION_OPEN, VF_FILTER_IMAGE, maybe_read_world_file, &cw);
854 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.ce_spin), vgl->corner.easting );
855 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.cn_spin), vgl->corner.northing );
856 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.x_spin), vgl->mpp_easting );
857 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.y_spin), vgl->mpp_northing );
859 vik_file_entry_set_filename ( VIK_FILE_ENTRY(cw.imageentry), vgl->image );
861 gtk_table_attach_defaults ( GTK_TABLE(table), imagelabel, 0, 1, 0, 1 );
862 gtk_table_attach_defaults ( GTK_TABLE(table), cw.imageentry, 1, 2, 0, 1 );
863 gtk_table_attach_defaults ( GTK_TABLE(table), wfp_hbox, 0, 2, 1, 2 );
864 gtk_table_attach_defaults ( GTK_TABLE(table), xlabel, 0, 1, 2, 3 );
865 gtk_table_attach_defaults ( GTK_TABLE(table), cw.x_spin, 1, 2, 2, 3 );
866 gtk_table_attach_defaults ( GTK_TABLE(table), ylabel, 0, 1, 3, 4 );
867 gtk_table_attach_defaults ( GTK_TABLE(table), cw.y_spin, 1, 2, 3, 4 );
869 cw.tabs = gtk_notebook_new();
870 GtkWidget *table_utm = gtk_table_new ( 3, 2, FALSE );
872 gtk_table_attach_defaults ( GTK_TABLE(table_utm), ce_label, 0, 1, 0, 1 );
873 gtk_table_attach_defaults ( GTK_TABLE(table_utm), cw.ce_spin, 1, 2, 0, 1 );
874 gtk_table_attach_defaults ( GTK_TABLE(table_utm), cn_label, 0, 1, 1, 2 );
875 gtk_table_attach_defaults ( GTK_TABLE(table_utm), cw.cn_spin, 1, 2, 1, 2 );
877 GtkWidget *utm_hbox = gtk_hbox_new ( FALSE, 0 );
878 cw.utm_zone_spin = gtk_spin_button_new ((GtkAdjustment*)gtk_adjustment_new( vgl->corner.zone, 1, 60, 1, 5, 0 ), 1, 0 );
879 gtk_box_pack_start ( GTK_BOX(utm_hbox), gtk_label_new(_("Zone:")), TRUE, TRUE, 0 );
880 gtk_box_pack_start ( GTK_BOX(utm_hbox), cw.utm_zone_spin, TRUE, TRUE, 0 );
881 gtk_box_pack_start ( GTK_BOX(utm_hbox), gtk_label_new(_("Letter:")), TRUE, TRUE, 0 );
882 cw.utm_letter_entry = gtk_entry_new ();
883 gtk_entry_set_max_length ( GTK_ENTRY(cw.utm_letter_entry), 1 );
884 gtk_entry_set_width_chars ( GTK_ENTRY(cw.utm_letter_entry), 2 );
886 tmp_letter[0] = vgl->corner.letter;
887 tmp_letter[1] = '\0';
888 gtk_entry_set_text ( GTK_ENTRY(cw.utm_letter_entry), tmp_letter );
889 gtk_box_pack_start ( GTK_BOX(utm_hbox), cw.utm_letter_entry, TRUE, TRUE, 0 );
891 gtk_table_attach_defaults ( GTK_TABLE(table_utm), utm_hbox, 0, 2, 2, 3 );
894 GtkWidget *table_ll = gtk_table_new ( 5, 2, FALSE );
896 GtkWidget *lat_tl_label = gtk_label_new ( _("Upper left latitude:") );
897 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 );
898 GtkWidget *lon_tl_label = gtk_label_new ( _("Upper left longitude:") );
899 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 );
900 GtkWidget *lat_br_label = gtk_label_new ( _("Lower right latitude:") );
901 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 );
902 GtkWidget *lon_br_label = gtk_label_new ( _("Lower right longitude:") );
903 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 );
905 gtk_table_attach_defaults ( GTK_TABLE(table_ll), lat_tl_label, 0, 1, 0, 1 );
906 gtk_table_attach_defaults ( GTK_TABLE(table_ll), cw.lat_tl_spin, 1, 2, 0, 1 );
907 gtk_table_attach_defaults ( GTK_TABLE(table_ll), lon_tl_label, 0, 1, 1, 2 );
908 gtk_table_attach_defaults ( GTK_TABLE(table_ll), cw.lon_tl_spin, 1, 2, 1, 2 );
909 gtk_table_attach_defaults ( GTK_TABLE(table_ll), lat_br_label, 0, 1, 2, 3 );
910 gtk_table_attach_defaults ( GTK_TABLE(table_ll), cw.lat_br_spin, 1, 2, 2, 3 );
911 gtk_table_attach_defaults ( GTK_TABLE(table_ll), lon_br_label, 0, 1, 3, 4 );
912 gtk_table_attach_defaults ( GTK_TABLE(table_ll), cw.lon_br_spin, 1, 2, 3, 4 );
914 GtkWidget *calc_mpp_button = gtk_button_new_with_label ( _("Calculate MPP values from coordinates") );
915 gtk_widget_set_tooltip_text ( calc_mpp_button, _("Enter all corner coordinates before calculating the MPP values from the image size") );
916 gtk_table_attach_defaults ( GTK_TABLE(table_ll), calc_mpp_button, 0, 2, 4, 5 );
919 vik_coord_load_from_utm (&vc, VIK_COORD_LATLON, &(vgl->corner));
920 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.lat_tl_spin), vc.north_south );
921 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.lon_tl_spin), vc.east_west );
922 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.lat_br_spin), vgl->ll_br.lat );
923 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.lon_br_spin), vgl->ll_br.lon );
925 gtk_notebook_append_page(GTK_NOTEBOOK(cw.tabs), GTK_WIDGET(table_utm), gtk_label_new(_("UTM")));
926 gtk_notebook_append_page(GTK_NOTEBOOK(cw.tabs), GTK_WIDGET(table_ll), gtk_label_new(_("Latitude/Longitude")));
927 gtk_box_pack_start ( dgbox, cw.tabs, TRUE, TRUE, 0 );
929 GtkWidget *alpha_hbox = gtk_hbox_new ( FALSE, 0 );
930 // GTK3 => GtkWidget *alpha_scale = gtk_scale_new_with_range ( GTK_ORIENTATION_HORIZONTAL, 0, 255, 1 );
931 GtkWidget *alpha_scale = gtk_hscale_new_with_range ( 0, 255, 1 );
932 gtk_scale_set_digits ( GTK_SCALE(alpha_scale), 0 );
933 gtk_range_set_value ( GTK_RANGE(alpha_scale), vgl->alpha );
934 gtk_box_pack_start ( GTK_BOX(alpha_hbox), gtk_label_new(_("Alpha:")), TRUE, TRUE, 0 );
935 gtk_box_pack_start ( GTK_BOX(alpha_hbox), alpha_scale, TRUE, TRUE, 0 );
936 gtk_box_pack_start ( dgbox, alpha_hbox, TRUE, TRUE, 0 );
940 g_signal_connect ( G_OBJECT(vgl->cw.tabs), "switch-page", G_CALLBACK(switch_tab), vgl );
941 g_signal_connect ( G_OBJECT(calc_mpp_button), "clicked", G_CALLBACK(calculate_mpp_from_coords), vgl );
943 g_signal_connect_swapped ( G_OBJECT(wfp_button), "clicked", G_CALLBACK(georef_layer_dialog_load), &cw );
946 gtk_widget_grab_focus ( response_w );
948 gtk_widget_show_all ( dialog );
950 // Remember setting the notebook page must be done after the widget is visible.
952 if ( a_settings_get_integer ( VIK_SETTINGS_GEOREF_TAB, &page_num ) )
953 if ( page_num < 0 || page_num > 1 )
955 gtk_notebook_set_current_page ( GTK_NOTEBOOK(cw.tabs), page_num );
957 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
959 align_coords ( vgl );
961 vgl->corner.easting = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cw.ce_spin) );
962 vgl->corner.northing = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cw.cn_spin) );
963 vgl->corner.zone = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(cw.utm_zone_spin) );
964 const gchar *letter = gtk_entry_get_text ( GTK_ENTRY(cw.utm_letter_entry) );
966 vgl->corner.letter = toupper(*letter);
967 vgl->mpp_easting = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cw.x_spin) );
968 vgl->mpp_northing = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cw.y_spin) );
969 vgl->ll_br = get_ll_br (vgl);
970 check_br_is_good_or_msg_user ( vgl );
971 // TODO check if image has changed otherwise no need to regenerate pixbuf
974 if ( g_strcmp0 (vgl->image, vik_file_entry_get_filename(VIK_FILE_ENTRY(cw.imageentry)) ) != 0 )
976 georef_layer_set_image ( vgl, vik_file_entry_get_filename(VIK_FILE_ENTRY(cw.imageentry)) );
977 georef_layer_load_image ( vgl, VIK_VIEWPORT(vp), FALSE );
981 vgl->alpha = (guint8) gtk_range_get_value ( GTK_RANGE(alpha_scale) );
982 if ( vgl->pixbuf && vgl->alpha <= 255 )
983 vgl->pixbuf = ui_pixbuf_set_alpha ( vgl->pixbuf, vgl->alpha );
984 if ( vgl->scaled && vgl->alpha <= 255 )
985 vgl->scaled = ui_pixbuf_set_alpha ( vgl->scaled, vgl->alpha );
987 a_settings_set_integer ( VIK_SETTINGS_GEOREF_TAB, gtk_notebook_get_current_page(GTK_NOTEBOOK(cw.tabs)) );
989 gtk_widget_destroy ( GTK_WIDGET(dialog) );
992 gtk_widget_destroy ( GTK_WIDGET(dialog) );
996 static void georef_layer_zoom_to_fit ( gpointer vgl_vlp[2] )
998 vik_viewport_set_xmpp ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1])), VIK_GEOREF_LAYER(vgl_vlp[0])->mpp_easting );
999 vik_viewport_set_ympp ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1])), VIK_GEOREF_LAYER(vgl_vlp[0])->mpp_northing );
1000 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vgl_vlp[1]) );
1003 static void georef_layer_goto_center ( gpointer vgl_vlp[2] )
1005 VikGeorefLayer *vgl = VIK_GEOREF_LAYER ( vgl_vlp[0] );
1006 VikViewport *vp = vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1]));
1010 vik_coord_to_utm ( vik_viewport_get_center ( vp ), &utm );
1012 utm.easting = vgl->corner.easting + (vgl->width * vgl->mpp_easting / 2); /* only an approximation */
1013 utm.northing = vgl->corner.northing - (vgl->height * vgl->mpp_northing / 2);
1015 vik_coord_load_from_utm ( &coord, vik_viewport_get_coord_mode ( vp ), &utm );
1016 vik_viewport_set_center_coord ( vp, &coord, TRUE );
1018 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vgl_vlp[1]) );
1021 static void georef_layer_add_menu_items ( VikGeorefLayer *vgl, GtkMenu *menu, gpointer vlp )
1023 static gpointer pass_along[2];
1025 pass_along[0] = vgl;
1026 pass_along[1] = vlp;
1028 item = gtk_menu_item_new();
1029 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1030 gtk_widget_show ( item );
1032 /* Now with icons */
1033 item = gtk_image_menu_item_new_with_mnemonic ( _("_Zoom to Fit Map") );
1034 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
1035 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_zoom_to_fit), pass_along );
1036 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1037 gtk_widget_show ( item );
1039 item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto Map Center") );
1040 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
1041 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_goto_center), pass_along );
1042 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1043 gtk_widget_show ( item );
1045 item = gtk_image_menu_item_new_with_mnemonic ( _("_Export to World File") );
1046 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_HARDDISK, GTK_ICON_SIZE_MENU) );
1047 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_export_params), pass_along );
1048 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1049 gtk_widget_show ( item );
1053 static gpointer georef_layer_move_create ( VikWindow *vw, VikViewport *vvp)
1058 static gboolean georef_layer_move_release ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
1060 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
1063 if ( vgl->click_x != -1 )
1065 vgl->corner.easting += (event->x - vgl->click_x) * vik_viewport_get_xmpp (vvp);
1066 vgl->corner.northing -= (event->y - vgl->click_y) * vik_viewport_get_ympp (vvp);
1067 vik_layer_emit_update ( VIK_LAYER(vgl) );
1070 return FALSE; /* I didn't move anything on this layer! */
1073 static gpointer georef_layer_zoom_create ( VikWindow *vw, VikViewport *vvp)
1078 static gboolean georef_layer_zoom_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
1080 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
1082 if ( event->button == 1 )
1084 if ( vgl->mpp_easting < (VIK_VIEWPORT_MAX_ZOOM / 1.05) && vgl->mpp_northing < (VIK_VIEWPORT_MAX_ZOOM / 1.05) )
1086 vgl->mpp_easting *= 1.01;
1087 vgl->mpp_northing *= 1.01;
1092 if ( vgl->mpp_easting > (VIK_VIEWPORT_MIN_ZOOM * 1.05) && vgl->mpp_northing > (VIK_VIEWPORT_MIN_ZOOM * 1.05) )
1094 vgl->mpp_easting /= 1.01;
1095 vgl->mpp_northing /= 1.01;
1098 vik_viewport_set_xmpp ( vvp, vgl->mpp_easting );
1099 vik_viewport_set_ympp ( vvp, vgl->mpp_northing );
1100 vik_layer_emit_update ( VIK_LAYER(vgl) );
1104 static gboolean georef_layer_move_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
1106 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
1108 vgl->click_x = event->x;
1109 vgl->click_y = event->y;
1113 static void goto_center_ll ( VikViewport *vp,
1114 struct LatLon ll_tl,
1115 struct LatLon ll_br )
1118 struct LatLon ll_center;
1120 ll_center.lat = (ll_tl.lat + ll_br.lat) / 2.0;
1121 ll_center.lon = (ll_tl.lon + ll_br.lon) / 2.0;
1123 vik_coord_load_from_latlon ( &vc_center, vik_viewport_get_coord_mode (vp), &ll_center );
1124 vik_viewport_set_center_coord ( vp, &vc_center, TRUE );
1130 VikGeorefLayer *vik_georef_layer_create ( VikViewport *vp,
1131 VikLayersPanel *vlp,
1135 VikCoord *coord_br )
1137 VikGeorefLayer *vgl = georef_layer_new ( vp );
1138 vik_layer_rename ( VIK_LAYER(vgl), name );
1140 vgl->pixbuf = pixbuf;
1142 vik_coord_to_utm ( coord_tl, &(vgl->corner) );
1143 vik_coord_to_latlon ( coord_br, &(vgl->ll_br) );
1145 if ( vgl->pixbuf ) {
1146 vgl->width = gdk_pixbuf_get_width ( vgl->pixbuf );
1147 vgl->height = gdk_pixbuf_get_height ( vgl->pixbuf );
1149 if ( vgl->width > 0 && vgl->height > 0 ) {
1151 struct LatLon ll_tl;
1152 vik_coord_to_latlon ( coord_tl, &ll_tl);
1153 struct LatLon ll_br;
1154 vik_coord_to_latlon ( coord_br, &ll_br);
1156 VikCoordMode mode = vik_viewport_get_coord_mode (vp);
1159 georef_layer_mpp_from_coords ( mode, ll_tl, ll_br, vgl->width, vgl->height, &xmpp, &ympp );
1160 vgl->mpp_easting = xmpp;
1161 vgl->mpp_northing = ympp;
1163 goto_center_ll ( vp, ll_tl, ll_br);
1164 // Set best zoom level
1165 struct LatLon maxmin[2] = { ll_tl, ll_br };
1166 vu_zoom_to_show_latlons ( vik_viewport_get_coord_mode(vp), vp, maxmin );
1173 georef_layer_free ( vgl );