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