From e1dde2a674348cf8d8805242561df4b0aab55490 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sat, 9 Mar 2013 10:29:46 +0000 Subject: [PATCH] Extend map scales down to support 1/32 zoom level. Refactor all usage of 'GZ()' and *_mpp_to_scale() to use common definitions. Including the addition of map_utils_mpp_to_zoom_level() and use it with WebToolCenter. --- src/Makefile.am | 1 + src/bingmapsource.c | 3 +- src/maputils.c | 74 ++++++++++++++++++++++++++++++++++++++++ src/maputils.h | 30 ++++++++++++++++ src/vikslippymapsource.c | 44 +++++------------------- src/vikslippymapsource.h | 2 -- src/viktmsmapsource.c | 49 ++++++-------------------- src/vikwebtoolcenter.c | 29 +++------------- src/vikwmscmapsource.c | 59 +++++++++----------------------- 9 files changed, 146 insertions(+), 145 deletions(-) create mode 100644 src/maputils.c create mode 100644 src/maputils.h diff --git a/src/Makefile.am b/src/Makefile.am index af17ff66..14976f3f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -90,6 +90,7 @@ libviking_a_SOURCES = \ vikradiogroup.c vikradiogroup.h \ vikcoord.c vikcoord.h \ mapcache.c mapcache.h \ + maputils.c maputils.h \ vikmapsource.c vikmapsource.h \ vikmapsourcedefault.c vikmapsourcedefault.h \ vikmapslayer.c vikmapslayer.h \ diff --git a/src/bingmapsource.c b/src/bingmapsource.c index cf72e214..81ba1fd4 100644 --- a/src/bingmapsource.c +++ b/src/bingmapsource.c @@ -47,6 +47,7 @@ #include #include "globals.h" #include "bingmapsource.h" +#include "maputils.h" #include "bbox.h" #include "background.h" #include "icons/icons.h" @@ -238,7 +239,7 @@ _get_copyright(VikMapSource * self, LatLonBBox bbox, gdouble zoom, void (*fct)(V BingMapSourcePrivate *priv = BING_MAP_SOURCE_GET_PRIVATE(self); - int level = vik_slippy_map_source_zoom_to_scale (zoom); + int level = map_utils_mpp_to_scale (zoom); /* Loop over all known attributions */ GList *attribution = priv->attributions; diff --git a/src/maputils.c b/src/maputils.c new file mode 100644 index 00000000..fa576b29 --- /dev/null +++ b/src/maputils.c @@ -0,0 +1,74 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ +/* + * viking -- GPS Data and Topo Analyzer, Explorer, and Manager + * + * Copyright (C) 2013, Rob Norris + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include "maputils.h" + +// World Scale: VIK_GZ(17) +// down to +// Submeter scale: 1/VIK_GZ(5) +// No map provider is going to have tiles at the highest zoom in level - but we can interpolate to that. + +static const gdouble scale_mpps[] = { VIK_GZ(0), VIK_GZ(1), VIK_GZ(2), VIK_GZ(3), VIK_GZ(4), VIK_GZ(5), + VIK_GZ(6), VIK_GZ(7), VIK_GZ(8), VIK_GZ(9), VIK_GZ(10), VIK_GZ(11), + VIK_GZ(12), VIK_GZ(13), VIK_GZ(14), VIK_GZ(15), VIK_GZ(16), VIK_GZ(17) }; +static const gint num_scales = (sizeof(scale_mpps) / sizeof(scale_mpps[0])); + +static const gdouble scale_neg_mpps[] = { 1.0/VIK_GZ(0), 1.0/VIK_GZ(1), 1.0/VIK_GZ(2), + 1.0/VIK_GZ(3), 1.0/VIK_GZ(4), 1.0/VIK_GZ(5) }; +static const gint num_scales_neg = (sizeof(scale_neg_mpps) / sizeof(scale_neg_mpps[0])); + +#define ERROR_MARGIN 0.01 +/** + * map_utils_mpp_to_scale: + * @mpp: The so called 'mpp' + * + * Returns: the zoom scale value which may be negative. + */ +gint map_utils_mpp_to_scale ( gdouble mpp ) { + gint i; + for ( i = 0; i < num_scales; i++ ) { + if ( ABS(scale_mpps[i] - mpp) < ERROR_MARGIN ) { + return i; + } + } + for ( i = 0; i < num_scales_neg; i++ ) { + if ( ABS(scale_neg_mpps[i] - mpp) < 0.000001 ) { + return -i; + } + } + + return 255; +} + +/** + * map_utils_mpp_to_zoom_level: + * @mpp: The so called 'mpp' + * + * Returns: a Zoom Level + * See: http://wiki.openstreetmap.org/wiki/Zoom_levels + */ +guint8 map_utils_mpp_to_zoom_level ( gdouble mpp ) +{ + gint answer = 17 - map_utils_mpp_to_scale ( mpp ); + if ( answer < 0 ) + answer = 17; + return answer; +} diff --git a/src/maputils.h b/src/maputils.h new file mode 100644 index 00000000..97a1634a --- /dev/null +++ b/src/maputils.h @@ -0,0 +1,30 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ +/* + * viking -- GPS Data and Topo Analyzer, Explorer, and Manager + * + * Copyright (C) 2013, Rob Norris + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include + +/* 1 << (x) is like a 2**(x) */ +#define VIK_GZ(x) ((1<<(x))) +// Not sure what GZ stands for probably Google Zoom + +gint map_utils_mpp_to_scale ( gdouble mpp ); + +guint8 map_utils_mpp_to_zoom_level ( gdouble mpp ); diff --git a/src/vikslippymapsource.c b/src/vikslippymapsource.c index 0fd926bf..f2971dcd 100644 --- a/src/vikslippymapsource.c +++ b/src/vikslippymapsource.c @@ -51,6 +51,7 @@ #include "globals.h" #include "vikslippymapsource.h" +#include "maputils.h" static gboolean _coord_to_mapcoord ( VikMapSource *self, const VikCoord *src, gdouble xzoom, gdouble yzoom, MapCoord *dest ); static void _mapcoord_to_center_coord ( VikMapSource *self, MapCoord *src, VikCoord *dest ); @@ -299,35 +300,6 @@ vik_slippy_map_source_class_init (VikSlippyMapSourceClass *klass) object_class->finalize = vik_slippy_map_source_finalize; } -/* 1 << (x) is like a 2**(x) */ -#define GZ(x) ((1<<(x))) - -static const gdouble scale_mpps[] = { GZ(0), GZ(1), GZ(2), GZ(3), GZ(4), GZ(5), GZ(6), GZ(7), GZ(8), GZ(9), - GZ(10), GZ(11), GZ(12), GZ(13), GZ(14), GZ(15), GZ(16), GZ(17) }; - -static const gint num_scales = (sizeof(scale_mpps) / sizeof(scale_mpps[0])); - -static const gdouble scale_neg_mpps[] = { 1.0/GZ(0), 1.0/GZ(1), 1.0/GZ(2), 1.0/GZ(3) }; -static const gint num_scales_neg = (sizeof(scale_neg_mpps) / sizeof(scale_neg_mpps[0])); - -#define ERROR_MARGIN 0.01 -gint -vik_slippy_map_source_zoom_to_scale ( gdouble mpp ) { - gint i; - for ( i = 0; i < num_scales; i++ ) { - if ( ABS(scale_mpps[i] - mpp) < ERROR_MARGIN ) { - return i; - } - } - for ( i = 0; i < num_scales_neg; i++ ) { - if ( ABS(scale_neg_mpps[i] - mpp) < 0.000001 ) { - return -i; - } - } - - return 255; -} - gboolean _is_direct_file_access (VikMapSource *self) { @@ -356,12 +328,12 @@ _coord_to_mapcoord ( VikMapSource *self, const VikCoord *src, gdouble xzoom, gdo if ( xzoom != yzoom ) return FALSE; - dest->scale = vik_slippy_map_source_zoom_to_scale ( xzoom ); + dest->scale = map_utils_mpp_to_scale ( xzoom ); if ( dest->scale == 255 ) return FALSE; - dest->x = (src->east_west + 180) / 360 * GZ(17) / xzoom; - dest->y = (180 - MERCLAT(src->north_south)) / 360 * GZ(17) / xzoom; + dest->x = (src->east_west + 180) / 360 * VIK_GZ(17) / xzoom; + dest->y = (180 - MERCLAT(src->north_south)) / 360 * VIK_GZ(17) / xzoom; dest->z = 0; return TRUE; @@ -372,12 +344,12 @@ _mapcoord_to_center_coord ( VikMapSource *self, MapCoord *src, VikCoord *dest ) { gdouble socalled_mpp; if (src->scale >= 0) - socalled_mpp = GZ(src->scale); + socalled_mpp = VIK_GZ(src->scale); else - socalled_mpp = 1.0/GZ(-src->scale); + socalled_mpp = 1.0/VIK_GZ(-src->scale); dest->mode = VIK_COORD_LATLON; - dest->east_west = ((src->x+0.5) / GZ(17) * socalled_mpp * 360) - 180; - dest->north_south = DEMERCLAT(180 - ((src->y+0.5) / GZ(17) * socalled_mpp * 360)); + dest->east_west = ((src->x+0.5) / VIK_GZ(17) * socalled_mpp * 360) - 180; + dest->north_south = DEMERCLAT(180 - ((src->y+0.5) / VIK_GZ(17) * socalled_mpp * 360)); } static gchar * diff --git a/src/vikslippymapsource.h b/src/vikslippymapsource.h index bbb53c1e..a39d2f33 100644 --- a/src/vikslippymapsource.h +++ b/src/vikslippymapsource.h @@ -49,8 +49,6 @@ struct _VikSlippyMapSource GType vik_slippy_map_source_get_type (void) G_GNUC_CONST; VikSlippyMapSource * vik_slippy_map_source_new_with_id (guint8 id, const gchar *label, const gchar *hostname, const gchar *url); -gint vik_slippy_map_source_zoom_to_scale ( gdouble mpp ); - G_END_DECLS diff --git a/src/viktmsmapsource.c b/src/viktmsmapsource.c index afaed4de..674a5f2d 100644 --- a/src/viktmsmapsource.c +++ b/src/viktmsmapsource.c @@ -43,6 +43,7 @@ #include "globals.h" #include "viktmsmapsource.h" +#include "maputils.h" static gboolean _coord_to_mapcoord ( VikMapSource *self, const VikCoord *src, gdouble xzoom, gdouble yzoom, MapCoord *dest ); static void _mapcoord_to_center_coord ( VikMapSource *self, MapCoord *src, VikCoord *dest ); @@ -255,34 +256,6 @@ vik_tms_map_source_class_init (VikTmsMapSourceClass *klass) object_class->finalize = vik_tms_map_source_finalize; } -/* 1 << (x) is like a 2**(x) */ -#define GZ(x) ((1<<(x))) - -static const gdouble scale_mpps[] = { GZ(0), GZ(1), GZ(2), GZ(3), GZ(4), GZ(5), GZ(6), GZ(7), GZ(8), GZ(9), - GZ(10), GZ(11), GZ(12), GZ(13), GZ(14), GZ(15), GZ(16), GZ(17) }; - -static const gint num_scales = (sizeof(scale_mpps) / sizeof(scale_mpps[0])); - -static const gdouble scale_neg_mpps[] = { 1.0/GZ(0), 1.0/GZ(1), 1.0/GZ(2), 1.0/GZ(3) }; -static const gint num_scales_neg = (sizeof(scale_neg_mpps) / sizeof(scale_neg_mpps[0])); - -#define ERROR_MARGIN 0.01 -static gint tms_zoom ( gdouble mpp ) { - gint i; - for ( i = 0; i < num_scales; i++ ) { - if ( ABS(scale_mpps[i] - mpp) < ERROR_MARGIN ) { - return i; - } - } - for ( i = 0; i < num_scales_neg; i++ ) { - if ( ABS(scale_neg_mpps[i] - mpp) < 0.000001 ) { - return -i; - } - } - - return 255; -} - static gboolean _is_direct_file_access ( VikMapSource *self ) { @@ -307,18 +280,18 @@ _coord_to_mapcoord ( VikMapSource *self, const VikCoord *src, gdouble xzoom, gdo if ( xzoom != yzoom ) return FALSE; - dest->scale = tms_zoom ( xzoom ); + dest->scale = map_utils_mpp_to_scale ( xzoom ); if ( dest->scale == 255 ) return FALSE; - /* Note : GZ(17) / xzoom / 2 = number of tile on Y axis */ + /* Note : VIK_GZ(17) / xzoom / 2 = number of tile on Y axis */ g_debug("%s: xzoom=%f yzoom=%f -> %f", __FUNCTION__, - xzoom, yzoom, GZ(17) / xzoom / 2); - dest->x = floor((src->east_west + 180) / 180 * GZ(17) / xzoom / 2); + xzoom, yzoom, VIK_GZ(17) / xzoom / 2); + dest->x = floor((src->east_west + 180) / 180 * VIK_GZ(17) / xzoom / 2); /* We should restore logic of viking: * tile index on Y axis follow a screen logic (top -> down) */ - dest->y = floor((180 - (src->north_south + 90)) / 180 * GZ(17) / xzoom / 2); + dest->y = floor((180 - (src->north_south + 90)) / 180 * VIK_GZ(17) / xzoom / 2); dest->z = 0; g_debug("%s: %f,%f -> %d,%d", __FUNCTION__, src->east_west, src->north_south, dest->x, dest->y); @@ -330,15 +303,15 @@ _mapcoord_to_center_coord ( VikMapSource *self, MapCoord *src, VikCoord *dest ) { gdouble socalled_mpp; if (src->scale >= 0) - socalled_mpp = GZ(src->scale); + socalled_mpp = VIK_GZ(src->scale); else - socalled_mpp = 1.0/GZ(-src->scale); + socalled_mpp = 1.0/VIK_GZ(-src->scale); dest->mode = VIK_COORD_LATLON; - dest->east_west = (src->x+0.5) * 180 / GZ(17) * socalled_mpp * 2 - 180; + dest->east_west = (src->x+0.5) * 180 / VIK_GZ(17) * socalled_mpp * 2 - 180; /* We should restore logic of viking: * tile index on Y axis follow a screen logic (top -> down) */ - dest->north_south = -((src->y+0.5) * 180 / GZ(17) * socalled_mpp * 2 - 90); + dest->north_south = -((src->y+0.5) * 180 / VIK_GZ(17) * socalled_mpp * 2 - 90); g_debug("%s: %d,%d -> %f,%f", __FUNCTION__, src->x, src->y, dest->east_west, dest->north_south); } @@ -354,7 +327,7 @@ _get_uri( VikMapSourceDefault *self, MapCoord *src ) */ /* Note : nb tiles on Y axis */ - gint nb_tiles = GZ(17 - src->scale - 1); + gint nb_tiles = VIK_GZ(17 - src->scale - 1); gchar *uri = g_strdup_printf (priv->url, 17 - src->scale - 1, src->x, nb_tiles - src->y - 1); diff --git a/src/vikwebtoolcenter.c b/src/vikwebtoolcenter.c index c3d9316e..0ea87f54 100644 --- a/src/vikwebtoolcenter.c +++ b/src/vikwebtoolcenter.c @@ -32,6 +32,7 @@ #include "util.h" #include "globals.h" +#include "maputils.h" static GObjectClass *parent_class; @@ -167,28 +168,8 @@ static void webtool_center_finalize ( GObject *gob ) G_OBJECT_CLASS(parent_class)->finalize(gob); } -/* 1 << (x) is like a 2**(x) */ -#define GZ(x) (1<<(x)) - -static const gdouble scale_mpps[] = { GZ(0), GZ(1), GZ(2), GZ(3), GZ(4), GZ(5), GZ(6), GZ(7), GZ(8), GZ(9), - GZ(10), GZ(11), GZ(12), GZ(13), GZ(14), GZ(15), GZ(16), GZ(17) }; - -static const gint num_scales = (sizeof(scale_mpps) / sizeof(scale_mpps[0])); - -#define ERROR_MARGIN 0.01 static guint8 webtool_center_mpp_to_zoom ( VikWebtool *self, gdouble mpp ) { - gint i; - for ( i = 0; i < num_scales; i++ ) { - if ( ABS(scale_mpps[i] - mpp) < ERROR_MARGIN ) { - g_debug ( "webtool_center_mpp_to_zoom: %f -> %d", mpp, i ); - return i; - } - } - // Handle mpp smaller than 1 - // return a useful value such that '17 - this number' gives a natural number. - // Ideally should return '-1' or '0.5' but that's tricky with an unsigned int type! - // (i.e. should rework to support zoom levels of 18 or 19) - return 0; + return map_utils_mpp_to_zoom_level ( mpp ); } static gchar *webtool_center_get_url ( VikWebtool *self, VikWindow *vwindow ) @@ -196,7 +177,7 @@ static gchar *webtool_center_get_url ( VikWebtool *self, VikWindow *vwindow ) VikWebtoolCenterPrivate *priv = NULL; VikViewport *viewport = NULL; const VikCoord *coord = NULL; - guint8 zoom = 0; + guint8 zoom = 17; struct LatLon ll; gchar strlat[G_ASCII_DTOSTR_BUF_SIZE], strlon[G_ASCII_DTOSTR_BUF_SIZE]; @@ -210,15 +191,13 @@ static gchar *webtool_center_get_url ( VikWebtool *self, VikWindow *vwindow ) // zoom - ideally x & y factors need to be the same otherwise use a default if ( vik_viewport_get_xmpp ( viewport ) == vik_viewport_get_ympp ( viewport ) ) zoom = vik_webtool_center_mpp_to_zoom ( self, vik_viewport_get_zoom ( viewport ) ); - else - zoom = 1.0; // Cannot simply use g_strdup_printf and gdouble due to locale. // As we compute an URL, we have to think in C locale. g_ascii_dtostr (strlat, G_ASCII_DTOSTR_BUF_SIZE, ll.lat); g_ascii_dtostr (strlon, G_ASCII_DTOSTR_BUF_SIZE, ll.lon); - return g_strdup_printf ( priv->url, strlat, strlon, 17-zoom ); + return g_strdup_printf ( priv->url, strlat, strlon, zoom ); } guint8 vik_webtool_center_mpp_to_zoom (VikWebtool *self, gdouble mpp) diff --git a/src/vikwmscmapsource.c b/src/vikwmscmapsource.c index d2744683..5b760312 100644 --- a/src/vikwmscmapsource.c +++ b/src/vikwmscmapsource.c @@ -36,6 +36,7 @@ #include "globals.h" #include "vikwmscmapsource.h" +#include "maputils.h" static gboolean _coord_to_mapcoord ( VikMapSource *self, const VikCoord *src, gdouble xzoom, gdouble yzoom, MapCoord *dest ); static void _mapcoord_to_center_coord ( VikMapSource *self, MapCoord *src, VikCoord *dest ); @@ -248,34 +249,6 @@ vik_wmsc_map_source_class_init (VikWmscMapSourceClass *klass) object_class->finalize = vik_wmsc_map_source_finalize; } -/* 1 << (x) is like a 2**(x) */ -#define GZ(x) ((1<scale = wmsc_zoom ( xzoom ); + dest->scale = map_utils_mpp_to_scale ( xzoom ); if ( dest->scale == 255 ) return FALSE; - /* Note : GZ(17) / xzoom / 2 = number of tile on Y axis */ + /* Note : VIK_GZ(17) / xzoom / 2 = number of tile on Y axis */ g_debug("%s: xzoom=%f yzoom=%f -> %f", __FUNCTION__, - xzoom, yzoom, GZ(17) / xzoom / 2); - dest->x = floor((src->east_west + 180) / 180 * GZ(17) / xzoom / 2); + xzoom, yzoom, VIK_GZ(17) / xzoom / 2); + dest->x = floor((src->east_west + 180) / 180 * VIK_GZ(17) / xzoom / 2); /* We should restore logic of viking: * tile index on Y axis follow a screen logic (top -> down) */ - dest->y = floor((180 - (src->north_south + 90)) / 180 * GZ(17) / xzoom / 2); + dest->y = floor((180 - (src->north_south + 90)) / 180 * VIK_GZ(17) / xzoom / 2); dest->z = 0; g_debug("%s: %f,%f -> %d,%d", __FUNCTION__, src->east_west, src->north_south, dest->x, dest->y); @@ -323,15 +296,15 @@ _mapcoord_to_center_coord ( VikMapSource *self, MapCoord *src, VikCoord *dest ) { gdouble socalled_mpp; if (src->scale >= 0) - socalled_mpp = GZ(src->scale); + socalled_mpp = VIK_GZ(src->scale); else - socalled_mpp = 1.0/GZ(-src->scale); + socalled_mpp = 1.0/VIK_GZ(-src->scale); dest->mode = VIK_COORD_LATLON; - dest->east_west = (src->x+0.5) * 180 / GZ(17) * socalled_mpp * 2 - 180; + dest->east_west = (src->x+0.5) * 180 / VIK_GZ(17) * socalled_mpp * 2 - 180; /* We should restore logic of viking: * tile index on Y axis follow a screen logic (top -> down) */ - dest->north_south = -((src->y+0.5) * 180 / GZ(17) * socalled_mpp * 2 - 90); + dest->north_south = -((src->y+0.5) * 180 / VIK_GZ(17) * socalled_mpp * 2 - 90); g_debug("%s: %d,%d -> %f,%f", __FUNCTION__, src->x, src->y, dest->east_west, dest->north_south); } @@ -344,16 +317,16 @@ _get_uri( VikMapSourceDefault *self, MapCoord *src ) VikWmscMapSourcePrivate *priv = VIK_WMSC_MAP_SOURCE_PRIVATE(self); gdouble socalled_mpp; if (src->scale >= 0) - socalled_mpp = GZ(src->scale); + socalled_mpp = VIK_GZ(src->scale); else - socalled_mpp = 1.0/GZ(-src->scale); - gdouble minx = (gdouble)src->x * 180 / GZ(17) * socalled_mpp * 2 - 180; - gdouble maxx = (gdouble)(src->x + 1) * 180 / GZ(17) * socalled_mpp * 2 - 180; + socalled_mpp = 1.0/VIK_GZ(-src->scale); + gdouble minx = (gdouble)src->x * 180 / VIK_GZ(17) * socalled_mpp * 2 - 180; + gdouble maxx = (gdouble)(src->x + 1) * 180 / VIK_GZ(17) * socalled_mpp * 2 - 180; /* We should restore logic of viking: * tile index on Y axis follow a screen logic (top -> down) */ - gdouble miny = -((gdouble)(src->y + 1) * 180 / GZ(17) * socalled_mpp * 2 - 90); - gdouble maxy = -((gdouble)(src->y) * 180 / GZ(17) * socalled_mpp * 2 - 90); + gdouble miny = -((gdouble)(src->y + 1) * 180 / VIK_GZ(17) * socalled_mpp * 2 - 90); + gdouble maxy = -((gdouble)(src->y) * 180 / VIK_GZ(17) * socalled_mpp * 2 - 90); gchar sminx[G_ASCII_DTOSTR_BUF_SIZE]; gchar smaxx[G_ASCII_DTOSTR_BUF_SIZE]; -- 2.39.5