Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

center-hopping #101

Open
DTJF opened this issue Aug 25, 2023 · 0 comments
Open

center-hopping #101

DTJF opened this issue Aug 25, 2023 · 0 comments

Comments

@DTJF
Copy link

DTJF commented Aug 25, 2023

Perhaps you're aware of the center-hopping issue: at certain points, when zooming in the map, the map center swaps between two positions, mostly between zoom levels 17, 18 and 19. (ie @ N0°0.0, E15°24.6065). This is due to a rounding issue computing float variables (6.5 digits accuracy), while the global map needs 7 digits accuracy.

I fixed this bug. But sorry, filing a pull request is over my head. So I post a patch here:

From 348ef5fc230641f442f79297e0be4894e199cf28 Mon Sep 17 00:00:00 2001
From: Thomas Freiherr <Thomas[ dot )Freiherr{ at ]gmx( dot }net>
Date: Fri, 25 Aug 2023 13:20:36 +0200
Subject: [PATCH] fix center hopping

Signed-off-by: Thomas Freiherr
---
 src/converter.c          | 45 ++++++++++++----------------------------
 src/osm-gps-map-widget.c | 16 +++++++-------
 2 files changed, 21 insertions(+), 40 deletions(-)

diff --git a/src/converter.c b/src/converter.c
index cfa7093..d822577 100644
--- a/src/converter.c
+++ b/src/converter.c
@@ -9,7 +9,7 @@
  * 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
@@ -55,11 +55,6 @@ int
 lat2pixel(  int zoom,
             float lat)
 {
-    float lat_m;
-    int pixel_y;
-
-    lat_m = atanh(sin(lat));
-
     /* the formula is
      *
      * some more notes
@@ -67,11 +62,8 @@ lat2pixel(  int zoom,
      *
      * pixel_y = -(2^zoom * TILESIZE * lat_m) / 2PI + (2^zoom * TILESIZE) / 2
      */
-    pixel_y = -(int)( (lat_m * TILESIZE * (1 << zoom) ) / (2*M_PI)) +
-        ((1 << zoom) * (TILESIZE/2) );
-
-
-    return pixel_y;
+    float y = atanh(sin(lat)) * TILESIZE * (1 << zoom) / (2*M_PI);
+    return -(int)(y) + (((1 << zoom) * TILESIZE) >> 1);
 }
 
 
@@ -79,41 +71,28 @@ int
 lon2pixel(  int zoom,
             float lon)
 {
-    int pixel_x;
-
     /* the formula is
      *
      * pixel_x = (2^zoom * TILESIZE * lon) / 2PI + (2^zoom * TILESIZE) / 2
      */
-    pixel_x = (int)(( lon * TILESIZE * (1 << zoom) ) / (2*M_PI)) +
-        ( (1 << zoom) * (TILESIZE/2) );
-    return pixel_x;
+    float x = lon * TILESIZE * (1 << zoom) / (2*M_PI);
+    return (int)(x) + (((1 << zoom) * TILESIZE) >> 1);
 }
 
 float
 pixel2lon(  float zoom,
             int pixel_x)
 {
-    float lon;
-
-    lon = ((pixel_x - ( exp(zoom * M_LN2) * (TILESIZE/2) ) ) *2*M_PI) / 
-        (TILESIZE * exp(zoom * M_LN2) );
-
-    return lon;
+    float x = exp(zoom * M_LN2) * TILESIZE;
+    return 2*M_PI * (pixel_x - (x / 2)) / x;
 }
 
 float
 pixel2lat(  float zoom,
             int pixel_y)
 {
-    float lat, lat_m;
-
-    lat_m = (-( pixel_y - ( exp(zoom * M_LN2) * (TILESIZE/2) ) ) * (2*M_PI)) /
-        (TILESIZE * exp(zoom * M_LN2));
-
-    lat = asin(tanh(lat_m));
-
-    return lat;
+    float y = exp(zoom * M_LN2) * TILESIZE;
+    return asin(tanh(2*M_PI * ((y / 2) - pixel_y) / y));
 }
 
 int
@@ -126,7 +105,9 @@ latlon2zoom(int pix_height,
 {
     float lat1_m = atanh(sin(lat1));
     float lat2_m = atanh(sin(lat2));
-    int zoom_lon = LOG2((double)(2 * pix_width * M_PI) / (TILESIZE * (lon2 - lon1)));
-    int zoom_lat = LOG2((double)(2 * pix_height * M_PI) / (TILESIZE * (lat2_m - lat1_m)));
+    float d_lon = (TILESIZE * (lon2 - lon1));
+    float d_lat = (TILESIZE * (lat2_m - lat1_m));
+    int zoom_lon = (d_lon) ? LOG2((double)(2*M_PI * pix_width ) / d_lon) : 1;
+    int zoom_lat = (d_lat) ? LOG2((double)(2*M_PI * pix_height) / d_lat) : 1;
     return MIN(zoom_lon, zoom_lat);
 }
diff --git a/src/osm-gps-map-widget.c b/src/osm-gps-map-widget.c
index e3158cd..a374aab 100644
--- a/src/osm-gps-map-widget.c
+++ b/src/osm-gps-map-widget.c
@@ -1122,8 +1122,8 @@ osm_gps_map_fill_tiles_pixel (OsmGpsMap *map, cairo_t *cr)
     tiles_nx = (allocation.width  - offset_x) / TILESIZE + 1;
     tiles_ny = (allocation.height - offset_y) / TILESIZE + 1;
 
-    tile_x0 =  floorf((float)priv->map_x / (float)TILESIZE);
-    tile_y0 =  floorf((float)priv->map_y / (float)TILESIZE);
+    tile_x0 =  priv->map_x / TILESIZE;
+    tile_y0 =  priv->map_y / TILESIZE;
 
     for (i=tile_x0; i<(tile_x0+tiles_nx);i++)
     {
@@ -1491,10 +1491,10 @@ osm_gps_map_map_redraw (OsmGpsMap *map)
 
     priv->redraw_cycle++;
 
-    /* clear white background */
-    w = gtk_widget_get_allocated_width (widget);
-    h = gtk_widget_get_allocated_width (widget);
-    draw_white_rectangle(cr, 0, 0, w + EXTRA_BORDER * 2, h + EXTRA_BORDER * 2);
+    ///* clear white background */
+    //w = gtk_widget_get_allocated_width (widget);
+    //h = gtk_widget_get_allocated_width (widget);
+    //draw_white_rectangle(cr, 0, 0, w + EXTRA_BORDER * 2, h + EXTRA_BORDER * 2);
 
     osm_gps_map_fill_tiles_pixel(map, cr);
 
@@ -3117,8 +3117,8 @@ osm_gps_map_set_center (OsmGpsMap *map, float latitude, float longitude)
     pixel_x = lon2pixel(priv->map_zoom, priv->center_rlon);
     pixel_y = lat2pixel(priv->map_zoom, priv->center_rlat);
 
-    priv->map_x = pixel_x - allocation.width/2;
-    priv->map_y = pixel_y - allocation.height/2;
+    priv->map_x = pixel_x - (allocation.width  >> 1);
+    priv->map_y = pixel_y - (allocation.height >> 1);
 
     osm_gps_map_map_redraw_idle(map);
 
-- 
2.34.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant