懸案であった PorterDuff演算について、まずはパターン塗りつぶしで実現できた。 目下、マルチポリゴン(穴あきポリゴン)について取り組んでいる。
急がなければ、何かと、より良い方法を思いつくものである。
陸地ポリゴンに続き、まず、森林の描画を行った。GISアプリに比べて森林の描画が大幅に少ない。
どこに問題があるかを掴むために、間引き無しデータもスマホに転送した。
どうやら、リレーションによるポリゴンに問題があるようだ。
原因判明:fillMultiPolygonを実装していなかった。取りあえず、outer polygon が正常に描画できることを確認した。
OSMParserの作り直しはざっと終えた。relation処理は以前のままである。
japan.osm に対しては、下記の通りでエラーはない。
c:\gisa\OSMParser>java -Dfile.encoding=UTF-8 -Xmx5g OSMParser OSMParser japan norm readWords 1592823語 relationセクションパース開始. (空読み時間 3.52分) 116238 relations. way members = 795658 3.57分 nodeセクション終了: 8.46分 wayセクション終了: 20.05分 ブロック数=610 maxNodes=4329823 totalNodes=227849492 実行時間: 20.94分
kanto.osm に対しては、relation処理中にエラーが頻発する。
c:\gisa\OSMParser>java -Dfile.encoding=UTF-8 -Xmx5g OSMParser kanto OSMParser kanto norm readWords 1592823語 relationセクションパース開始. (空読み時間 0.71分) 33209 relations. way members = 231056 0.73分 nodeセクション終了: 1.56分 wayセクション終了: 3.90分 no! id=2419612162 blk=144 sid=3693058 no! id=2419610411 blk=144 sid=3691307 no! id=357116313 blk=21 sid=4794777 no! id=357116531 blk=21 sid=4794995 … ブロック数=610 maxNodes=888899 totalNodes=42781765 実行時間: 8.39分【解決】
バス路線に登録されたバス停でエラーが起きていることが分かった。 これはエラーではない。例えば、千葉から京都への高速バスの場合、kanto.osm の relation には全区間のバス停が登録されているが、 バス停 node 自体は関東エリアにないものは含まれていない。 したがって、データがないのはエラーではない。
以前も気づいていたが、月日が経ちそのことを忘れていた。 エラーメッセージを出さないようにした。
陸地ポリゴンの描画ではマージンがなくても今のところ不具合は見つかっていないが、 内陸タイル判定に使う場合、マージンがある方が安心であるため、マージンを追加する。 内陸タイル判定をせずに、陸地ポリゴンをそのままレンダリングする場合は、このマージンにより、 余分なレンダリングがおきる可能性はある。つまり、マージンとはそういうものである。
現在の span は 1048576 である。マージンを 50 としておく。
水平分割に対しては次のようにした。垂直分割もこれに倣った。
//分割で生まれるポリゴン x1, i1+1, ... , i2, x2, x1 Polygon pN = new Polygon(i2 - i1 + 3); pN.add(x1, y); for (int i = i1+1; i <= i2; i++) { pN.add(xs[i], ys[i]); } pN.add(x2, y+MARGIN); pN.add(x1, y+MARGIN); pN.setMinMax(); pN.fSplit = true; fSplit = true; // 分割が起きた //System.out.printf("assign=%d length=%d\n", i2 - i1 + 3, pN.length); ここでの矛盾はない dst.add(pN); // 元のポリゴン(小さくなる) set(i1+1, x1, y-MARGIN); set(i2, x2, y-MARGIN); remove(i1+2, i2); // i1+2, i1+3, ... , i2-1 を削除 setMinMax();
うまく描画される zoom が多いが、次のエラーが出る zoom がある。 キャッシュにタイル画像がないため、レンダリングすべきだが、何故かそうしていないようだ。
onDraw error: status=free, path=null onDraw 1ms zoom=8
HashMapによるキャッシュ管理をやめて、順次検索に変えた。エラーはなくなった。
南極大陸のエラーは消えたが、北米で次のエラーが出た。
垂直分割結果を水平分割しても、エラーメッセージはこれだけであった。 ただし、分割によりファイルサイズは大きくならず、逆に減少する。何か、おかしい。
エラーメッセージよりもこちらが問題である。 このデータで地図を描画すると、ごく一部しか、描画されなかった。 この間違いはすぐわかった。赤字の poly. が抜けていた。予想通り、分割によりファイルサイズは少し増えた。
List<Polygon> splitPolygon(int span) {
List<Polygon> listOut = new ArrayList<>();
List<Polygon> list = splitPolygonVertically(span);
for (Polygon poly : list) {
listOut.addAll(poly.splitPolygonHorizontally(span));
}
return listOut;
}
なぜ、下のように、y1 と y2 の大小関係が逆になるケースがあるのか分からないが、分割は除外しているので問題はない。
Err x=192937984(0.1797) y1=206627837 y2=206530715 X(0.179686~0.179688) Y(0.192350~0.192345) i1=135 i2=171 iXmax=0 len=1748
南極大陸の右端(東)でエラーが検出されている。
垂直分割結果を水平分割すると無数のエラーが出る。現在の分割方法に問題があり、 i1、i2 が小さいとき、エラーが起きるのかも知れない。
i2 がノード列データの末尾であるのが特徴と言える。
最後の水平線分が長ければ必然的にそうなるのでおかしくない。
交差判定に問題はないか? 判定回数に過不足はないか?
if ((xs[k] - (long)x) * (xs[next(k)] - x) < 0) { // 交差判定
i1+1、i2+1 が問題であった。巡回が必要なため、next(i1)、next(i2) とすべき。
ノード座標値読み込み完了 num_node=69994719 procCoastLine antarctica 2分割 3分割 1分割 2分割 1分割 2分割 2分割 1分割 2分割 2分割 1分割 Err x=1019215872(0.9492) y1=835864880 y2=-1812152464 X(0.9453~0.9453) Y(1.0653~0.7745) i1=65363 i2=66250 iXmax=0 len=66251 Err x=1048576000(0.9766) y1=912725841 y2=-1029607766 X(0.9453~0.9453) Y(1.0653~0.7745) i1=525 i2=66250 iXmax=0 len=66251 Err x=1050673152(0.9785) y1=912970227 y2=-360144960 X(0.9453~0.9453) Y(1.0653~0.7745) i1=500 i2=66250 iXmax=0 len=66251 Err x=1052770304(0.9805) y1=913196947 y2=309317846 X(0.9453~0.9453) Y(1.0653~0.7745) i1=459 i2=66250 iXmax=0 len=66251 Err x=1056964608(0.9844) y1=913789055 y2=-1931044030 X(0.9824~0.9823) Y(0.9116~0.8506) i1=364 i2=408 iXmax=0 len=409 Err x=1059061760(0.9863) y1=914006026 y2=-545901416 X(0.9824~0.9823) Y(0.9116~0.8506) i1=336 i2=408 iXmax=0 len=409 Err x=1061158912(0.9883) y1=914536049 y2=839241197 X(0.9824~0.9823) Y(0.9116~0.8506) i1=283 i2=408 iXmax=0 len=409 Err x=1063256064(0.9902) y1=915884784 y2=-2070583485 X(0.9824~0.9823) Y(0.9116~0.8506) i1=210 i2=408 iXmax=0 len=409 Err x=1065353216(0.9922) y1=917100957 y2=-685440872 X(0.9824~0.9823) Y(0.9116~0.8506) i1=181 i2=408 iXmax=0 len=409 Err x=1067450368(0.9941) y1=917407864 y2=699701742 X(0.9824~0.9823) Y(0.9116~0.8506) i1=149 i2=408 iXmax=0 len=409 389分割 1分割 mapCoastLines エントリ数=0
プログラムの分かりやすさのために、メソッド呼び出しに変更した。 FCコマンドで結果が同じであることを確認した。
procCoastLine australia-oceania 2分割 3分割 1分割 2分割 2分割 1分割 2分割 2分割 2分割 3分割 2分割 3分割 3分割 1分割 3分割 4分割 1分割 1分割 3分割 3分割 15分割 8分割 6分割 mapCoastLines エントリ数=34 5分割 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3 at Polygon.splitPolygonHorizontally(Polygon.java:125) at Polygon.splitPolygon(Polygon.java:98) at LandPolygon.writePolygon(LandPolygon.java:466) at LandPolygon.unclosedCoastlines(LandPolygon.java:485) at LandPolygon.generateLandPolygon(LandPolygon.java:300) at LandPolygon.main(LandPolygon.java:532)
赤字の部分を追加した。
if (cntCross == 2 && i2 - i1 >= 2 && i2+1 < xs.length) { // 水平分割可能
このデータで描画すると、かなりの数のポリゴンが描画されない。
zoom 5以上では描画され、zoom 4以下で描画されないようである。
【原因判明】間引き無しのデータは zoom 5 と zoom 1 で分割している。zoom 5 にあるデータは zoom 4 以下では 取り出さない。
zoom 9 以下は zoom 1で分割した低ズーム用データを使うので、これで問題はない。
気晴らしを兼ねてここ1週間ほど横道にそれたが、そこでの成果も活かして、陸地ポリゴンの分割を 再開したい。
プログラムを分かりやすくするため、属性の取り出しをメソッド化した。 結果は FCコマンドで確認した。
c:\gisa>fc /b \osm\lands_low.dat \osm\lands_low204.dat ファイル \OSM\lands_low.dat と \OSM\LANDS_LOW204.DAT を比較しています FC: 相違点は検出されませんでした
SAXによるパースも行ったが、時間がかかる。自前のパースをより分かりやすく直す方が良さそう。
陸地ポリゴンの分割が足踏み状態だったため、低ズーム用陸地ポリゴンデータの作成を行った。 少し手間取ったが、正しく陸地ポリゴンが形成できた。
西から東へ縦方向にスライスする。zoom は 7~10 くらいを考えている。縦方向に長い場合、 上(北)と下(南)と中央の矩形に3分する。中央の矩形は可能な限り大きくする。
スライスでは大きなポリゴンが一つだけのときと小さなポリゴンが1つ以上切り出されることがある。
スライスにより、新しい頂点(分割線と海岸線との交点)が生まれる。
少なくともトーメンはマージン(オーバラップ)は考えない。
Mapの空間検索で、最初の2レコードで次のようになった。 先頭が head、次が rec_length で、ix はその次を指すので、ix は問題がない。
OSMDividerでは差分コード化でレコードが元より小さくなっている。 元のレコード長を出力していたのが誤まりであった。
ix=2 head=34 length=51 ix=55 head=940596986 length=106794340