行政境界線(都道府県境界線、市町村境界線など)の描画は簡単であるが、境界線に沿って、 都道府県名や市町村名を描画するのは簡単ではない。
境界線は line型レコードであるが、行政区域名を描画するには、 行政区域をマルチポリゴンとして把握する必要がある。例えば神奈川県川崎市麻生区と東京都町田市の境界線は 神奈川県、川崎市、麻生区、東京都、町田市の境界線であるため、これだけでデータは5倍に膨れる。 特に都道府県ポリゴンは巨大であるから、メモリ使用量も大きい。主メモリ8GBのパソコンでは、 一つのアプリで4、5GBのメモリを使用することもできるが、Androidスマホでは 0.5GB が上限である。 また、CPUパワーも一桁劣るため、巨大な都道府県や市町村ポリゴンは現在のスマホには負担が重い。
そこで、パソコンとは描画方法を抜本的に変える。都道府県名などは境界線に沿ってびっしり描画するわけではない。 適当な間隔を空けて、所々に描画するだけである。この描画位置の候補を予め求めておき、 この部分データだけを lineレコードとして出力する。これにより、データ量は大幅に減らせ、 また、巨大なポリゴンではなく、無数の小さなラインレコードとなるため、 一つのタイルのレンダリングに必要な総データは大幅に少なくて済む。
boundary=administrativeについても一旦マルチポリゴンデータを生成する。 ファイル出力するときに、分解して、一部をラインレコードとして出力する。 例えば神奈川県川崎市麻生区と東京都町田市の境界線の場合、神奈川県、川崎市、麻生区の三つ、東京都と町田市の二つ が重なることがある。ポリゴンレコードとしては神奈川県、 川崎市、麻生区は独立しているため、重なりのないように出力するのは簡単ではない。しかし レンダリングはタイル単位である。都道府県名や市区町村名がタイルをまたぐことは起こりうる。 一方のタイルでレンダリングする場合、他方のタイルでもレンダリングしないと、描画がおかしくなる。
まずは、タイルをまたぐ描画は行わないこととする。
現在は type=multipolygon と boundary=administrative は同じ扱いであり、 最終的には以下のようにして OSMバイナリレコードを出力している。 ここで、newOuter は outer が一つ、inner が 0個以上のマルチポリゴンである。 multi配列が null のとき inner のない単純なポリゴンである。
int type = multi==null ? 2 : 3; OSM osm = new OSM(type, -rel.id, multi, newOuter, rel.tags); writeOSM(osm);
boundary=administrativeについては少なくとも当面は innerポリゴンは無視して、outerポリゴンのみに 行政区域名を描画する。 inner は別の自治体の飛び地である。 多分、この別の自治体では outerポリゴンとなり、そこで行政区域名が描画されるであろう。
ただひとつの outerポリゴンについて、適当な間隔を空けて、2点からなる線分レコードだけを生成して出力すればよい。 実際のレンダリングでは、タイル境界をまたがるものは棄却する。また、描画が重なるものも棄却する。 しかし、確率的には大半が描画されるであろう。
とりあえず、線分を 1/10 に間引いてみた。
if (isBoundary) { for (int i = 0; i+1 < outer.length; i += 10) { long[] lonlats = new long[2]; lonlats[0] = outer[i]; lonlats[1] = outer[i+1]; OSM osm = new OSM(1, -rel.id, null, lonlats, rel.tags); writeOSM(osm); } } else { int type = multi==null ? 2 : 3; OSM osm = new OSM(type, -rel.id, multi, newOuter, rel.tags); writeOSM(osm); }
kanto.osm に対する OSMバイナリレコードは変更前が kanto12(709MB)、kanto7(31.5MB) が kanto12(715MB)、kanto7(22.1MB) に変わった。
巨大なレコードが kanto7 に置かれており、この3割ほどが減少した。 小さなレコードが増えたため、kanto12 は 1%ほど増加した。この程度の増加は負担にならない。 kanto7の減少により、主メモリの使用量が減少するはずである。
現在のプログラムによる結果を下に示す。境界線からの距離が y 軸方向だけで計算している。角度を考慮した垂直距離に直す必要がある。 この図にはないが、直線区間でないところでの描画を避ける、あるいは工夫する必要がある。
matrix の rotate(回転)、translate(移動)、set/pre/post をどう使うべきかまだよく理解できていない。 垂直方向の移動はもう少し小さくする必要がある。水平方向への移動も必要であるが、これが全くできていない。 水平と垂直だけならば簡単であるが、斜めがあるため、正しい方法を理解しなければ上手くいかない。
試行錯誤の結果、以下のようにして所望の結果を得た。
Matrix matrix = new Matrix(); float deg = (float) getDegree(x, y+dy, px, py+dy); if (deg > 90 || deg < -90) { if (deg > 90) deg -= 180; if (deg < -90) deg += 180; dy = -dy; } matrix.preTranslate(0, dy); matrix.postRotate(deg, w/2, h/2); matrix.postTranslate((px+x-w)/2, (py+y-h)/2+dy*0); canvas.drawBitmap(bmpWork, matrix, null);
行政境界線はノード数が多いので、許容誤差範囲で間引いた方がプログラムが楽になりそうである。許容誤差を約5mとして間引いた。 OSMバイナリレコードは kanto12(708MB)、kanto7(20.5MB) に減少した。