2015年11月3日 星期二

Mapsforge:Get Started


前置準備Preparation


Mapsforge是一個很棒的Vector Map Library,相信讀者一定很想要趕快著手開發 但在開始前需要先準備好一些東西

API部分

  • mapsforge-core: 這是Mapsforge的核心Library所有相關Mapsforge的Library都是以他為基礎
  • mapsforge-map: 這個是負責Mapsforge中地圖相關處裡的Library
  • mapsforge-map-android: 這個Library中提供了一些如MapView, AndroidGraphicFactory等讓Android可以充分使用Mapsforge的物件
  • mapsforge-map-reader: 這個Mapsforge的.map檔的解析器Library
以上可以在 Mapsforge專案 中找到

圖資部分

這個範例是離線地圖,所以首先你需要2個圖資
  • 1. world-lowres-0-7.map
  • 2. taiwan.map
以上兩個檔案須放在外部儲存空間中的mapsforge/maps/(所屬的洲)裡 所以如果兩個檔案的完整路徑則為
  • 1. mapsforge/maps/world/world-lowres-0-7.map
  • 2. mapsforge/maps/asia/taiwan.map

範例程式Sample

(本範例所使用的Mapsforge版本為0.6.0-rc1)




SampleMapView.java
import android.app.Activity;
import android.os.Bundle;

import org.mapsforge.core.model.LatLong;
import org.mapsforge.core.model.MapPosition;
import org.mapsforge.map.android.graphics.AndroidGraphicFactory;
import org.mapsforge.map.android.util.AndroidUtil;
import org.mapsforge.map.android.view.MapView;
import org.mapsforge.map.datastore.MapDataStore;
import org.mapsforge.map.datastore.MultiMapDataStore;
import org.mapsforge.map.layer.cache.TileCache;
import org.mapsforge.map.layer.renderer.TileRendererLayer;
import org.mapsforge.map.reader.MapFile;
import org.mapsforge.map.rendertheme.InternalRenderTheme;

import java.io.File;

/**
 * Created by lienching on 10/17/15.
 */
public class SimpleMapView extends Activity {

    private MapView mapView;
    private MultiMapDataStore multiMapDataStore;
    private MapDataStore worldMap,taiwanMap;
    private TileCache tileCache;
    private TileRendererLayer tileRendererLayer;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        AndroidGraphicFactory.createInstance(this.getApplication());//使用Mapsforge Library必須呼叫此方法來初始化
        mapView = new MapView(this);
        mapView.setClickable(true);
        mapView.getMapScaleBar().setVisible(true);
        mapView.setBuiltInZoomControls(true);
        mapView.getMapZoomControls().setZoomLevelMin((byte) 5);
        mapView.getMapZoomControls().setZoomLevelMax((byte) 20);

        worldMap = new MapFile(new File(Constant.PATH_WORLDMAP));
        taiwanMap = new MapFile(new File(Constant.PATH_TAIWANMAP));
        multiMapDataStore = new MultiMapDataStore(MultiMapDataStore.DataPolicy.RETURN_ALL);

        tileCache = AndroidUtil.createTileCache(this, "mapcache", mapView.getModel().displayModel.getTileSize(), 1f, this.mapView.getModel().frameBufferModel.getOverdrawFactor());
        setContentView(mapView);
    }

    @Override
    protected void onStart() {
        super.onStart();
        multiMapDataStore.addMapDataStore(worldMap,true,true);
        multiMapDataStore.addMapDataStore(taiwanMap,false,false);
        //multiMapDataStore.setStartPosition(new LatLong(23, 121));
        //multiMapDataStore.setStartZoomLevel((byte) 7);
        tileRendererLayer = new TileRendererLayer(tileCache,multiMapDataStore,mapView.getModel().mapViewPosition,false,true, AndroidGraphicFactory.INSTANCE);
        tileRendererLayer.setXmlRenderTheme(InternalRenderTheme.OSMARENDER);

        mapView.getModel().mapViewPosition.setMapPosition(new MapPosition(new LatLong(23, 121), (byte) 7));
        mapView.getLayerManager().getLayers().add(tileRendererLayer);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        this.mapView.destroyAll();
    }
}

Constant.java
import android.os.Environment;

/**
 * Created by lienching on 10/19/15.
 */
public class Constant {
    private static final String PATH_MAPSFORGE = Environment.getExternalStorageDirectory().toString() + "/mapsforge/maps/";
    public static final String PATH_WORLDMAP = PATH_MAPSFORGE + "world/world-lowres-0-7.map";
    public static final String PATH_TAIWANMAP = PATH_MAPSFORGE + "asia/taiwan.map";

}


Q&A


1. 如果我很懶,我有甚麼辦法可以讓App自己下載圖資呢?

那妳可以建立一個專門下載圖資的類別,範例如下
import android.app.DownloadManager;
import android.content.Context;
import android.net.Uri;
import android.os.Environment;


/**
 * Created by lienching on 10/14/15.
 * The purpose of this class is to define the map resource download methods, so we
 * can easily download a map resource by this class.
 */
public class MapDownloadManager{
    private DownloadManager downloadManager;
    private DownloadManager.Request request;
    private String external_path = Environment.getExternalStorageDirectory().toString();
    private Context context;
    public MapDownloadManager(Context context){
        this.context = context;
        downloadManager = (DownloadManager)context.getSystemService(Context.DOWNLOAD_SERVICE);

    }
    public void downloadMapResource(String mapfile){
        Uri download_URI = Uri.parse("http://download.mapsforge.org/maps/"+mapfile);
        request = new DownloadManager.Request(download_URI);
        //Set the network type which is allow to process the download request
        request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
        //Set whether this download may proceed over a roaming connection.
        request.setAllowedOverRoaming(false);
        request.setTitle("Mapsforge Map Download");
        request.setDestinationInExternalPublicDir("/mapsforge/maps/",mapfile);
        downloadManager.enqueue(request);
    }
}

之後只要在主類別中呼叫就能使用囉~