日本国内にランダムにマーカーを配置する②

とりあえずここまでいった。寝よ。

12/3

できた。

MapBoxで

上のやつはできた勢いで書いただけなので、さらっと流れを書いておく。書く以外にも難儀していたけどそこまで覚えてないや。基本的な流れはこちらを参考にした。道路上とかはやってない。大変ありがたかったです。

日本の範囲内にマーカーを散らばす

参考サイトではturfのrandomを使っていたけど、java版には無いみたいなのでそこは手動でやる。そんでJSONObjectができたと。

JSONObject obj = new JSONObject();
obj = makeJSON();
FeatureCollection featureCollection = FeatureCollection.fromJson(obj.toString());

JSONObjectをtoStringでString型にして、FeatureCollection.fromJsonでMapboxで扱えるようになった。日本範囲内のPointのデータの集まりなので、そこには座標も含まれてる。その座標を元にマーカーを設置していけば、↑の1枚目の画像になる。

参考

https://medium.com/nextome/show-a-geojson-layer-on-google-maps-osm-mapbox-on-android-cd75b8377ba

そういえば↑見るとGoogleMapでもgeoJSON扱えそうなんだよな…。

https://developers.google.com/maps/documentation/android-sdk/utility/geojson

これとか、どうなんだろ。

日本の陸地に含まれてるマーカーだけにする

参考サイトに日本のポリゴンがあったので、それを拝借した。それを同じようにMapboxで扱えるようにして、Turfのinsideメソッドで判定してあげれば、残るのは陸地内ということだ。

アプリローカルにファイルを設置

assetsフォルダを作る。

以前別の記事でraw作る時に上の方のAndroidResourceDirectryを使っていたけど、普通に下の方にそれそのものがあった。えへへ。ちなみになんでassetsなのかは知らない。そんで、その中に落としてきたjapan_outline.geojsonをペースト。

assetsから読み込んでJSONにする

ここがすごーく難儀した。いやちゃんと理解してないままやろうとした自分が全部悪いんだけどさ。

MultiPolygon mp;
StringBuilder builder = new StringBuilder();
InputStream is;
FeatureCollection fc;
AssetManager assetManager = getResources().getAssets();

try {
    is = assetManager.open("japan_outline.geojson");
} catch (IOException e) {
    e.printStackTrace();
}

try {

    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
    String str;

    while ((str = bufferedReader.readLine()) != null) {
        builder.append(str);
    }

    JSONObject json = new JSONObject(builder.toString());

動いてくれたコードね。知らなかった言葉がたくさんある。AssetManager, InputStream, BufferedReader, StringBuilder,List<>ふんわり理解していこう。

AssetManager

assetsフォルダにあるファイルを使う時に使用するやつ。getResouce().getAssets()で使う準備。そんでassetManager.open(filename)でファイルを開く。

InputStream, InputStreamReader, BufferedReader
  • InputStream

読み込んだファイルをふわっとした感じにしてくれる。

  • InputStreamReader

ふわっとした感じをJavaで扱える感じにしてくれる。

  • BufferedReader

Javaで扱える感じをゆったり読み込んでくれる。

StringBuilder

文字列を組み立てるんだろうなー。今回は、BufferedReaderで一行ずつ読み込んだやつを、1個にまとめてくれる。そういえば、元のファイルが複数行になっている場合

while ((str = bufferedReader.readLine()) != null) { 
    builder.append(str); 
}

としないと、全部読み込んでくれない。俺ははこれをやってなくて、最初の行しか読み込まれずエラー出まくって、デバックしてやっと気づいた。

ほいでStringBuilderからtoStringして、JSONObjectにすると。

…これはもう定形として覚えるだけでいいかな…。

参考

http://d.hatena.ne.jp/seinzumtode/20130426/1366934641

https://teratail.com/questions/94566

http://ria10.hatenablog.com/entry/20121128/1354081081

turfJoins.insideで扱えるようにgeoJSON型にする

今読み込んでるのは、日本の陸地のポリゴンで、JSONObject型になってる。turfJoins.insideは

public static boolean inside(com.mapbox.geojson.Point point,
                             com.mapbox.geojson.MultiPolygon multiPolygon)

と、引数をMultiPolygon型(もしくはPolygon型)にしないといけない。

    fc = FeatureCollection.fromJson(json.toString());
    List<Feature> featuresjp = fc.features();
    Feature ft = featuresjp.get(0);
    mp = (MultiPolygon) ft.geometry();

} catch (JSONException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

先ほどと同じようにFeatureCollection型にする。FeatureCollectionは.fetures()でList<Feature>を返す。List<>っつーのは動的配列みたいなもんらしい。.get(index)で単体のFeatureが取得できる。indexは0始まりみたい、japan_outline.geojsonの構成を見ながらどこに何が配置されてるか理解しながらやんないとダメだった。ちなみにindexを1にしてエラー出したのが私だ。そんで.geometry()でFeatureの内部を取得できる。geometryはいくつか種類があるので、適切な形(ここではMultiPlygon)にキャストしてあげる。できた。

参考

https://www.mapbox.com/android-docs/api/mapbox-java/libjava-turf/4.1.1/index.html?com/mapbox/turf/TurfJoins.html

https://eng-entrance.com/java-array-list

日本の範囲内のPointデータと日本の範囲を表すデータを比較してマーカーを配置する

やっとturfが使える。

List<Feature> features = featureCollection.features();

mapView.getMapAsync(new OnMapReadyCallback() {
    @Override
    public void onMapReady(@NonNull MapboxMap mapboxMap) {
        mapboxMapm = mapboxMap;

        for (Feature f : features) {
            Point p = (Point) f.geometry();
            if (TurfJoins.inside(p, mp)) {
                marker = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(p.latitude(), p.longitude())));
                marker.setIcon(icon01);
            }
        }
    }
});

これ↓は

mapView.getMapAsync(new OnMapReadyCallback() {
    @Override
    public void onMapReady(@NonNull MapboxMap mapboxMap) { … };

こう書こうねとサンプルがなってたのでこう書いた。

ランダムPointのデータをList<Feature>型にする。Listは拡張for文が使えるみたいなので、それぞれのFeatureをPoint型にキャストし、それが日本の範囲内にあるかどうかをturfjoins.insideで判定する。戻り値がtrueだったらmarkerをその位置に追加し、.setIcon()する。

これで上から2番目の画像になった、と。

カテゴリー: したい タグ: , , , , , , パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です