]> git.street.me.uk Git - andy/viking.git/blame - src/maputils.c
Improve function comments as these don't return anything
[andy/viking.git] / src / maputils.c
CommitLineData
e1dde2a6
RN
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2/*
3 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 *
5ff65f40 5 * Copyright (C) 2013-2014, Rob Norris <rw_norris@hotmail.com>
e1dde2a6
RN
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#include "maputils.h"
39519ab8
RN
23#include "globals.h"
24#include <math.h>
e1dde2a6
RN
25
26// World Scale: VIK_GZ(17)
27// down to
28// Submeter scale: 1/VIK_GZ(5)
29// No map provider is going to have tiles at the highest zoom in level - but we can interpolate to that.
30
31static const gdouble scale_mpps[] = { VIK_GZ(0), VIK_GZ(1), VIK_GZ(2), VIK_GZ(3), VIK_GZ(4), VIK_GZ(5),
32 VIK_GZ(6), VIK_GZ(7), VIK_GZ(8), VIK_GZ(9), VIK_GZ(10), VIK_GZ(11),
33 VIK_GZ(12), VIK_GZ(13), VIK_GZ(14), VIK_GZ(15), VIK_GZ(16), VIK_GZ(17) };
34static const gint num_scales = (sizeof(scale_mpps) / sizeof(scale_mpps[0]));
35
36static const gdouble scale_neg_mpps[] = { 1.0/VIK_GZ(0), 1.0/VIK_GZ(1), 1.0/VIK_GZ(2),
37 1.0/VIK_GZ(3), 1.0/VIK_GZ(4), 1.0/VIK_GZ(5) };
38static const gint num_scales_neg = (sizeof(scale_neg_mpps) / sizeof(scale_neg_mpps[0]));
39
40#define ERROR_MARGIN 0.01
41/**
42 * map_utils_mpp_to_scale:
43 * @mpp: The so called 'mpp'
44 *
45 * Returns: the zoom scale value which may be negative.
46 */
47gint map_utils_mpp_to_scale ( gdouble mpp ) {
48 gint i;
49 for ( i = 0; i < num_scales; i++ ) {
50 if ( ABS(scale_mpps[i] - mpp) < ERROR_MARGIN ) {
51 return i;
52 }
53 }
54 for ( i = 0; i < num_scales_neg; i++ ) {
55 if ( ABS(scale_neg_mpps[i] - mpp) < 0.000001 ) {
56 return -i;
57 }
58 }
59
60 return 255;
61}
62
63/**
64 * map_utils_mpp_to_zoom_level:
65 * @mpp: The so called 'mpp'
66 *
67 * Returns: a Zoom Level
68 * See: http://wiki.openstreetmap.org/wiki/Zoom_levels
69 */
70guint8 map_utils_mpp_to_zoom_level ( gdouble mpp )
71{
72 gint answer = 17 - map_utils_mpp_to_scale ( mpp );
73 if ( answer < 0 )
74 answer = 17;
75 return answer;
76}
39519ab8
RN
77
78/**
79 * SECTION:maputils
80 * @short_description: Notes about TMS / Spherical Mercator conversion
81 *
82 * VikCoords are in Spherical Mercator projection (#VIK_COORD_LATLON)
83 * MapCoords are in Inverse TMS
84 *
85 * See: http://docs.openlayers.org/library/spherical_mercator.html
86 * See: http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification
87 * NB: the Y axis is inverted, ie the origin is at top-left corner.
88 */
89
90/**
91 * map_utils_vikcoord_to_iTMS:
92 * @src: Original #VikCoord in #VIK_COORD_LATLON format
93 * @xzoom: Viking zoom level in x direction
94 * @yzoom: Viking zoom level in y direction (actually needs to be same as xzoom)
95 * @dest: The resulting Inverse TMS coordinates in #MapCoord
96 *
97 * Convert a #VikCoord in VIK_COORD_LATLON format into Inverse TMS coordinates
98 *
99 * Returns: whether the conversion was performed
100 */
101gboolean map_utils_vikcoord_to_iTMS ( const VikCoord *src, gdouble xzoom, gdouble yzoom, MapCoord *dest )
102{
103 if ( src->mode != VIK_COORD_LATLON )
104 return FALSE;
105
106 if ( xzoom != yzoom )
107 return FALSE;
108
109 dest->scale = map_utils_mpp_to_scale ( xzoom );
110 if ( dest->scale == 255 )
111 return FALSE;
112
113 dest->x = (src->east_west + 180) / 360 * VIK_GZ(17) / xzoom;
114 dest->y = (180 - MERCLAT(src->north_south)) / 360 * VIK_GZ(17) / xzoom;
115 dest->z = 0;
116
117 return TRUE;
118}
119
120// Internal convenience function
121static void _to_vikcoord_with_offset ( const MapCoord *src, VikCoord *dest, gdouble offset )
122{
123 gdouble socalled_mpp;
124 if (src->scale >= 0)
125 socalled_mpp = VIK_GZ(src->scale);
126 else
127 socalled_mpp = 1.0/VIK_GZ(-src->scale);
128 dest->mode = VIK_COORD_LATLON;
129 dest->east_west = ((src->x+offset) / VIK_GZ(17) * socalled_mpp * 360) - 180;
130 dest->north_south = DEMERCLAT(180 - ((src->y+offset) / VIK_GZ(17) * socalled_mpp * 360));
131}
132
133/**
134 * map_utils_iTMS_to_center_vikcoord:
135 * @src: Original #MapCoord in Inverse TMS format
136 * @dest: The resulting Spherical Mercator coordinates in #VikCoord
137 *
138 * Convert a #MapCoord in Inverse TMS format into Spherical Mercator coordinates for the center of the TMS area
39519ab8
RN
139 */
140void map_utils_iTMS_to_center_vikcoord ( const MapCoord *src, VikCoord *dest )
141{
142 _to_vikcoord_with_offset ( src, dest, 0.5 );
143}
5ff65f40
RN
144
145/**
146 * map_utils_iTMS_to_vikcoord:
147 * @src: Original #MapCoord in Inverse TMS format
148 * @dest: The resulting Spherical Mercator coordinates in #VikCoord
149 *
150 * Convert a #MapCoord in Inverse TMS format into Spherical Mercator coordinates
151 * (for the top left corner of the Inverse TMS area)
5ff65f40
RN
152 */
153void map_utils_iTMS_to_vikcoord ( const MapCoord *src, VikCoord *dest )
154{
155 _to_vikcoord_with_offset ( src, dest, 0.0 );
156}