タイルサービスの作成 (WMS)

id:yellow_73:20111122#p1 のつづき。
最後にブサイクとか言ってた問題については、そのまま放置にすると、とりあえずできたことになった。あと、KMLの自動生成等をやってしまえばできあがり。
GeoWebCacheでは WMS が出ます (サーバが対応できる解像度と違うリクエストに対してはエラーを返すという WMS としては非常な造り)。これをやりたい、と。
結局はタイルを特定してファイルキャッシュにタイルが存在するならそれを返し、存在しないなら作成して返す、という仕組み自体は変わらないので、まあできます。
問題は、BBOX (地図単位ベースの範囲) からタイルを特定する方法。

z (ズームレベル) の特定

X軸について、uppx (unit-per-pixel) を (maxx-minx)/width で出るので、ズームレベル z から出す upp(z) = uw0/(width*(2^z)) に近い z を求めればOK。uw0 はズームレベル 0 の際のX軸の地図単位ベースのサイズです。 geodetic なプロファイルでは 360 で、mercator なプロファイルでは 40075017 です。
実際は f1(z) = uppx/upp(z) = (maxx-minx) / uw0 * (2^z) を出して、1に近いかどうかを、zのループでテストしました。いやこれもうちょっとスマートにできそうな気がせんでもないのですが、log使うと逆にコストがかかるので、放置。
X軸について zが求まれば、求まったzを使って uppy/upp(z) = (maxy-miny) / uw0 * (2^z) をチェックして、1に近くないなら、エラーとします。

タイルインデクスの特定

BBOXから地図単位ベースの中心点 ( (maxx+minx)/2, (maxy+miny)/2 ) を求めて、upp(z) で割るとピクセル単位の座標が出るので 256 で割って小数点以下を切り捨てるとタイルインデクスが特定できます。ここで中心をとらずにコーナーでやろうとすると、ほぼタイルと同じ範囲を指しているのに若干はみ出している場合に、対応できない可能性があるかな、と思います。

タイルが適切かのチェック

タイルインデクスから、そのタイルの地図単位ベースでの範囲を求め、コーナーごとにだいたいあってる(差が一定範囲内にある)かどうかをチェック。アウトならエラー、OKなら画像を返す、とします。