トップMy OpenStreetMap > 地名を描画する

地名を描画する

はじめに

地名描画メソッドはシンプルなものであるが、その裏に苦労が隠されている。 下の図では、地名間は適当な間隔があいているが、これは事前に間引き処理を行っているからである。 都会には地名がびっしりあり、とても描ききれない。

間引き自体はさほど難しくないが、描画がタイル毎に行われることに難しさがある。 タイルをまたがる地名は無数に存在するため、タイル単位の間引きが難しい。

タイルAとタイルBにまたがる地名があったとする。 もし、タイルAで間引いたとすればタイルBでも間引かねばならない。 タイルAで描画したのであればタイルBでも描画しなければならない。 タイルA、タイルBのどちらが先に描画されるかは決まっていない。

このような状況で矛盾なく地名を描画するのは実際上不可能に近い。 このため、現在は地名に限り、日本全体を対象に描画するかしないかを事前に決定している。 zoom毎に異なり、OSMバイナリレコードにそのデータを含めている。

できれば事前処理の要らない方法を考えたい。

地名描画メソッドおよび描画結果

public class RenderPlacename extends SuperRenderer {
    Paint paProvince, paCity, paTown, paSuburb, paQuarter, paNeighbourhood, paHamlet, paLocality;

    public RenderPlacename() {
        paProvince = getPaint(0xff917296, 17);
        paCity = getPaint(0xff4c4c4c, 15);
        paTown = getPaint(0xff3c3c3c, 13);
        paSuburb = getPaint(0xff555555, 12);
        paQuarter = getPaint(0xff777777, 11);
        paNeighbourhood = getPaint(0xff777777, 11);
        paHamlet = getPaint(0xff777777, 11);
        paLocality = getPaint(0xff777777, 11);
    }   // GIS起動時に一度だけ実行する

    void render(Canvas cv, TileToRender tile, OSM[] osms, int fromIndex, int toIndex) {
        final int zoom = tile.zoom;

        for (int n = fromIndex; n < toIndex; n++) {
            OSM osm = osms[n];
            if (osm.type != 0 || (osm.tag_flags&bitPlace)==0 || (osm.tag_flags&bitName)==0) {
                continue;
            }
            Tag.Val place = osm.getVal(Tag.Key.place);
            switch (place) {
                case province:
                    if (zoom >= 5) osm.drawPlacename(cv, paProvince, tile, 0, 0);
                    break;
                case city:
                    if (zoom >= 7) osm.drawPlacename(cv, paCity, tile,  0, 1);
                    break;
                case suburb:
                    osm.drawSurburbname(cv, paSuburb, tile, 0, 1);
                    break;
                case town:
                    if (zoom >= 9) osm.drawPlacename(cv, paTown, tile, 0, 1);
                    break;
                case village:
                    if (zoom >= 10) osm.drawPlacename(cv, paTown, tile, 0, 1);
                    break;
                case quarter:
                    if (zoom >= 14) osm.drawPlacename(cv, paQuarter, tile, 0, 1.5f);
                    break;
                case neighbourhood:
                    if (zoom >= 15) osm.drawPlacename(cv, paNeighbourhood, tile, 0, 1.5f);
                    break;
                case hamlet:
                    if (zoom >= 15) osm.drawPlacename(cv, paHamlet, tile, 0, 1.5f);
                    break;
                case locality:
                    if (zoom >= 18) osm.drawPlacename(cv, paLocality, tile, 0, 1.5f);
                    break;
            }
        }
    }
}

リファレンス

[1] Android Java: 文字列の描画
[2] 画面に配置せずにViewからBitmapを生成する
[3] Create a multiline TextView in Android application
[4] draw Multi Line Text on Canvas - Android java.lang
[5] get Multi Line Text Bounds - Android java.lang