]> git.street.me.uk Git - andy/viking.git/blame - src/vikgeoreflayer.c
Don't remove project name if one decides not to delete all layers.
[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"
1b14d0d2 28#include "vikutils.h"
a0008235 29#include <glib.h>
6af463da 30#include <glib/gstdio.h>
4c77d5e0 31#include <glib/gi18n.h>
7960e897 32#include <string.h>
be75ec20
MR
33#include <math.h>
34#include <stdlib.h>
69c4125a 35#include <ctype.h>
50a14534 36
b7a0cc40 37#include "ui_util.h"
3bd57299 38#include "preferences.h"
bce3a7b0 39#include "icons/icons.h"
584cb1cf
RN
40#include "vikmapslayer.h"
41
a7023a1b 42/*
a7023a1b
RN
43static VikLayerParamData image_default ( void )
44{
45 VikLayerParamData data;
46 data.s = g_strdup ("");
47 return data;
48}
a7023a1b 49*/
bce3a7b0 50
50a14534 51VikLayerParam georef_layer_params[] = {
a87f8fa1
RN
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 },
69c4125a
RN
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 },
b7a0cc40 59 { VIK_LAYER_GEOREF, "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
50a14534
EB
60};
61
69c4125a
RN
62enum {
63 PARAM_IMAGE = 0,
64 PARAM_CE,
65 PARAM_CN,
66 PARAM_ME,
67 PARAM_MN,
68 PARAM_CZ,
69 PARAM_CL,
b7a0cc40 70 PARAM_AA,
69c4125a 71 NUM_PARAMS };
50a14534 72
e6b64c5d 73static const gchar* georef_layer_tooltip ( VikGeorefLayer *vgl );
0a6cab71
AF
74static void georef_layer_marshall( VikGeorefLayer *vgl, guint8 **data, gint *len );
75static VikGeorefLayer *georef_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
158b3642
RN
76static gboolean georef_layer_set_param ( VikGeorefLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
77static VikLayerParamData georef_layer_get_param ( VikGeorefLayer *vgl, guint16 id, gboolean is_file_operation );
a7023a1b 78static VikGeorefLayer *georef_layer_new ( VikViewport *vvp );
a6b90ba4 79static VikGeorefLayer *georef_layer_create ( VikViewport *vp );
50a14534 80static void georef_layer_free ( VikGeorefLayer *vgl );
a6b90ba4 81static gboolean georef_layer_properties ( VikGeorefLayer *vgl, gpointer vp );
fd22ce3e 82static void georef_layer_draw ( VikGeorefLayer *vgl, VikViewport *vp );
50a14534
EB
83static void georef_layer_add_menu_items ( VikGeorefLayer *vgl, GtkMenu *menu, gpointer vlp );
84static void georef_layer_set_image ( VikGeorefLayer *vgl, const gchar *image );
f6d4661b 85static gboolean georef_layer_dialog ( VikGeorefLayer *vgl, gpointer vp, GtkWindow *w );
fd22ce3e 86static void georef_layer_load_image ( VikGeorefLayer *vgl, VikViewport *vp, gboolean from_file );
941aa6e9
AF
87
88/* tools */
89static gpointer georef_layer_move_create ( VikWindow *vw, VikViewport *vvp);
50a14534
EB
90static gboolean georef_layer_move_release ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
91static gboolean georef_layer_move_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
941aa6e9 92static gpointer georef_layer_zoom_create ( VikWindow *vw, VikViewport *vvp);
50a14534
EB
93static gboolean georef_layer_zoom_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
94
79dce0cb 95// See comment in viktrwlayer.c for advice on values used
50a14534 96static VikToolInterface georef_tools[] = {
79dce0cb
RN
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,
bce3a7b0 99 (VikToolMouseFunc) georef_layer_move_press, NULL, (VikToolMouseFunc) georef_layer_move_release,
ef5e8132
RN
100 (VikToolKeyFunc) NULL,
101 FALSE,
63959706 102 GDK_CURSOR_IS_PIXMAP, &cursor_geomove_pixbuf, NULL },
941aa6e9 103
79dce0cb
RN
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,
bce3a7b0 106 (VikToolMouseFunc) georef_layer_zoom_press, NULL, NULL,
ef5e8132
RN
107 (VikToolKeyFunc) NULL,
108 FALSE,
63959706 109 GDK_CURSOR_IS_PIXMAP, &cursor_geozoom_pixbuf, NULL },
50a14534
EB
110};
111
112VikLayerInterface vik_georef_layer_interface = {
db386630 113 "GeoRef Map",
affcc0f2 114 N_("GeoRef Map"),
75078768 115 NULL,
5bfafde9 116 &vikgeoreflayer_pixbuf, /*icon */
50a14534
EB
117
118 georef_tools,
119 sizeof(georef_tools) / sizeof(VikToolInterface),
120
121 georef_layer_params,
122 NUM_PARAMS,
123 NULL,
124 0,
125
5a4a28bf
QT
126 VIK_MENU_ITEM_ALL,
127
50a14534
EB
128 (VikLayerFuncCreate) georef_layer_create,
129 (VikLayerFuncRealize) NULL,
130 (VikLayerFuncPostRead) georef_layer_load_image,
131 (VikLayerFuncFree) georef_layer_free,
132
133 (VikLayerFuncProperties) georef_layer_properties,
134 (VikLayerFuncDraw) georef_layer_draw,
135 (VikLayerFuncChangeCoordMode) NULL,
136
03c97bc3
RN
137 (VikLayerFuncGetTimestamp) NULL,
138
20c7a3a0
QT
139 (VikLayerFuncSetMenuItemsSelection) NULL,
140 (VikLayerFuncGetMenuItemsSelection) NULL,
141
50a14534
EB
142 (VikLayerFuncAddMenuItems) georef_layer_add_menu_items,
143 (VikLayerFuncSublayerAddMenuItems) NULL,
144
145 (VikLayerFuncSublayerRenameRequest) NULL,
146 (VikLayerFuncSublayerToggleVisible) NULL,
9da7faf2 147 (VikLayerFuncSublayerTooltip) NULL,
e6b64c5d 148 (VikLayerFuncLayerTooltip) georef_layer_tooltip,
a5dcfdb7 149 (VikLayerFuncLayerSelected) NULL,
50a14534 150
0a6cab71
AF
151 (VikLayerFuncMarshall) georef_layer_marshall,
152 (VikLayerFuncUnmarshall) georef_layer_unmarshall,
50a14534
EB
153
154 (VikLayerFuncSetParam) georef_layer_set_param,
155 (VikLayerFuncGetParam) georef_layer_get_param,
db43cfa4 156 (VikLayerFuncChangeParam) NULL,
50a14534
EB
157
158 (VikLayerFuncReadFileData) NULL,
159 (VikLayerFuncWriteFileData) NULL,
160
33534cd8 161 (VikLayerFuncDeleteItem) NULL,
d5874ef9 162 (VikLayerFuncCutItem) NULL,
50a14534
EB
163 (VikLayerFuncCopyItem) NULL,
164 (VikLayerFuncPasteItem) NULL,
165 (VikLayerFuncFreeCopiedItem) NULL,
70a23263 166 (VikLayerFuncDragDropRequest) NULL,
77ad64fa
RN
167
168 (VikLayerFuncSelectClick) NULL,
08f14055
RN
169 (VikLayerFuncSelectMove) NULL,
170 (VikLayerFuncSelectRelease) NULL,
e46f259a 171 (VikLayerFuncSelectedViewportMenu) NULL,
50a14534
EB
172};
173
69c4125a
RN
174typedef struct {
175 GtkWidget *x_spin;
176 GtkWidget *y_spin;
177 // UTM widgets
178 GtkWidget *ce_spin; // top left
179 GtkWidget *cn_spin; // "
180 GtkWidget *utm_zone_spin;
181 GtkWidget *utm_letter_entry;
182
183 GtkWidget *lat_tl_spin;
184 GtkWidget *lon_tl_spin;
185 GtkWidget *lat_br_spin;
186 GtkWidget *lon_br_spin;
187 //
188 GtkWidget *tabs;
189 GtkWidget *imageentry;
190} changeable_widgets;
191
50a14534
EB
192struct _VikGeorefLayer {
193 VikLayer vl;
194 gchar *image;
195 GdkPixbuf *pixbuf;
b7a0cc40
RN
196 guint8 alpha;
197
69c4125a 198 struct UTM corner; // Top Left
50a14534 199 gdouble mpp_easting, mpp_northing;
69c4125a 200 struct LatLon ll_br; // Bottom Right
50a14534
EB
201 guint width, height;
202
f3505ea3
MR
203 GdkPixbuf *scaled;
204 guint32 scaled_width, scaled_height;
205
50a14534 206 gint click_x, click_y;
69c4125a 207 changeable_widgets cw;
50a14534
EB
208};
209
3bd57299
RN
210static 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}
213};
50a14534 214
3bd57299
RN
215void vik_georef_layer_init (void)
216{
217 VikLayerParamData tmp;
218 tmp.b = TRUE;
219 a_preferences_register(&io_prefs[0], tmp, VIKING_PREFERENCES_IO_GROUP_KEY);
220}
50a14534
EB
221
222GType vik_georef_layer_get_type ()
223{
224 static GType vgl_type = 0;
225
226 if (!vgl_type)
227 {
228 static const GTypeInfo vgl_info =
229 {
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),
237 0,
238 NULL /* instance init */
239 };
240 vgl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikGeorefLayer", &vgl_info, 0 );
241 }
242
243 return vgl_type;
244}
245
e6b64c5d
RN
246static const gchar* georef_layer_tooltip ( VikGeorefLayer *vgl )
247{
248 return vgl->image;
249}
250
0a6cab71
AF
251static void georef_layer_marshall( VikGeorefLayer *vgl, guint8 **data, gint *len )
252{
253 vik_layer_marshall_params ( VIK_LAYER(vgl), data, len );
254}
255
256static VikGeorefLayer *georef_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
257{
a7023a1b 258 VikGeorefLayer *rv = georef_layer_new ( vvp );
0a6cab71
AF
259 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
260 if (rv->image) {
fd22ce3e 261 georef_layer_load_image ( rv, vvp, TRUE );
0a6cab71
AF
262 }
263 return rv;
264}
265
158b3642 266static gboolean georef_layer_set_param ( VikGeorefLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
50a14534
EB
267{
268 switch ( id )
269 {
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;
69c4125a
RN
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;
b7a0cc40 277 case PARAM_AA: if ( data.u <= 255 ) vgl->alpha = data.u; break;
9351abc4 278 default: break;
50a14534
EB
279 }
280 return TRUE;
281}
282
584cb1cf
RN
283static void create_image_file ( VikGeorefLayer *vgl )
284{
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 );
289 if ( error ) {
290 g_warning ( "%s", error->message );
291 g_error_free ( error );
292 }
293 else
294 vgl->image = g_strdup ( filename );
295
296 g_free ( filename );
297}
298
158b3642 299static VikLayerParamData georef_layer_get_param ( VikGeorefLayer *vgl, guint16 id, gboolean is_file_operation )
50a14534
EB
300{
301 VikLayerParamData rv;
302 switch ( id )
303 {
88542aa9
RN
304 case PARAM_IMAGE: {
305 gboolean set = FALSE;
306 if ( is_file_operation ) {
584cb1cf
RN
307 if ( vgl->pixbuf && !vgl->image ) {
308 // Force creation of image file
309 create_image_file ( vgl );
310 }
88542aa9
RN
311 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
312 gchar *cwd = g_get_current_dir();
313 if ( cwd ) {
314 rv.s = file_GetRelativeFilename ( cwd, vgl->image );
584cb1cf
RN
315 if ( !rv.s ) rv.s = "";
316 set = TRUE;
317 }
318 }
88542aa9
RN
319 }
320 if ( !set )
321 rv.s = vgl->image ? vgl->image : "";
322 break;
323 }
50a14534
EB
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;
69c4125a
RN
328 case PARAM_CZ: rv.u = vgl->corner.zone; break;
329 case PARAM_CL: rv.u = vgl->corner.letter; break;
b7a0cc40 330 case PARAM_AA: rv.u = vgl->alpha; break;
9351abc4 331 default: break;
50a14534
EB
332 }
333 return rv;
334}
335
a7023a1b 336static VikGeorefLayer *georef_layer_new ( VikViewport *vvp )
50a14534
EB
337{
338 VikGeorefLayer *vgl = VIK_GEOREF_LAYER ( g_object_new ( VIK_GEOREF_LAYER_TYPE, NULL ) );
a0c65899 339 vik_layer_set_type ( VIK_LAYER(vgl), VIK_LAYER_GEOREF );
50a14534 340
a7023a1b
RN
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 );
344
26342bd8
RN
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) );
349
50a14534
EB
350 vgl->image = NULL;
351 vgl->pixbuf = NULL;
352 vgl->click_x = -1;
353 vgl->click_y = -1;
f3505ea3
MR
354 vgl->scaled = NULL;
355 vgl->scaled_width = 0;
356 vgl->scaled_height = 0;
69c4125a
RN
357 vgl->ll_br.lat = 0.0;
358 vgl->ll_br.lon = 0.0;
b7a0cc40 359 vgl->alpha = 255;
50a14534
EB
360 return vgl;
361}
362
f783290c
RN
363/**
364 * Return mpp for the given coords, coord mode and image size.
365 */
366static void georef_layer_mpp_from_coords ( VikCoordMode mode, struct LatLon ll_tl, struct LatLon ll_br, guint width, guint height, gdouble *xmpp, gdouble *ympp )
367{
368 struct LatLon ll_tr;
369 ll_tr.lat = ll_tl.lat;
370 ll_tr.lon = ll_br.lon;
371
372 struct LatLon ll_bl;
373 ll_bl.lat = ll_br.lat;
374 ll_bl.lon = ll_tl.lon;
375
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
381
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;
387 }
388
389 gdouble diffx = a_coords_latlon_diff ( &ll_tl, &ll_tr );
390 *xmpp = (diffx / width) / factor;
391
392 gdouble diffy = a_coords_latlon_diff ( &ll_tl, &ll_bl );
393 *ympp = (diffy / height) / factor;
394}
395
fd22ce3e 396static void georef_layer_draw ( VikGeorefLayer *vgl, VikViewport *vp )
50a14534 397{
50a14534
EB
398 if ( vgl->pixbuf )
399 {
50a14534 400 gdouble xmpp = vik_viewport_get_xmpp(vp), ympp = vik_viewport_get_ympp(vp);
be75ec20
MR
401 GdkPixbuf *pixbuf = vgl->pixbuf;
402 guint layer_width = vgl->width;
403 guint layer_height = vgl->height;
404
be75ec20
MR
405 guint width = vik_viewport_get_width(vp), height = vik_viewport_get_height(vp);
406 gint32 x, y;
be75ec20
MR
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 );
1b4b9e3b
RN
410
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 )
414 {
415 scale = TRUE;
416 layer_width = round(vgl->width * vgl->mpp_easting / xmpp);
417 layer_height = round(vgl->height * vgl->mpp_northing / ympp);
418 }
419
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 ) {
422
423 if ( scale )
424 {
425 /* rescale if necessary */
426 if (layer_width == vgl->scaled_width && layer_height == vgl->scaled_height && vgl->scaled != NULL)
427 pixbuf = vgl->scaled;
428 else
429 {
430 pixbuf = gdk_pixbuf_scale_simple(
431 vgl->pixbuf,
432 layer_width,
433 layer_height,
434 GDK_INTERP_BILINEAR
435 );
436
437 if (vgl->scaled != NULL)
438 g_object_unref(vgl->scaled);
439
440 vgl->scaled = pixbuf;
441 vgl->scaled_width = layer_width;
442 vgl->scaled_height = layer_height;
443 }
444 }
be75ec20 445 vik_viewport_draw_pixbuf ( vp, pixbuf, 0, 0, x, y, layer_width, layer_height ); /* todo: draw only what we need to. */
1b4b9e3b 446 }
50a14534
EB
447 }
448}
449
450static void georef_layer_free ( VikGeorefLayer *vgl )
451{
452 if ( vgl->image != NULL )
453 g_free ( vgl->image );
f3505ea3
MR
454 if ( vgl->scaled != NULL )
455 g_object_unref ( vgl->scaled );
50a14534
EB
456}
457
a6b90ba4 458static VikGeorefLayer *georef_layer_create ( VikViewport *vp )
50a14534 459{
a7023a1b 460 return georef_layer_new ( vp );
50a14534
EB
461}
462
a6b90ba4 463static gboolean georef_layer_properties ( VikGeorefLayer *vgl, gpointer vp )
50a14534 464{
f6d4661b 465 return georef_layer_dialog ( vgl, vp, VIK_GTK_WINDOW_FROM_WIDGET(vp) );
50a14534
EB
466}
467
fd22ce3e 468static void georef_layer_load_image ( VikGeorefLayer *vgl, VikViewport *vp, gboolean from_file )
50a14534
EB
469{
470 GError *gx = NULL;
471 if ( vgl->image == NULL )
472 return;
473
474 if ( vgl->pixbuf )
475 g_object_unref ( G_OBJECT(vgl->pixbuf) );
f3505ea3
MR
476 if ( vgl->scaled )
477 {
478 g_object_unref ( G_OBJECT(vgl->scaled) );
479 vgl->scaled = NULL;
480 }
50a14534
EB
481
482 vgl->pixbuf = gdk_pixbuf_new_from_file ( vgl->image, &gx );
483
484 if (gx)
485 {
28424566
RN
486 if ( !from_file )
487 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(vp), _("Couldn't open image file: %s"), gx->message );
50a14534
EB
488 g_error_free ( gx );
489 }
490 else
491 {
492 vgl->width = gdk_pixbuf_get_width ( vgl->pixbuf );
493 vgl->height = gdk_pixbuf_get_height ( vgl->pixbuf );
b7a0cc40
RN
494
495 if ( vgl->pixbuf && vgl->alpha < 255 )
496 vgl->pixbuf = ui_pixbuf_set_alpha ( vgl->pixbuf, vgl->alpha );
50a14534 497 }
50a14534
EB
498 /* should find length and width here too */
499}
500
501static void georef_layer_set_image ( VikGeorefLayer *vgl, const gchar *image )
502{
503 if ( vgl->image )
504 g_free ( vgl->image );
f3505ea3
MR
505 if ( vgl->scaled )
506 {
507 g_object_unref ( vgl->scaled );
508 vgl->scaled = NULL;
509 }
50a14534
EB
510 if ( image == NULL )
511 vgl->image = NULL;
1b14d0d2
RN
512
513 if ( g_strcmp0 (image, "") != 0 )
514 vgl->image = vu_get_canonical_filename ( VIK_LAYER(vgl), image );
515 else
516 vgl->image = g_strdup (image);
50a14534
EB
517}
518
92e8adf5
RN
519// Only positive values allowed here
520static void gdouble2spinwidget ( GtkWidget *widget, gdouble val )
50a14534 521{
92e8adf5
RN
522 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(widget), val > 0 ? val : -val );
523}
524
525static void set_widget_values ( changeable_widgets *cw, gdouble values[4] )
526{
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] );
531}
532
533static gboolean world_file_read_line ( FILE *ff, gdouble *value, gboolean use_value )
534{
535 gboolean answer = TRUE; // Success
536 gchar buffer[1024];
537 if ( !fgets ( buffer, 1024, ff ) ) {
538 answer = FALSE;
50a14534 539 }
92e8adf5
RN
540 if ( answer && use_value )
541 *value = g_strtod ( buffer, NULL );
542
543 return answer;
544}
545
546/**
547 * http://en.wikipedia.org/wiki/World_file
548 *
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
553 */
554static gint world_file_read_file ( const gchar* filename, gdouble values[4] )
555{
556 g_debug ("%s - trying world file %s", __FUNCTION__, filename);
557
558 FILE *f = g_fopen ( filename, "r" );
559 if ( !f )
560 return 1;
561 else {
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
570 )
571 {
572 // Success
573 g_debug ("%s - %s - world file read success", __FUNCTION__, filename);
574 answer = 0;
575 }
576 fclose ( f );
577 return answer;
50a14534 578 }
50a14534
EB
579}
580
92e8adf5 581static void georef_layer_dialog_load ( changeable_widgets *cw )
50a14534 582{
6e4a49aa
MA
583 GtkWidget *file_selector = gtk_file_chooser_dialog_new (_("Choose World file"),
584 NULL,
585 GTK_FILE_CHOOSER_ACTION_OPEN,
586 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
587 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
588 NULL);
589
590 if ( gtk_dialog_run ( GTK_DIALOG ( file_selector ) ) == GTK_RESPONSE_ACCEPT )
50a14534 591 {
92e8adf5
RN
592 gdouble values[4];
593 gint answer = world_file_read_file ( gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_selector)), values );
594 if ( answer == 1 )
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.") );
598 else
599 // NB answer should == 0 for success
600 set_widget_values ( cw, values );
50a14534 601 }
92e8adf5
RN
602
603 gtk_widget_destroy ( file_selector );
50a14534
EB
604}
605
606static void georef_layer_export_params ( gpointer *pass_along[2] )
607{
608 VikGeorefLayer *vgl = VIK_GEOREF_LAYER(pass_along[0]);
6e4a49aa
MA
609 GtkWidget *file_selector = gtk_file_chooser_dialog_new (_("Choose World file"),
610 NULL,
611 GTK_FILE_CHOOSER_ACTION_SAVE,
612 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
613 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
614 NULL);
615 if ( gtk_dialog_run ( GTK_DIALOG ( file_selector ) ) == GTK_RESPONSE_ACCEPT )
50a14534 616 {
8c060406 617 FILE *f = g_fopen ( gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER(file_selector) ), "w" );
6e4a49aa 618
50a14534
EB
619 gtk_widget_destroy ( file_selector );
620 if ( !f )
621 {
4c77d5e0 622 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(pass_along[0]), _("The file you requested could not be opened for writing.") );
50a14534
EB
623 return;
624 }
625 else
626 {
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 );
628 fclose ( f );
8c060406 629 f = NULL;
50a14534
EB
630 }
631 }
632 else
633 gtk_widget_destroy ( file_selector );
634}
635
3bd57299
RN
636/**
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.
640 */
641static void maybe_read_world_file ( VikFileEntry *vfe, gpointer user_data )
642{
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));
645 gdouble values[4];
646 if ( filename && user_data ) {
647
648 changeable_widgets *cw = user_data;
649
650 gboolean upper = g_ascii_isupper (filename[strlen(filename)-1]);
651 gchar* filew = g_strconcat ( filename, (upper ? "W" : "w") , NULL );
652
653 if ( world_file_read_file ( filew, values ) == 0 ) {
654 set_widget_values ( cw, values );
655 }
656 else {
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 );
662 }
663 g_free ( file1 );
664 g_free ( file0 );
665 }
666 }
667 g_free ( filew );
668 }
669 }
670}
671
69c4125a
RN
672static struct LatLon get_ll_tl (VikGeorefLayer *vgl)
673{
674 struct LatLon ll_tl;
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) );
677 return ll_tl;
678}
679
680static struct LatLon get_ll_br (VikGeorefLayer *vgl)
681{
682 struct LatLon ll_br;
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) );
685 return ll_br;
686}
687
688// Align displayed UTM values with displayed Lat/Lon values
689static void align_utm2ll (VikGeorefLayer *vgl)
690{
691 struct LatLon ll_tl = get_ll_tl (vgl);
692
693 struct UTM utm;
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 );
697
698 gchar tmp_letter[2];
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 );
702
703 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.utm_zone_spin), utm.zone );
704}
705
706// Align displayed Lat/Lon values with displayed UTM values
707static void align_ll2utm (VikGeorefLayer *vgl)
708{
709 struct UTM corner;
710 const gchar *letter = gtk_entry_get_text ( GTK_ENTRY(vgl->cw.utm_letter_entry) );
711 if (*letter)
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) );
716
717 struct LatLon ll;
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 );
721}
722
723/**
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.
728 */
729static void align_coords ( VikGeorefLayer *vgl )
730{
731 if (gtk_notebook_get_current_page(GTK_NOTEBOOK(vgl->cw.tabs)) == 0)
732 align_ll2utm ( vgl );
733 else
734 align_utm2ll ( vgl );
735}
736
737static void switch_tab (GtkNotebook *notebook, gpointer tab, guint tab_num, gpointer user_data)
738{
739 VikGeorefLayer *vgl = user_data;
740 if ( tab_num == 0 )
741 align_utm2ll (vgl);
742 else
743 align_ll2utm (vgl);
744}
745
746/**
747 *
748 */
749static void check_br_is_good_or_msg_user ( VikGeorefLayer *vgl )
750{
751 // if a 'blank' ll value that's alright
752 if ( vgl->ll_br.lat == 0.0 && vgl->ll_br.lon == 0.0 )
753 return;
754
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") );
758}
759
760/**
761 *
762 */
763static void calculate_mpp_from_coords ( GtkWidget *ww, VikGeorefLayer *vgl )
764{
765 const gchar* filename = vik_file_entry_get_filename(VIK_FILE_ENTRY(vgl->cw.imageentry));
766 if ( !filename ) {
767 return;
768 }
769 GError *gx = NULL;
770 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( filename, &gx );
771 if ( gx ) {
772 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(ww), _("Couldn't open image file: %s"), gx->message );
773 g_error_free ( gx );
774 return;
775 }
776
777 guint width = gdk_pixbuf_get_width ( pixbuf );
778 guint height = gdk_pixbuf_get_height ( pixbuf );
779
780 if ( width == 0 || height == 0 ) {
781 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(ww), _("Invalid image size: %s"), filename);
782 }
783 else {
784 align_coords ( vgl );
785
786 struct LatLon ll_tl = get_ll_tl (vgl);
787 struct LatLon ll_br = get_ll_br (vgl);
788
f783290c
RN
789 gdouble xmpp, ympp;
790 georef_layer_mpp_from_coords ( VIK_COORD_LATLON, ll_tl, ll_br, width, height, &xmpp, &ympp );
69c4125a
RN
791
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 );
794
795 check_br_is_good_or_msg_user ( vgl );
796 }
797
798 g_object_unref ( G_OBJECT(pixbuf) );
799}
800
801#define VIK_SETTINGS_GEOREF_TAB "georef_coordinate_tab"
802
50a14534 803/* returns TRUE if OK was pressed. */
f6d4661b 804static gboolean georef_layer_dialog ( VikGeorefLayer *vgl, gpointer vp, GtkWindow *w )
50a14534 805{
4c77d5e0 806 GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Layer Properties"),
50a14534
EB
807 w,
808 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
809 GTK_STOCK_CANCEL,
810 GTK_RESPONSE_REJECT,
811 GTK_STOCK_OK,
812 GTK_RESPONSE_ACCEPT,
10888930 813 NULL );
535747e9
RN
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 );
819#endif
69c4125a 820 GtkWidget *table, *wfp_hbox, *wfp_label, *wfp_button, *ce_label, *cn_label, *xlabel, *ylabel, *imagelabel;
92e8adf5 821 changeable_widgets cw;
50a14534 822
69c4125a
RN
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 );
50a14534
EB
826
827 wfp_hbox = gtk_hbox_new ( FALSE, 0 );
4c77d5e0
GB
828 wfp_label = gtk_label_new ( _("World File Parameters:") );
829 wfp_button = gtk_button_new_with_label ( _("Load From File...") );
50a14534
EB
830
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 );
833
4c77d5e0 834 ce_label = gtk_label_new ( _("Corner pixel easting:") );
92e8adf5
RN
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") );
50a14534 837
4c77d5e0 838 cn_label = gtk_label_new ( _("Corner pixel northing:") );
92e8adf5
RN
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") );
50a14534 841
4c77d5e0
GB
842 xlabel = gtk_label_new ( _("X (easting) scale (mpp): "));
843 ylabel = gtk_label_new ( _("Y (northing) scale (mpp): "));
50a14534 844
92e8adf5
RN
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)") );
50a14534 849
4c77d5e0 850 imagelabel = gtk_label_new ( _("Map Image:") );
69c4125a 851 cw.imageentry = vik_file_entry_new (GTK_FILE_CHOOSER_ACTION_OPEN, VF_FILTER_IMAGE, maybe_read_world_file, &cw);
50a14534 852
92e8adf5
RN
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 );
f6d4661b 857 if ( vgl->image )
69c4125a 858 vik_file_entry_set_filename ( VIK_FILE_ENTRY(cw.imageentry), vgl->image );
50a14534
EB
859
860 gtk_table_attach_defaults ( GTK_TABLE(table), imagelabel, 0, 1, 0, 1 );
69c4125a 861 gtk_table_attach_defaults ( GTK_TABLE(table), cw.imageentry, 1, 2, 0, 1 );
50a14534
EB
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 );
92e8adf5 864 gtk_table_attach_defaults ( GTK_TABLE(table), cw.x_spin, 1, 2, 2, 3 );
50a14534 865 gtk_table_attach_defaults ( GTK_TABLE(table), ylabel, 0, 1, 3, 4 );
92e8adf5 866 gtk_table_attach_defaults ( GTK_TABLE(table), cw.y_spin, 1, 2, 3, 4 );
69c4125a
RN
867
868 cw.tabs = gtk_notebook_new();
869 GtkWidget *table_utm = gtk_table_new ( 3, 2, FALSE );
870
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 );
875
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 );
884 gchar tmp_letter[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 );
889
890 gtk_table_attach_defaults ( GTK_TABLE(table_utm), utm_hbox, 0, 2, 2, 3 );
891
892 // Lat/Lon
893 GtkWidget *table_ll = gtk_table_new ( 5, 2, FALSE );
894
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 );
903
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 );
912
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 );
916
917 VikCoord vc;
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 );
923
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 );
927
b7a0cc40
RN
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 );
936
69c4125a
RN
937 vgl->cw = cw;
938
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 );
50a14534 941
92e8adf5 942 g_signal_connect_swapped ( G_OBJECT(wfp_button), "clicked", G_CALLBACK(georef_layer_dialog_load), &cw );
50a14534 943
535747e9
RN
944 if ( response_w )
945 gtk_widget_grab_focus ( response_w );
946
69c4125a
RN
947 gtk_widget_show_all ( dialog );
948
949 // Remember setting the notebook page must be done after the widget is visible.
950 gint page_num = 0;
951 if ( a_settings_get_integer ( VIK_SETTINGS_GEOREF_TAB, &page_num ) )
952 if ( page_num < 0 || page_num > 1 )
953 page_num = 0;
954 gtk_notebook_set_current_page ( GTK_NOTEBOOK(cw.tabs), page_num );
50a14534
EB
955
956 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
957 {
69c4125a
RN
958 align_coords ( vgl );
959
92e8adf5
RN
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) );
69c4125a
RN
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) );
964 if (*letter)
965 vgl->corner.letter = toupper(*letter);
92e8adf5
RN
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) );
69c4125a
RN
968 vgl->ll_br = get_ll_br (vgl);
969 check_br_is_good_or_msg_user ( vgl );
584cb1cf
RN
970 // TODO check if image has changed otherwise no need to regenerate pixbuf
971 if ( !vgl->pixbuf )
50a14534 972 {
584cb1cf
RN
973 if ( g_strcmp0 (vgl->image, vik_file_entry_get_filename(VIK_FILE_ENTRY(cw.imageentry)) ) != 0 )
974 {
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 );
977 }
50a14534
EB
978 }
979
b7a0cc40
RN
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 );
985
69c4125a
RN
986 a_settings_set_integer ( VIK_SETTINGS_GEOREF_TAB, gtk_notebook_get_current_page(GTK_NOTEBOOK(cw.tabs)) );
987
50a14534
EB
988 gtk_widget_destroy ( GTK_WIDGET(dialog) );
989 return TRUE;
990 }
991 gtk_widget_destroy ( GTK_WIDGET(dialog) );
992 return FALSE;
993}
994
995static void georef_layer_zoom_to_fit ( gpointer vgl_vlp[2] )
996{
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]) );
1000}
1001
1002static void georef_layer_goto_center ( gpointer vgl_vlp[2] )
1003{
1004 VikGeorefLayer *vgl = VIK_GEOREF_LAYER ( vgl_vlp[0] );
1005 VikViewport *vp = vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1]));
1006 struct UTM utm;
1007 VikCoord coord;
1008
1009 vik_coord_to_utm ( vik_viewport_get_center ( vp ), &utm );
1010
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);
1013
1014 vik_coord_load_from_utm ( &coord, vik_viewport_get_coord_mode ( vp ), &utm );
be5554c5 1015 vik_viewport_set_center_coord ( vp, &coord, TRUE );
50a14534
EB
1016
1017 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vgl_vlp[1]) );
1018}
1019
1020static void georef_layer_add_menu_items ( VikGeorefLayer *vgl, GtkMenu *menu, gpointer vlp )
1021{
1022 static gpointer pass_along[2];
1023 GtkWidget *item;
1024 pass_along[0] = vgl;
1025 pass_along[1] = vlp;
1026
1027 item = gtk_menu_item_new();
1028 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1029 gtk_widget_show ( item );
1030
d6de71f9
RN
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) );
50a14534
EB
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 );
1037
d6de71f9
RN
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) );
50a14534
EB
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 );
1043
d6de71f9
RN
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) );
50a14534
EB
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 );
1049}
1050
941aa6e9
AF
1051
1052static gpointer georef_layer_move_create ( VikWindow *vw, VikViewport *vvp)
1053{
1054 return vvp;
1055}
1056
50a14534
EB
1057static gboolean georef_layer_move_release ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
1058{
941aa6e9
AF
1059 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
1060 return FALSE;
1061
50a14534
EB
1062 if ( vgl->click_x != -1 )
1063 {
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);
da121f9b 1066 vik_layer_emit_update ( VIK_LAYER(vgl) );
50a14534
EB
1067 return TRUE;
1068 }
1069 return FALSE; /* I didn't move anything on this layer! */
1070}
1071
941aa6e9
AF
1072static gpointer georef_layer_zoom_create ( VikWindow *vw, VikViewport *vvp)
1073{
1074 return vvp;
1075}
1076
50a14534
EB
1077static gboolean georef_layer_zoom_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
1078{
941aa6e9
AF
1079 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
1080 return FALSE;
50a14534
EB
1081 if ( event->button == 1 )
1082 {
1083 if ( vgl->mpp_easting < (VIK_VIEWPORT_MAX_ZOOM / 1.05) && vgl->mpp_northing < (VIK_VIEWPORT_MAX_ZOOM / 1.05) )
1084 {
1085 vgl->mpp_easting *= 1.01;
1086 vgl->mpp_northing *= 1.01;
1087 }
1088 }
1089 else
1090 {
1091 if ( vgl->mpp_easting > (VIK_VIEWPORT_MIN_ZOOM * 1.05) && vgl->mpp_northing > (VIK_VIEWPORT_MIN_ZOOM * 1.05) )
1092 {
1093 vgl->mpp_easting /= 1.01;
1094 vgl->mpp_northing /= 1.01;
1095 }
1096 }
1097 vik_viewport_set_xmpp ( vvp, vgl->mpp_easting );
1098 vik_viewport_set_ympp ( vvp, vgl->mpp_northing );
da121f9b 1099 vik_layer_emit_update ( VIK_LAYER(vgl) );
50a14534
EB
1100 return TRUE;
1101}
1102
1103static gboolean georef_layer_move_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
1104{
941aa6e9
AF
1105 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
1106 return FALSE;
50a14534
EB
1107 vgl->click_x = event->x;
1108 vgl->click_y = event->y;
1109 return TRUE;
1110}
584cb1cf
RN
1111
1112static void goto_center_ll ( VikViewport *vp,
1113 struct LatLon ll_tl,
1114 struct LatLon ll_br )
1115{
1116 VikCoord vc_center;
1117 struct LatLon ll_center;
1118
1119 ll_center.lat = (ll_tl.lat + ll_br.lat) / 2.0;
1120 ll_center.lon = (ll_tl.lon + ll_br.lon) / 2.0;
1121
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 );
1124}
1125
1126/**
1127 *
1128 */
1129VikGeorefLayer *vik_georef_layer_create ( VikViewport *vp,
1130 VikLayersPanel *vlp,
1131 const gchar *name,
1132 GdkPixbuf *pixbuf,
1133 VikCoord *coord_tl,
1134 VikCoord *coord_br )
1135{
1136 VikGeorefLayer *vgl = georef_layer_new ( vp );
1137 vik_layer_rename ( VIK_LAYER(vgl), name );
1138
1139 vgl->pixbuf = pixbuf;
1140
1141 vik_coord_to_utm ( coord_tl, &(vgl->corner) );
1142 vik_coord_to_latlon ( coord_br, &(vgl->ll_br) );
1143
1144 if ( vgl->pixbuf ) {
1145 vgl->width = gdk_pixbuf_get_width ( vgl->pixbuf );
1146 vgl->height = gdk_pixbuf_get_height ( vgl->pixbuf );
1147
1148 if ( vgl->width > 0 && vgl->height > 0 ) {
1149
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);
1154
1155 VikCoordMode mode = vik_viewport_get_coord_mode (vp);
1156
1157 gdouble xmpp, ympp;
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;
1161
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 );
1166
1167 return vgl;
1168 }
1169 }
1170
1171 // Bad image
1172 georef_layer_free ( vgl );
1173 return NULL;
1174}