smellman's Broken Diary

クソみたいなもんです

Tilemillを使ってGeoTiff形式からタイルを作成する

www.mapbox.com

こちらの記事を応用して、TilemillからGeoTiff形式のファイルを作成してみました。

まず、対象となるファイルを用意します。
今回は地球地図を使いました。

Home - International Steering Committee for Global Mapping

こちらからセルビアのLand Cover(土地被覆)とElevation(標高)のデータをダウンロードします。
作業内容は割愛します。

用意したのはbilファイルなので、これをQGISを使ってGeoTiffファイルに変換します。
やり方はまずラスタレイヤーの追加でbilファイルを開いて、ラスタの変換(形式変換)のメニューを開きます。
mapboxのblogではターゲットのSRSがGoogle Mercator(EPSG:900913)になっていますが、これだとうまくいかなかったのでWGS 84(EPSG:4326)を選択します。
最終的に以下のようなコマンドが生成できればOKです。

gdal_translate -a_srs EPSG:4326 -of GTiff (path to globalmap)/gm-srb-el_2_0/el_srb.bil (path to globalmap)/gm-srb-el_2_0/el_srb.tif

もちろん、gdal_translateをそのまま使うという方法でもよいです。

次にTilemillを起動して初期状態で何もないプロジェクトを作ってから、レイヤーにGeoTiffを追加します。
今回はel_srb.tif(標高データ)を対象にします。
追加するときは以下のことに気をつけてください。

  1. 複数の国などを扱う場合はclassを指定しましょう。今回はelというクラスを追加しています。
  2. SRSは先程WGS 84として作成したのでこれを選びます。
  3. Advancedでは対象となるGeoTiffのbandを指定します。今回は band="1" を指定しています。

以下のようになっていればOKです。

f:id:smellman:20150927003928p:plain

これでSaveをします。
それではスタイルを設定していきます。
今回elクラスに対して設定したスタイルは以下のとおりです。

.el {
  raster-opacity:1;
  raster-scaling:bilinear;
  raster-colorizer-default-mode: linear;
  raster-colorizer-default-color: transparent;
  raster-colorizer-stops:
    stop(-9999, #284eb0)
    stop(-9998, #55B499)
    stop(-1000, #4CB896)
    stop(-500, #57BA8A)
    stop(-200, #58BE7E)
    stop(-100, #59C272)
    stop(-50, #5AC666)
stop(-25, #5BCA5A)
stop(-10, #5CCE4E)
stop(-5, #5DD242)
stop(0, #62DD34)
stop(10, #67E037)
stop(25, #6CE33B)
stop(50, #71E73F)
stop(75, #7DEB44)
stop(100, #88F048)
stop(125, #94F54E)
stop(150, #A1F457)
stop(175, #AFF266)
stop(200, #BCF071)
stop(225, #C2EE75)
stop(250, #C9EC78)
stop(275, #CFE97D)
stop(300, #D9E682)
stop(350, #E4DB8E)
stop(400, #EED89A)
stop(450, #ECD18D)
stop(500, #EACB81)
stop(600, #E8C474)
stop(700, #E5B95F)
stop(800, #E1AD4B)
stop(900, #DEA236)
stop(1000, #CD9633)
stop(1500, #BD8A30)
stop(2000, #AC7E2C)
stop(3000, #9C7229)
stop(4000, #896527)
stop(5000, #765825)
stop(6000, #644A23)
stop(7000, #513D22)
stop(9988, transparent)
stop(10000, transparent)
}

かなり長いのですが、二つに分けて解説します。

まず、最初の部分で基本的な設定を行っています。

  raster-opacity:1;
  raster-scaling:bilinear;
  raster-colorizer-default-mode: linear;
  raster-colorizer-default-color: transparent;

ここではレイヤーを不透明にして、レンタリング時のscaleをbilinearにしてなめらかにしています。
raster-colorizer-default-modeはlinearを設定してあとで設定するraster-colorizer-stopsでグラデーションになるようにしています。
raster-colorizer-default-colorは基本の色を指定しているのですが、ここでは透明色を指定しています。

次のstopsが厄介です。

  raster-colorizer-stops:
    stop(-9999, #284eb0)
    stop(-9998, #55B499)
    stop(-1000, #4CB896)
    stop(-500, #57BA8A)
    stop(-200, #58BE7E)
    stop(-100, #59C272)
    stop(-50, #5AC666)
stop(-25, #5BCA5A)
stop(-10, #5CCE4E)
stop(-5, #5DD242)
stop(0, #62DD34)
stop(10, #67E037)
stop(25, #6CE33B)
stop(50, #71E73F)

raster-colorizer-stopsはtagとしてstopを連続して与えていくことになります。
この時二つのstop間の値がグラデーションになるようにしているという定義になります。
詳しいことraster-colorizer自体の説明はMapnikのWikiのRasterColorizerを参照としてください。
ちなみにCartoCSSの公式ドキュメントではここらへんまだ記述されていませんw

github.com

上手くスタイル付けができると以下のようになります。

f:id:smellman:20150927005006p:plain

あとはTilemillでmbtiles形式にexportして、mbutilを使ってmbtilesをzxy形式にバラしてあげればよいです。

github.com

スタイリングのコツとしては標高データのようなグラデーションのものと値がそのまま色になるものの設定を使い分けるのが重要です。

Land Cover(土地被覆)では値がそのまま色になるべきなので、以下のようにしています。

.lc {
  raster-opacity:1;
  raster-scaling:near;
  raster-colorizer-default-mode: exact;
  raster-colorizer-default-color: transparent;
  raster-colorizer-stops:
	stop(0, #000000)
	stop(1, #003200)
	stop(2, #3c9600)
	stop(3, #006e00)
	stop(4, #556e19)
	stop(5, #00c800)
	stop(6, #8cbe8c)
	stop(7, #467864)
	stop(8, #b4e664)
	stop(9, #9bc832)
	stop(10, #ebff64)
	stop(11, #f06432)
	stop(12, #9132e6)
	stop(13, #e664e6)
	stop(14, #9b82e6)
	stop(15, #b4fef0)
	stop(16, #646464)
	stop(17, #c8c8c8)
	stop(18, #ff0000)
	stop(19, #ffffff)
	stop(20, #5adcdc)
	stop(255, transparent)
}

raster-scaling を near に、 raster-colorizer-default-mode を exact にすると綺麗にでます。

これらの違いはQGISで色付けするとき(qmlファイル)にも使いますが、僕の方でJICAの講習用にQGISのスタイルデータを公開しています。

github.com

これらのスタイルをstopに変換する簡単なワンライナーを作っています。


One Liner to get raster-colorizer-stops tags from ...

もし、QGISで色付けをしている資産がある人はこちらも試してみると良いと思います。

Mapbox Android SDK で地理院地図を表示してみる

(追記) Mapbox Android SDKmapbox-gl-nativeベースのものに(無事)置き換えられたのでこの記事はもう役に立たなくなりました。古い実装がひつようなひとだけチェックしてね(はぁと

昨日の記事 に続いて Mapbox Android SDK でも地理院地図を表示してみようと思いました。

手順は以下の感じです。

  1. 適当にプロジェクトを作成。
  2. Mapbox Android SDKgradle の解説にそって app/build.gradle を編集。
  3. AndroidManifest.xmlネットワークアクセスなどの許可を書く。
  4. activity_main.xmlMapView を追加する。なお、 mapid 及び accesstoken は追加しない。
  5. プログラムを書く。

圧倒的に可愛い名前のプログラミング言語で書いたプログラムだけ貼っておきます。


mapbox sdk + gsimap (kotlin)

起動するとこんな感じ。

f:id:smellman:20150921075540p:plain

で、マルチタッチが何故か動かないので、実機で動かしてみたら普通にさくさく動きました。

mapbox-gl-native for ios で地理院地図を表示してみる

シミュレータの段階ですが、なんかできた。

手順はざっくり言うと以下でOKだった。

  1. xcodeで適当なSingle View Applicationを作成(今回はmapboxsdktestという名前で作った。雑だ)
  2. Podfileを作成して pod install を実行する。(参照)
  3. mapboxsdktest.xcworkspaceを開く
  4. Settings.bundle をプロジェクトに入れる。(参照)
  5. 地理院地図のタイルサーバはHTTPだけでしか配布してないのでApp Transport Securityを追加する(ios9以降)
  6. Mapbox GL Style Spec に沿ったjsonファイルを作成する。
  7. Viewにコードを書く。

ATSはこんな感じのものを書きます。

        <key>NSAppTransportSecurity</key>
        <dict>
                <key>NSExceptionDomains</key>
                <dict>
                        <key>cyberjapandata.gsi.go.jp</key>
                        <dict>
                                <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
                                <true/>
                        </dict>
                </dict>
        </dict>

jsonはこんな感じです。


raster for gsi

gistに貼っておけばrawでアクセス可能になってとても便利です。

最後にViewController.swiftを以下のようにします。


ViewController.swift for gsimap with mapbox-gl-nat ...

ビルドするとこんな感じになります。

f:id:smellman:20150920065617p:plain

でかすぎてなにがなんだかわかりません!!!!

地理院地図のソースコードを盛大にパクってLeafletのプラグインを作った

地理院地図に中心十字線っていうのがあるんだけど、お客さんからこれと同じものがあると嬉しいと言われて、だったらプラグイン化してしまえばイイのではと思ってやってみた。

github.com

Markerの実装を変えたり、わざわざimageディレクトリの位置を検出するのが面倒なので画像をBase64化したりしましたが、まぁいちおうLeaflet 0.7.5とLeaflet 1.0 beta1で動作確認して上手く動いたのでアップした。
コミットログが雑すぎるが、本当に初回のコミットなので仕方がない...

結構この中心十字線って便利だとは思うのでぜひ使ってみるもしくは弊社に仕事ください。

追記

何を思ったのかいきなりFactoryの実装を変更したりしています。
元々の実装がILayerっぽく出せなかったので仕方なくっていう感じです。
おかげで実装の見通しがよくなったので満足はしている。

すごいHaskellたのしく学ぼう!(第1版) 第3章のbmiの計算でハマった件について

タイトルどおりの感じですが、なかなか面白かったのでメモ。ちなみにうちの環境は以下のとおり。

$ ghci --version
The Glorious Glasgow Haskell Compilation System, version 7.6.3

今回は最初に作ったbaby.hsにひたすら出てきた関数を書いていくようにして試していたのだけど、P.37 の訳注でこんな記述がありました。

.hs ファイルの先頭に {-# OPTIONS -Wall -Werror #-} を付けてコーディングすれば、意図せぬ動作やクラッシュの原因になりがちな箇所を GHC が指摘してくれるので、良い Haskell コードを書く訓練になりますよ!

とあったので追加してみました。

当然、今まで書いたものは型を定義してないので warning が出るのでひと通り型の定義を追加してしてから先に進めたのですが、 P.42 のガードで計算しているところでドはまりしました。

まず、このプログラム自体本に書いてある内容は古いようで、原著の記述では Double ではなく RealFloat を使うようになっています。

bmiTell :: (RealFloat a) => a -> a -> String  
bmiTell weight height  
    | weight / height ^ 2 <= 18.5 = "You're underweight, you emo, you!"  
    | weight / height ^ 2 <= 25.0 = "You're supposedly normal. Pffft, I bet you're ugly!"  
    | weight / height ^ 2 <= 30.0 = "You're fat! Lose some weight, fatty!"  
    | otherwise                 = "You're a whale, congratulations!"  

Syntax in Functions - Learn You a Haskell for Great Good!

これを読み込むと前述の OPTIONS を付けた状態だと warning が出て通らなくなります(もちろん、 OPTIONS を付けて無ければ通って動作します)。

Prelude> :l baby
[1 of 1] Compiling Main             ( baby.hs, interpreted )

baby.hs:80:23: Warning:
    Defaulting the following constraint(s) to type `Integer'
      (Integral b0) arising from a use of `^' at baby.hs:80:23
      (Num b0) arising from the literal `2' at baby.hs:80:25
    In the second argument of `(/)', namely `height ^ 2'
    In the first argument of `(<=)', namely `weight / height ^ 2'
    In the expression: weight / height ^ 2 <= 18.5

baby.hs:81:23: Warning:
    Defaulting the following constraint(s) to type `Integer'
      (Integral b0) arising from a use of `^' at baby.hs:81:23
      (Num b0) arising from the literal `2' at baby.hs:81:25
    In the second argument of `(/)', namely `height ^ 2'
    In the first argument of `(<=)', namely `weight / height ^ 2'
    In the expression: weight / height ^ 2 <= 25.0

baby.hs:82:23: Warning:
    Defaulting the following constraint(s) to type `Integer'
      (Integral b0) arising from a use of `^' at baby.hs:82:23
      (Num b0) arising from the literal `2' at baby.hs:82:25
    In the second argument of `(/)', namely `height ^ 2'
    In the first argument of `(<=)', namely `weight / height ^ 2'
    In the expression: weight / height ^ 2 <= 30.0

<no location info>:
Failing due to -Werror.
Failed, modules loaded: none.

ここで注目するのは以下の記述です。

    Defaulting the following constraint(s) to type `Integer'
      (Integral b0) arising from a use of `^' at baby.hs:80:23
      (Num b0) arising from the literal `2' at baby.hs:80:25

この記述では通常 Integer となるところが '^' を使ってるので Integral と推測されて、 2 から Num だと推測されてわからんっていう状態になるというものっぽいです。
ということは Integer 型として処理をしてくれと明示的に指定すればよいというものです。
以下のように修正すると無事通るようになります。

bmiTell :: (RealFloat a) => a -> a -> String  
bmiTell weight height  
    | weight / height ^ (2 :: Integer) <= 18.5 = "You're underweight, you emo, you!"  
    | weight / height ^ (2 :: Integer) <= 25.0 = "You're supposedly normal. Pffft, I bet you're ugly!"  
    | weight / height ^ (2 :: Integer) <= 30.0 = "You're fat! Lose some weight, fatty!"  
    | otherwise                 = "You're a whale, congratulations!"  

最後に今朝の僕の情報を入れて試してみましょう。

Prelude> :l baby
[1 of 1] Compiling Main             ( baby.hs, interpreted )
Ok, modules loaded: Main.
*Main> bmiTell 70.4 1.65
"You're fat! Lose some weight, fatty!"

うるせぇ、これでも今年だけで約10キロ減ってるんだよ!!!!

Sutegma / Drugs in the morning noon evening

www.otherman-records.com

忙しくてSNSかなにかでしか書けなかった話を日記の方に書くような感じのものです。

平たくいうとbreakcoreという音楽のジャンルで知らん人は最初にまずこの曲を聞きましょうっていうことです。

このEP自体最高なんですが、僕が推したいのがSutegmaさんのDrugs in the morning noon eveningです。

物ネタの曲全然わからないんけど、さっきミラクル9見てたらなんか流れてました。多分有名なやつなんだろうと思います。

本当にわかりやすい楽曲を使ってブレイクコアというジャンルの面白さをやってるっていうのがよくわかるんですよ。
物ネタ全然知らないけど、この楽曲はツボにハマりましてリリース当時何十回風呂場で聞いてたかわかりません。(なんで風呂場で永遠リピートしてたのかもわからない)
とにかく、ブレイクコアを知る上で初めての人にもわかりやすい上に死ぬほど最高の曲ですのでみんな聞いて倒れましょう!!!!!!

つーかブレイクコア聞いて倒れましょう!!!!!!!

あと、酔ってます。