[libshumate] map-layer: Implement continuous zoom
- From: Marcus Lundblad <mlundblad src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libshumate] map-layer: Implement continuous zoom
- Date: Thu, 6 May 2021 17:48:57 +0000 (UTC)
commit 96b55dbfea5ac6cab81824b7a14bd92b1dfe8be2
Author: James Westman <james jwestman net>
Date: Tue May 4 14:28:27 2021 -0500
map-layer: Implement continuous zoom
The map layer now accepts fractional zoom levels by scaling the entire
map layer with gtk_snapshot_scale().
shumate/shumate-map-layer.c | 25 ++++++++++++++++++++++---
shumate/shumate-map-source.c | 22 +++++++++++++---------
shumate/shumate-scale.c | 2 +-
shumate/shumate-view.c | 8 ++++----
shumate/shumate-viewport.c | 20 +++++++++++++-------
5 files changed, 53 insertions(+), 24 deletions(-)
---
diff --git a/shumate/shumate-map-layer.c b/shumate/shumate-map-layer.c
index 13fb7bf..7cdabb1 100644
--- a/shumate/shumate-map-layer.c
+++ b/shumate/shumate-map-layer.c
@@ -501,7 +501,7 @@ shumate_map_layer_size_allocate (GtkWidget *widget,
viewport = shumate_layer_get_viewport (SHUMATE_LAYER (self));
tile_size = shumate_map_source_get_tile_size (self->map_source);
- zoom_level = shumate_viewport_get_zoom_level (viewport);
+ zoom_level = (guint) shumate_viewport_get_zoom_level (viewport);
latitude = shumate_location_get_latitude (SHUMATE_LOCATION (viewport));
longitude = shumate_location_get_longitude (SHUMATE_LOCATION (viewport));
latitude_y = (guint) shumate_map_source_get_y (self->map_source, zoom_level, latitude);
@@ -606,13 +606,13 @@ shumate_map_layer_measure (GtkWidget *widget,
if (natural)
{
ShumateViewport *viewport;
- guint tile_size;
+ double tile_size;
guint zoom_level;
guint count;
viewport = shumate_layer_get_viewport (SHUMATE_LAYER (self));
- tile_size = shumate_map_source_get_tile_size (self->map_source);
zoom_level = shumate_viewport_get_zoom_level (viewport);
+ tile_size = shumate_map_source_get_tile_size (self->map_source) * (fmod (zoom_level, 1.0) + 1.0);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
count = shumate_map_source_get_column_count (self->map_source, zoom_level);
else
@@ -622,6 +622,24 @@ shumate_map_layer_measure (GtkWidget *widget,
}
}
+static void
+shumate_map_layer_snapshot (GtkWidget *widget, GtkSnapshot *snapshot)
+{
+ ShumateMapLayer *self = SHUMATE_MAP_LAYER (widget);
+ ShumateViewport *viewport = shumate_layer_get_viewport (SHUMATE_LAYER (self));
+ double zoom_level = shumate_viewport_get_zoom_level (viewport);
+ double extra_zoom = fmod (zoom_level, 1.0) + 1.0;
+ int width = gtk_widget_get_width (GTK_WIDGET (self));
+ int height = gtk_widget_get_height (GTK_WIDGET (self));
+
+ /* Scale around the center of the view */
+ gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (width / 2.0, height / 2.0));
+ gtk_snapshot_scale (snapshot, extra_zoom, extra_zoom);
+ gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (-width / 2.0, -height / 2.0));
+
+ GTK_WIDGET_CLASS (shumate_map_layer_parent_class)->snapshot (widget, snapshot);
+}
+
static void
shumate_map_layer_class_init (ShumateMapLayerClass *klass)
{
@@ -634,6 +652,7 @@ shumate_map_layer_class_init (ShumateMapLayerClass *klass)
object_class->constructed = shumate_map_layer_constructed;
widget_class->size_allocate = shumate_map_layer_size_allocate;
+ widget_class->snapshot = shumate_map_layer_snapshot;
widget_class->measure = shumate_map_layer_measure;
obj_properties[PROP_MAP_SOURCE] =
diff --git a/shumate/shumate-map-source.c b/shumate/shumate-map-source.c
index 66571b1..e04cc67 100644
--- a/shumate/shumate-map-source.c
+++ b/shumate/shumate-map-source.c
@@ -52,6 +52,12 @@ shumate_map_source_class_init (ShumateMapSourceClass *klass)
klass->fill_tile_async = NULL;
}
+static double
+map_size (ShumateMapSource *self, double zoom_level)
+{
+ return shumate_map_source_get_column_count (self, zoom_level) * shumate_map_source_get_tile_size (self) *
(fmod (zoom_level, 1.0) + 1.0);
+}
+
static void
shumate_map_source_init (ShumateMapSource *map_source)
@@ -215,7 +221,7 @@ shumate_map_source_get_x (ShumateMapSource *map_source,
longitude = CLAMP (longitude, SHUMATE_MIN_LONGITUDE, SHUMATE_MAX_LONGITUDE);
/* FIXME: support other projections */
- return ((longitude + 180.0) / 360.0) * shumate_map_source_get_tile_size (map_source) * pow (2.0,
zoom_level);
+ return ((longitude + 180.0) / 360.0) * map_size (map_source, zoom_level);
}
@@ -242,7 +248,7 @@ shumate_map_source_get_y (ShumateMapSource *map_source,
latitude = CLAMP (latitude, SHUMATE_MIN_LATITUDE, SHUMATE_MAX_LATITUDE);
/* FIXME: support other projections */
sin_latitude = sin (latitude * G_PI / 180.0);
- return (0.5 - log ((1.0 + sin_latitude) / (1.0 - sin_latitude)) / (4.0 * G_PI)) *
shumate_map_source_get_tile_size (map_source) * pow (2.0, zoom_level);
+ return (0.5 - log ((1.0 + sin_latitude) / (1.0 - sin_latitude)) / (4.0 * G_PI)) * map_size (map_source,
zoom_level);
}
@@ -265,9 +271,9 @@ shumate_map_source_get_longitude (ShumateMapSource *map_source,
double longitude;
g_return_val_if_fail (SHUMATE_IS_MAP_SOURCE (map_source), 0.0);
+
/* FIXME: support other projections */
- double dx = x / (double) shumate_map_source_get_tile_size (map_source);
- longitude = dx / pow (2.0, zoom_level) * 360.0 - 180.0;
+ longitude = x / map_size (map_source, zoom_level) * 360.0 - 180.0;
return CLAMP (longitude, SHUMATE_MIN_LONGITUDE, SHUMATE_MAX_LONGITUDE);
}
@@ -289,12 +295,11 @@ shumate_map_source_get_latitude (ShumateMapSource *map_source,
double zoom_level,
double y)
{
- double latitude, map_size, dy;
+ double latitude, dy;
g_return_val_if_fail (SHUMATE_IS_MAP_SOURCE (map_source), 0.0);
/* FIXME: support other projections */
- map_size = shumate_map_source_get_tile_size (map_source) * shumate_map_source_get_row_count (map_source,
zoom_level);
- dy = 0.5 - y / map_size;
+ dy = 0.5 - y / map_size (map_source, zoom_level);
latitude = 90.0 - 360.0 / G_PI * atan (exp (-dy * 2.0 * G_PI));
return CLAMP (latitude, SHUMATE_MIN_LATITUDE, SHUMATE_MAX_LATITUDE);
@@ -368,9 +373,8 @@ shumate_map_source_get_meters_per_pixel (ShumateMapSource *map_source,
* radius_at_latitude = 2pi * k * sin (pi/2-theta)
*/
- double map_size = shumate_map_source_get_tile_size (map_source) * shumate_map_source_get_row_count
(map_source, zoom_level);
/* FIXME: support other projections */
- return 2.0 * G_PI * EARTH_RADIUS * sin (G_PI / 2.0 - G_PI / 180.0 * latitude) / map_size;
+ return 2.0 * G_PI * EARTH_RADIUS * sin (G_PI / 2.0 - G_PI / 180.0 * latitude) / map_size (map_source,
zoom_level);
}
diff --git a/shumate/shumate-scale.c b/shumate/shumate-scale.c
index ff91d0f..9cef5a1 100644
--- a/shumate/shumate-scale.c
+++ b/shumate/shumate-scale.c
@@ -91,7 +91,7 @@ shumate_scale_compute_length (ShumateScale *self,
gboolean *out_is_small_unit)
{
ShumateMapSource *map_source;
- int zoom_level;
+ double zoom_level;
double lat, lon;
float scale_width;
float base;
diff --git a/shumate/shumate-view.c b/shumate/shumate-view.c
index fff54ba..cb04afd 100644
--- a/shumate/shumate-view.c
+++ b/shumate/shumate-view.c
@@ -248,8 +248,8 @@ move_viewport_from_pixel_offset (ShumateView *self,
ShumateMapSource *map_source;
double x, y;
double lat, lon;
- guint zoom_level;
- guint tile_size, max_x, max_y;
+ double zoom_level;
+ double tile_size, max_x, max_y;
g_assert (SHUMATE_IS_VIEW (self));
@@ -261,7 +261,7 @@ move_viewport_from_pixel_offset (ShumateView *self,
x = shumate_map_source_get_x (map_source, zoom_level, longitude) - offset_x;
y = shumate_map_source_get_y (map_source, zoom_level, latitude) - offset_y;
- tile_size = shumate_map_source_get_tile_size (map_source);
+ tile_size = shumate_map_source_get_tile_size (map_source) * (fmod (zoom_level, 1.0) + 1.0);
max_x = shumate_map_source_get_column_count (map_source, zoom_level) * tile_size;
max_y = shumate_map_source_get_row_count (map_source, zoom_level) * tile_size;
@@ -544,7 +544,7 @@ on_scroll_controller_scroll (ShumateView *self,
double scroll_map_x, scroll_map_y;
double view_center_x, view_center_y;
double x_offset, y_offset;
- guint zoom_level;
+ double zoom_level;
scroll_map_x = shumate_viewport_longitude_to_widget_x (priv->viewport, GTK_WIDGET (self),
scroll_longitude);
scroll_map_y = shumate_viewport_latitude_to_widget_y (priv->viewport, GTK_WIDGET (self),
scroll_latitude);
diff --git a/shumate/shumate-viewport.c b/shumate/shumate-viewport.c
index 8b18004..bbfea60 100644
--- a/shumate/shumate-viewport.c
+++ b/shumate/shumate-viewport.c
@@ -411,29 +411,35 @@ shumate_viewport_get_min_zoom_level (ShumateViewport *self)
* shumate_viewport_zoom_in:
* @self: a #ShumateViewport
*
- * Increments the zoom level
+ * Increases the zoom level
*/
void shumate_viewport_zoom_in (ShumateViewport *self)
{
+ double zoom_level;
+
g_return_if_fail (SHUMATE_IS_VIEWPORT (self));
- shumate_viewport_set_zoom_level (self, self->zoom_level + 1);
+ /* Round to the nearest 1/5 of a zoom level to prevent floating point
+ * error accumulation. */
+
+ zoom_level = roundf ((self->zoom_level + 0.2) * 5) / 5;
+ shumate_viewport_set_zoom_level (self, zoom_level);
}
/**
* shumate_viewport_zoom_out:
* @self: a #ShumateViewport
*
- * Decrements the zoom level
+ * Decreases the zoom level
*/
void shumate_viewport_zoom_out (ShumateViewport *self)
{
- g_return_if_fail (SHUMATE_IS_VIEWPORT (self));
+ double zoom_level;
- if (self->zoom_level == 0)
- return;
+ g_return_if_fail (SHUMATE_IS_VIEWPORT (self));
- shumate_viewport_set_zoom_level (self, self->zoom_level - 1);
+ zoom_level = roundf ((self->zoom_level - 0.2) * 5) / 5;
+ shumate_viewport_set_zoom_level (self, zoom_level);
}
/**
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]