Topics & News
マピオンラボリニューアルしました。

Mapion マピオンラボ モバイル 独自画像をAndroid Maps APIで表示する方法(ImageMagick編)

独自画像をAndroid Maps APIで表示する方法(ImageMagick編)

Posted by 本城 博昭  エンジニア 

Mapion Android Maps APIで独自画像を表示する方法を紹介します。
デモアプリの「独自地図画像を指定する」の実現方法です。
今回はImageMagick編です。
前回記事の通りGMap Image Cutterを使えば簡単にタイルを作成できますが、ImageMagickを使えばもっと自由にタイルを作れます。
GMap Image Cutterの場合はググルマップに最適化されるので、タイルサイズが256x256に強制されたり、ズーム率が固定だったりします。
けれど、Maps APIはタイルサイズもズーム率も自由に設定できるので、ImageMagickを使えば元画像を最大限利用できるのです。

※独自画像を実装するためにはmaps API 2.5以上が推奨です(それ以前のVerはスクロール遅いなど問題あり)

手順

1.ImageMagickを使ってタイルを作成する

※前回記事と同じ画像を使って同じように縮尺3つ、各倍率2倍とした場合の例です

レベル3作成(画像を320x200に分割)
$ convert -crop 320x200 sa.png level3.png

レベル2作成(50%の画像を320x200に分割)
$ convert -geometry 50% sa.png level2_tmp.png
$ convert -crop 320x200 level2_tmp.png level2.png

レベル1作成(25%の画像)
$ convert -geometry 25% sa.png level1_0.png

tmpファイル削除
$ rm *_tmp.png

ファイル名内のハイフンをアンスコに変更(Androidではリソースにハイフン使えないので)
$ rename 's/-/_/' *

2.res/drawable-nodpiにタイルをコピーする

my_01.png


3.Mapのサブクラスを作る

可変な部分は、tileWidth(タイルの横幅), tileHeight(タイルの高さ), cols(各縮尺のタイルの横の枚数), rows(各縮尺のタイルの縦の枚数) , ratios(各縮尺の倍率)です。
package jp.co.mapion.android.mymap;

import java.lang.reflect.Field;
import java.util.HashMap;

import jp.co.mapion.android.maps.GeoPoint;
import jp.co.mapion.android.maps.Map;
import jp.co.mapion.android.maps.Tile;
import android.graphics.Point;

public class MyMap extends Map {

	protected int tileWidth = 320;
	protected int tileHeight = 200;

	protected HashMap<Integer, Integer> cols = new HashMap<Integer, Integer>();
	protected HashMap<Integer, Integer> rows = new HashMap<Integer, Integer>();

	protected HashMap<Integer, Float> ratios = new HashMap<Integer, Float>();

	private HashMap<String, Integer> tileNameMap = new HashMap<String, Integer>();

	private String key;

	private int noimage;

	public MapionTownMap(String key, int noimage) {
		this.key = key;
		this.noimage = noimage;
		init();
	}

	protected void init() {
		cols.put(1, 1);
		cols.put(2, 2);
		cols.put(3, 4);

		rows.put(1, 1);
		rows.put(2, 2);
		rows.put(3, 4);

		ratios.put(1, 4.0f);
		ratios.put(2, 2.0f);
		ratios.put(3, 1.0f);
	}

	@Override
	protected int getMaxZoomLevel() {
		return ratios.size();
	}

	@Override
	protected void setup() {
		setCenter(new GeoPoint(0, 0));
		setZoom(1);
	}

	@Override
	protected int getTileWidth() {
		return tileWidth;
	}

	@Override
	protected int getTileHeight() {
		return tileHeight;
	}

	@Override
	protected Point geoToPixel(GeoPoint geo) {
		int x = (int) (geo.getLongitudeE6() / getRatio());
		int y = (int) (geo.getLatitudeE6() / getRatio());
		return new Point(x, y);
	}

	@Override
	protected GeoPoint pixelToGeo(Point pixel) {
		int lat = (int) (pixel.y * getRatio());
		int lon = (int) (pixel.x * getRatio());
		return new GeoPoint(lat, lon);
	}

	@Override
	protected GeoPoint getOrigin() {
		double originRatio = ratios.get(1);
		int centerx = tileWidth * rows.get(1) / 2;
		int centery = tileHeight * cols.get(1) / 2;
		int lat = (int) (centery * originRatio);
		int lon = (int) (-centerx * originRatio);
		return new GeoPoint(lat, lon);
	}

	@Override
	protected String getURL(Tile tile) {
		if (isOut(tile)) {
			return noMap();
		}
		int x = (int) tile.getX();
		int y = (int) tile.getY();
		int tileNo = y * cols.get(getZoom()) + x;
		String name = "level" + getZoom() + "_" + tileNo;
		int id = getResourceInt(name);
		if (id == -1) {
			return noMap();
		} else {
			String ret = String.valueOf(id);
			return ret;
		}
	}

	@Override
	protected String getKey() {
		return key;
	}

	private double getRatio() {
		return ratios.get(getZoom());
	}

	private int getResourceInt(String name) {
		if (tileNameMap.containsKey(name)) {
			return tileNameMap.get(name);
		}
		try {
			Field field = R.drawable.class.getDeclaredField(name);
			int tileId = field.getInt(R.drawable.class);
			tileNameMap.put(name, tileId);
			return tileId;
		} catch (Exception e) {
		}
		return -1;
	}

	private String noMap() {
		return String.valueOf(noimage);
	}

	private boolean isOut(Tile tile) {
		int x = (int) tile.getX();
		int y = (int) tile.getY();
		if (x < 0 || y < 0) {
			return true;
		}
		if (x >= cols.get(getZoom())) {
			return true;
		}
		return false;
	}
}

これで完成です。
APIの機能が全て使えるのでアイコンやテキストなどをOverlayしたり、回転させたりできます。
例ではローカルに画像を置いていますが、サーバに置くことも可能です。
comment
ニックネーム 
trackback

この記事のトラックバックURLhttp://labs.mapion.co.jp/mtos/mt-tb.cgi/95

Mashup Awards 7 (#MA7)
ユーザーアーカイブ