download: http://cyberjapandata.gsi.go.jp/xyz/std/15/28633/12986.png でエラーが出た。現在は https:// とすべきのはず。 単に、http を https に変えるだけでは次のエラーとなる。
download error: System.Net.WebException: 要求は中止されました: SSL/TLS のセキュリティで保護されているチャネルを作成でき ませんでした 場所 System.Net.WebClient.DownloadDataInternal(Uri address, WebRequest& request) 場所 System.Net.WebClient.DownloadData(Uri address) 場所 Renderer.download(Tile tile) download error: System.Net.WebException: 要求は中止されました: SSL/TLS のセキュリティで保護されているチャネルを作成でき ませんでした
記事 C#でHTTPSのWebページをダウンロードする により、
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; WebClient wc = new WebClient();とすることにより解決した。
place=island や place=islet のレンダリングが陸地ポリゴンで行っている。 名前は place=island や place=islet の multipolygon や polygon の中心を求めて、 point レコードとして出力する必要がある。
本州、北海道、四国、九州は除外する。
空間検索結果で確認すると、島はもとより本州も抽出されていることが分かった。 描画されない理由は別にあるようだ。
【解決】type を 0 に限定していた。これを解除することにより、十和田湖の小島(islet)の名前も描画されるようになった。
八千代市の後ろの2文字だけが、4タイルの左上に描画される。明らかにエラーであるが、 今までに経験したことがないエラーである。 文字の色と場所から判断すると、八千代市の境界線に沿って描く文字であろう。 実際、osm.DrawAdminTextをコメントアウトすると消えた。
g.ResetTransform();の位置を間違えていた。修正により、以下のように訂正された。
DrawLinesメソッドではヒゲが出るが、DrawLineメソッドで線分毎の描画にするとヒゲは出なくなった。 空振り描画が多い場合、DrawLinesメソッドではDrawLineの繰り返しよりオーバヘッドが大きい。 異なるアルゴリズムで描画が行われているようだ。
ともあれ、ヒゲは自作プログラムの影響でないことははっきりした。
//g.DrawLines(pen, pnts); for (int n = 0; n < pnts.Length-1; n++) { g.DrawLine(pen, pnts[n], pnts[n+1]); }
PC地図システムは直手から1か月でほぼ完成した。細かい点では漏れもあるであろうが、 全体的には過去を上回るレベルに達しているであろう。
この先は、スマホへの移植に重点を置いて、リファインを図る。
スマホ地図アプリはこれまで殆どが実機デバッグであったが、 できればレンダリングはエミュレータでデバッグしたい。ただし、8GBではメモリ不足かもしれない。
これはテーマパーク・動物園境界線エラーとは別のエラーである。
【原因判明】点レコード(type=0)で natural=cliff が登録されていた。type=0 を除外することで解決した。
下側の図は一見正しく見えるが、境界線の内側が濃く、外側が薄い。正しくはこの逆である。 他の場所でもこの逆転があった。
上側の図は、境界線がばらばらになり、描画箇所が大きくずれている。 別の場所では、データ上存在しない場所に崖(natural=cliff)が多数現れた。
その他のレンダリングは見た目では異常はない。 このようなエラーがいつから出るようになったか不明だが、おそらく、最近のことであろう。
内と外との逆転は少ないが、境界線がばらばらになる箇所は多い。
まず、内と外の逆転は崖のレンダリングでは閉ループをポリゴン扱いで向きを変えてはならないので、 reverse をやめたが、ポリゴン扱いの場合には、必要に応じて向きを変えねばならない。
タグにより、ポリゴン扱いにするかどうかを決める必要がある。当面、natural=cliffだけを例外扱いに改める。 これで、内と外の誤りはなくなった。境界線がばらばらになるのは止まらない。
最後に RenderOverlayを実行しているが、これを前に移すと、ばらばらになるののが止まった。 別のレイヤのレンダリングの影響を受けるのであろうか? 書き込み先のタイルを間違えているような現象である。
RenderAdminを止めるとエラーは消えた。
【解決】やはり最近のプログラムで変換処理後の g.ResetTransform(); を忘れていたのが原因であった。この追加で治った。
地図アプリGISでもレンダリングされていなかった。
【解決】wetland=wet_meadow に対応していなかった。レンダリングは wetland=marsh と同じ。
basin=detention は intermittent=yes と同じようにレンダリングする。
これまで無視していたタグを有効にしたのであるから、ファイルサイズが少し増加するはずだが、変化しない。
タグの値が未定義の時は 0 を出力していたので、ファイルサイズの無変化は異常ではなかった。
閉ループの場合、type=2 となるが、一般の道路は常にライン描画のため、type=1 扱いとなる。
OSM道路は highway=service と highway=pedestrian だけ area=yes により、エリア描画となる。 この例外処理のため、service と pedestrian でバグが出やすい。
以下の場合、閉ループの描画にエラーがある。OSMデータに area=yes がないことは確認した。 renderRoadCase か renderRoadFill のどこかにバグがある。
閉ループ(type=2)に対して、renderRoadFillが実行されていないことが分かった。
建物が道路のような描画になっている。
これは renderFill のバグであり、修正で正常に描画されるようになった。
また、境内の色が間違っている。公園タグと境内タグあった場合、 境内タグを優先することにより、解決した。
PC/タブレット版と同様に CompoundArray を使う。配列を {0.4, 1} とした場合には、 描画されるのは境界線の内側の40%である。境界線は濃い実線を引いているため 40%としたが、 50%(0.5)としても実質は同じである。
これでヒゲは出なくなった。
float width = 1.2f + (zoom - 10)*0.6f; Pen pen = new Pen(Color.FromArgb(0x66ee33aa), width*2); pen.CompoundArray = new float[] {0.4f, 1}; osm.DrawLine(g, pen, tile); osm.DrawPolygon(g, 0xaacc0066, width*0.5f, 0, tile); // outer
低ズームで座標値が急峻に変化するところでヒゲが発生している。C# のレンダリングソフトによるものかも知れない。 細長い矩形で、線の幅が太いと線と線の重なりが生まれる。そのようなケースでヒゲが発生するのであろう。
下の図で言えば、横浜美術大学という文字の左側と画面の左の駐車場の幅が狭い。 zoom 13 では、両側の太い薄色の線が重なる。このようなケースでヒゲが生まれるようである。
右側の小さい部分は低ズームでは全ノード間引いても問題はない。 左側は細長いので、全部間引くのは少し問題である。
二つの大きなエリアがこのような細い通路でつながる場合、 間引けば二つのエリアに分かれることになり、プログラム上処理が面倒である。
陸地ポリゴンのレンダリングで以前から気になっていたことであるが、厄介な話である。
ポリゴンの塗りつぶしでは問題であっても、境界線描画では、 単に線の描画が重なるだけのはずと思うが、なぜだろう。
Android Javaではこの方法でヒゲは出ないので、C# で固執するのはやめよう。 C#の場合、内側の太い線はもっと簡単に描画する方法がある。 その方法でもヒゲが出るかどうか試そう。
内側の太い線は境界線を移動させるのではなく、線の中心から外側は描画なし、
中央のリス園(tourism=zoo)の二重境界線の左上で、道路に向かって細いヒゲが伸びている。 他の二重境界線でも似た現象が起きる。この場合、 zoom 16以上ではこの髭のような線は消える。
別の地域では zoom 13 でヒゲが二か所に現れ、zoom 14以上では正常になる。 ヒゲは細く、長さは同じくらい。 また、全くこのヒゲは現れないものもある。
やはり、平行線の交点計算で求めた内側の境界線の描画で起きることが分かった。 平行線分計算か交点計算に問題があるのであろう。
初期化、リセット忘れなどが原因の可能性もある。
ざっとみた限りでは座標値に異状はない。 差分は丁度2倍になるはず。ヒゲを除けば、描画は正しいので、 計算エラーで生まれるヒゲではないのであろう。線は細い。
ヒゲが出るとき(上図 zoom=14)の座標データ
X=146.761 Y=223.6841 X=146.7202 Y=223.6548 X=146.67 Y=223.5168 X=146.6656 Y=223.2366 X=146.6734 Y=223.2198 X=147.2121 Y=222.6811 X=148.1265 Y=217.3677 X=142.9599 Y=206.1545 X=142.9729 Y=206.1942 X=142.9522 Y=206.6592 X=142.671 Y=207.0924 X=143.9276 Y=206.2812 X=143.9226 Y=206.2695 X=149.7678 Y=203.601 X=149.7921 Y=203.6412 X=151.2507 Y=203.2639 X=150.738 Y=203.2224 X=150.6419 Y=203.1292 X=150.7138 Y=203.1784 X=156.656 Y=216.2377 X=156.7356 Y=216.2062 X=157.1492 Y=217.7446 X=157.2176 Y=217.3271 X=157.4887 Y=217.0039 X=147.3422 Y=221.6969 X=147.4717 Y=223.5028 X=147.4522 Y=223.561 X=147.3669 Y=223.6379 X=147.097 Y=223.7115
ヒゲが出ないとき(zoom=15)の座標データ
X=36.98547 Y=192.8293 X=36.18918 Y=192.2581 X=35.84421 Y=191.3094 X=35.82605 Y=190.1523 X=36.09882 Y=189.5663 X=37.02679 Y=188.6384 X=38.6958 Y=178.94 X=28.52095 Y=156.8573 X=28.4352 Y=156.5945 X=28.42411 Y=156.844 X=28.25871 Y=157.0987 X=29.98188 Y=155.9863 X=29.89473 Y=155.7806 X=44.1295 Y=149.2818 X=44.29127 Y=149.5501 X=46.37063 Y=149.0124 X=46.13381 Y=148.9932 X=46.23656 Y=149.0928 X=46.6199 Y=149.3553 X=59.33039 Y=177.2897 X=59.26709 Y=177.3148 X=59.83095 Y=179.4123 X=59.84887 Y=179.3029 X=59.91128 Y=179.2285 X=40.2547 Y=188.3203 X=40.46116 Y=191.1986 X=40.2007 Y=191.9729 X=39.47295 Y=192.629 X=38.33451 Y=192.9395
ふと水域描画エラーに気づいた。多分、今日か昨日のレンダリングの追加修正により生まれたものと思われる。 これまでのこれに似たエラーの原因は type チェック漏れにより、点データでポリゴン描画を行っていた。
OSMデータのレンダリングエラーではなく、最初の陸地ポリゴンのレンダリングで起きていることが分かった。
最近行った修正としては、接近した点の間引きである。 因みにこれをやめるとエラーがなくなった。 ここに思い違いがあるようだ。
間引きを 0.01 以下としてもだめで、0.001 以下にした場合にはこのエラーは消えた。 腑に落ちないが当面こうしておく。
スマホの現地図アプリGISでもほぼ同じように東京都の島しょ部で境界線が描画されないものが多くある。
例えば 小笠原諸島のひとつ 325387789 についてチェックしてみる。OSMデータに名前はないが、多分西之島であろう。 zoom 7 では小笠原諸島のレンダリングは確認できるが、境界線が描画されない。
この wayレコードは kanto_norm.dat にはあるが、kanto_low.dat には出力されていないようだ。
【解決】low, mid 出力で閉ループ(type==2)を除外していたのが誤りだった。ファイルサイズの増加は微々たるものである。 前アプリでも間違えていた。
特定の地域で起きる。Graphics.DrawLines(Pen pen, PointF[] points)で起きる。 同地域で二つのタイルのレンダリングもおかしい。斜めの太い実線は地下鉄の地上部の高架部分であり、 エラーではなく、レンダリングを見直した方がいい箇所である。 エラーは主に縦方向の細い無数の線と下のタイルで黒く塗りつぶされた部分である。 zoom 15 で現れ、zoom 16 では消え、正常にレンダリングされる。
座標値に異状があるのかもしれない。特定の場所で起きるのは、同じ人のデータのためかも知れない。
目下のところ別の地域では観測されていない。 エラーでダウンするのも原因は同じ可能性がある。 「インデックスが配列の境界外です。」でダウンすることもある。
ノード数が非常に多いといったケースかも知れない。
エラーは renderLandcover.render(g, ttr, osms, 0, ttr.ixRecord) で起きていることが 分かった。
更に絞り込むと、下のプログラムで赤字の部分が問題であることが分かった。 このプログラムかまたはosm.DrawLine(g, 255, 0x888888, 1.0f, tile);に問題がある。
【解決】下のプログラムで青字の osm.type == 0 || は後から追加したものである。バグの原因はこれが漏れていたことである。 この地域をマッピングした人は、多分、ポイントレコードに barrier=yes タグを多用しているのであろう。
fence や wall は一般にラインであるが、車止めなどはポイントレコードであるから、 barrier=yes をポイントレコードに使っても誤りではないであろう。
ポイントレコードをラインレコードとして描画したため、おかしな線が描画されたり、データ不足でダウンしたようである。 これで特定地域でしかこのエラーが起きなかったわけもわかった。
念のため、OSM#DrawLine では type == 0 を除外するようにした。
if (zoom >= 15) { for (int n = fromIndex; n < toIndex; n++) { OSM osm = osms[n]; if (osm.type == 0 || (osm.tag_flags & bitBarrier) == 0) continue; Val barrier = osm.getVal(Key.barrier); Val area = osm.getVal(Key.area); switch (barrier) { case Val.hedge: if (osm.type == 1 || area != Val.yes) { osm.DrawLine(g, 255, 0xaed1a0, 3.0f, tile); } else if (area != Val.yes) { osm.FillPolygon(g, colorHedge, tile); } break; case Val.retaining_wall: case Val.wall: case Val.fence: case Val.yes: if (osm.type == 1 || area != Val.yes) { osm.DrawLine(g, 0xff888888, 1.0f, tile); } break; } } }
ハンドルされていない例外: System.ArgumentException: 使用されたパラメーターが有効ではありません。 場所 System.Drawing.Graphics.CheckErrorStatus(Int32 status) 場所 System.Drawing.Graphics.DrawLines(Pen pen, PointF[] points) 場所 RenderRoads.renderRoadFill(Graphics g, TileToRender tile, OSM[] osms, Int32 fromIx, Int32 toIx, Int32 layer) 場所 Renderer.render(Tile tile)
ハンドルされていない例外: System.IndexOutOfRangeException: インデックスが配列の境界外です。 場所 OSM.GetPointArray(TileToRender tile, Int32 offset, Int32 length) 場所 RenderLandcover.render(Graphics g, TileToRender tile, OSM[] osms, Int32 fromIndex, Int32 toIndex) 場所 Renderer.render(Tile tile)
階段は道路より先に描画するため、はみ出さないはずである。zorder に誤りがないかチェックする。
また、中央は閉ループではなく、highway=service;area=yes のため、塗りつぶしが必要。枠線も要る。
階段の zorder に誤りはなかったが、道路の zorder に誤りがあった。 zorder = -479 layer = -5 になっていた。
【原因判明】1 bit足りなかった。この修正で階段が道路にはみ出すことはなくなった。
//int zorder = (int)((head & 0x000fffff) >> 11); // 11~20bit int zorder = (int)((head & 0x001fffff) >> 11); // 11~20bit
highway=service;area=yesはまだ実装していなかっただけ。 zorderの修正とエリア描画の実装により、下のように修正された。
大枠は終わったが、積み残しは山のようにある。しかし、急いではならない。 よりスリム化を目指して行きつ戻りつ少しずつ進めていく。
他にもバグがある。 highway=pedestrian tunnel=yes osm_id=465410121 layer=9 zorder=937 head=727D4881 となった。
head から zorder(11~20bit) を取り出すところでエラーが入り込んだのかも知れない。
zorderを bit割り当てに変えたが、負値が面倒である。+500した値に変更する。
描画は未完成であるが、zorder、layer の値は予定通りの値になった。
getOSMs でチェックすると、tunnel=yes タグがなかった(way id=193329900)。
OSMDividerでこの wayレコードをチェックすると、tunnelタグはあるが値が0(unknown)であった。
【原因判明】enum Keyの順序を入れ替えたため、タグのコードに修正が必要となっていた。
試行錯誤の末、これまでのプログラムをスリムにしたプログラムに落ち着いた。
道路同様、low での描画がない。mid 以上では描画される。low だけにエラーがあるようだ。
zoom 7以下に boundary=administrative がない。
OSMDivider の下記の部分に問題はないか。 下位10ビットは影響がないから、問題ないはず。
int zorder1 = (zorder & 0x07ff) << 11; // 11ビット int wid1 = (wid & 0x003f) << 21; // 6ビット int minzoom1 = (minzoom & 0x001f) << 27; // 5ビット head |= zorder1 | wid1 | minzoom1;
japan_low.dat は 28.5MB であるのに、分割ファイルの合計は 12.3MB に過ぎない。 多くのレコードが出力されていない。
【原因判明】最近追加した面積の絞り込みに問題があった。これで、低ズームでの道路描画も解決した。
type や wid に誤りが入り込んでいるようだ。OSMDividerで head を書き換えているが、 この影響かも知れない。 先に進めてから再検討する。
まずkanto.osmで確認する。kanto_low.dat には道路・鉄道レコードが含まれている。
c:\map>java -Dfile.encoding=UTF-8 OSMParser kanto low in: c:/map/data/kanto_norm.dat, out:c:/map/data/kanto_low.dat 42185/8030026, ファイルサイズ=4661544(4.4MB), 平均レコード長=110.5 地名: 210, 森林: 50372, 水域: 1217, 道路: 11991, 鉄道: 19051, Admin: 682 98 point: 218 80, line: 31771 96, polygon: 7796 98, multipolygon: 2400 339 OSMParser実行時間 = 0.37分
getOSMsで確認すると wid=1だけはある。
type の値に誤りがある。1ではなく、2とか3になっている。
head は OSMDivider で変更している。また、Java と C# では endian が異なる。 endian については、ブロック全体で一括して変換しているため、head にだけエラーが入り込むとは思えない。
長さ0の inner polygon があった。これを除外すると正常に描画された。
OSMバイナリレコードブロックのキャッシュ管理に問題がありそうである。短い間隔で同じファイルの読み込みが起きている。
1ファイルだけで起きる。プレロードをやめた場合にはこの現象は起きていない。
zoom 12以下の道路、鉄道の描画を行った。
おそらく、type = 3 の水域がレンダリングされていないのであろう。 高ズームでも描画されない。
全て描画されないわけではない。例えば宮ケ瀬ダムは描画される。琵琶湖や芦ノ湖は描画されない。
relation であっても multipolygon とは限らない。
芦ノ湖(relation)の osm_id は 10349338 である。検出されているが、描画できていない。 マルチポリゴンではないので type は 2 になっている。
キー natural はあるがその値が 0 であった。OSMParser のバグか? OSMとしてはマルチポリゴンであるが、inner はない。このケースの処理に漏れがあるのであろう。
【解決】原因はたわいのないものであった。下のプログラムで * 2 を忘れていた。
public int getNumber(Key key) {
for (int n = 0; n < num_tags*2; n += 2) {
if (buff[pos + ixTags + n] == (int)key) {
return buff[pos + ixTags + n + 1];
}
}
return int.MinValue; // 該当なし
}
ときたま閉ループもあるが、大抵は閉ループになっていない。 offset はノード数ではなく、int配列上の位置である。
この修正により所望の結果を得た。 下図で、ほぼ中央の森林には多くの inner polygon がある。 それらを除外して outer polygon が描画されている。
建物のレンダリング(ハイズーム)と低ズーム森林レンダリング(下図)を確認した。
中高ズーム森林については、outer polygonだけのレンダリング&描画について確認した。
OSMのデータ構造の見直しを行っている。ここに座標値列データなど全てのデータを取り込むことも試したが、 メモリ使用量が増大する。パソコンでは問題ないがスマホではメモリ不足に陥る危険性がある。 やはり、データそのものはブロックに置いて、その位置だけを、OSMのメンバー変数にする。 しかし、その詳細は以前より少しコンパクトにした。
簡単な建物レコードは、wid = 52 として、タグ、osm_id、way_area を省いた。 OSM構造の変更またはコンパクト化によりバグが入り込んだ。建物のノード座標値データがひとつ少ないようだ。 たとえば、 (205.58 4.28) (236.09 153.19) (205.58 4.31) (205.58 4.34) (205.58 6.02) となるが、先頭と最後の座標が同じになっていない。先頭か末尾にもうひとつノードがあるはずである。
OSMバイナリレコード形式の修正を行い、陸地ポリゴンレンダリングの確認まで行った。
メニューの最初のプログラムおよびマウスイベントのキャッチテストプログラムを作成した。