Using the MAP Library

The Mosync MAP library is a standard library that provides a MapWidget for displaying geographical maps, sometimes called slippy or panning maps, consisting of tiles provided by a map source. This guide introduces the basics of the MAP library and shows you how to create map applications from scratch.

Important: MoSync 2.5 includes an improved MAP Library. If you want to compile in MoSync 2.5 an existing application that uses the 2.4 MAP Library you will need to update that application. See Migrating to the 2.5 MAP Library

Introduction

At the heart of the MAP Library is MapWidget. You can use it as is, or extend it to overlay information on top of the map. The library contains map classes for using one or more tile-based map servers such as OpenStreetMap, CloudMade, and Google Maps.

Latitude and longitude co-ordinates can be converted to meters and pixels (both global and device). Connection to a location-aware sensor is performed by the client, and is outside of the scope of the library itself.

The primary public map source is OpenStreetMap (openstreetmap.org). There is a working hook into Google Static Maps; however use of Google Static Maps requires a license agreement with Google, so this is more of a code sample.

Example Programs

There are two examples programs you can use to study the use of the MAP Library:  

  • HelloMap is a simple Moblet that displays an OpenStreetMap across the entire device screen. The user can use the phone keys to pan the map and to zoom in and out. The core of the HelloMap sample application is in HelloMapScreen.cpp.
  • MapDemo is a more full-blown example that illustrates the use of the map library in an application.

 These examples are written using a memory tracker to allocate and deallocate memory. This makes the code a little more complex than is strictly necessary, but will prove useful if you want to use a memory tracker in your application.

The MAP Library

The Map Library provides classes for downloading, managing and displaying map tiles. The library includes:

  • MapSource is a base class with implementations for OpenStreetMap, Google Static Maps, CloudMade, as well as an extensible API for other map sources.
  • MapWidget is a class for displaying a slippy map in a Mosync Moblet-based application. MapWidget uses class MapViewport to handle panning and zooming of the map.
  • Tile management and caching classes, notably the MapCache class which is a singleton that provides map tiles.
  • Utility and support classes.

Important MAP classes

MapSourceAbstract base class for provider of map tiles
CloudMadeMapSourceMapSource using CloudMade public map tile server
GoogleMapSourceMapSource using Google Static Maps as map tile server
OpenStreetMapSourceMapSource using OpenStreetMap tile server
MapCacheCaches tiles provided by MapSource
MapTileSingle tile from MapSource
LonLatCoordinate class
PixelCoordinateGlobal map pixel coordinate at a specified magnification
MapTileCoordinateDescribes a tile’s position in global grid of tiles at a certain magnification
MapWidgetWidget displaying slippy map
MapViewportHandles panning and zooming of the map
DateTimeUtility class for date
TimespanUtility class for time span
MemoryMgrUtility class for heap resource tracking for debugging
BroadcasterUtility template class for broadcasting to multiple listeners
QueueUtility template class for a simple object queue
DebugPrintfUtility functions for debug output under MSVC compiler

How to use map sources

Include the header files for the map sources you wish to use, for example:

#include <MAP/OpenStreetMapSource.h>
#include <MAP/GoogleMapSource.h>

Generally, it is a good idea to use instance variables in your class to refer to the map sources, for example:

MapSource* mOpenStreetMapSource;
MapSource* mGoogleStreetMapSource;
MapSource* mGoogleAerialMapSource;
MapSource* mGoogleHybridMapSource;

The map library comes with two map sources that have been set up for you, OpenStreetMap and GoogleMaps. Here is how to create and set up map sources:

mOpenStreetMapSource = new OpenStreetMapSource();
mGoogleStreetMapSource = new GoogleMapSource(GoogleMapKind_StreetMap);
mGoogleAerialMapSource = new GoogleMapSource(GoogleMapKind_Aerial);
mGoogleHybridMapSource = new GoogleMapSource(GoogleMapKind_Hybrid);

Set the current map source like this:

mMapWidget->setMapSource(mGoogleAerialMapSource);

Basic example

This is a bare-bones application with touch interaction -- single touch and drag pans the map; a second touch zooms in a fixed step while pressed, and zooms out when released.

#include <MAUtil/Moblet.h>
#include <MAUI/Screen.h>
#include <MAP/MapWidget.h>
#include <MAP/OpenStreetMapSource.h>

using namespace MAUtil;
using namespace MAUI;
using namespace MAP;

class MapMoblet : public Moblet
{
public:
    MapMoblet()
    {
         mMapWidget = new MapWidget(
            0,
            0,
            EXTENT_X(maGetScrSize()),
            EXTENT_Y(maGetScrSize()),
            NULL);

        // Create a MapViewport for the MapWidget.
        // The MapWidget will deallocate the viewport upon destruction.
        mMapWidget->setViewport(new MapViewport());

        mOpenStreetMapSource = new OpenStreetMapSource();
        mMapWidget->setMapSource(mOpenStreetMapSource);

        mMapWidget->getViewport()->setCenterPosition(
            LonLat(18.07, 59.33), // Position for Stockholm.
            true, // Redraw now.
            false // Not called from pointer event.
            );

        // Magnification level (logarithmic scale).
        mMagnification = 11.0;
        setMagnification(mMagnification);

        mScreen = new Screen();
        mScreen->setMain(mMapWidget);
        mScreen->show();
    }

    virtual ~MapMoblet()
    {
        delete mScreen;
        delete mMapWidget;
        delete mOpenStreetMapSource;
    }

    void keyPressEvent(int keyCode, int nativeCode)
    {
        if (MAK_BACK == keyCode || MAK_0 == keyCode)
        {
            close();
        }
    }

    void multitouchPressEvent(MAPoint2d point, int touchId)
    {
        if (0 == touchId)
        {
            beginPanning(point);
        }
        else if (1 == touchId)
        {
            zoomIn();
        }
    }

    void multitouchMoveEvent(MAPoint2d point, int touchId)
    {
        if (0 == touchId)
        {
            updatePanning(point);
        }
    }

    void multitouchReleaseEvent(MAPoint2d point, int touchId)
    {
        if (0 == touchId)
        {
            endPanning();
        }
        else if (1 == touchId)
        {
            zoomOut();
        }
    }

    void beginPanning(MAPoint2d point)
    {
        mMapWidget->getViewport()->beginPanning(point);
    }

    void updatePanning(MAPoint2d point)
    {
        mMapWidget->getViewport()->updatePanning(point);
    }

    void endPanning()
    {
        mMapWidget->getViewport()->endPanning();
    }

    void zoomIn()
    {
        mMagnification += 3.0;
        setMagnification(mMagnification);
    }

    void zoomOut()
    {
        mMagnification -= 3.0;
        setMagnification(mMagnification);
    }

    void setMagnification(double magnification)
    {
        mMapWidget->getViewport()->setMagnification(
            MagnificationType(magnification));
    }

private:
    Screen* mScreen;
    MapWidget* mMapWidget;
    MapSource* mOpenStreetMapSource;
    double mMagnification;
};

extern "C" int MAMain()
{
    // Optionally, for example if you encounter memory problems, you can
    // experiment with the size of the tile cache. Set the cache size like this:
    //MapCache::get()->setCapacity(30);
 
    Moblet* moblet = new MapMoblet();
    Moblet::run(moblet);
    delete moblet;
    MapCache::shutdown();
    return 0;
}

Migrating to the 2.5 MAP Library

To be able to compile them with MoSync SDK 2.5, existing applications that use an older versions of the MAP Library need to be updated, since the new API is not backwards compatible. Here we explain how to update your existing code.
 
The major change in the API is how map sources are represented. A map source is a map provider, like OpenStreetMap or GoogleMaps. The old API used a predefined enumeration of map providers. The new API, by contrast, uses a more flexible model where the application can define map source providers.

Initialize/shutdown


MoSync 2.4 and earlier:

MapMoblet* moblet = new MapMoblet();
Moblet::run(moblet);
delete moblet;

MoSync 2.5:

// Create and run the moblet in the same way as before.
MapMoblet* moblet = new MapMoblet();
Moblet::run(moblet);
delete moblet;

// Free resources allocated by the Map cache.
MapCache::shutdown();

Header files

The header files for the map source has been changed.

MoSync 2.4 and earlier:

// This header file has been removed from the new map library.
#include <MAP/MapSourceMgr.h>

MoSync 2.5:

#include <MAP/MapSource.h>

// Typically you include only the header files for the map sources you
// wish to use, for example:
#include <MAP/OpenStreetMapSource.h>
#include <MAP/GoogleMapSource.h>

Using map sources

The MapSourceKind enumeration is replaced by map source classes.

MoSync 2.4 and earlier:

MapSourceKind mMapSourceKind;

MoSync 2.5:

MapSource* mOpenStreetMapSource;
MapSource* mGoogleStreetMapSource;
MapSource* mGoogleAerialMapSource;
MapSource* mGoogleHybridMapSource;

Create the MapWidget

MoSync 2.4 and earlier:

mMapWidget = new MapWidget(0, 0, width, height, NULL);

MoSync 2.5:

// You need to create a MapViewport for the MapWidget.
// The MapWidget will deallocate the viewport upon destruction.
mMapWidget = new MapWidget(0, 0, width, height, NULL);
mMapWidget->setViewport(new MapViewport());

How to create/set the map source

MoSync 2.4 and earlier:

// In the old API an enumeration constant was used to
// specify the map source (this was inflexible).
mMapWidget->setMapSourceKind(MapSourceKind_OpenStreetMap);

MoSync 2.5:

// In the new API, the application can create the map source,
// which is a more flexible approach. The map library comes
// with two map sources that have been set up for you,
// OpenStreetMap and GoogleMaps. This is how to create and
// set these map sources:
mOpenStreetMapSource = new OpenStreetMapSource();
mGoogleStreetMapSource = new GoogleMapSource(GoogleMapKind_StreetMap);
mGoogleAerialMapSource = new GoogleMapSource(GoogleMapKind_Aerial);
mGoogleHybridMapSource = new GoogleMapSource(GoogleMapKind_Hybrid);

// Set the map source like this:
mMapWidget->setMapSource(mGoogleAerialMapSource);