Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Xamarinで作る 
「オリジナルタイル地図」アプリ 
Code for NARA 大塚恒平 
@kochizufan 
http://www.slideshare.net/kokogiko/jxug2014-osaka-3-2 
1 201...
目次 
1.自己紹介 
2.タイル地図って? 
3.TMSを使う場合 
4.MBTilesを使う場合 
5.TMSからMBTilesキャッシュ 
6.Google Maps以外の選択 
2 2014/11/08
1.自己紹介 
2001年頃に自学でGISを勉強しジオメディア業界へ 
2007〜2009年、マピオンで位置ゲー「ケータイ国盗り合戦」 
を企画開発 
2010〜2011年、ATR(けいはんな研究機関)でiOS古地図アプ 
リ「ちずぶらり」を企...
Xamarinとの出会い 
モバイル開発離れたけど、余暇でも自分でなんかやりたい 
な 
どうせならAndroidでも動くマルチプラットフォームで作ってみ 
たいな 
でもHTML5でUI作ってガワアプリってなんかちゃうよな 
特にモバイル地図...
C#暦ありません(汗 
LINQ、Rx…あまり判ってません 
ネイティブ(Java)Android開発歴もありません 
iOS8もLolipopも未体験 
現役モバイル開発者ちゃうし 
MVVMとかFormsとか全く追いついてません 
現役(r...
来年は客席で待つ! 
(。+・`ω・´) 
Xamarinは君を欲している! 
立てよX6ama民! 2014/11/08
2.タイル地図って? 
みなさんスマホ開発での地図というと何を想像されま 
すか? 
MapKit? 
Google Maps? 
Y!地図? 
7 © Apple/Google/2Y0A14H/1O1/O08 Japan
実はこんなんも使えます 
OpenStreetMap 
(OpenMapsより) 
地理院地図 
(FieldAccessより) 
© OpenStreetMap/8 IZE Ltd./国土地理院2/d01e4n/1d1r/0o8copos
こんなんだって 
© ovalgear/国土地理院/埼玉大学/Mapbox 
古地図(time toursより) 
官製地形図 
(今昔マップon the webより) 
デザイン地図 
(Mapbox社) 
9 2014/11/08
これみんなタイル地図 
GoogleがGoogle Mapsで発明した、球面メルカトル図 
法を使った四分木タイル地図 
南北緯85度付近以上を除く世界全域が正方形画像で 
表せる(最小ズームで256px四方) 
ズームを一つ大きくする度、タイ...
こんな感じ 
Google Maps APIリファレンスより 
ズームレベル0 ズームレベル2 
256px 
256px 
11 2014/11©/0 G8oogle
難しいかもしれませんが 
ズームレベルzとx座標x、y座標yを指定されたら、そこ 
に対応する地図画像を返してやると地図表示できる仕 
様と思っておk 
ぶっちゃけ対応している地図APIなら、インタフェースで 
勝手にx, y, zを与えてくれ...
使える地図は? 
OpenStreetMap系 
OpenStreetMapをいろんなデザインでレンダリングした 
タイルセットが利用できます 
http://wiki.openstreetmap.org/wiki/Tiles に一覧 
13 ...
OpenStreetMap系 
14 © O2p0e1n4S/1t1r/e0e8tMap
使える地図、他には? 
国土地理院系 
国土地理院が用意した様々なタイルセット(昔の航空 
写真とかもあります)が利用できます 
http://portal.cyberjapan.jp/help/development/ichiran. 
ht...
地理院地図の数々 
16 2©01 国4/1土1/0地8 理院
自分で作る事もできます 
ラスタ画像地図から作成 
GISツール(gdal2tiles等)を使います 
詳細は拙Slideshare参照 
http://www.slideshare.net/kokogiko/ss-15067961 
これ説明...
こんな感じで作れます 
© Google/国土地理院/気仙沼市 
気仙沼市ハザードマップから 
官製地形図から 
地形数値データから 
陰影図描画して 
18 2014/11/08
OpenStreetMapの 
データから独自デザイン 
Mapboxという会社のMapbox Studioというアプリで自 
由デザイン 
https://www.mapbox.com/mapbox-studio/ 
←cssみたいな感じで ...
Mapboxはこんな感じ 
20 2014/©11 /M08apbox
タイル地図を使うと 
誰もが使うMapKitやGoogle Maps等とは一味違う地図アプリが作 
れます! 
(ニーズがあるかはさておき^^) 
むしろ地図自身が表現手段になる! 
Webもアプリも共通仕様!(Google Earthで使うに...
3.TMSを使う場合 
TMS(Tile Map Service)とは? 
タイル地図で画像のURLを指定する仕様 
例:地理院地図標準レイヤ 
http://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{...
下準備 
(SharedProject or PCL) 
public partial class URLConstructor { 
private string baseURL = "http://t.tilemap.jp/jcp_maps...
下準備 
(SharedProject or PCL) 
public partial class URLConstructor { 
private string baseURL = "http://t.tilemap.jp/jcp_maps...
下準備 
(SharedProject or PCL) 
public partial class URLConstructor { 
private string baseURL = "http://t.tilemap.jp/jcp_maps...
TMS仕様には 
2つの流儀がある 
GIS業界型(本来のTMS) Web地図業界型 
x、y、z x、y、z 
・y座標が南から北へ 
・GISツールで作るとこちらになる 
・y座標が北から南へ 
・Google、OpenStreetMap、...
GISツールで作ったデータを 
Google Maps SDKで使うに 
は 
y座標が逆向きなので変換してやる必要がある 
定型文で覚えれば無問題 
y = (int)Math.Pow (2.0, (double)z) - y - 1; 
こ...
Xamarin iOS 
URLConstructor constructor = new URLConstructor (); 
… 
MapView mapView = new MapView (); 
… 
var tmsProvider...
Xamarin Android(1) 
若干面倒くさい 
class URLTilesProvider : UrlTileProvider 
{ 
private URLConstructor constructor; 
UrlTileProv...
Xamarin Android(2) 
protected override void OnResume () 
{ 
var mapView = ((MapFragment)FragmentManager.FindFragmentById 
...
TMS利用の結果 
簡単…ですよね? 
なんとこれだけで 
一味違うタイル地図が 
あなたのお手元に! 
31 2014/11/08
TMSの問題点 
地図画像をURL指定でネットから取ってくるために… 
描画がネットレイテンシのため遅い 
オフラインで使えない 
「せっかく自分で地図用意してるのに、オフラインでも使 
いたいんだよ!」 
というワガママなあなたのために… 
...
4.MBTilesを使う場合 
MBTilesとは 
タイル地図画像をオフラインで保持・流通させるための 
フォーマット仕様 
SQLiteファイル形式を使用 
なので普通のSQLite APIで余裕で使える 
33 2014/11/08
MBTilesのスキーマ 
(Ver.1.0) 
CREATE TABLE metadata (name text, value text); 
CREATE TABLE tiles (zoom_level integer, tile_colu...
MBTilesのスキーマ 
(私が今使ってるもの) 
CREATE TABLE map ( zoom_level INTEGER, tile_column INTEGER, tile_row INTEGER, tile_id TEXT, gri...
MBTilesを作るには 
Mapbox Studio等からは直接生成可能 
GISツールから画像タイルを作成した際等は、拙作の 
Tile2MBTiles 
https://github.com/tilemapjp/Tile2MBTiles ...
Shared Project (or PCL) MBTiles 
ファイルのコピー処理 
MBTilesファイルはEmbededResourceを使ってプロジェ 
クトに含める 
MBTilesファイルのコピー先は 
System.Enviro...
EmbededResource? 
これ 
iOSにも 
Androidにもあるよ! 
38 2014/11/08
EmbededResourceを 
使う利点と欠点 
利点 
MBTilesファイル処理周りを全部共通ロジック化できる! 
プラットフォームでの処理分けが不要! 
欠点 
AndroidのAssetsはともかく 
iOSのBundleResou...
Shared Project (or PCL) MBTiles 
ファイルのコピー処理 
this.dbFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocumen...
Shared Project (or PCL) MBTiles 
ファイルのコピー処理 
this.dbFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocumen...
Shared Project (or PCL) MBTiles 
ファイルのコピー処理 
this.dbFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocumen...
Shared Project (or PCL) 
xyzから画像の取得 
public class tiles { 
public int zoom_level { get; set; } 
public int tile_column { g...
Shared Project (or PCL) 
xyzから画像の取得 
public class tiles { 
public int zoom_level { get; set; } 
public int tile_column { g...
Xamarin iOS 
public class MBTilesProvider : SyncTileLayer { 
public override UIImage Tile (uint x, uint y, uint zoom) { 
v...
Xamarin Android 
class MBTilesProvider : Java.Lang.Object, ITileProvider { 
public Tile GetTile(int x, int y, int zoom) { ...
MBTiles利用の結果 
…は見た目はTMSと変わらないので省略 
簡単でしょ?こっちも 
MBTilesの問題点 
ローカルに地図データがあるので描画は速く、オフライ 
ンでも使えるが… 
データサイズが大きく、アプリサイズも大きくなる 
...
5.TMSから 
MBTilesキャッシュ 
オンラインはTMSで地図画像を配信しながら、ローカル 
でMBTilesにキャッシュすれば多くの問題が解決 
方針 
TMSのURLを生成してSDKに渡し、画像取得はSDKに任 
せて、画像を横取り...
実装の詳細 
省略 
そろそろかなり煩雑になるので…Githubで見てください 
いくつかのキモ: 
MBTilesへのキャッシュの書き込みは複数スレッドから同時に 
発生しないようにバックグラウンド化と直列化 
Xamarin iOSでは、U...
サンプルのおまけ 
タイル地図セットの提供する最大ズーム以上に拡大し 
ても、最大ズームでの画像をデジタルズームする機能 
もつけてます 
詳しくはGithubのソースと 
以前にQiitaで記事を書いてるので参照 
http://qiita....
TMSでネット地図取得+ 
MBTilesキャッシュで 
アプリサイズが小さく、表示したところは以後軽くオフラ 
イン表示も可能な地図アプリが作れる 
これで文句は言わせない 
OpenStreetMap、地理院地図等も、普段はネット取得、 
...
6.Google Maps 
以外の選択 
タイル地図使えるのってGoogle Maps SDKだけ? 
他にもいろいろある 
むしろタイル地図を使うなら本来FOSS4Gライブラリを使う 
のが本筋なんだけど 
Xamarinだとポーティングが...
Google Maps SDKだと 
こういうのが 
消せないのが 
イマイチ 
53 2014/11/08
ネイティブSDKで有名系 
のXamarinバインディング 
Route-Me(iOS) 
https://github.com/mono/monotouch-bindings/ 
tree/master/Route-Me 
非常に軽く高機能だ...
.NET マネージド系での 
OSS地図SDK 
OsmSharp 
http://www.osmsharp.com/ 
ベクトルデータに対応してるが若干重い 
マーカー機能とかまだこれから 
コマーシャルライセンス+GPLv2 
Mapsui...
Xamarin未ポートの高機能 
マルチプラットフォームSDK 
Mapbox SDK系 
https://www.mapbox.com/developers/ 
タイル地図業界の期待の星企業 
RouteMeやosmdroidを魔改造してる、...
Xamarin未ポートの高機能 
マルチプラットフォームSDK 
Globe3Mobile 
http://www.glob3mobile.com/ 
3D描画の地図エンジン 
iOS、Android両対応、共通エンジンっぽい 
BSD 
いつ...
地図SDKだけやない 
.NET位置情報ライブラリ 
http://qiita.com/kochizufan/items/f7e2024be7079ded8697 
Proj.NET 
c版ではproj.4と呼ばれる座標変換ライブラリ 
世界測...
最後に会場の 
マイクロソフトさんに 
Bing Mapsは本当にいい地図です(デザインとか) 
私大好きです 
なのに…なのに… 
59 2014/11/08 
© Zenrin/Microsoft
なんでWindowsPhoneの 
標準地図を 
NokiaのHEREにしてしもたんやーーーーーー! 
なんですかこれは 
10年前の 
OpenStreetMap 
ですか… 
60 2014/11/08 
© Nokia/Microsoft
技術資産の相乗りは 
わかりますが 
データ資産は既存のもの活かしましょうや… 
データはZenrinとの絡みもあって難しいとは思います 
が、デザイン資産とかはMSのもんでしょうし… 
ぜひ日本のマイクロソフトから、日本の地図ちゃんと 
せー...
ご清聴おおきに! 
今日聞いてくださった人の中から、タイル地図や位置 
情報APIを使った「一味違う地図アプリ」を作ってくれる 
方が出てくれれば光栄です! 
Xamarin、.NET、c#のますますの発展を! 
大事な事なので二度目言います、...
Upcoming SlideShare
Loading in …5
×

Xamarinで作る 「オリジナルタイル地図」アプリ

5,154 views

Published on

Japan Xamarin User Group Conference 西日本編での発表資料です。

Published in: Technology

Xamarinで作る 「オリジナルタイル地図」アプリ

  1. 1. Xamarinで作る 「オリジナルタイル地図」アプリ Code for NARA 大塚恒平 @kochizufan http://www.slideshare.net/kokogiko/jxug2014-osaka-3-2 1 2014/11/08
  2. 2. 目次 1.自己紹介 2.タイル地図って? 3.TMSを使う場合 4.MBTilesを使う場合 5.TMSからMBTilesキャッシュ 6.Google Maps以外の選択 2 2014/11/08
  3. 3. 1.自己紹介 2001年頃に自学でGISを勉強しジオメディア業界へ 2007〜2009年、マピオンで位置ゲー「ケータイ国盗り合戦」 を企画開発 2010〜2011年、ATR(けいはんな研究機関)でiOS古地図アプ リ「ちずぶらり」を企画開発 現在、某大手ポータルのフリーWiFi網構築事業の開発を担 当(Web、サーバサイド) Code for NARAで、奈良のオープンデータ活用活動をボラン タリーで 3 2014/11/08
  4. 4. Xamarinとの出会い モバイル開発離れたけど、余暇でも自分でなんかやりたい な どうせならAndroidでも動くマルチプラットフォームで作ってみ たいな でもHTML5でUI作ってガワアプリってなんかちゃうよな 特にモバイル地図はHTML5とネイティブで使用感がダンチ UIはネイティブ、バックエンドロジックは共通化= Xamarin、 おおこれや! 1年ほど前から余暇で触ってます 4 2014/11/08
  5. 5. C#暦ありません(汗 LINQ、Rx…あまり判ってません ネイティブ(Java)Android開発歴もありません iOS8もLolipopも未体験 現役モバイル開発者ちゃうし MVVMとかFormsとか全く追いついてません 現役(ry 今日もお客さんのつもりが、話してと言われたさかいに… 地図は得意なので、Xamarinでの特殊な地図アプリの作り方を話 します 5 2014/11/08
  6. 6. 来年は客席で待つ! (。+・`ω・´) Xamarinは君を欲している! 立てよX6ama民! 2014/11/08
  7. 7. 2.タイル地図って? みなさんスマホ開発での地図というと何を想像されま すか? MapKit? Google Maps? Y!地図? 7 © Apple/Google/2Y0A14H/1O1/O08 Japan
  8. 8. 実はこんなんも使えます OpenStreetMap (OpenMapsより) 地理院地図 (FieldAccessより) © OpenStreetMap/8 IZE Ltd./国土地理院2/d01e4n/1d1r/0o8copos
  9. 9. こんなんだって © ovalgear/国土地理院/埼玉大学/Mapbox 古地図(time toursより) 官製地形図 (今昔マップon the webより) デザイン地図 (Mapbox社) 9 2014/11/08
  10. 10. これみんなタイル地図 GoogleがGoogle Mapsで発明した、球面メルカトル図 法を使った四分木タイル地図 南北緯85度付近以上を除く世界全域が正方形画像で 表せる(最小ズームで256px四方) ズームを一つ大きくする度、タイルを四分割 競合他社(マイクロソフト等)やオープンソースも採用し、 事実上Web地図標準 10 2014/11/08
  11. 11. こんな感じ Google Maps APIリファレンスより ズームレベル0 ズームレベル2 256px 256px 11 2014/11©/0 G8oogle
  12. 12. 難しいかもしれませんが ズームレベルzとx座標x、y座標yを指定されたら、そこ に対応する地図画像を返してやると地図表示できる仕 様と思っておk ぶっちゃけ対応している地図APIなら、インタフェースで 勝手にx, y, zを与えてくれるので、対応する画像や画像 URLを返してやるだけ MapKitは対応してなかったはず…使うなら自分で原理 を理解して各位置の画像をオーバーレイ 12 2014/11/08
  13. 13. 使える地図は? OpenStreetMap系 OpenStreetMapをいろんなデザインでレンダリングした タイルセットが利用できます http://wiki.openstreetmap.org/wiki/Tiles に一覧 13 © O2p0e1n4S/1t1r/e0e8tMap
  14. 14. OpenStreetMap系 14 © O2p0e1n4S/1t1r/e0e8tMap
  15. 15. 使える地図、他には? 国土地理院系 国土地理院が用意した様々なタイルセット(昔の航空 写真とかもあります)が利用できます http://portal.cyberjapan.jp/help/development/ichiran. html に一覧 探せば 他にもたくさん 15 2©01 国4/1土1/0地8 理院
  16. 16. 地理院地図の数々 16 2©01 国4/1土1/0地8 理院
  17. 17. 自分で作る事もできます ラスタ画像地図から作成 GISツール(gdal2tiles等)を使います 詳細は拙Slideshare参照 http://www.slideshare.net/kokogiko/ss-15067961 これ説明し出すと マジXamarin関係なくなってしまう 17 2014/11/08
  18. 18. こんな感じで作れます © Google/国土地理院/気仙沼市 気仙沼市ハザードマップから 官製地形図から 地形数値データから 陰影図描画して 18 2014/11/08
  19. 19. OpenStreetMapの データから独自デザイン Mapboxという会社のMapbox Studioというアプリで自 由デザイン https://www.mapbox.com/mapbox-studio/ ←cssみたいな感じで 地図をデザイン 19 2014/©11 /M08apbox
  20. 20. Mapboxはこんな感じ 20 2014/©11 /M08apbox
  21. 21. タイル地図を使うと 誰もが使うMapKitやGoogle Maps等とは一味違う地図アプリが作 れます! (ニーズがあるかはさておき^^) むしろ地図自身が表現手段になる! Webもアプリも共通仕様!(Google Earthで使うには一工夫必要) Google Maps SDKはタイル地図が使えて、iOS/Android両方で提 供されているので、Xamarinでタイル地図を使うのに向いてます 以後の説明のソースコードは https://github.com/tilemapjp/xamarinMapJXUG で公開しています 21 2014/11/08
  22. 22. 3.TMSを使う場合 TMS(Tile Map Service)とは? タイル地図で画像のURLを指定する仕様 例:地理院地図標準レイヤ http://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png ズームz,x座標,y座標の値で{z},{x},{y}を置き換えてやれ ば画像のURLになる このURLをSDKにあげればいい 簡単! 22 2014/11/08
  23. 23. 下準備 (SharedProject or PCL) public partial class URLConstructor { private string baseURL = "http://t.tilemap.jp/jcp_maps/harima/{z}/{x}/{y}.png"; private string regexURL = null; public URLConstructor () { regexURL = baseURL.Replace("{x}", "{0}"); regexURL = regexURL.Replace("{y}", "{1}"); regexURL = regexURL.Replace("{z}", "{2}"); } public string GetUrl(int x, int y, int z) { //TMS形式はGoogleのY座標と正負の方向が逆なので直す y = (int)Math.Pow (2.0, (double)z) - y - 1; string url = String.Format (regexURL, x, y, z); return url; } } 元定義 23 2014/11/08
  24. 24. 下準備 (SharedProject or PCL) public partial class URLConstructor { private string baseURL = "http://t.tilemap.jp/jcp_maps/harima/{z}/{x}/{y}.png"; private string regexURL = null; public URLConstructor () { regexURL = baseURL.Replace("{x}", "{0}"); regexURL = regexURL.Replace("{y}", "{1}"); regexURL = regexURL.Replace("{z}", "{2}"); } TMS表記をFormat表記に public string GetUrl(int x, int y, int z) { //TMS形式はGoogleのY座標と正負の方向が逆なので直す y = (int)Math.Pow (2.0, (double)z) - y - 1; string url = String.Format (regexURL, x, y, z); return url; } } 24 2014/11/08
  25. 25. 下準備 (SharedProject or PCL) public partial class URLConstructor { private string baseURL = "http://t.tilemap.jp/jcp_maps/harima/{z}/{x}/{y}.png"; private string regexURL = null; public URLConstructor () { regexURL = baseURL.Replace("{x}", "{0}"); regexURL = regexURL.Replace("{y}", "{1}"); regexURL = regexURL.Replace("{z}", "{2}"); } public string GetUrl(int x, int y, int z) { //TMS形式はGoogleのY座標と正負の方向が逆なので直す y = (int)Math.Pow (2.0, (double)z) - y - 1; string url = String.Format (regexURL, x, y, z); return url; } } これは何? 25 2014/11/08
  26. 26. TMS仕様には 2つの流儀がある GIS業界型(本来のTMS) Web地図業界型 x、y、z x、y、z ・y座標が南から北へ ・GISツールで作るとこちらになる ・y座標が北から南へ ・Google、OpenStreetMap、 国土地理院、Mapbox他 26 2014/11/08
  27. 27. GISツールで作ったデータを Google Maps SDKで使うに は y座標が逆向きなので変換してやる必要がある 定型文で覚えれば無問題 y = (int)Math.Pow (2.0, (double)z) - y - 1; このくらい覚えろ! すみません覚えてください 27 2014/11/08
  28. 28. Xamarin iOS URLConstructor constructor = new URLConstructor (); … MapView mapView = new MapView (); … var tmsProvider = UrlTileLayer.FromUrlConstructor ((uint x, uint y, uint zoom) => { string url = constructor.GetUrl((int)x,(int)y,(int)zoom); return new NSUrl(url); }); tmsProvider.Map = mapView; UrlTileLayer.FromUrlConstructorに NSUrlを生成するラムダ式を食わせて UrlTileLayerを生成し MapプロパティにMapViewを指定するだけ 28 2014/11/08
  29. 29. Xamarin Android(1) 若干面倒くさい class URLTilesProvider : UrlTileProvider { private URLConstructor constructor; UrlTileProviderを継承 public URLTilesProvider () : base (256, 256) { constructor = new URLConstructor (); } public override Java.Net.URL GetTileUrl (int x, int y, int z) { var url = constructor.GetUrl (x, y, z); return new Java.Net.URL (url); } } Java.Net.URLを返すGetTileUrlメソッドを実装 29 2014/11/08
  30. 30. Xamarin Android(2) protected override void OnResume () { var mapView = ((MapFragment)FragmentManager.FindFragmentById (Resource.Id.map)).Map; MapViewはMapFragmentから取得 if (mapView != null) { var tmsProvider = new URLTilesProvider (); var mbOptions = new TileOverlayOptions(); mapView.AddTileOverlay( mbOptions.InvokeTileProvider(tmsProvider) ); } } TileOverlayOptions#InvokeTileProviderに 作成したUrlTileProviderを食わせ、 TileOverlayを生成してMapViewにAddTileOverlay 30 2014/11/08
  31. 31. TMS利用の結果 簡単…ですよね? なんとこれだけで 一味違うタイル地図が あなたのお手元に! 31 2014/11/08
  32. 32. TMSの問題点 地図画像をURL指定でネットから取ってくるために… 描画がネットレイテンシのため遅い オフラインで使えない 「せっかく自分で地図用意してるのに、オフラインでも使 いたいんだよ!」 というワガママなあなたのために… 32 2014/11/08
  33. 33. 4.MBTilesを使う場合 MBTilesとは タイル地図画像をオフラインで保持・流通させるための フォーマット仕様 SQLiteファイル形式を使用 なので普通のSQLite APIで余裕で使える 33 2014/11/08
  34. 34. MBTilesのスキーマ (Ver.1.0) CREATE TABLE metadata (name text, value text); CREATE TABLE tiles (zoom_level integer, tile_column integer, tile_row integer, tile_data blob); ズームレベルx座標y座標画像 ぶっちゃけこれだけ!! (インデックスも張られますが…) 34 2014/11/08
  35. 35. MBTilesのスキーマ (私が今使ってるもの) CREATE TABLE map ( zoom_level INTEGER, tile_column INTEGER, tile_row INTEGER, tile_id TEXT, grid_id TEXT );"); 正規化されたり CREATE TABLE grid_key ( grid_id TEXT, key_name TEXT );"); 他のデータも加わってるが、 CREATE TABLE keymap ( key_name TEXT, key_json TEXT );"); CREATE TABLE grid_utfgrid ( grid_id TEXT, grid_utfgrid BLOB );"); viewがあるのでSELECT CREATE TABLE images ( tile_data blob, tile_id text );"); する分には1.0と同じ CREATE TABLE metadata ( name text, value text );"); CREATE UNIQUE INDEX map_index ON map (zoom_level, tile_column, tile_row);"); CREATE UNIQUE INDEX grid_key_lookup ON grid_key (grid_id, key_name);"); CREATE UNIQUE INDEX keymap_lookup ON keymap (key_name);"); CREATE UNIQUE INDEX grid_utfgrid_lookup ON grid_utfgrid (grid_id);"); CREATE UNIQUE INDEX images_id ON images (tile_id);"); CREATE UNIQUE INDEX name ON metadata (name);"); CREATE VIEW tiles AS SELECT map.zoom_level AS zoom_level, map.tile_column AS tile_column, map.tile_row AS tile_row, images.tile_data AS tile_data FROM map JOIN images ON images.tile_id = map.tile_id;"); CREATE VIEW grids AS SELECT map.zoom_level AS zoom_level, map.tile_column AS tile_column, map.tile_row AS tile_row, grid_utfgrid.grid_utfgrid AS grid FROM map JOIN grid_utfgrid ON grid_utfgrid.grid_id = map.grid_id;"); CREATE VIEW grid_data AS SELECT map.zoom_level AS zoom_level, map.tile_column AS tile_column, map.tile_row AS tile_row, keymap.key_name AS key_name, keymap.key_json AS key_json FROM map JOIN grid_key ON map.grid_id = grid_key.grid_id JOIN keymap ON grid_key.key_name = keymap.key_name;"); 実は仕様の出所不明… と最近気付いた 謎仕様!!! 35 2014/11/08
  36. 36. MBTilesを作るには Mapbox Studio等からは直接生成可能 GISツールから画像タイルを作成した際等は、拙作の Tile2MBTiles https://github.com/tilemapjp/Tile2MBTiles 等を使ってMBTiles化 できあがりは謎仕様です 仕様簡単なので自前でプログラムも君達なら楽勝のはず! 最近はGISツールからも直接出せるようになったという話も (未確認) 36 2014/11/08
  37. 37. Shared Project (or PCL) MBTiles ファイルのコピー処理 MBTilesファイルはEmbededResourceを使ってプロジェ クトに含める MBTilesファイルのコピー先は System.Environment.GetFolderPath(System.Environ ment.SpecialFolder.MyDocuments); で取得すると、マルチプラットフォームで共通化できる こうするとSQLite周りの処理はコピーからデータ読み込 みまで全部マルチプラットフォーム化できてウマーー 37 2014/11/08
  38. 38. EmbededResource? これ iOSにも Androidにもあるよ! 38 2014/11/08
  39. 39. EmbededResourceを 使う利点と欠点 利点 MBTilesファイル処理周りを全部共通ロジック化できる! プラットフォームでの処理分けが不要! 欠点 AndroidのAssetsはともかく iOSのBundleResourceは直接MBTilesとしてリードオン リーで開けるので、初回に本来無用なコピー処理が発生 する お好みで… 39 2014/11/08
  40. 40. Shared Project (or PCL) MBTiles ファイルのコピー処理 this.dbFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); this.dbPath = Path.Combine (this.dbFolder, this.dbFile); Type type = this.GetType (); Stream myInput = type.Assembly.GetManifestResourceStream ("JXUGMBTiles." + this.dbFile); Stream myOutput = new FileStream(this.dbPath, FileMode.OpenOrCreate); byte[] buffer = new byte[1024]; int b = buffer.Length; int length; while ((length = myInput.Read(buffer, 0, b)) > 0) { myOutput.Write(buffer, 0, length); } myOutput.Flush(); myOutput.Close(); myInput.Close(); コピー先のフォルダを取得 40 2014/11/08
  41. 41. Shared Project (or PCL) MBTiles ファイルのコピー処理 this.dbFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); this.dbPath = Path.Combine (this.dbFolder, this.dbFile); Type type = this.GetType (); Stream myInput = type.Assembly.GetManifestResourceStream ("JXUGMBTiles." + this.dbFile); Stream myOutput = new FileStream(this.dbPath, FileMode.OpenOrCreate); byte[] buffer = new byte[1024]; int b = buffer.Length; int length; while ((length = myInput.Read(buffer, 0, b)) > 0) { myOutput.Write(buffer, 0, length); } myOutput.Flush(); myOutput.Close(); myInput.Close(); EmbededResourceのStreamを開く コピー先のStreamも開く 41 2014/11/08
  42. 42. Shared Project (or PCL) MBTiles ファイルのコピー処理 this.dbFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); this.dbPath = Path.Combine (this.dbFolder, this.dbFile); Type type = this.GetType (); Stream myInput = type.Assembly.GetManifestResourceStream ("JXUGMBTiles." + this.dbFile); Stream myOutput = new FileStream(this.dbPath, FileMode.OpenOrCreate); byte[] buffer = new byte[1024]; int b = buffer.Length; int length; while ((length = myInput.Read(buffer, 0, b)) > 0) { myOutput.Write(buffer, 0, length); } myOutput.Flush(); myOutput.Close(); myInput.Close(); コピー処理 42 2014/11/08
  43. 43. Shared Project (or PCL) xyzから画像の取得 public class tiles { public int zoom_level { get; set; } public int tile_column { get; set; } public int tile_row { get; set; } public byte[] tile_data { get; set; } } … public byte[] GetTileImage(int x, int y, int z) { byte[] image = null; y = (int)Math.Pow (2.0, (double)z) - y – 1; using (var conn = new SQLiteConnection(this.dbPath)) { var query = conn.Table<tiles> ().Where (v => v.zoom_level == z && v.tile_column == x && v.tile_row == y); if (query.Count () != 0) { var tile = query.First (); image = tile.tile_data; } } return image; } SQLite.Netを使用、スキーマクラス 43 2014/11/08
  44. 44. Shared Project (or PCL) xyzから画像の取得 public class tiles { public int zoom_level { get; set; } public int tile_column { get; set; } public int tile_row { get; set; } public byte[] tile_data { get; set; } } … public byte[] GetTileImage(int x, int y, int z) { byte[] image = null; y = (int)Math.Pow (2.0, (double)z) - y – 1; using (var conn = new SQLiteConnection(this.dbPath)) { var query = conn.Table<tiles> ().Where (v => v.zoom_level == z && v.tile_column == x && v.tile_row == y); if (query.Count () != 0) { var tile = query.First (); image = tile.tile_data; } } return image; } SQLite.Netでx,y,zが一致する画像を検索 44 2014/11/08
  45. 45. Xamarin iOS public class MBTilesProvider : SyncTileLayer { public override UIImage Tile (uint x, uint y, uint zoom) { var image = accessor.GetTileImage ((int)x, (int)y, (int)zoom); SyncTileLayerを継承したTileLayerを作成し、 UIImageを返すTileメソッドを実装 if (image == null) { return Constants.TileLayerNoTile; } else { return UIImage.LoadFromData (NSData.FromArray(image)); } } } … public override void ViewDidLoad () { var mbProvider = new MBTilesProvider (); mbProvider.Map = mapView; } TileLayerのMapプロパティに MapViewを指定するだけ 45 2014/11/08
  46. 46. Xamarin Android class MBTilesProvider : Java.Lang.Object, ITileProvider { public Tile GetTile(int x, int y, int zoom) { var image = accessor.GetTileImage (x, y, zoom); Java.Lang.Object、ITileProviderを 継承したTileProviderを作成し、 Tileを返すGetTileメソッドを実装 if (image == null) { return TileProvider.NoTile; } else { return new Tile(TILE_WIDTH, TILE_HEIGHT, image); } } } … var mbProvider = new MBTilesProvider (); var mbOptions = new TileOverlayOptions(); mapView.AddTileOverlay( mbOptions.InvokeTileProvider(mbProvider) ); TileOverlayOptions経由で生成した TileOverlayをAddTileOverlayで MapViewに追加 46 2014/11/08
  47. 47. MBTiles利用の結果 …は見た目はTMSと変わらないので省略 簡単でしょ?こっちも MBTilesの問題点 ローカルに地図データがあるので描画は速く、オフライ ンでも使えるが… データサイズが大きく、アプリサイズも大きくなる 遅いのもイヤ、デブッチョもイヤな方々には… 47 2014/11/08
  48. 48. 5.TMSから MBTilesキャッシュ オンラインはTMSで地図画像を配信しながら、ローカル でMBTilesにキャッシュすれば多くの問題が解決 方針 TMSのURLを生成してSDKに渡し、画像取得はSDKに任 せて、画像を横取りしてキャッシュ 画像の取得自体をHTTPエージェントを使い自分で実装 する手もあるが、その辺はGoogleさんの実装の方が上 手だろうと思って… 48 2014/11/08
  49. 49. 実装の詳細 省略 そろそろかなり煩雑になるので…Githubで見てください いくつかのキモ: MBTilesへのキャッシュの書き込みは複数スレッドから同時に 発生しないようにバックグラウンド化と直列化 Xamarin iOSでは、UrlTileLayerを継承できない 画像を受け取るには、非同期のコールバックオブジェクトをデ コレートして受け取る必要がある Xamarin Androidでも、UrlTileProviderのGetTileメソッドは virtualでなくオーバーライドできないので、デコレートオブジェ クトを作る必要 49 2014/11/08
  50. 50. サンプルのおまけ タイル地図セットの提供する最大ズーム以上に拡大し ても、最大ズームでの画像をデジタルズームする機能 もつけてます 詳しくはGithubのソースと 以前にQiitaで記事を書いてるので参照 http://qiita.com/kochizufan/items/be19de4d9a4b6466a 9cf http://qiita.com/kochizufan/items/f6cdc8925d254c1833 8d 50 2014/11/08
  51. 51. TMSでネット地図取得+ MBTilesキャッシュで アプリサイズが小さく、表示したところは以後軽くオフラ イン表示も可能な地図アプリが作れる これで文句は言わせない OpenStreetMap、地理院地図等も、普段はネット取得、 必要な範囲だけ事前にダウンロードしてMBTilesキャッ シュしてOK ネットが繋がらないところでも使えるオフライン地図 Google MapsやMapKitでは不可能(キャッシュはするが 制御はできない) 51 2014/11/08
  52. 52. 6.Google Maps 以外の選択 タイル地図使えるのってGoogle Maps SDKだけ? 他にもいろいろある むしろタイル地図を使うなら本来FOSS4Gライブラリを使う のが本筋なんだけど Xamarinだとポーティングが少ないのが難 52 2014/11/08
  53. 53. Google Maps SDKだと こういうのが 消せないのが イマイチ 53 2014/11/08
  54. 54. ネイティブSDKで有名系 のXamarinバインディング Route-Me(iOS) https://github.com/mono/monotouch-bindings/ tree/master/Route-Me 非常に軽く高機能だが、実装思想が若干古い ライセンスは利用している事を記述?よう判らん osmdroid(Android) http://components.xamarin.com/view/osmdroid-android- binding Android界では有名だが、すんませんあまり知らん Apache 2.0 54 2014/11/08
  55. 55. .NET マネージド系での OSS地図SDK OsmSharp http://www.osmsharp.com/ ベクトルデータに対応してるが若干重い マーカー機能とかまだこれから コマーシャルライセンス+GPLv2 Mapsui https://github.com/pauldendulk/Mapsui ラスタタイルのみの対応だがサクサク奇麗 地図描画のみの実装?マーカーとかが見当たらん… LGPLライセンス もちろんどっちもWindows Phoneでもいけまっせ 55 2014/11/08
  56. 56. Xamarin未ポートの高機能 マルチプラットフォームSDK Mapbox SDK系 https://www.mapbox.com/developers/ タイル地図業界の期待の星企業 RouteMeやosmdroidを魔改造してる、最新のOpenGL版も 登場中 Apache 2.0 (Android) Maply https://github.com/mousebird/WhirlyGlobe 3D描画版がWihrlyGlobe、2D描画版がMaply iOSだが最新のβでMaplyはAndroidも対応開始 描画エンジンはc++で共通 Apache 2.0 56 2014/11/08
  57. 57. Xamarin未ポートの高機能 マルチプラットフォームSDK Globe3Mobile http://www.glob3mobile.com/ 3D描画の地図エンジン iOS、Android両対応、共通エンジンっぽい BSD いつかポーティングできれば… 日曜プログラマじゃ無理?^^; 優秀なXama民の力をオラに貸してけれ! 57 2014/11/08
  58. 58. 地図SDKだけやない .NET位置情報ライブラリ http://qiita.com/kochizufan/items/f7e2024be7079ded8697 Proj.NET c版ではproj.4と呼ばれる座標変換ライブラリ 世界測地系日本測地系とか、経緯度メルカトル座標と か .NET Topology Suite c版ではgeosと呼ばれる図形演算ライブラリ ポリゴン等の足し算引き算や、衝突判定等 http://qiita.com/amay077/items/7a99df1c0da881cc47f6 ↑あめい師匠の詳細解説! 58 2014/11/08
  59. 59. 最後に会場の マイクロソフトさんに Bing Mapsは本当にいい地図です(デザインとか) 私大好きです なのに…なのに… 59 2014/11/08 © Zenrin/Microsoft
  60. 60. なんでWindowsPhoneの 標準地図を NokiaのHEREにしてしもたんやーーーーーー! なんですかこれは 10年前の OpenStreetMap ですか… 60 2014/11/08 © Nokia/Microsoft
  61. 61. 技術資産の相乗りは わかりますが データ資産は既存のもの活かしましょうや… データはZenrinとの絡みもあって難しいとは思います が、デザイン資産とかはMSのもんでしょうし… ぜひ日本のマイクロソフトから、日本の地図ちゃんと せー、と声を挙げていただきたい 61 © N2o0k1i4a//1M1/0ic8rosoft
  62. 62. ご清聴おおきに! 今日聞いてくださった人の中から、タイル地図や位置 情報APIを使った「一味違う地図アプリ」を作ってくれる 方が出てくれれば光栄です! Xamarin、.NET、c#のますますの発展を! 大事な事なので二度目言います、 「来年は客席で待つ」 62 2014/11/08

×