Verified Commit c54ed6c6 authored by James Westman's avatar James Westman
Browse files

Add support for rotation

Add support for rotating the map using touchscreen/trackpad gestures.
This involved changing the gesture tracking code to support zooming and
rotating at the same time. Also, some of the viewport methods had to be
changed since the calculations now depend on both coordinates.
parent a8febd85
Pipeline #301384 passed with stages
in 2 minutes and 32 seconds
......@@ -209,12 +209,23 @@ recompute_grid (ShumateMapLayer *self)
int source_rows = shumate_map_source_get_row_count (self->map_source, zoom_level);
int source_columns = shumate_map_source_get_column_count (self->map_source, zoom_level);
double rotation = shumate_viewport_get_rotation (viewport);
int size_x = MAX (
abs (cos (rotation) * width/2.0 - sin (rotation) * height/2.0),
abs (cos (rotation) * -width/2.0 - sin (rotation) * height/2.0)
);
int size_y = MAX (
abs (sin (rotation) * width/2.0 + cos (rotation) * height/2.0),
abs (sin (rotation) * -width/2.0 + cos (rotation) * height/2.0)
);
// This is the (column, row) of the top left tile
int tile_initial_column = floor ((longitude_x - width/2) / (double) tile_size);
int tile_initial_row = floor ((latitude_y - height/2) / (double) tile_size);
int tile_initial_column = floor ((longitude_x - size_x) / (double) tile_size);
int tile_initial_row = floor ((latitude_y - size_y) / (double) tile_size);
int required_columns = (width / tile_size) + 2;
int required_rows = (height / tile_size) + 2;
int required_columns = (size_x * 2 / tile_size) + 2;
int required_rows = (size_y * 2 / tile_size) + 2;
gboolean all_filled = TRUE;
......@@ -342,6 +353,16 @@ on_view_zoom_level_changed (ShumateMapLayer *self,
gtk_widget_queue_allocate (GTK_WIDGET (self));
}
static void
on_view_rotation_changed (ShumateMapLayer *self,
GParamSpec *pspec,
ShumateViewport *view)
{
g_assert (SHUMATE_IS_MAP_LAYER (self));
gtk_widget_queue_allocate (GTK_WIDGET (self));
}
static void
shumate_map_layer_set_property (GObject *object,
guint property_id,
......@@ -414,6 +435,8 @@ shumate_map_layer_constructed (GObject *object)
g_signal_connect_swapped (viewport, "notify::longitude", G_CALLBACK (on_view_longitude_changed), self);
g_signal_connect_swapped (viewport, "notify::latitude", G_CALLBACK (on_view_latitude_changed), self);
g_signal_connect_swapped (viewport, "notify::zoom-level", G_CALLBACK (on_view_zoom_level_changed), self);
g_signal_connect_swapped (viewport, "notify::rotation", G_CALLBACK (on_view_rotation_changed), self);
}
static void
......@@ -502,10 +525,12 @@ shumate_map_layer_snapshot (GtkWidget *widget, GtkSnapshot *snapshot)
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));
double rotation = shumate_viewport_get_rotation (viewport);
/* Scale around the center of the view */
/* Scale and rotate 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_rotate (snapshot, rotation * 180 / G_PI);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (-width / 2.0, -height / 2.0));
GTK_WIDGET_CLASS (shumate_map_layer_parent_class)->snapshot (widget, snapshot);
......
......@@ -154,18 +154,70 @@ typedef struct
double current_y;
double zoom_level_begin;
double zoom_center_x;
double zoom_center_y;
double rotate_begin;
double focus_lat;
double focus_lon;
double accumulated_scroll_dy;
double drag_begin_lat;
double drag_begin_lon;
double gesture_begin_lat;
double gesture_begin_lon;
double drag_begin_x;
double drag_begin_y;
} ShumateMapPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (ShumateMap, shumate_map, GTK_TYPE_WIDGET);
static double
positive_mod (double i, double n)
{
return fmod (fmod (i, n) + n, n);
}
static void
move_location_to_coords (ShumateMap *self,
double lat,
double lon,
double x,
double y)
{
ShumateMapPrivate *priv = shumate_map_get_instance_private (self);
ShumateMapSource *map_source = shumate_viewport_get_reference_map_source (priv->viewport);
double zoom_level = shumate_viewport_get_zoom_level (priv->viewport);
double tile_size, map_width, map_height;
double map_x, map_y;
double target_lat, target_lon;
double target_map_x, target_map_y;
double current_lat, current_lon;
double current_map_x, current_map_y;
double new_map_x, new_map_y;
if (map_source == NULL)
return;
tile_size = shumate_map_source_get_tile_size (map_source) * (fmod (zoom_level, 1.0) + 1.0);
map_width = tile_size * shumate_map_source_get_column_count (map_source, zoom_level);
map_height = tile_size * shumate_map_source_get_row_count (map_source, zoom_level);
map_x = shumate_map_source_get_x (map_source, zoom_level, lon);
map_y = shumate_map_source_get_y (map_source, zoom_level, lat);
current_lat = shumate_location_get_latitude (SHUMATE_LOCATION (priv->viewport));
current_lon = shumate_location_get_longitude (SHUMATE_LOCATION (priv->viewport));
current_map_x = shumate_map_source_get_x (map_source, zoom_level, current_lon);
current_map_y = shumate_map_source_get_y (map_source, zoom_level, current_lat);
shumate_viewport_widget_coords_to_location (priv->viewport, GTK_WIDGET (self), x, y, &target_lat, &target_lon);
target_map_x = shumate_map_source_get_x (map_source, zoom_level, target_lon);
target_map_y = shumate_map_source_get_y (map_source, zoom_level, target_lat);
new_map_x = positive_mod (current_map_x - (target_map_x - map_x), map_width);
new_map_y = positive_mod (current_map_y - (target_map_y - map_y), map_height);
shumate_location_set_location (SHUMATE_LOCATION (priv->viewport),
shumate_map_source_get_latitude (map_source, zoom_level, new_map_y),
shumate_map_source_get_longitude (map_source, zoom_level, new_map_x));
}
static void
move_viewport_from_pixel_offset (ShumateMap *self,
double latitude,
......@@ -177,8 +229,6 @@ move_viewport_from_pixel_offset (ShumateMap *self,
ShumateMapSource *map_source;
double x, y;
double lat, lon;
double zoom_level;
double tile_size, max_x, max_y;
g_assert (SHUMATE_IS_MAP (self));
......@@ -186,24 +236,15 @@ move_viewport_from_pixel_offset (ShumateMap *self,
if (!map_source)
return;
zoom_level = shumate_viewport_get_zoom_level (priv->viewport);
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) * (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;
shumate_viewport_location_to_widget_coords (priv->viewport, GTK_WIDGET (self), latitude, longitude, &x, &y);
x = fmod (x, max_x);
if (x < 0)
x += max_x;
x -= offset_x;
y -= offset_y;
y = fmod (y, max_y);
if (y < 0)
y += max_y;
shumate_viewport_widget_coords_to_location (priv->viewport, GTK_WIDGET (self), x, y, &lat, &lon);
lat = shumate_map_source_get_latitude (map_source, zoom_level, y);
lon = shumate_map_source_get_longitude (map_source, zoom_level, x);
lat = fmod (lat + 90, 180) - 90;
lon = fmod (lon + 180, 360) - 180;
shumate_location_set_location (SHUMATE_LOCATION (priv->viewport), lat, lon);
}
......@@ -389,8 +430,13 @@ on_drag_gesture_drag_begin (ShumateMap *self,
cancel_deceleration (self);
priv->drag_begin_lon = shumate_location_get_longitude (SHUMATE_LOCATION (priv->viewport));
priv->drag_begin_lat = shumate_location_get_latitude (SHUMATE_LOCATION (priv->viewport));
priv->drag_begin_x = start_x;
priv->drag_begin_y = start_y;
shumate_viewport_widget_coords_to_location (priv->viewport, GTK_WIDGET (self),
start_x, start_y,
&priv->gesture_begin_lat,
&priv->gesture_begin_lon);
gtk_widget_set_cursor_from_name (GTK_WIDGET (self), "grabbing");
}
......@@ -403,11 +449,11 @@ on_drag_gesture_drag_update (ShumateMap *self,
{
ShumateMapPrivate *priv = shumate_map_get_instance_private (self);
move_viewport_from_pixel_offset (self,
priv->drag_begin_lat,
priv->drag_begin_lon,
offset_x,
offset_y);
move_location_to_coords (self,
priv->gesture_begin_lat,
priv->gesture_begin_lon,
priv->drag_begin_x + offset_x,
priv->drag_begin_y + offset_y);
}
static void
......@@ -422,14 +468,8 @@ on_drag_gesture_drag_end (ShumateMap *self,
gtk_widget_set_cursor_from_name (GTK_WIDGET (self), "grab");
move_viewport_from_pixel_offset (self,
priv->drag_begin_lat,
priv->drag_begin_lon,
offset_x,
offset_y);
priv->drag_begin_lon = 0;
priv->drag_begin_lat = 0;
priv->gesture_begin_lon = 0;
priv->gesture_begin_lat = 0;
}
static void
......@@ -447,41 +487,22 @@ set_zoom_level (ShumateMap *self,
{
ShumateMapPrivate *priv = shumate_map_get_instance_private (self);
ShumateMapSource *map_source;
double scroll_latitude, scroll_longitude;
double view_lon, view_lat;
double lat, lon;
g_object_freeze_notify (G_OBJECT (priv->viewport));
view_lon = shumate_location_get_longitude (SHUMATE_LOCATION (priv->viewport));
view_lat = shumate_location_get_latitude (SHUMATE_LOCATION (priv->viewport));
map_source = shumate_viewport_get_reference_map_source (priv->viewport);
if (map_source)
{
scroll_longitude = shumate_viewport_widget_x_to_longitude (priv->viewport, GTK_WIDGET (self), priv->current_x);
scroll_latitude = shumate_viewport_widget_y_to_latitude (priv->viewport, GTK_WIDGET (self), priv->current_y);
}
shumate_viewport_widget_coords_to_location (priv->viewport,
GTK_WIDGET (self),
priv->current_x, priv->current_y,
&lat, &lon);
shumate_viewport_set_zoom_level (priv->viewport, zoom_level);
if (map_source)
{
double scroll_map_x, scroll_map_y;
double view_center_x, view_center_y;
double x_offset, y_offset;
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);
zoom_level = shumate_viewport_get_zoom_level (priv->viewport);
view_center_x = shumate_map_source_get_x (map_source, zoom_level, view_lon);
view_center_y = shumate_map_source_get_y (map_source, zoom_level, view_lat);
x_offset = scroll_map_x - priv->current_x;
y_offset = scroll_map_y - priv->current_y;
shumate_location_set_location (SHUMATE_LOCATION (priv->viewport),
shumate_map_source_get_latitude (map_source, zoom_level, view_center_y + y_offset),
shumate_map_source_get_longitude (map_source, zoom_level, view_center_x + x_offset));
}
move_location_to_coords (self, lat, lon, priv->current_x, priv->current_y);
g_object_thaw_notify (G_OBJECT (priv->viewport));
}
......@@ -512,15 +533,18 @@ on_zoom_gesture_begin (ShumateMap *self,
{
ShumateMapPrivate *priv = shumate_map_get_instance_private (self);
double zoom_level = shumate_viewport_get_zoom_level (priv->viewport);
double x, y;
gtk_gesture_set_state (GTK_GESTURE (zoom), GTK_EVENT_SEQUENCE_CLAIMED);
cancel_deceleration (self);
priv->zoom_level_begin = zoom_level;
gtk_gesture_get_bounding_box_center (GTK_GESTURE (zoom), &priv->zoom_center_x, &priv->zoom_center_y);
priv->drag_begin_lon = shumate_location_get_longitude (SHUMATE_LOCATION (priv->viewport));
priv->drag_begin_lat = shumate_location_get_latitude (SHUMATE_LOCATION (priv->viewport));
gtk_gesture_get_bounding_box_center (GTK_GESTURE (zoom), &x, &y);
shumate_viewport_widget_coords_to_location (priv->viewport, GTK_WIDGET (self),
x, y,
&priv->gesture_begin_lat,
&priv->gesture_begin_lon);
}
static void
......@@ -533,21 +557,42 @@ on_zoom_gesture_update (ShumateMap *self,
double scale = gtk_gesture_zoom_get_scale_delta (zoom);
gtk_gesture_get_bounding_box_center (GTK_GESTURE (zoom), &x, &y);
shumate_viewport_set_zoom_level (priv->viewport, priv->zoom_level_begin + log (scale) / G_LN2);
move_location_to_coords (self, priv->gesture_begin_lat, priv->gesture_begin_lon, x, y);
}
move_viewport_from_pixel_offset (self,
priv->drag_begin_lat,
priv->drag_begin_lon,
x - priv->zoom_center_x,
y - priv->zoom_center_y);
static void
on_rotate_gesture_begin (ShumateMap *self,
GdkEventSequence *seq,
GtkGestureRotate *rotate)
{
ShumateMapPrivate *priv = shumate_map_get_instance_private (self);
double rotation = shumate_viewport_get_rotation (priv->viewport);
priv->current_x = x;
priv->current_y = y;
set_zoom_level (self, priv->zoom_level_begin + log (scale) / G_LN2);
gtk_gesture_set_state (GTK_GESTURE (rotate), GTK_EVENT_SEQUENCE_CLAIMED);
cancel_deceleration (self);
priv->rotate_begin = rotation;
}
static void
on_rotate_gesture_update (ShumateMap *self,
GdkEventSequence *seq,
GtkGestureRotate *rotate)
{
ShumateMapPrivate *priv = shumate_map_get_instance_private (self);
double rotation;
double x, y;
rotation = gtk_gesture_rotate_get_angle_delta (rotate) + priv->rotate_begin;
priv->drag_begin_lon = shumate_location_get_longitude (SHUMATE_LOCATION (priv->viewport));
priv->drag_begin_lat = shumate_location_get_latitude (SHUMATE_LOCATION (priv->viewport));
priv->zoom_center_x = x;
priv->zoom_center_y = y;
/* snap to due north */
if (fabs (fmod (rotation - 0.25, G_PI * 2)) < 0.5)
rotation = 0.0;
shumate_viewport_set_rotation (priv->viewport, rotation);
gtk_gesture_get_bounding_box_center (GTK_GESTURE (rotate), &x, &y);
move_location_to_coords (self, priv->gesture_begin_lat, priv->gesture_begin_lon, x, y);
}
static void
......@@ -775,6 +820,7 @@ shumate_map_init (ShumateMap *self)
GtkEventController *motion_controller;
GtkGesture *swipe_gesture;
GtkGesture *zoom_gesture;
GtkGesture *rotate_gesture;
priv->viewport = shumate_viewport_new ();
priv->zoom_on_double_click = TRUE;
......@@ -818,6 +864,13 @@ shumate_map_init (ShumateMap *self)
g_signal_connect_swapped (motion_controller, "motion", G_CALLBACK (on_motion_controller_motion), self);
gtk_widget_add_controller (GTK_WIDGET (self), motion_controller);
rotate_gesture = gtk_gesture_rotate_new ();
g_signal_connect_swapped (rotate_gesture, "begin", G_CALLBACK (on_rotate_gesture_begin), self);
g_signal_connect_swapped (rotate_gesture, "update", G_CALLBACK (on_rotate_gesture_update), self);
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (rotate_gesture));
gtk_gesture_group (zoom_gesture, rotate_gesture);
gtk_widget_set_overflow (GTK_WIDGET (self), GTK_OVERFLOW_HIDDEN);
}
......
......@@ -123,8 +123,9 @@ update_marker_visibility (ShumateMarkerLayer *layer,
gtk_widget_measure (GTK_WIDGET (marker), GTK_ORIENTATION_HORIZONTAL, -1, 0, &marker_width, NULL, NULL);
gtk_widget_measure (GTK_WIDGET (marker), GTK_ORIENTATION_VERTICAL, -1, 0, &marker_height, NULL, NULL);
x = floorf (shumate_viewport_longitude_to_widget_x (viewport, GTK_WIDGET (layer), lon) - marker_width/2.f);
y = floorf (shumate_viewport_latitude_to_widget_y (viewport, GTK_WIDGET (layer), lat) - marker_height/2.f);
shumate_viewport_location_to_widget_coords (viewport, GTK_WIDGET (layer), lat, lon, &x, &y);
x = floorf (x - marker_width/2.f);
y = floorf (y - marker_height/2.f);
within_viewport = x > -marker_width && x <= width &&
y > -marker_height && y <= height &&
......@@ -186,6 +187,16 @@ on_view_zoom_level_changed (ShumateMarkerLayer *self,
shumate_marker_layer_reposition_markers (self);
}
static void
on_view_rotation_changed (ShumateMarkerLayer *self,
GParamSpec *pspec,
ShumateViewport *view)
{
g_assert (SHUMATE_IS_MARKER_LAYER (self));
shumate_marker_layer_reposition_markers (self);
}
static void
shumate_marker_layer_size_allocate (GtkWidget *widget,
int width,
......@@ -217,8 +228,9 @@ shumate_marker_layer_size_allocate (GtkWidget *widget,
gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1, 0, &marker_width, NULL, NULL);
gtk_widget_measure (child, GTK_ORIENTATION_VERTICAL, -1, 0, &marker_height, NULL, NULL);
x = floorf (shumate_viewport_longitude_to_widget_x (viewport, widget, lon) - marker_width/2.f);
y = floorf (shumate_viewport_latitude_to_widget_y (viewport, widget, lat) - marker_height/2.f);
shumate_viewport_location_to_widget_coords (viewport, widget, lat, lon, &x, &y);
x = floorf (x - marker_width/2.f);
y = floorf (y - marker_height/2.f);
allocation.x = x;
allocation.y = y;
......@@ -312,6 +324,7 @@ shumate_marker_layer_constructed (GObject *object)
g_signal_connect_swapped (viewport, "notify::longitude", G_CALLBACK (on_view_longitude_changed), self);
g_signal_connect_swapped (viewport, "notify::latitude", G_CALLBACK (on_view_latitude_changed), self);
g_signal_connect_swapped (viewport, "notify::zoom-level", G_CALLBACK (on_view_zoom_level_changed), self);
g_signal_connect_swapped (viewport, "notify::rotation", G_CALLBACK (on_view_rotation_changed), self);
}
......
......@@ -107,6 +107,16 @@ on_view_zoom_level_changed (ShumatePathLayer *self,
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
on_view_rotation_changed (ShumatePathLayer *self,
GParamSpec *pspec,
ShumateViewport *view)
{
g_assert (SHUMATE_IS_PATH_LAYER (self));
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
shumate_path_layer_get_property (GObject *object,
......@@ -235,7 +245,7 @@ shumate_path_layer_constructed (GObject *object)
g_signal_connect_swapped (viewport, "notify::longitude", G_CALLBACK (on_view_longitude_changed), self);
g_signal_connect_swapped (viewport, "notify::latitude", G_CALLBACK (on_view_latitude_changed), self);
g_signal_connect_swapped (viewport, "notify::zoom-level", G_CALLBACK (on_view_zoom_level_changed), self);
g_signal_connect_swapped (viewport, "notify::rotation", G_CALLBACK (on_view_rotation_changed), self);
}
......@@ -278,10 +288,11 @@ shumate_path_layer_snapshot (GtkWidget *widget,
for (elem = priv->nodes; elem != NULL; elem = elem->next)
{
ShumateLocation *location = SHUMATE_LOCATION (elem->data);
double x, y;
double x, y, lat, lon;
x = shumate_viewport_longitude_to_widget_x (viewport, widget, shumate_location_get_longitude (location));
y = shumate_viewport_latitude_to_widget_y (viewport, widget, shumate_location_get_latitude (location));
lat = shumate_location_get_latitude (location);
lon = shumate_location_get_longitude (location);
shumate_viewport_location_to_widget_coords (viewport, widget, lat, lon, &x, &y);
cairo_line_to (cr, x, y);
}
......
......@@ -43,6 +43,7 @@ struct _ShumateViewport
double zoom_level;
guint min_zoom_level;
guint max_zoom_level;
double rotation;
ShumateMapSource *ref_map_source;
};
......@@ -58,6 +59,7 @@ enum
PROP_MIN_ZOOM_LEVEL,
PROP_MAX_ZOOM_LEVEL,
PROP_REFERENCE_MAP_SOURCE,
PROP_ROTATION,
N_PROPERTIES,
PROP_LONGITUDE,
......@@ -127,6 +129,10 @@ shumate_viewport_get_property (GObject *object,
g_value_set_object (value, self->ref_map_source);
break;
case PROP_ROTATION:
g_value_set_double (value, self->rotation);
break;
case PROP_LONGITUDE:
g_value_set_double (value, self->lon);
break;
......@@ -167,6 +173,10 @@ shumate_viewport_set_property (GObject *object,
shumate_viewport_set_reference_map_source (self, g_value_get_object (value));
break;
case PROP_ROTATION:
shumate_viewport_set_rotation (self, g_value_get_double (value));
break;
case PROP_LONGITUDE:
self->lon = CLAMP (g_value_get_double (value), SHUMATE_MIN_LONGITUDE, SHUMATE_MAX_LONGITUDE);
g_object_notify (object, "longitude");
......@@ -249,6 +259,18 @@ shumate_viewport_class_init (ShumateViewportClass *klass)
"The reference map source being displayed",
SHUMATE_TYPE_MAP_SOURCE,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* ShumateViewport:rotation:
*
* The rotation of the map view, in radians clockwise from up being due north
*/
obj_properties[PROP_ROTATION] =
g_param_spec_double ("rotation",
"Rotation",
"The rotation of the map view in radians",
0, G_PI * 2.0, 0,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class,
N_PROPERTIES,
......@@ -480,139 +502,160 @@ shumate_viewport_get_reference_map_source (ShumateViewport *self)
}
/**
* shumate_viewport_widget_x_to_longitude:
* shumate_viewport_set_rotation:
* @self: a #ShumateViewport
* @widget: a #GtkWidget that uses @self as viewport
* @x: the x coordinate
* @rotation: the rotation
*
* Get the longitude from an x coordinate of a widget.
* The widget is assumed to be using the viewport.
*
* Returns: the longitude
* Sets the rotation
*/
double
shumate_viewport_widget_x_to_longitude (ShumateViewport *self,
GtkWidget *widget,
double x)
void
shumate_viewport_set_rotation (ShumateViewport *self,
double rotation)
{
double center_x;
int width;
g_return_if_fail (SHUMATE_IS_VIEWPORT (self));
g_return_val_if_fail (SHUMATE_IS_VIEWPORT (self), 0.0);
g_return_val_if_fail (GTK_IS_WIDGET (widget), 0.0);
rotation = fmod (rotation, G_PI * 2.0);
if (!self->ref_map_source)
{
g_critical ("A reference map source is required to compute the longitude from X.");
return 0.0;
}
if (self->rotation == rotation)
return;
width = gtk_widget_get_width (widget);
center_x = shumate_map_source_get_x (self->ref_map_source, self->zoom_level, self->lon);
return shumate_map_source_get_longitude (self->ref_map_source, self->zoom_level, center_x - width/2 + x);
self->rotation = rotation;
g_object_notify_by_pspec (G_OBJECT (self), obj_properties[PROP_ROTATION]);
}
/**
* shumate_viewport_widget_y_to_latitude:
* shumate_viewport_get_rotation:
* @self: a #ShumateViewport
* @widget: a #GtkWidget that uses @self as viewport
* @y: the y coordinate
*
* Get the latitude from an y coordinate of a widget.
* The widget is assumed to be using the viewport.
*
* Returns: the latitude
* Gets the current rotation
*
* Returns: the current rotation
*/
double
shumate_viewport_widget_y_to_latitude (ShumateViewport *self,
GtkWidget *widget,
double y)
shumate_viewport_get_rotation (ShumateViewport *self)
{
double center_y;
int height;
g_return_val_if_fail (SHUMATE_IS_VIEWPORT (self), 0);
g_return_val_if_fail (SHUMATE_IS_VIEWPORT (self), 0.0);
g_return_val_if_fail (GTK_IS_WIDGET (widget), 0.0);
return self->rotation;
}
if (!self->ref_map_source)
{
g_critical ("A reference map source is required to compute Y from the latitude.");
return 0.0;
}
static void
rotate_around_center (double *x, double *y, double width, double height, double angle)
{