]> git.street.me.uk Git - andy/viking.git/blame - src/vikgeoreflayer.c
[DOC] Mention map tilesize configuration.
[andy/viking.git] / src / vikgeoreflayer.c
CommitLineData
50a14534
EB
1/*
2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3 *
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
69c4125a 5 * Copyright (c) 2014, Rob Norris <rw_norris@hotmail.com>
50a14534
EB
6 *
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.
11 *
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.
16 *
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
20 *
21 */
22
4c77d5e0
GB
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
50a14534 27#include "viking.h"
a0008235 28#include <glib.h>
6af463da 29#include <glib/gstdio.h>
4c77d5e0 30#include <glib/gi18n.h>
7960e897 31#include <string.h>
be75ec20
MR
32#include <math.h>
33#include <stdlib.h>
69c4125a 34#include <ctype.h>
50a14534 35
b7a0cc40 36#include "ui_util.h"
3bd57299 37#include "preferences.h"
bce3a7b0 38#include "icons/icons.h"
584cb1cf
RN
39#include "vikmapslayer.h"
40
a7023a1b 41/*
a7023a1b
RN
42static VikLayerParamData image_default ( void )
43{
44 VikLayerParamData data;
45 data.s = g_strdup ("");
46 return data;
47}
a7023a1b 48*/
bce3a7b0 49
50a14534 50VikLayerParam georef_layer_params[] = {
a87f8fa1
RN
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 },
69c4125a
RN
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 },
b7a0cc40 58 { VIK_LAYER_GEOREF, "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
50a14534
EB
59};
60
69c4125a
RN
61enum {
62 PARAM_IMAGE = 0,
63 PARAM_CE,
64 PARAM_CN,
65 PARAM_ME,
66 PARAM_MN,
67 PARAM_CZ,
68 PARAM_CL,
b7a0cc40 69 PARAM_AA,
69c4125a 70 NUM_PARAMS };
50a14534 71
e6b64c5d 72static const gchar* georef_layer_tooltip ( VikGeorefLayer *vgl );
0a6cab71
AF
73static void georef_layer_marshall( VikGeorefLayer *vgl, guint8 **data, gint *len );
74static VikGeorefLayer *georef_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
158b3642
RN
75static gboolean georef_layer_set_param ( VikGeorefLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
76static VikLayerParamData georef_layer_get_param ( VikGeorefLayer *vgl, guint16 id, gboolean is_file_operation );
a7023a1b 77static VikGeorefLayer *georef_layer_new ( VikViewport *vvp );
a6b90ba4 78static VikGeorefLayer *georef_layer_create ( VikViewport *vp );
50a14534 79static void georef_layer_free ( VikGeorefLayer *vgl );
a6b90ba4 80static gboolean georef_layer_properties ( VikGeorefLayer *vgl, gpointer vp );
fd22ce3e 81static void georef_layer_draw ( VikGeorefLayer *vgl, VikViewport *vp );
50a14534
EB
82static void georef_layer_add_menu_items ( VikGeorefLayer *vgl, GtkMenu *menu, gpointer vlp );
83static void georef_layer_set_image ( VikGeorefLayer *vgl, const gchar *image );
f6d4661b 84static gboolean georef_layer_dialog ( VikGeorefLayer *vgl, gpointer vp, GtkWindow *w );
fd22ce3e 85static void georef_layer_load_image ( VikGeorefLayer *vgl, VikViewport *vp, gboolean from_file );
941aa6e9
AF
86
87/* tools */
88static gpointer georef_layer_move_create ( VikWindow *vw, VikViewport *vvp);
50a14534
EB
89static gboolean georef_layer_move_release ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
90static gboolean georef_layer_move_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
941aa6e9 91static gpointer georef_layer_zoom_create ( VikWindow *vw, VikViewport *vvp);
50a14534
EB
92static gboolean georef_layer_zoom_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
93
79dce0cb 94// See comment in viktrwlayer.c for advice on values used
50a14534 95static VikToolInterface georef_tools[] = {
79dce0cb
RN
96 { { "GeorefMoveMap", "vik-icon-Georef Move Map", N_("_Georef Move Map"), NULL, N_("Georef Move Map"), 0 },
97 (VikToolConstructorFunc) georef_layer_move_create, NULL, NULL, NULL,
bce3a7b0 98 (VikToolMouseFunc) georef_layer_move_press, NULL, (VikToolMouseFunc) georef_layer_move_release,
ef5e8132
RN
99 (VikToolKeyFunc) NULL,
100 FALSE,
63959706 101 GDK_CURSOR_IS_PIXMAP, &cursor_geomove_pixbuf, NULL },
941aa6e9 102
79dce0cb
RN
103 { { "GeorefZoomTool", "vik-icon-Georef Zoom Tool", N_("Georef Z_oom Tool"), NULL, N_("Georef Zoom Tool"), 0 },
104 (VikToolConstructorFunc) georef_layer_zoom_create, NULL, NULL, NULL,
bce3a7b0 105 (VikToolMouseFunc) georef_layer_zoom_press, NULL, NULL,
ef5e8132
RN
106 (VikToolKeyFunc) NULL,
107 FALSE,
63959706 108 GDK_CURSOR_IS_PIXMAP, &cursor_geozoom_pixbuf, NULL },
50a14534
EB
109};
110
111VikLayerInterface vik_georef_layer_interface = {
db386630 112 "GeoRef Map",
affcc0f2 113 N_("GeoRef Map"),
75078768 114 NULL,
5bfafde9 115 &vikgeoreflayer_pixbuf, /*icon */
50a14534
EB
116
117 georef_tools,
118 sizeof(georef_tools) / sizeof(VikToolInterface),
119
120 georef_layer_params,
121 NUM_PARAMS,
122 NULL,
123 0,
124
5a4a28bf
QT
125 VIK_MENU_ITEM_ALL,
126
50a14534
EB
127 (VikLayerFuncCreate) georef_layer_create,
128 (VikLayerFuncRealize) NULL,
129 (VikLayerFuncPostRead) georef_layer_load_image,
130 (VikLayerFuncFree) georef_layer_free,
131
132 (VikLayerFuncProperties) georef_layer_properties,
133 (VikLayerFuncDraw) georef_layer_draw,
134 (VikLayerFuncChangeCoordMode) NULL,
135
03c97bc3
RN
136 (VikLayerFuncGetTimestamp) NULL,
137
20c7a3a0
QT
138 (VikLayerFuncSetMenuItemsSelection) NULL,
139 (VikLayerFuncGetMenuItemsSelection) NULL,
140
50a14534
EB
141 (VikLayerFuncAddMenuItems) georef_layer_add_menu_items,
142 (VikLayerFuncSublayerAddMenuItems) NULL,
143
144 (VikLayerFuncSublayerRenameRequest) NULL,
145 (VikLayerFuncSublayerToggleVisible) NULL,
9da7faf2 146 (VikLayerFuncSublayerTooltip) NULL,
e6b64c5d 147 (VikLayerFuncLayerTooltip) georef_layer_tooltip,
a5dcfdb7 148 (VikLayerFuncLayerSelected) NULL,
50a14534 149
0a6cab71
AF
150 (VikLayerFuncMarshall) georef_layer_marshall,
151 (VikLayerFuncUnmarshall) georef_layer_unmarshall,
50a14534
EB
152
153 (VikLayerFuncSetParam) georef_layer_set_param,
154 (VikLayerFuncGetParam) georef_layer_get_param,
db43cfa4 155 (VikLayerFuncChangeParam) NULL,
50a14534
EB
156
157 (VikLayerFuncReadFileData) NULL,
158 (VikLayerFuncWriteFileData) NULL,
159
33534cd8 160 (VikLayerFuncDeleteItem) NULL,
d5874ef9 161 (VikLayerFuncCutItem) NULL,
50a14534
EB
162 (VikLayerFuncCopyItem) NULL,
163 (VikLayerFuncPasteItem) NULL,
164 (VikLayerFuncFreeCopiedItem) NULL,
70a23263 165 (VikLayerFuncDragDropRequest) NULL,
77ad64fa
RN
166
167 (VikLayerFuncSelectClick) NULL,
08f14055
RN
168 (VikLayerFuncSelectMove) NULL,
169 (VikLayerFuncSelectRelease) NULL,
e46f259a 170 (VikLayerFuncSelectedViewportMenu) NULL,
50a14534
EB
171};
172
69c4125a
RN
173typedef struct {
174 GtkWidget *x_spin;
175 GtkWidget *y_spin;
176 // UTM widgets
177 GtkWidget *ce_spin; // top left
178 GtkWidget *cn_spin; // "
179 GtkWidget *utm_zone_spin;
180 GtkWidget *utm_letter_entry;
181
182 GtkWidget *lat_tl_spin;
183 GtkWidget *lon_tl_spin;
184 GtkWidget *lat_br_spin;
185 GtkWidget *lon_br_spin;
186 //
187 GtkWidget *tabs;
188 GtkWidget *imageentry;
189} changeable_widgets;
190
50a14534
EB
191struct _VikGeorefLayer {
192 VikLayer vl;
193 gchar *image;
194 GdkPixbuf *pixbuf;
b7a0cc40
RN
195 guint8 alpha;
196
69c4125a 197 struct UTM corner; // Top Left
50a14534 198 gdouble mpp_easting, mpp_northing;
69c4125a 199 struct LatLon ll_br; // Bottom Right
50a14534
EB
200 guint width, height;
201
f3505ea3
MR
202 GdkPixbuf *scaled;
203 guint32 scaled_width, scaled_height;
204
50a14534 205 gint click_x, click_y;
69c4125a 206 changeable_widgets cw;
50a14534
EB
207};
208
3bd57299
RN
209static VikLayerParam io_prefs[] = {
210 { 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,
211 N_("Automatically attempt to read associated world file of a new image for a GeoRef layer"), NULL, NULL, NULL}
212};
50a14534 213
3bd57299
RN
214void vik_georef_layer_init (void)
215{
216 VikLayerParamData tmp;
217 tmp.b = TRUE;
218 a_preferences_register(&io_prefs[0], tmp, VIKING_PREFERENCES_IO_GROUP_KEY);
219}
50a14534
EB
220
221GType vik_georef_layer_get_type ()
222{
223 static GType vgl_type = 0;
224
225 if (!vgl_type)
226 {
227 static const GTypeInfo vgl_info =
228 {
229 sizeof (VikGeorefLayerClass),
230 NULL, /* base_init */
231 NULL, /* base_finalize */
232 NULL, /* class init */
233 NULL, /* class_finalize */
234 NULL, /* class_data */
235 sizeof (VikGeorefLayer),
236 0,
237 NULL /* instance init */
238 };
239 vgl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikGeorefLayer", &vgl_info, 0 );
240 }
241
242 return vgl_type;
243}
244
e6b64c5d
RN
245static const gchar* georef_layer_tooltip ( VikGeorefLayer *vgl )
246{
247 return vgl->image;
248}
249
0a6cab71
AF
250static void georef_layer_marshall( VikGeorefLayer *vgl, guint8 **data, gint *len )
251{
252 vik_layer_marshall_params ( VIK_LAYER(vgl), data, len );
253}
254
255static VikGeorefLayer *georef_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
256{
a7023a1b 257 VikGeorefLayer *rv = georef_layer_new ( vvp );
0a6cab71
AF
258 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
259 if (rv->image) {
fd22ce3e 260 georef_layer_load_image ( rv, vvp, TRUE );
0a6cab71
AF
261 }
262 return rv;
263}
264
158b3642 265static gboolean georef_layer_set_param ( VikGeorefLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
50a14534
EB
266{
267 switch ( id )
268 {
269 case PARAM_IMAGE: georef_layer_set_image ( vgl, data.s ); break;
270 case PARAM_CN: vgl->corner.northing = data.d; break;
271 case PARAM_CE: vgl->corner.easting = data.d; break;
272 case PARAM_MN: vgl->mpp_northing = data.d; break;
69c4125a
RN
273 case PARAM_ME: vgl->mpp_easting = data.d; break;
274 case PARAM_CZ: if ( data.u <= 60 ) vgl->corner.zone = data.u; break;
275 case PARAM_CL: if ( data.u >= 65 || data.u <= 90 ) vgl->corner.letter = data.u; break;
b7a0cc40 276 case PARAM_AA: if ( data.u <= 255 ) vgl->alpha = data.u; break;
9351abc4 277 default: break;
50a14534
EB
278 }
279 return TRUE;
280}
281
584cb1cf
RN
282static void create_image_file ( VikGeorefLayer *vgl )
283{
284 // Create in .viking-maps
285 gchar *filename = g_strconcat ( maps_layer_default_dir(), vik_layer_get_name(VIK_LAYER(vgl)), ".jpg", NULL );
286 GError *error = NULL;
287 gdk_pixbuf_save ( vgl->pixbuf, filename, "jpeg", &error, NULL );
288 if ( error ) {
289 g_warning ( "%s", error->message );
290 g_error_free ( error );
291 }
292 else
293 vgl->image = g_strdup ( filename );
294
295 g_free ( filename );
296}
297
158b3642 298static VikLayerParamData georef_layer_get_param ( VikGeorefLayer *vgl, guint16 id, gboolean is_file_operation )
50a14534
EB
299{
300 VikLayerParamData rv;
301 switch ( id )
302 {
88542aa9
RN
303 case PARAM_IMAGE: {
304 gboolean set = FALSE;
305 if ( is_file_operation ) {
584cb1cf
RN
306 if ( vgl->pixbuf && !vgl->image ) {
307 // Force creation of image file
308 create_image_file ( vgl );
309 }
88542aa9
RN
310 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
311 gchar *cwd = g_get_current_dir();
312 if ( cwd ) {
313 rv.s = file_GetRelativeFilename ( cwd, vgl->image );
584cb1cf
RN
314 if ( !rv.s ) rv.s = "";
315 set = TRUE;
316 }
317 }
88542aa9
RN
318 }
319 if ( !set )
320 rv.s = vgl->image ? vgl->image : "";
321 break;
322 }
50a14534
EB
323 case PARAM_CN: rv.d = vgl->corner.northing; break;
324 case PARAM_CE: rv.d = vgl->corner.easting; break;
325 case PARAM_MN: rv.d = vgl->mpp_northing; break;
326 case PARAM_ME: rv.d = vgl->mpp_easting; break;
69c4125a
RN
327 case PARAM_CZ: rv.u = vgl->corner.zone; break;
328 case PARAM_CL: rv.u = vgl->corner.letter; break;
b7a0cc40 329 case PARAM_AA: rv.u = vgl->alpha; break;
9351abc4 330 default: break;
50a14534
EB
331 }
332 return rv;
333}
334
a7023a1b 335static VikGeorefLayer *georef_layer_new ( VikViewport *vvp )
50a14534
EB
336{
337 VikGeorefLayer *vgl = VIK_GEOREF_LAYER ( g_object_new ( VIK_GEOREF_LAYER_TYPE, NULL ) );
a0c65899 338 vik_layer_set_type ( VIK_LAYER(vgl), VIK_LAYER_GEOREF );
50a14534 339
a7023a1b
RN
340 // Since GeoRef layer doesn't use uibuilder
341 // initializing this way won't do anything yet..
342 vik_layer_set_defaults ( VIK_LAYER(vgl), vvp );
343
26342bd8
RN
344 // Make these defaults based on the current view
345 vgl->mpp_northing = vik_viewport_get_ympp ( vvp );
346 vgl->mpp_easting = vik_viewport_get_xmpp ( vvp );
347 vik_coord_to_utm ( vik_viewport_get_center ( vvp ), &(vgl->corner) );
348
50a14534
EB
349 vgl->image = NULL;
350 vgl->pixbuf = NULL;
351 vgl->click_x = -1;
352 vgl->click_y = -1;
f3505ea3
MR
353 vgl->scaled = NULL;
354 vgl->scaled_width = 0;
355 vgl->scaled_height = 0;
69c4125a
RN
356 vgl->ll_br.lat = 0.0;
357 vgl->ll_br.lon = 0.0;
b7a0cc40 358 vgl->alpha = 255;
50a14534
EB
359 return vgl;
360}
361
f783290c
RN
362/**
363 * Return mpp for the given coords, coord mode and image size.
364 */
365static void georef_layer_mpp_from_coords ( VikCoordMode mode, struct LatLon ll_tl, struct LatLon ll_br, guint width, guint height, gdouble *xmpp, gdouble *ympp )
366{
367 struct LatLon ll_tr;
368 ll_tr.lat = ll_tl.lat;
369 ll_tr.lon = ll_br.lon;
370
371 struct LatLon ll_bl;
372 ll_bl.lat = ll_br.lat;
373 ll_bl.lon = ll_tl.lon;
374
375 // UTM mode should be exact MPP
376 gdouble factor = 1.0;
377 if ( mode == VIK_COORD_LATLON ) {
378 // NB the 1.193 - is at the Equator.
379 // http://wiki.openstreetmap.org/wiki/Zoom_levels
380
381 // Convert from actual image MPP to Viking 'pixelfact'
382 gdouble mid_lat = (ll_bl.lat + ll_tr.lat ) / 2.0;
383 // Protect against div by zero (but shouldn't have 90 degrees for mid latitude...)
384 if ( fabs(mid_lat) < 89.9 )
385 factor = cos(DEG2RAD(mid_lat)) * 1.193;
386 }
387
388 gdouble diffx = a_coords_latlon_diff ( &ll_tl, &ll_tr );
389 *xmpp = (diffx / width) / factor;
390
391 gdouble diffy = a_coords_latlon_diff ( &ll_tl, &ll_bl );
392 *ympp = (diffy / height) / factor;
393}
394
fd22ce3e 395static void georef_layer_draw ( VikGeorefLayer *vgl, VikViewport *vp )
50a14534 396{
50a14534
EB
397 if ( vgl->pixbuf )
398 {
50a14534 399 gdouble xmpp = vik_viewport_get_xmpp(vp), ympp = vik_viewport_get_ympp(vp);
be75ec20
MR
400 GdkPixbuf *pixbuf = vgl->pixbuf;
401 guint layer_width = vgl->width;
402 guint layer_height = vgl->height;
403
be75ec20
MR
404 guint width = vik_viewport_get_width(vp), height = vik_viewport_get_height(vp);
405 gint32 x, y;
be75ec20
MR
406 VikCoord corner_coord;
407 vik_coord_load_from_utm ( &corner_coord, vik_viewport_get_coord_mode(vp), &(vgl->corner) );
408 vik_viewport_coord_to_screen ( vp, &corner_coord, &x, &y );
1b4b9e3b
RN
409
410 /* mark to scale the pixbuf if it doesn't match our dimensions */
411 gboolean scale = FALSE;
412 if ( xmpp != vgl->mpp_easting || ympp != vgl->mpp_northing )
413 {
414 scale = TRUE;
415 layer_width = round(vgl->width * vgl->mpp_easting / xmpp);
416 layer_height = round(vgl->height * vgl->mpp_northing / ympp);
417 }
418
419 // If image not in viewport bounds - no need to draw it (or bother with any scaling)
420 if ( (x < 0 || x < width) && (y < 0 || y < height) && x+layer_width > 0 && y+layer_height > 0 ) {
421
422 if ( scale )
423 {
424 /* rescale if necessary */
425 if (layer_width == vgl->scaled_width && layer_height == vgl->scaled_height && vgl->scaled != NULL)
426 pixbuf = vgl->scaled;
427 else
428 {
429 pixbuf = gdk_pixbuf_scale_simple(
430 vgl->pixbuf,
431 layer_width,
432 layer_height,
433 GDK_INTERP_BILINEAR
434 );
435
436 if (vgl->scaled != NULL)
437 g_object_unref(vgl->scaled);
438
439 vgl->scaled = pixbuf;
440 vgl->scaled_width = layer_width;
441 vgl->scaled_height = layer_height;
442 }
443 }
be75ec20 444 vik_viewport_draw_pixbuf ( vp, pixbuf, 0, 0, x, y, layer_width, layer_height ); /* todo: draw only what we need to. */
1b4b9e3b 445 }
50a14534
EB
446 }
447}
448
449static void georef_layer_free ( VikGeorefLayer *vgl )
450{
451 if ( vgl->image != NULL )
452 g_free ( vgl->image );
f3505ea3
MR
453 if ( vgl->scaled != NULL )
454 g_object_unref ( vgl->scaled );
50a14534
EB
455}
456
a6b90ba4 457static VikGeorefLayer *georef_layer_create ( VikViewport *vp )
50a14534 458{
a7023a1b 459 return georef_layer_new ( vp );
50a14534
EB
460}
461
a6b90ba4 462static gboolean georef_layer_properties ( VikGeorefLayer *vgl, gpointer vp )
50a14534 463{
f6d4661b 464 return georef_layer_dialog ( vgl, vp, VIK_GTK_WINDOW_FROM_WIDGET(vp) );
50a14534
EB
465}
466
fd22ce3e 467static void georef_layer_load_image ( VikGeorefLayer *vgl, VikViewport *vp, gboolean from_file )
50a14534
EB
468{
469 GError *gx = NULL;
470 if ( vgl->image == NULL )
471 return;
472
473 if ( vgl->pixbuf )
474 g_object_unref ( G_OBJECT(vgl->pixbuf) );
f3505ea3
MR
475 if ( vgl->scaled )
476 {
477 g_object_unref ( G_OBJECT(vgl->scaled) );
478 vgl->scaled = NULL;
479 }
50a14534
EB
480
481 vgl->pixbuf = gdk_pixbuf_new_from_file ( vgl->image, &gx );
482
483 if (gx)
484 {
28424566
RN
485 if ( !from_file )
486 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(vp), _("Couldn't open image file: %s"), gx->message );
50a14534
EB
487 g_error_free ( gx );
488 }
489 else
490 {
491 vgl->width = gdk_pixbuf_get_width ( vgl->pixbuf );
492 vgl->height = gdk_pixbuf_get_height ( vgl->pixbuf );
b7a0cc40 493
8f45d0be 494 if ( vgl->pixbuf && vgl->alpha <= 255 )
b7a0cc40 495 vgl->pixbuf = ui_pixbuf_set_alpha ( vgl->pixbuf, vgl->alpha );
50a14534 496 }
50a14534
EB
497 /* should find length and width here too */
498}
499
500static void georef_layer_set_image ( VikGeorefLayer *vgl, const gchar *image )
501{
502 if ( vgl->image )
503 g_free ( vgl->image );
f3505ea3
MR
504 if ( vgl->scaled )
505 {
506 g_object_unref ( vgl->scaled );
507 vgl->scaled = NULL;
508 }
50a14534
EB
509 if ( image == NULL )
510 vgl->image = NULL;
1b14d0d2
RN
511
512 if ( g_strcmp0 (image, "") != 0 )
513 vgl->image = vu_get_canonical_filename ( VIK_LAYER(vgl), image );
514 else
515 vgl->image = g_strdup (image);
50a14534
EB
516}
517
92e8adf5
RN
518// Only positive values allowed here
519static void gdouble2spinwidget ( GtkWidget *widget, gdouble val )
50a14534 520{
92e8adf5
RN
521 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(widget), val > 0 ? val : -val );
522}
523
524static void set_widget_values ( changeable_widgets *cw, gdouble values[4] )
525{
526 gdouble2spinwidget ( cw->x_spin, values[0] );
527 gdouble2spinwidget ( cw->y_spin, values[1] );
528 gdouble2spinwidget ( cw->ce_spin, values[2] );
529 gdouble2spinwidget ( cw->cn_spin, values[3] );
530}
531
532static gboolean world_file_read_line ( FILE *ff, gdouble *value, gboolean use_value )
533{
534 gboolean answer = TRUE; // Success
535 gchar buffer[1024];
536 if ( !fgets ( buffer, 1024, ff ) ) {
537 answer = FALSE;
50a14534 538 }
92e8adf5
RN
539 if ( answer && use_value )
540 *value = g_strtod ( buffer, NULL );
541
542 return answer;
543}
544
545/**
546 * http://en.wikipedia.org/wiki/World_file
547 *
548 * Note world files do not define the units and nor are the units standardized :(
549 * Currently Viking only supports:
550 * x&y scale as meters per pixel
551 * x&y coords as UTM eastings and northings respectively
552 */
553static gint world_file_read_file ( const gchar* filename, gdouble values[4] )
554{
555 g_debug ("%s - trying world file %s", __FUNCTION__, filename);
556
557 FILE *f = g_fopen ( filename, "r" );
558 if ( !f )
559 return 1;
560 else {
561 gint answer = 2; // Not enough info read yet
562 // **We do not handle 'skew' values ATM - normally they are a value of 0 anyway to align with the UTM grid
563 if ( world_file_read_line ( f, &values[0], TRUE ) // x scale
564 && world_file_read_line ( f, NULL, FALSE ) // Ignore value in y-skew line**
565 && world_file_read_line ( f, NULL, FALSE ) // Ignore value in x-skew line**
566 && world_file_read_line ( f, &values[1], TRUE ) // y scale
567 && world_file_read_line ( f, &values[2], TRUE ) // x-coordinate of the upper left pixel
568 && world_file_read_line ( f, &values[3], TRUE ) // y-coordinate of the upper left pixel
569 )
570 {
571 // Success
572 g_debug ("%s - %s - world file read success", __FUNCTION__, filename);
573 answer = 0;
574 }
575 fclose ( f );
576 return answer;
50a14534 577 }
50a14534
EB
578}
579
92e8adf5 580static void georef_layer_dialog_load ( changeable_widgets *cw )
50a14534 581{
6e4a49aa
MA
582 GtkWidget *file_selector = gtk_file_chooser_dialog_new (_("Choose World file"),
583 NULL,
584 GTK_FILE_CHOOSER_ACTION_OPEN,
585 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
586 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
587 NULL);
588
589 if ( gtk_dialog_run ( GTK_DIALOG ( file_selector ) ) == GTK_RESPONSE_ACCEPT )
50a14534 590 {
92e8adf5
RN
591 gdouble values[4];
592 gint answer = world_file_read_file ( gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_selector)), values );
593 if ( answer == 1 )
594 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(cw->x_spin), _("The World file you requested could not be opened for reading.") );
595 else if ( answer == 2 )
596 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(cw->x_spin), _("Unexpected end of file reading World file.") );
597 else
598 // NB answer should == 0 for success
599 set_widget_values ( cw, values );
50a14534 600 }
92e8adf5
RN
601
602 gtk_widget_destroy ( file_selector );
50a14534
EB
603}
604
605static void georef_layer_export_params ( gpointer *pass_along[2] )
606{
607 VikGeorefLayer *vgl = VIK_GEOREF_LAYER(pass_along[0]);
6e4a49aa
MA
608 GtkWidget *file_selector = gtk_file_chooser_dialog_new (_("Choose World file"),
609 NULL,
610 GTK_FILE_CHOOSER_ACTION_SAVE,
611 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
612 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
613 NULL);
614 if ( gtk_dialog_run ( GTK_DIALOG ( file_selector ) ) == GTK_RESPONSE_ACCEPT )
50a14534 615 {
8c060406 616 FILE *f = g_fopen ( gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER(file_selector) ), "w" );
6e4a49aa 617
50a14534
EB
618 gtk_widget_destroy ( file_selector );
619 if ( !f )
620 {
4c77d5e0 621 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(pass_along[0]), _("The file you requested could not be opened for writing.") );
50a14534
EB
622 return;
623 }
624 else
625 {
626 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 );
627 fclose ( f );
8c060406 628 f = NULL;
50a14534
EB
629 }
630 }
631 else
632 gtk_widget_destroy ( file_selector );
633}
634
3bd57299
RN
635/**
636 * Auto attempt to read the world file associated with the image used for the georef
637 * Based on simple file name conventions
638 * Only attempted if the preference is on.
639 */
640static void maybe_read_world_file ( VikFileEntry *vfe, gpointer user_data )
641{
642 if ( a_preferences_get (VIKING_PREFERENCES_IO_NAMESPACE "georef_auto_read_world_file")->b ) {
643 const gchar* filename = vik_file_entry_get_filename(VIK_FILE_ENTRY(vfe));
644 gdouble values[4];
645 if ( filename && user_data ) {
646
647 changeable_widgets *cw = user_data;
648
649 gboolean upper = g_ascii_isupper (filename[strlen(filename)-1]);
650 gchar* filew = g_strconcat ( filename, (upper ? "W" : "w") , NULL );
651
652 if ( world_file_read_file ( filew, values ) == 0 ) {
653 set_widget_values ( cw, values );
654 }
655 else {
656 if ( strlen(filename) > 3 ) {
657 gchar* file0 = g_strndup ( filename, strlen(filename)-2 );
658 gchar* file1 = g_strdup_printf ( "%s%c%c", file0, filename[strlen(filename)-1], (upper ? 'W' : 'w') );
659 if ( world_file_read_file ( file1, values ) == 0 ) {
660 set_widget_values ( cw, values );
661 }
662 g_free ( file1 );
663 g_free ( file0 );
664 }
665 }
666 g_free ( filew );
667 }
668 }
669}
670
69c4125a
RN
671static struct LatLon get_ll_tl (VikGeorefLayer *vgl)
672{
673 struct LatLon ll_tl;
674 ll_tl.lat = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.lat_tl_spin) );
675 ll_tl.lon = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.lon_tl_spin) );
676 return ll_tl;
677}
678
679static struct LatLon get_ll_br (VikGeorefLayer *vgl)
680{
681 struct LatLon ll_br;
682 ll_br.lat = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.lat_br_spin) );
683 ll_br.lon = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.lon_br_spin) );
684 return ll_br;
685}
686
687// Align displayed UTM values with displayed Lat/Lon values
688static void align_utm2ll (VikGeorefLayer *vgl)
689{
690 struct LatLon ll_tl = get_ll_tl (vgl);
691
692 struct UTM utm;
693 a_coords_latlon_to_utm ( &ll_tl, &utm );
694 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.ce_spin), utm.easting );
695 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.cn_spin), utm.northing );
696
697 gchar tmp_letter[2];
698 tmp_letter[0] = utm.letter;
699 tmp_letter[1] = '\0';
700 gtk_entry_set_text ( GTK_ENTRY(vgl->cw.utm_letter_entry), tmp_letter );
701
702 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.utm_zone_spin), utm.zone );
703}
704
705// Align displayed Lat/Lon values with displayed UTM values
706static void align_ll2utm (VikGeorefLayer *vgl)
707{
708 struct UTM corner;
709 const gchar *letter = gtk_entry_get_text ( GTK_ENTRY(vgl->cw.utm_letter_entry) );
710 if (*letter)
711 corner.letter = toupper(*letter);
712 corner.zone = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(vgl->cw.utm_zone_spin) );
713 corner.easting = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.ce_spin) );
714 corner.northing = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.cn_spin) );
715
716 struct LatLon ll;
717 a_coords_utm_to_latlon ( &corner, &ll );
718 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.lat_tl_spin), ll.lat );
719 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.lon_tl_spin), ll.lon );
720}
721
722/**
723 * Align coordinates between tabs as the user may have changed the values
724 * Use this before acting on the user input
725 * This is easier then trying to use the 'value-changed' signal for each individual coordinate
726 * especiallly since it tends to end up in an infinite loop continually updating each other.
727 */
728static void align_coords ( VikGeorefLayer *vgl )
729{
730 if (gtk_notebook_get_current_page(GTK_NOTEBOOK(vgl->cw.tabs)) == 0)
731 align_ll2utm ( vgl );
732 else
733 align_utm2ll ( vgl );
734}
735
736static void switch_tab (GtkNotebook *notebook, gpointer tab, guint tab_num, gpointer user_data)
737{
738 VikGeorefLayer *vgl = user_data;
739 if ( tab_num == 0 )
740 align_utm2ll (vgl);
741 else
742 align_ll2utm (vgl);
743}
744
745/**
746 *
747 */
748static void check_br_is_good_or_msg_user ( VikGeorefLayer *vgl )
749{
750 // if a 'blank' ll value that's alright
751 if ( vgl->ll_br.lat == 0.0 && vgl->ll_br.lon == 0.0 )
752 return;
753
754 struct LatLon ll_tl = get_ll_tl (vgl);
755 if ( ll_tl.lat < vgl->ll_br.lat || ll_tl.lon > vgl->ll_br.lon )
756 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vgl), _("Lower right corner values may not be consistent with upper right values") );
757}
758
759/**
760 *
761 */
762static void calculate_mpp_from_coords ( GtkWidget *ww, VikGeorefLayer *vgl )
763{
764 const gchar* filename = vik_file_entry_get_filename(VIK_FILE_ENTRY(vgl->cw.imageentry));
765 if ( !filename ) {
766 return;
767 }
768 GError *gx = NULL;
769 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( filename, &gx );
770 if ( gx ) {
771 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(ww), _("Couldn't open image file: %s"), gx->message );
772 g_error_free ( gx );
773 return;
774 }
775
776 guint width = gdk_pixbuf_get_width ( pixbuf );
777 guint height = gdk_pixbuf_get_height ( pixbuf );
778
779 if ( width == 0 || height == 0 ) {
780 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(ww), _("Invalid image size: %s"), filename);
781 }
782 else {
783 align_coords ( vgl );
784
785 struct LatLon ll_tl = get_ll_tl (vgl);
786 struct LatLon ll_br = get_ll_br (vgl);
787
f783290c
RN
788 gdouble xmpp, ympp;
789 georef_layer_mpp_from_coords ( VIK_COORD_LATLON, ll_tl, ll_br, width, height, &xmpp, &ympp );
69c4125a
RN
790
791 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.x_spin), xmpp );
792 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.y_spin), ympp );
793
794 check_br_is_good_or_msg_user ( vgl );
795 }
796
797 g_object_unref ( G_OBJECT(pixbuf) );
798}
799
800#define VIK_SETTINGS_GEOREF_TAB "georef_coordinate_tab"
801
50a14534 802/* returns TRUE if OK was pressed. */
f6d4661b 803static gboolean georef_layer_dialog ( VikGeorefLayer *vgl, gpointer vp, GtkWindow *w )
50a14534 804{
4c77d5e0 805 GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Layer Properties"),
50a14534
EB
806 w,
807 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
808 GTK_STOCK_CANCEL,
809 GTK_RESPONSE_REJECT,
810 GTK_STOCK_OK,
811 GTK_RESPONSE_ACCEPT,
10888930 812 NULL );
535747e9
RN
813 /* Default to reject as user really needs to specify map file first */
814 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_REJECT );
815 GtkWidget *response_w = NULL;
816#if GTK_CHECK_VERSION (2, 20, 0)
817 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_REJECT );
818#endif
69c4125a 819 GtkWidget *table, *wfp_hbox, *wfp_label, *wfp_button, *ce_label, *cn_label, *xlabel, *ylabel, *imagelabel;
92e8adf5 820 changeable_widgets cw;
50a14534 821
69c4125a
RN
822 GtkBox *dgbox = GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog)));
823 table = gtk_table_new ( 4, 2, FALSE );
824 gtk_box_pack_start ( dgbox, table, TRUE, TRUE, 0 );
50a14534
EB
825
826 wfp_hbox = gtk_hbox_new ( FALSE, 0 );
4c77d5e0
GB
827 wfp_label = gtk_label_new ( _("World File Parameters:") );
828 wfp_button = gtk_button_new_with_label ( _("Load From File...") );
50a14534
EB
829
830 gtk_box_pack_start ( GTK_BOX(wfp_hbox), wfp_label, TRUE, TRUE, 0 );
831 gtk_box_pack_start ( GTK_BOX(wfp_hbox), wfp_button, FALSE, FALSE, 3 );
832
4c77d5e0 833 ce_label = gtk_label_new ( _("Corner pixel easting:") );
92e8adf5
RN
834 cw.ce_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, 0.0, 1500000.0, 1, 5, 0 ), 1, 4 );
835 gtk_widget_set_tooltip_text ( GTK_WIDGET(cw.ce_spin), _("the UTM \"easting\" value of the upper-left corner pixel of the map") );
50a14534 836
4c77d5e0 837 cn_label = gtk_label_new ( _("Corner pixel northing:") );
92e8adf5
RN
838 cw.cn_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, 0.0, 9000000.0, 1, 5, 0 ), 1, 4 );
839 gtk_widget_set_tooltip_text ( GTK_WIDGET(cw.cn_spin), _("the UTM \"northing\" value of the upper-left corner pixel of the map") );
50a14534 840
4c77d5e0
GB
841 xlabel = gtk_label_new ( _("X (easting) scale (mpp): "));
842 ylabel = gtk_label_new ( _("Y (northing) scale (mpp): "));
50a14534 843
92e8adf5
RN
844 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 );
845 gtk_widget_set_tooltip_text ( GTK_WIDGET(cw.x_spin), _("the scale of the map in the X direction (meters per pixel)") );
846 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 );
847 gtk_widget_set_tooltip_text ( GTK_WIDGET(cw.y_spin), _("the scale of the map in the Y direction (meters per pixel)") );
50a14534 848
4c77d5e0 849 imagelabel = gtk_label_new ( _("Map Image:") );
69c4125a 850 cw.imageentry = vik_file_entry_new (GTK_FILE_CHOOSER_ACTION_OPEN, VF_FILTER_IMAGE, maybe_read_world_file, &cw);
50a14534 851
92e8adf5
RN
852 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.ce_spin), vgl->corner.easting );
853 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.cn_spin), vgl->corner.northing );
854 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.x_spin), vgl->mpp_easting );
855 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.y_spin), vgl->mpp_northing );
f6d4661b 856 if ( vgl->image )
69c4125a 857 vik_file_entry_set_filename ( VIK_FILE_ENTRY(cw.imageentry), vgl->image );
50a14534
EB
858
859 gtk_table_attach_defaults ( GTK_TABLE(table), imagelabel, 0, 1, 0, 1 );
69c4125a 860 gtk_table_attach_defaults ( GTK_TABLE(table), cw.imageentry, 1, 2, 0, 1 );
50a14534
EB
861 gtk_table_attach_defaults ( GTK_TABLE(table), wfp_hbox, 0, 2, 1, 2 );
862 gtk_table_attach_defaults ( GTK_TABLE(table), xlabel, 0, 1, 2, 3 );
92e8adf5 863 gtk_table_attach_defaults ( GTK_TABLE(table), cw.x_spin, 1, 2, 2, 3 );
50a14534 864 gtk_table_attach_defaults ( GTK_TABLE(table), ylabel, 0, 1, 3, 4 );
92e8adf5 865 gtk_table_attach_defaults ( GTK_TABLE(table), cw.y_spin, 1, 2, 3, 4 );
69c4125a
RN
866
867 cw.tabs = gtk_notebook_new();
868 GtkWidget *table_utm = gtk_table_new ( 3, 2, FALSE );
869
870 gtk_table_attach_defaults ( GTK_TABLE(table_utm), ce_label, 0, 1, 0, 1 );
871 gtk_table_attach_defaults ( GTK_TABLE(table_utm), cw.ce_spin, 1, 2, 0, 1 );
872 gtk_table_attach_defaults ( GTK_TABLE(table_utm), cn_label, 0, 1, 1, 2 );
873 gtk_table_attach_defaults ( GTK_TABLE(table_utm), cw.cn_spin, 1, 2, 1, 2 );
874
875 GtkWidget *utm_hbox = gtk_hbox_new ( FALSE, 0 );
876 cw.utm_zone_spin = gtk_spin_button_new ((GtkAdjustment*)gtk_adjustment_new( vgl->corner.zone, 1, 60, 1, 5, 0 ), 1, 0 );
877 gtk_box_pack_start ( GTK_BOX(utm_hbox), gtk_label_new(_("Zone:")), TRUE, TRUE, 0 );
878 gtk_box_pack_start ( GTK_BOX(utm_hbox), cw.utm_zone_spin, TRUE, TRUE, 0 );
879 gtk_box_pack_start ( GTK_BOX(utm_hbox), gtk_label_new(_("Letter:")), TRUE, TRUE, 0 );
880 cw.utm_letter_entry = gtk_entry_new ();
881 gtk_entry_set_max_length ( GTK_ENTRY(cw.utm_letter_entry), 1 );
882 gtk_entry_set_width_chars ( GTK_ENTRY(cw.utm_letter_entry), 2 );
883 gchar tmp_letter[2];
884 tmp_letter[0] = vgl->corner.letter;
885 tmp_letter[1] = '\0';
886 gtk_entry_set_text ( GTK_ENTRY(cw.utm_letter_entry), tmp_letter );
887 gtk_box_pack_start ( GTK_BOX(utm_hbox), cw.utm_letter_entry, TRUE, TRUE, 0 );
888
889 gtk_table_attach_defaults ( GTK_TABLE(table_utm), utm_hbox, 0, 2, 2, 3 );
890
891 // Lat/Lon
892 GtkWidget *table_ll = gtk_table_new ( 5, 2, FALSE );
893
894 GtkWidget *lat_tl_label = gtk_label_new ( _("Upper left latitude:") );
895 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 );
896 GtkWidget *lon_tl_label = gtk_label_new ( _("Upper left longitude:") );
897 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 );
898 GtkWidget *lat_br_label = gtk_label_new ( _("Lower right latitude:") );
899 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 );
900 GtkWidget *lon_br_label = gtk_label_new ( _("Lower right longitude:") );
901 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 );
902
903 gtk_table_attach_defaults ( GTK_TABLE(table_ll), lat_tl_label, 0, 1, 0, 1 );
904 gtk_table_attach_defaults ( GTK_TABLE(table_ll), cw.lat_tl_spin, 1, 2, 0, 1 );
905 gtk_table_attach_defaults ( GTK_TABLE(table_ll), lon_tl_label, 0, 1, 1, 2 );
906 gtk_table_attach_defaults ( GTK_TABLE(table_ll), cw.lon_tl_spin, 1, 2, 1, 2 );
907 gtk_table_attach_defaults ( GTK_TABLE(table_ll), lat_br_label, 0, 1, 2, 3 );
908 gtk_table_attach_defaults ( GTK_TABLE(table_ll), cw.lat_br_spin, 1, 2, 2, 3 );
909 gtk_table_attach_defaults ( GTK_TABLE(table_ll), lon_br_label, 0, 1, 3, 4 );
910 gtk_table_attach_defaults ( GTK_TABLE(table_ll), cw.lon_br_spin, 1, 2, 3, 4 );
911
912 GtkWidget *calc_mpp_button = gtk_button_new_with_label ( _("Calculate MPP values from coordinates") );
913 gtk_widget_set_tooltip_text ( calc_mpp_button, _("Enter all corner coordinates before calculating the MPP values from the image size") );
914 gtk_table_attach_defaults ( GTK_TABLE(table_ll), calc_mpp_button, 0, 2, 4, 5 );
915
916 VikCoord vc;
917 vik_coord_load_from_utm (&vc, VIK_COORD_LATLON, &(vgl->corner));
918 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.lat_tl_spin), vc.north_south );
919 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.lon_tl_spin), vc.east_west );
920 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.lat_br_spin), vgl->ll_br.lat );
921 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.lon_br_spin), vgl->ll_br.lon );
922
923 gtk_notebook_append_page(GTK_NOTEBOOK(cw.tabs), GTK_WIDGET(table_utm), gtk_label_new(_("UTM")));
924 gtk_notebook_append_page(GTK_NOTEBOOK(cw.tabs), GTK_WIDGET(table_ll), gtk_label_new(_("Latitude/Longitude")));
925 gtk_box_pack_start ( dgbox, cw.tabs, TRUE, TRUE, 0 );
926
b7a0cc40
RN
927 GtkWidget *alpha_hbox = gtk_hbox_new ( FALSE, 0 );
928 // GTK3 => GtkWidget *alpha_scale = gtk_scale_new_with_range ( GTK_ORIENTATION_HORIZONTAL, 0, 255, 1 );
929 GtkWidget *alpha_scale = gtk_hscale_new_with_range ( 0, 255, 1 );
930 gtk_scale_set_digits ( GTK_SCALE(alpha_scale), 0 );
931 gtk_range_set_value ( GTK_RANGE(alpha_scale), vgl->alpha );
932 gtk_box_pack_start ( GTK_BOX(alpha_hbox), gtk_label_new(_("Alpha:")), TRUE, TRUE, 0 );
933 gtk_box_pack_start ( GTK_BOX(alpha_hbox), alpha_scale, TRUE, TRUE, 0 );
934 gtk_box_pack_start ( dgbox, alpha_hbox, TRUE, TRUE, 0 );
935
69c4125a
RN
936 vgl->cw = cw;
937
938 g_signal_connect ( G_OBJECT(vgl->cw.tabs), "switch-page", G_CALLBACK(switch_tab), vgl );
939 g_signal_connect ( G_OBJECT(calc_mpp_button), "clicked", G_CALLBACK(calculate_mpp_from_coords), vgl );
50a14534 940
92e8adf5 941 g_signal_connect_swapped ( G_OBJECT(wfp_button), "clicked", G_CALLBACK(georef_layer_dialog_load), &cw );
50a14534 942
535747e9
RN
943 if ( response_w )
944 gtk_widget_grab_focus ( response_w );
945
69c4125a
RN
946 gtk_widget_show_all ( dialog );
947
948 // Remember setting the notebook page must be done after the widget is visible.
949 gint page_num = 0;
950 if ( a_settings_get_integer ( VIK_SETTINGS_GEOREF_TAB, &page_num ) )
951 if ( page_num < 0 || page_num > 1 )
952 page_num = 0;
953 gtk_notebook_set_current_page ( GTK_NOTEBOOK(cw.tabs), page_num );
50a14534
EB
954
955 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
956 {
69c4125a
RN
957 align_coords ( vgl );
958
92e8adf5
RN
959 vgl->corner.easting = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cw.ce_spin) );
960 vgl->corner.northing = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cw.cn_spin) );
69c4125a
RN
961 vgl->corner.zone = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(cw.utm_zone_spin) );
962 const gchar *letter = gtk_entry_get_text ( GTK_ENTRY(cw.utm_letter_entry) );
963 if (*letter)
964 vgl->corner.letter = toupper(*letter);
92e8adf5
RN
965 vgl->mpp_easting = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cw.x_spin) );
966 vgl->mpp_northing = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cw.y_spin) );
69c4125a
RN
967 vgl->ll_br = get_ll_br (vgl);
968 check_br_is_good_or_msg_user ( vgl );
584cb1cf
RN
969 // TODO check if image has changed otherwise no need to regenerate pixbuf
970 if ( !vgl->pixbuf )
50a14534 971 {
584cb1cf
RN
972 if ( g_strcmp0 (vgl->image, vik_file_entry_get_filename(VIK_FILE_ENTRY(cw.imageentry)) ) != 0 )
973 {
974 georef_layer_set_image ( vgl, vik_file_entry_get_filename(VIK_FILE_ENTRY(cw.imageentry)) );
975 georef_layer_load_image ( vgl, VIK_VIEWPORT(vp), FALSE );
976 }
50a14534
EB
977 }
978
b7a0cc40 979 vgl->alpha = (guint8) gtk_range_get_value ( GTK_RANGE(alpha_scale) );
8f45d0be 980 if ( vgl->pixbuf && vgl->alpha <= 255 )
b7a0cc40 981 vgl->pixbuf = ui_pixbuf_set_alpha ( vgl->pixbuf, vgl->alpha );
8f45d0be 982 if ( vgl->scaled && vgl->alpha <= 255 )
b7a0cc40
RN
983 vgl->scaled = ui_pixbuf_set_alpha ( vgl->scaled, vgl->alpha );
984
69c4125a
RN
985 a_settings_set_integer ( VIK_SETTINGS_GEOREF_TAB, gtk_notebook_get_current_page(GTK_NOTEBOOK(cw.tabs)) );
986
50a14534
EB
987 gtk_widget_destroy ( GTK_WIDGET(dialog) );
988 return TRUE;
989 }
990 gtk_widget_destroy ( GTK_WIDGET(dialog) );
991 return FALSE;
992}
993
994static void georef_layer_zoom_to_fit ( gpointer vgl_vlp[2] )
995{
996 vik_viewport_set_xmpp ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1])), VIK_GEOREF_LAYER(vgl_vlp[0])->mpp_easting );
997 vik_viewport_set_ympp ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1])), VIK_GEOREF_LAYER(vgl_vlp[0])->mpp_northing );
998 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vgl_vlp[1]) );
999}
1000
1001static void georef_layer_goto_center ( gpointer vgl_vlp[2] )
1002{
1003 VikGeorefLayer *vgl = VIK_GEOREF_LAYER ( vgl_vlp[0] );
1004 VikViewport *vp = vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1]));
1005 struct UTM utm;
1006 VikCoord coord;
1007
1008 vik_coord_to_utm ( vik_viewport_get_center ( vp ), &utm );
1009
1010 utm.easting = vgl->corner.easting + (vgl->width * vgl->mpp_easting / 2); /* only an approximation */
1011 utm.northing = vgl->corner.northing - (vgl->height * vgl->mpp_northing / 2);
1012
1013 vik_coord_load_from_utm ( &coord, vik_viewport_get_coord_mode ( vp ), &utm );
be5554c5 1014 vik_viewport_set_center_coord ( vp, &coord, TRUE );
50a14534
EB
1015
1016 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vgl_vlp[1]) );
1017}
1018
1019static void georef_layer_add_menu_items ( VikGeorefLayer *vgl, GtkMenu *menu, gpointer vlp )
1020{
1021 static gpointer pass_along[2];
1022 GtkWidget *item;
1023 pass_along[0] = vgl;
1024 pass_along[1] = vlp;
1025
1026 item = gtk_menu_item_new();
1027 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1028 gtk_widget_show ( item );
1029
d6de71f9
RN
1030 /* Now with icons */
1031 item = gtk_image_menu_item_new_with_mnemonic ( _("_Zoom to Fit Map") );
1032 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
50a14534
EB
1033 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_zoom_to_fit), pass_along );
1034 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1035 gtk_widget_show ( item );
1036
d6de71f9
RN
1037 item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto Map Center") );
1038 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
50a14534
EB
1039 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_goto_center), pass_along );
1040 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1041 gtk_widget_show ( item );
1042
d6de71f9
RN
1043 item = gtk_image_menu_item_new_with_mnemonic ( _("_Export to World File") );
1044 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_HARDDISK, GTK_ICON_SIZE_MENU) );
50a14534
EB
1045 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_export_params), pass_along );
1046 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1047 gtk_widget_show ( item );
1048}
1049
941aa6e9
AF
1050
1051static gpointer georef_layer_move_create ( VikWindow *vw, VikViewport *vvp)
1052{
1053 return vvp;
1054}
1055
50a14534
EB
1056static gboolean georef_layer_move_release ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
1057{
941aa6e9
AF
1058 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
1059 return FALSE;
1060
50a14534
EB
1061 if ( vgl->click_x != -1 )
1062 {
1063 vgl->corner.easting += (event->x - vgl->click_x) * vik_viewport_get_xmpp (vvp);
1064 vgl->corner.northing -= (event->y - vgl->click_y) * vik_viewport_get_ympp (vvp);
da121f9b 1065 vik_layer_emit_update ( VIK_LAYER(vgl) );
50a14534
EB
1066 return TRUE;
1067 }
1068 return FALSE; /* I didn't move anything on this layer! */
1069}
1070
941aa6e9
AF
1071static gpointer georef_layer_zoom_create ( VikWindow *vw, VikViewport *vvp)
1072{
1073 return vvp;
1074}
1075
50a14534
EB
1076static gboolean georef_layer_zoom_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
1077{
941aa6e9
AF
1078 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
1079 return FALSE;
50a14534
EB
1080 if ( event->button == 1 )
1081 {
1082 if ( vgl->mpp_easting < (VIK_VIEWPORT_MAX_ZOOM / 1.05) && vgl->mpp_northing < (VIK_VIEWPORT_MAX_ZOOM / 1.05) )
1083 {
1084 vgl->mpp_easting *= 1.01;
1085 vgl->mpp_northing *= 1.01;
1086 }
1087 }
1088 else
1089 {
1090 if ( vgl->mpp_easting > (VIK_VIEWPORT_MIN_ZOOM * 1.05) && vgl->mpp_northing > (VIK_VIEWPORT_MIN_ZOOM * 1.05) )
1091 {
1092 vgl->mpp_easting /= 1.01;
1093 vgl->mpp_northing /= 1.01;
1094 }
1095 }
1096 vik_viewport_set_xmpp ( vvp, vgl->mpp_easting );
1097 vik_viewport_set_ympp ( vvp, vgl->mpp_northing );
da121f9b 1098 vik_layer_emit_update ( VIK_LAYER(vgl) );
50a14534
EB
1099 return TRUE;
1100}
1101
1102static gboolean georef_layer_move_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
1103{
941aa6e9
AF
1104 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
1105 return FALSE;
50a14534
EB
1106 vgl->click_x = event->x;
1107 vgl->click_y = event->y;
1108 return TRUE;
1109}
584cb1cf
RN
1110
1111static void goto_center_ll ( VikViewport *vp,
1112 struct LatLon ll_tl,
1113 struct LatLon ll_br )
1114{
1115 VikCoord vc_center;
1116 struct LatLon ll_center;
1117
1118 ll_center.lat = (ll_tl.lat + ll_br.lat) / 2.0;
1119 ll_center.lon = (ll_tl.lon + ll_br.lon) / 2.0;
1120
1121 vik_coord_load_from_latlon ( &vc_center, vik_viewport_get_coord_mode (vp), &ll_center );
1122 vik_viewport_set_center_coord ( vp, &vc_center, TRUE );
1123}
1124
1125/**
1126 *
1127 */
1128VikGeorefLayer *vik_georef_layer_create ( VikViewport *vp,
1129 VikLayersPanel *vlp,
1130 const gchar *name,
1131 GdkPixbuf *pixbuf,
1132 VikCoord *coord_tl,
1133 VikCoord *coord_br )
1134{
1135 VikGeorefLayer *vgl = georef_layer_new ( vp );
1136 vik_layer_rename ( VIK_LAYER(vgl), name );
1137
1138 vgl->pixbuf = pixbuf;
1139
1140 vik_coord_to_utm ( coord_tl, &(vgl->corner) );
1141 vik_coord_to_latlon ( coord_br, &(vgl->ll_br) );
1142
1143 if ( vgl->pixbuf ) {
1144 vgl->width = gdk_pixbuf_get_width ( vgl->pixbuf );
1145 vgl->height = gdk_pixbuf_get_height ( vgl->pixbuf );
1146
1147 if ( vgl->width > 0 && vgl->height > 0 ) {
1148
1149 struct LatLon ll_tl;
1150 vik_coord_to_latlon ( coord_tl, &ll_tl);
1151 struct LatLon ll_br;
1152 vik_coord_to_latlon ( coord_br, &ll_br);
1153
1154 VikCoordMode mode = vik_viewport_get_coord_mode (vp);
1155
1156 gdouble xmpp, ympp;
1157 georef_layer_mpp_from_coords ( mode, ll_tl, ll_br, vgl->width, vgl->height, &xmpp, &ympp );
1158 vgl->mpp_easting = xmpp;
1159 vgl->mpp_northing = ympp;
1160
1161 goto_center_ll ( vp, ll_tl, ll_br);
1162 // Set best zoom level
1163 struct LatLon maxmin[2] = { ll_tl, ll_br };
1164 vu_zoom_to_show_latlons ( vik_viewport_get_coord_mode(vp), vp, maxmin );
1165
1166 return vgl;
1167 }
1168 }
1169
1170 // Bad image
1171 georef_layer_free ( vgl );
1172 return NULL;
1173}