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

スポンサーリンク
スポンサーリンク

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

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枚目の画像になる。

参考

Render a GeoJson layer with Google Maps, OSM or Mapbox on Android
GeoJson is a relatively new open standard format (GeoJSON as RFC 7946 were released in August 2016) designed to represen...

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

Google Maps Android GeoJSON Utility  |  Maps SDK for Android  |  Google for Developers

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

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

参考サイトに日本のポリゴンがあったので、それを拝借した。それを同じように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にすると。

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

参考
JavaでJSONを使う - how to code something
JavaでJSONを使う方法を解説する。 1. (What) JSONとは何か 2. (Why) なぜJSONを使うのか 2-1. データベース的な視点から 2-2. Web的な視点から 2-3. モバイルアプリでなぜJSONを使うのか 3...
getAssetsやgetResourcesを使おうとするとエラーが発生してしまう
###前提・実現したいこと私はAndroid Studio上でGitHubにあるソースコードの中の、rmtheis氏の「android-ocr」というプロジェクトを「Checkout Projec
InputStreamやOutputStreamとはなにか - リア充爆発日記
InputStreamやらOutputStreamやらが出てきて、今までなんのこっちゃわからないで使ってきたので改めて調べてみたときの自分の理解メモ。 InputStreamとOutputStreamの目的 ここのやり取りがわかりやすかった...

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)にキャストしてあげる。できた。

参考
services-turf 4.2.0-SNAPSHOT API
【初心者向け】Javaリスト(List)と配列の違いとその使い方
Javaのリスト(List)と配列は似た性質を持つが使い方や有用性が異なる。このページではJavaのListと配列の違い、加えて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番目の画像になった、と。

コメント

タイトルとURLをコピーしました