/* GNOME canvas based interface to a map using a simple cylindrical proj */
/* */
/* Copyright (C) 1999 Red Hat, Incorportated */
/* Original work by Michael Fulbright <
[email protected]> */
#include <gnome.h>
#include <math.h>
#include "gnome-map.h"
/* look in <gdk/gdkcursors.h> for valid values */
#define MAP_CURSOR GDK_LEFT_PTR
/**
* gnome_map_set_image:
* @map: Map to apply image to.
* @imagefile: Filename of image for map.
*
* This function sets the image used for the map to @imagefile. It is
* assumed that this image is a simple cylindrical projection.
*
* Return value: 0 on success, -1 if image could not be loaded
**/
static gint
gnome_map_set_image ( GnomeMap *map, gchar *imagefile )
{
g_return_val_if_fail ( map != NULL, -1 );
g_return_val_if_fail ( map->image == NULL, -1 );
/* load map image */
if (map->aa)
map->image = gnome_canvas_load_alpha (imagefile);
else
map->image = gdk_imlib_load_image (imagefile);
if (!map->image)
return -1;
return 0;
}
static void
canvas_realize_event (GtkWidget *canvas, gpointer *data)
{
GdkCursor *ptrcursor;
ptrcursor = gdk_cursor_new (MAP_CURSOR);
if (!ptrcursor) {
g_warning ("Unable to load new cursor %d for map\n", MAP_CURSOR);
return;
}
gdk_window_set_cursor (canvas->window, ptrcursor);
gdk_cursor_destroy (ptrcursor);
}
/**
* gnome_map_new:
* @imagefile: File to be used map image.
* @width: Width of map view in pixels.
* @height: Height of map view in pixels.
* @antialias: Boolean used to set map to use antialias canvas or not.
*
* Creates a new map, using anti-aliased or normal canvas based on the
* value of @antialias. Of anti-aliased maps the image file must be
* in PNG format (this is a gnome-canvas limitation as of gnome-libs 1.0.10).
* If @width and @height are both <= 0, then the map image size is used.
* If only one of @width or @height is > 0, then the unspecified
* dimension is scaled (perserving the aspect of the original image).
*
* Return value: The newly-created map structure or NULL if image couldn't
* be loaded.
**/
GnomeMap *
gnome_map_new ( gchar *imagefile, gint width, gint height, gboolean aa )
{
GnomeCanvasGroup *canvas_root;
GnomeMap *map;
gint h, w;
map = g_new0 ( GnomeMap, 1 );
map->aa = aa;
if ( gnome_map_set_image ( map, imagefile ) < 0 ) {
g_free (map);
return NULL;
}
/* create a canvas */
if (aa) {
gtk_widget_push_visual (gdk_rgb_get_visual ());
gtk_widget_push_colormap (gdk_rgb_get_cmap ());
map->canvas = gnome_canvas_new_aa ();
} else {
gtk_widget_push_visual (gdk_imlib_get_visual ());
gtk_widget_push_colormap (gdk_imlib_get_colormap ());
map->canvas = gnome_canvas_new ();
}
/* set map size and scaling */
if ( width <= 0 && height <= 0 ) {
w = map->image->rgb_width;
h = map->image->rgb_height;
} else if ( width > 0 && height <= 0 ) {
w = width;
h = (int)(((float)w/(float)map->image->rgb_width)*map->image->rgb_height);
} else if ( width <= 0 && height > 0 ) {
h = height;
w = (int)(((float)h/(float)map->image->rgb_height)*map->image->rgb_width);
} else {
w = width;
h = height;
}
map->width = w;
map->height = h;
map->long1 = -180.0;
map->lat1 = -90.0;
map->long2 = 180.0;
map->lat2 = 90.0;
gtk_widget_set_usize (map->canvas, w, h);
gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (map->canvas), 1.0);
gnome_canvas_set_scroll_region (GNOME_CANVAS (map->canvas),
0.0, 0.0,
(double)w, (double)h);
gtk_widget_show(map->canvas);
/* Setup canvas items */
canvas_root = gnome_canvas_root (GNOME_CANVAS (map->canvas));
map->image_item = gnome_canvas_item_new (canvas_root,
gnome_canvas_image_get_type (),
"image", map->image,
"x", 0.0,
"y", 0.0,
"width", (double) w,
"height", (double) h,
"anchor", GTK_ANCHOR_NW,
NULL);
/* grap realize signal so we can set cursor for map */
gtk_signal_connect (GTK_OBJECT (map->canvas), "realize",
(GtkSignalFunc) canvas_realize_event,
NULL);
/* restore to original */
gtk_widget_pop_colormap ();
gtk_widget_pop_visual ();
return map;
}
/**
* gnome_map_get_image_size: Get the unscaled image size of map image.
* @map: The map which image size is desired for.
* @width: Width of map in pixels.
* @height: Height of map in pixels.
*
* Given the GnomeMap @map, this function returns the dimensions of the
* original unscaled map image.
*
* Return value: None.
**/
void
gnome_map_get_image_size ( GnomeMap *map, gint *width, gint *height )
{
g_return_if_fail ( map != NULL || map->image != NULL);
g_return_if_fail ( width != NULL || height != NULL );
*width = map->image->rgb_width;
*height = map->image->rgb_width;
}
/**
* gnome_map_set_size: Set screen dimensions (in pixels) of map view.
* @map: Map to apply dimensions to.
* @width: Desired width of map view.
* @height: Desired height of map view.
*
* Given a map which has an image associated with it via the
* gnome_map_set_image() call, set the onscreen size of the map view widget.
*
* Return value: None.
**/
void
gnome_map_set_size ( GnomeMap *map, gint width, gint height )
{
g_return_if_fail ( map != NULL );
g_return_if_fail ( map->canvas != NULL );
g_return_if_fail ( map->image != NULL );
g_return_if_fail ( width > 0 );
g_return_if_fail ( height > 0 );
}
/**
* gnome_map_xlat_map2screen: Convert from map coordinates to screen coordinates.
* @map: Map to apply dimensions to.
* @longitude: Longitude coordinate to convert (in degrees).
* @latitude: Latitude coordinate to convert (in degrees).
* @sx: Converted screen coordinate.
* @sy: Converted screen coordinate.
*
* A (longitude, latitude) pair is converted to a (x, y) canvas coordinate.
* (An obvious improvement to the gnome-map would be to just let the
* canvas do the mapping internally. If this change is made this function
* will still work but will be a small stub).
*
* Return value: None.
**/
void
gnome_map_xlat_map2screen ( GnomeMap *map,
double longitude, double latitude,
double *sx, double *sy )
{
g_return_if_fail ( map != NULL );
*sx = (map->width/2.0 + (map->width/2.0)*longitude/180.0);
*sy = (map->height/2.0 - (map->height/2.0)*latitude/90.0);
}
/**
* gnome_map_xlat_screen2map: Convert from screen coordinates to map coordinates.
* @map: Map to apply dimensions to.
* @sx: Screen coordinate to convert.
* @sy: Screen coordinate to convert.
* @longitude: Converted longitude coordinate (in degrees).
* @latitude: Converted latitude coordinate (in degrees).
*
* A (x, y) canvas coordinate is converted to a (longitude, latitude) pair.
* (An obvious improvement to the gnome-map would be to just let the
* canvas do the mapping internally. If this change is made this function
* will still work but will be a small stub).
*
* Return value: None.
**/
void
gnome_map_xlat_screen2map ( GnomeMap *map,
double sx, double sy,
double *longitude, double *latitude)
{
g_return_if_fail ( map != NULL );
*longitude = ( sx - (double)map->width/2.0)/((double)map->width/2.0)*180.0;
*latitude = ((double)map->height/2.0-sy)/((double)map->height/2.0)*90.0;
}
/**
* gnome_map_set_view: Set view of map in map coordinates.
* @map: Map to apply dimensions to.
* @longitude1: Longitude of corner 1.
* @latitude1: Latitude of corner 1.
* @longitude2: Longitude of corner 2.
* @latitude2: Latitude of corner 2.
*
* Sets view of map to a box defined by the two corners given in map
* coordinates.
*
* Return value: None.
**/
void
gnome_map_set_view ( GnomeMap *map,
double longitude1, double latitude1,
double longitude2, double latitude2)
{
double x1, y1, x2, y2;
double scale;
g_return_if_fail ( map != NULL );
g_return_if_fail ( longitude1 >= -180.0 && longitude1 <= 180.0 );
g_return_if_fail ( longitude2 >= -180.0 && longitude2 <= 180.0 );
g_return_if_fail ( latitude1 >= -90.0 && latitude1 <= 90.0 );
g_return_if_fail ( latitude2 >= -90.0 && latitude2 <= 90.0 );
gnome_map_xlat_map2screen (map, longitude1, latitude1, &x1, &y1);
gnome_map_xlat_map2screen (map, longitude2, latitude2, &x2, &y2);
gnome_canvas_set_scroll_region (GNOME_CANVAS(map->canvas),
x1, y1, x2, y2);
if (longitude1 < longitude2) {
map->long1 = longitude1;
map->long2 = longitude2;
} else {
map->long1 = longitude2;
map->long2 = longitude1;
}
if (latitude1 < latitude2) {
map->lat1 = latitude1;
map->lat2 = latitude2;
} else {
map->lat1 = latitude2;
map->lat2 = latitude1;
}
scale = ((double)map->width)/fabs(x1-x2);
gnome_canvas_set_pixels_per_unit (GNOME_CANVAS(map->canvas), scale);
}
/**
* gnome_map_is_loc_in_view: Test to see if location is on current view
* @map: Map to apply dimensions to.
* @longitude: Longitude of location to test.
* @latitude: Latitude of location to test.
*
* Tests whether (longitude, latitude) is within current map view.
*
* Return value: TRUE is visible, FALSE if not.
**/
gboolean
gnome_map_is_loc_in_view (GnomeMap *map, double longitude, double latitude)
{
return !(longitude < map->long1 || longitude > map->long2 ||
latitude < map->lat1 || latitude > map->lat2);
}