]> git.street.me.uk Git - andy/viking.git/commitdiff
Add support for more standard TMS
authorGuilhem Bonnefille <guilhem.bonnefille@gmail.com>
Sat, 27 Nov 2010 23:15:36 +0000 (00:15 +0100)
committerGuilhem Bonnefille <guilhem.bonnefille@gmail.com>
Sat, 27 Nov 2010 23:15:36 +0000 (00:15 +0100)
OpenStreetMap project provides a sort of TMS service.
But it use some specificities: top-left origin with
spherical-mercator pojection.

We need a more standard support: origin in bottom-left corner
with EPSG:4326 projection.

Signed-off-by: Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
doc/examples/maps.xml
doc/viking.xml
help/C/viking.xml
src/Makefile.am
src/viktmsmapsource.c [new file with mode: 0644]
src/viktmsmapsource.h [new file with mode: 0644]
test/Makefile.am
test/test_coord_conversion.c [new file with mode: 0644]

index 6be78146c956226eebe564599f56f9a0cbe11423..adfcc1a19e1089f0c94c641dd2eac3fe417c1ef6 100644 (file)
     <property name="id">20</property>
   </object>
 -->
+  <object class="VikWmscMapSource">
+    <property name="id">18</property>
+    <property name="label">OpenStreetMap (WMS)</property>
+    <property name="hostname">full.wms.geofabrik.de</property>
+    <property name="url">/std/demo_key?LAYERS=osm-full&amp;FORMAT=image/png&amp;SERVICE=WMS&amp;VERSION=1.1.1&amp;REQUEST=GetMap&amp;STYLES=&amp;EXCEPTIONS=&amp;SRS=EPSG:4326&amp;BBOX=%s,%s,%s,%s&amp;WIDTH=256&amp;HEIGHT=256</property>
+    <property name="check-file-server-time">FALSE</property>
+  </object>
   <object class="VikSlippyMapSource">
     <property name="label">Letuffe/hiking</property>
     <property name="hostname">beta.letuffe.org</property>
index f510d7e47d9ff5545a62d466e6bb49ce5bf067c5..f4777614a83dd12884f6f80b29950df5e8cc484c 100644 (file)
@@ -181,8 +181,7 @@ and docbook-xsl in your Build-Depends control field.
         <title>Map Source</title>
         <para>It is possible to add new map's sources. The file is <filename>~/.viking/maps.xml</filename>.</para>
         <para>An example of the file in the distribution <filename>doc/examples/maps.xml</filename>.</para>
-        <para>Currently, there is a single object class available: VikSlippyMapSource. Such feature allows to declare any map's source working like OpenStreetMap.</para>
-        <para>The related properties are:
+        <para>The VikSlippyMapSource allows to declare any map's source working like OpenStreetMap. It supports the following properties:
           <variablelist>
             <varlistentry>
               <term>id</term>
@@ -202,6 +201,26 @@ and docbook-xsl in your Build-Depends control field.
             </varlistentry>
           </variablelist>
         </para>
+        <para>The VikWmscMapSource allows to declare any WMS or WMS-C service. It supports the following properties:
+          <variablelist>
+            <varlistentry>
+              <term>id</term>
+              <listitem><para>this is an integer and should be unique as it used to identify the map source</para></listitem>
+            </varlistentry>
+            <varlistentry>
+              <term>label</term>
+              <listitem><para>the text displayed in the map's source selection dialog</para></listitem>
+            </varlistentry>
+            <varlistentry>
+              <term>hostname</term>
+              <listitem><para>the server's hostname (eg. "tile.openstreetmap.org")</para></listitem>
+            </varlistentry>
+            <varlistentry>
+              <term>url</term>
+              <listitem><para>the parametrized address of the tile, in the spirit of C printf format, with 4 "%s" fields for bounding box coordinates (eg. "/coord=%s,%s,%s,%s")</para></listitem>
+            </varlistentry>
+          </variablelist>
+        </para>
       </formalpara>
 
       <formalpara>
index 2adff614295edd9b07f7d3bcb2a74fef0afea2a7..dc9a31b3dbcbc38b63e60fae22800ea885c43911 100644 (file)
@@ -960,8 +960,7 @@ to write the waypoints to this file.
         <title>Map Source</title>
         <para>It is possible to add new map's sources. The file is <filename>~/.viking/maps.xml</filename>.</para>
         <para>An example of the file in the distribution <filename>doc/examples/maps.xml</filename>.</para>
-        <para>Currently, there is a single object class available: VikSlippyMapSource. Such feature allows to declare any map's source working like OpenStreetMap.</para>
-        <para>The related properties are:
+        <para>The VikSlippyMapSource allows to declare any map's source working like OpenStreetMap. It supports the following properties:
           <variablelist>
             <varlistentry>
               <term>id</term>
@@ -981,6 +980,26 @@ to write the waypoints to this file.
             </varlistentry>
           </variablelist>
         </para>
+        <para>The VikWmscMapSource allows to declare any WMS or WMS-C service. It supports the following properties:
+          <variablelist>
+            <varlistentry>
+              <term>id</term>
+              <listitem><para>this is an integer and should be unique as it used to identify the map source</para></listitem>
+            </varlistentry>
+            <varlistentry>
+              <term>label</term>
+              <listitem><para>the text displayed in the map's source selection dialog</para></listitem>
+            </varlistentry>
+            <varlistentry>
+              <term>hostname</term>
+              <listitem><para>the server's hostname (eg. "tile.openstreetmap.org")</para></listitem>
+            </varlistentry>
+            <varlistentry>
+              <term>url</term>
+              <listitem><para>the parametrized address of the tile, in the spirit of C printf format, with 4 "%s" fields for bounding box coordinates (eg. "/coord=%s,%s,%s,%s")</para></listitem>
+            </varlistentry>
+          </variablelist>
+        </para>
       </section>
 
       <section>
index 153606c917213c1f6796ee995187e1b6d4d04880..af87fd34815220b20a707abead8a72f6501f4bc6 100644 (file)
@@ -95,6 +95,7 @@ libviking_a_SOURCES = \
        vikmapslayer_compat.c vikmapslayer_compat.h \
        vikmaptype.c vikmaptype.h \
        vikslippymapsource.c vikslippymapsource.h \
+       viktmsmapsource.c viktmsmapsource.h \
         gpx.c gpx.h \
        garminsymbols.c garminsymbols.h \
        acquire.c acquire.h \
diff --git a/src/viktmsmapsource.c b/src/viktmsmapsource.c
new file mode 100644 (file)
index 0000000..fc5a577
--- /dev/null
@@ -0,0 +1,368 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * viking
+ * Copyright (C) 2010, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
+ * 
+ * viking 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 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * viking 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, see <http://www.gnu.org/licenses/>.
+ */
+  
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_MATH_H
+#include <math.h>
+#endif
+
+#include "globals.h"
+#include "viktmsmapsource.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 );
+static gboolean _supports_download_only_new (VikMapSource *self );
+
+static gchar *_get_uri( VikMapSourceDefault *self, MapCoord *src );
+static gchar *_get_hostname( VikMapSourceDefault *self );
+static DownloadMapOptions *_get_download_options( VikMapSourceDefault *self );
+
+typedef struct _VikTmsMapSourcePrivate VikTmsMapSourcePrivate;
+struct _VikTmsMapSourcePrivate
+{
+  gchar *hostname;
+  gchar *url;
+  DownloadMapOptions options;
+};
+
+#define VIK_TMS_MAP_SOURCE_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), VIK_TYPE_TMS_MAP_SOURCE, VikTmsMapSourcePrivate))
+
+/* properties */
+enum
+{
+  PROP_0,
+
+  PROP_HOSTNAME,
+  PROP_URL,
+  PROP_REFERER,
+  PROP_FOLLOW_LOCATION,
+  PROP_CHECK_FILE_SERVER_TIME,
+};
+
+G_DEFINE_TYPE (VikTmsMapSource, vik_tms_map_source, VIK_TYPE_MAP_SOURCE_DEFAULT);
+
+static void
+vik_tms_map_source_init (VikTmsMapSource *self)
+{
+  /* initialize the object here */
+  VikTmsMapSourcePrivate *priv = VIK_TMS_MAP_SOURCE_PRIVATE (self);
+
+  priv->hostname = NULL;
+  priv->url = NULL;
+  priv->options.referer = NULL;
+  priv->options.follow_location = 0;
+  priv->options.check_file = a_check_map_file;
+  priv->options.check_file_server_time = FALSE;
+
+  g_object_set (G_OBJECT (self),
+                "tilesize-x", 256,
+                "tilesize-y", 256,
+                "drawmode", VIK_VIEWPORT_DRAWMODE_LATLON,
+                NULL);
+}
+
+static void
+vik_tms_map_source_finalize (GObject *object)
+{
+  VikTmsMapSource *self = VIK_TMS_MAP_SOURCE (object);
+  VikTmsMapSourcePrivate *priv = VIK_TMS_MAP_SOURCE_PRIVATE (self);
+
+  g_free (priv->hostname);
+  priv->hostname = NULL;
+  g_free (priv->url);
+  priv->url = NULL;
+  g_free (priv->options.referer);
+  priv->options.referer = NULL;
+
+  G_OBJECT_CLASS (vik_tms_map_source_parent_class)->finalize (object);
+}
+
+static void
+vik_tms_map_source_set_property (GObject      *object,
+                                    guint         property_id,
+                                    const GValue *value,
+                                    GParamSpec   *pspec)
+{
+  VikTmsMapSource *self = VIK_TMS_MAP_SOURCE (object);
+  VikTmsMapSourcePrivate *priv = VIK_TMS_MAP_SOURCE_PRIVATE (self);
+
+  switch (property_id)
+    {
+    case PROP_HOSTNAME:
+      g_free (priv->hostname);
+      priv->hostname = g_value_dup_string (value);
+      break;
+
+    case PROP_URL:
+      g_free (priv->url);
+      priv->url = g_value_dup_string (value);
+      break;
+
+    case PROP_REFERER:
+      g_free (priv->options.referer);
+      priv->options.referer = g_value_dup_string (value);
+      break;
+
+    case PROP_FOLLOW_LOCATION:
+      priv->options.follow_location = g_value_get_long (value);
+      break;
+
+    case PROP_CHECK_FILE_SERVER_TIME:
+      priv->options.check_file_server_time = g_value_get_boolean (value);
+      break;
+
+    default:
+      /* We don't have any other property... */
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+vik_tms_map_source_get_property (GObject    *object,
+                                    guint       property_id,
+                                    GValue     *value,
+                                    GParamSpec *pspec)
+{
+  VikTmsMapSource *self = VIK_TMS_MAP_SOURCE (object);
+  VikTmsMapSourcePrivate *priv = VIK_TMS_MAP_SOURCE_PRIVATE (self);
+
+  switch (property_id)
+    {
+    case PROP_HOSTNAME:
+      g_value_set_string (value, priv->hostname);
+      break;
+
+    case PROP_URL:
+      g_value_set_string (value, priv->url);
+      break;
+
+    case PROP_REFERER:
+      g_value_set_string (value, priv->options.referer);
+      break;
+
+    case PROP_FOLLOW_LOCATION:
+      g_value_set_long (value, priv->options.follow_location);
+      break;
+
+    case PROP_CHECK_FILE_SERVER_TIME:
+      g_value_set_boolean (value, priv->options.check_file_server_time);
+      break;
+         
+    default:
+      /* We don't have any other property... */
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+vik_tms_map_source_class_init (VikTmsMapSourceClass *klass)
+{
+       GObjectClass* object_class = G_OBJECT_CLASS (klass);
+       VikMapSourceClass* granparent_class = VIK_MAP_SOURCE_CLASS (klass);
+       VikMapSourceDefaultClass* parent_class = VIK_MAP_SOURCE_DEFAULT_CLASS (klass);
+       GParamSpec *pspec = NULL;
+               
+       object_class->set_property = vik_tms_map_source_set_property;
+    object_class->get_property = vik_tms_map_source_get_property;
+
+       /* Overiding methods */
+       granparent_class->coord_to_mapcoord =        _coord_to_mapcoord;
+       granparent_class->mapcoord_to_center_coord = _mapcoord_to_center_coord;
+       granparent_class->supports_download_only_new = _supports_download_only_new;
+       
+       parent_class->get_uri = _get_uri;
+       parent_class->get_hostname = _get_hostname;
+       parent_class->get_download_options = _get_download_options;
+
+       pspec = g_param_spec_string ("hostname",
+                                    "Hostname",
+                                    "The hostname of the map server",
+                                    "<no-set>" /* default value */,
+                                    G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+       g_object_class_install_property (object_class, PROP_HOSTNAME, pspec);
+
+       pspec = g_param_spec_string ("url",
+                                    "URL",
+                                    "The template of the tiles' URL",
+                                    "<no-set>" /* default value */,
+                                    G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+       g_object_class_install_property (object_class, PROP_URL, pspec);
+
+       pspec = g_param_spec_string ("referer",
+                                    "Referer",
+                                    "The REFERER string to use in HTTP request",
+                                    NULL /* default value */,
+                                    G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+       g_object_class_install_property (object_class, PROP_REFERER, pspec);
+       
+       pspec = g_param_spec_long ("follow-location",
+                                  "Follow location",
+                               "Specifies the number of retries to follow a redirect while downloading a page",
+                               0  /* minimum value */,
+                               G_MAXLONG /* maximum value */,
+                               0  /* default value */,
+                               G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+       g_object_class_install_property (object_class, PROP_FOLLOW_LOCATION, pspec);
+       
+       pspec = g_param_spec_boolean ("check-file-server-time",
+                                     "Check file server time",
+                                  "Age of current cache before redownloading tile",
+                                  FALSE  /* default value */,
+                                  G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+       g_object_class_install_property (object_class, PROP_CHECK_FILE_SERVER_TIME, pspec);
+
+       g_type_class_add_private (klass, sizeof (VikTmsMapSourcePrivate));
+       
+       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;
+}
+
+gboolean
+_supports_download_only_new (VikMapSource *self)
+{
+       g_return_val_if_fail (VIK_IS_TMS_MAP_SOURCE(self), FALSE);
+       
+    VikTmsMapSourcePrivate *priv = VIK_TMS_MAP_SOURCE_PRIVATE(self);
+       
+       return priv->options.check_file_server_time;
+}
+
+static gboolean
+_coord_to_mapcoord ( VikMapSource *self, const VikCoord *src, gdouble xzoom, gdouble yzoom, MapCoord *dest )
+{
+  g_assert ( src->mode == VIK_COORD_LATLON );
+
+  if ( xzoom != yzoom )
+    return FALSE;
+
+  dest->scale = tms_zoom ( xzoom );
+  if ( dest->scale == 255 )
+    return FALSE;
+
+  /* Note : 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);
+  /* 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->z = 0;
+  g_debug("%s: %f,%f -> %d,%d", __FUNCTION__,
+          src->east_west, src->north_south, dest->x, dest->y);
+  return TRUE;
+}
+
+static void
+_mapcoord_to_center_coord ( VikMapSource *self, MapCoord *src, VikCoord *dest )
+{
+  gdouble socalled_mpp;
+  if (src->scale >= 0)
+    socalled_mpp = GZ(src->scale);
+  else
+    socalled_mpp = 1.0/GZ(-src->scale);
+  dest->mode = VIK_COORD_LATLON;
+  dest->east_west = (src->x+0.5) * 180 / 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);
+  g_debug("%s: %d,%d -> %f,%f", __FUNCTION__,
+          src->x, src->y, dest->east_west, dest->north_south);
+}
+
+static gchar *
+_get_uri( VikMapSourceDefault *self, MapCoord *src )
+{
+       g_return_val_if_fail (VIK_IS_TMS_MAP_SOURCE(self), NULL);
+       
+    VikTmsMapSourcePrivate *priv = VIK_TMS_MAP_SOURCE_PRIVATE(self);
+       gdouble socalled_mpp;
+       if (src->scale >= 0)
+               socalled_mpp = GZ(src->scale);
+       else
+               socalled_mpp = 1.0/GZ(-src->scale);
+       /* We should restore logic of viking:
+     * tile index on Y axis follow a screen logic (top -> down)
+     */
+
+       /* Note : nb tiles on Y axis */
+       gint nb_tiles = GZ(17 - src->scale - 1);
+
+       gchar *uri = g_strdup_printf (priv->url, 17 - src->scale - 1, src->x, nb_tiles - src->y - 1);
+       
+       return uri;
+} 
+
+static gchar *
+_get_hostname( VikMapSourceDefault *self )
+{
+       g_return_val_if_fail (VIK_IS_TMS_MAP_SOURCE(self), NULL);
+       
+    VikTmsMapSourcePrivate *priv = VIK_TMS_MAP_SOURCE_PRIVATE(self);
+       return g_strdup( priv->hostname );
+}
+
+static DownloadMapOptions *
+_get_download_options( VikMapSourceDefault *self )
+{
+       g_return_val_if_fail (VIK_IS_TMS_MAP_SOURCE(self), NULL);
+       
+       VikTmsMapSourcePrivate *priv = VIK_TMS_MAP_SOURCE_PRIVATE(self);
+       return &(priv->options);
+}
+
+VikTmsMapSource *
+vik_tms_map_source_new_with_id (guint8 id, const gchar *label, const gchar *hostname, const gchar *url)
+{
+       return g_object_new(VIK_TYPE_TMS_MAP_SOURCE,
+                           "id", id, "label", label, "hostname", hostname, "url", url, NULL);
+}
diff --git a/src/viktmsmapsource.h b/src/viktmsmapsource.h
new file mode 100644 (file)
index 0000000..2df40f2
--- /dev/null
@@ -0,0 +1,55 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * viking
+ * Copyright (C) 2010, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
+ * 
+ * viking 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 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * viking 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _VIK_TMS_MAP_SOURCE_H
+#define _VIK_TMS_MAP_SOURCE_H
+
+#include "vikcoord.h"
+#include "mapcoord.h"
+#include "vikmapsourcedefault.h"
+
+G_BEGIN_DECLS
+
+#define VIK_TYPE_TMS_MAP_SOURCE             (vik_tms_map_source_get_type ())
+#define VIK_TMS_MAP_SOURCE(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIK_TYPE_TMS_MAP_SOURCE, VikTmsMapSource))
+#define VIK_TMS_MAP_SOURCE_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), VIK_TYPE_TMS_MAP_SOURCE, VikTmsMapSourceClass))
+#define VIK_IS_TMS_MAP_SOURCE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIK_TYPE_TMS_MAP_SOURCE))
+#define VIK_IS_TMS_MAP_SOURCE_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), VIK_TYPE_TMS_MAP_SOURCE))
+#define VIK_TMS_MAP_SOURCE_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), VIK_TYPE_TMS_MAP_SOURCE, VikTmsMapSourceClass))
+
+typedef struct _VikTmsMapSourceClass VikTmsMapSourceClass;
+typedef struct _VikTmsMapSource VikTmsMapSource;
+
+struct _VikTmsMapSourceClass
+{
+       VikMapSourceDefaultClass parent_class;
+};
+
+struct _VikTmsMapSource
+{
+       VikMapSourceDefault parent_instance;
+};
+
+GType vik_tms_map_source_get_type (void) G_GNUC_CONST;
+
+VikTmsMapSource * vik_tms_map_source_new_with_id (guint8 id, const gchar *label, const gchar *hostname, const gchar *url);
+
+G_END_DECLS
+
+#endif /* _VIK_TMS_MAP_SOURCE_H_ */
index 0c8530883ba293cb83be5b92e4b1c1ec1a3d9470..f8334e297b39e803f757c2a9920b27bd358f0220 100644 (file)
@@ -7,7 +7,7 @@ endif
 
 TESTS = check_degrees_conversions.sh
 
-check_PROGRAMS = degrees_converter gpx2gpx test_vikgotoxmltool
+check_PROGRAMS = degrees_converter gpx2gpx test_vikgotoxmltool test_coord_conversion
 
 check_SCRIPTS = check_degrees_conversions.sh
 
@@ -27,3 +27,8 @@ test_vikgotoxmltool_SOURCES = test_vikgotoxmltool.c
 test_vikgotoxmltool_LDADD = \
   $(top_builddir)/src/libviking.a \
   $(LDADD)
+
+test_coord_conversion_SOURCES = test_coord_conversion.c
+test_coord_conversion_LDADD = \
+  $(top_builddir)/src/libviking.a \
+  $(LDADD)
diff --git a/test/test_coord_conversion.c b/test/test_coord_conversion.c
new file mode 100644 (file)
index 0000000..e49fd6f
--- /dev/null
@@ -0,0 +1,74 @@
+#include <math.h>
+#include <vikwmscmapsource.h>
+#include <vikslippymapsource.h>
+
+void test_coord_to_mapcoord(VikMapSource *source, gdouble lat, gdouble lon, gdouble zoom)
+{
+  VikCoord vikCoord;
+  MapCoord mapCoord;
+  vikCoord.mode = VIK_COORD_LATLON;
+  vikCoord.east_west = lon;
+  vikCoord.north_south = lat;
+  printf("%s: %f %f %f => ", g_type_name(G_OBJECT_TYPE(source)), vikCoord.east_west, vikCoord.north_south, zoom);
+  vik_map_source_coord_to_mapcoord (source, &vikCoord, zoom, zoom, &mapCoord);
+  printf("x=%d y=%d\n", mapCoord.x, mapCoord.y);
+}
+
+void test_mapcoord_to_center_coord (VikMapSource *source, int x, int y, int scale)
+{
+  VikCoord vikCoord;
+  MapCoord mapCoord;
+  mapCoord.x = x;
+  mapCoord.y = y;
+  mapCoord.scale = scale;
+  printf("%s: %d %d %d => ", g_type_name(G_OBJECT_TYPE(source)), mapCoord.x, mapCoord.y, scale);
+  vik_map_source_mapcoord_to_center_coord (source, &mapCoord, &vikCoord);
+  printf("lon=%f lat=%f\n", vikCoord.east_west, vikCoord.north_south);
+}
+
+int main(int argc, char *argv[])
+{
+  g_type_init();
+  
+  VikMapSource *spotmaps4osm_wmsc_type = 
+    VIK_MAP_SOURCE(g_object_new(VIK_TYPE_WMSC_MAP_SOURCE,
+                                "id", 202,
+                                "label", "Spotmaps (WMS-C)",
+                                "hostname", "spotmaps.youmapps.org",
+                                "url", "/spotmaps4osm/?LAYERS=spotmaps4osm&SERVICE=SPOTMAPS4OSM&SRS=EPSG:4326&bbox=%s,%s,%s,%s&width=256&height=256",
+                                NULL));
+
+  VikMapSource *osmarender_type = 
+    VIK_MAP_SOURCE(g_object_new(VIK_TYPE_SLIPPY_MAP_SOURCE,
+                                "id", 12,
+                                "label", "OpenStreetMap (Osmarender)",
+                                "hostname", "tah.openstreetmap.org",
+                                "url", "/Tiles/tile/%d/%d/%d.png",
+                                "check-file-server-time", TRUE,
+                                NULL));
+    
+  gdouble lats[] = { 0, 90, 45, -45, -90 };
+  gdouble lons[] = { 0, 180, 90, 45, -45, -90, -180 };
+  int scale;
+  for (scale = 0 ; scale < 18 ; scale++)
+  {
+    int i;
+    for (i=0 ; i<sizeof(lats)/sizeof(lats[0]) ; i++)
+    {
+      int j;
+      for (j=0 ; j<sizeof(lons)/sizeof(lons[0]) ; j++)
+      {
+        test_coord_to_mapcoord (spotmaps4osm_wmsc_type, lats[i], lons[j], 2<<scale);
+        test_coord_to_mapcoord (osmarender_type, lats[i], lons[j], 2<<scale);
+      }
+    }
+  }
+
+  for (scale = 0 ; scale < 18 ; scale++)
+  {
+    test_mapcoord_to_center_coord (spotmaps4osm_wmsc_type, 0, 0, scale);
+    test_mapcoord_to_center_coord (osmarender_type, 0, 0, scale);
+  }
+
+  return 0;
+}