低ズーム用はノードを間引くことによりポリゴンデータのサイズを小さくできるが、 高ズーム用の場合、そのままでは、スマホのメモリには載らないほどの大きなポリゴン(ユーラシア大陸など)がある。
このため、ポリゴンの分割が必須となる。また、メモリに載るとしても分割した方がレンダリング時間か短くなる。
まず、水平分割プログラム splitPolygonHorizontally メソッドを作成、デバッグして、 スマホで地図を表示して問題がないことをチェックした。
実際には zoom 9か10以上で使うがチェックは zoom 5 で行った。 ハイズームではごく一部のチェックしかできないためである。
次に、垂直分割をチェックした。
南極と北米で分割エラーが出た。垂直分割線とポリゴンの交点の座標を求めている。 y1 < y2 となるはずが逆のケースがある。特に、X, Y座標は負の値をとらないのに 交点が負の値になっているケースが多い。
当然、ここでの分割は行っていないので、描画上のエラーは生じていないことを確認した。 しかし、気になるので、いずれ原因を究明したい。
【原因判明】水平分割で海岸線が偶然水平分割線と重なった場合、交点は算出できない。 同様に、垂直分割で海岸線が垂直分割線と重なった場合、交点は算出できない。 南極大陸でエラーが多いのはこのためである。
取りあえず、ここでは分割をやめればいい。
procCoastLine antarctica Error y1=835864880 y2=-1812152464 Error y1=912725841 y2=-1029607766 Error y1=912970227 y2=-360144960 Error y1=913196947 y2=309317846 Error y1=913789055 y2=-1931044030 Error y1=914006026 y2=-545901416 Error y1=914536049 y2=839241197 Error y1=915884784 y2=-2070583485 Error y1=917100957 y2=-685440872 Error y1=917407864 y2=699701742 procCoastLine north-america Error y1=206627837 y2=206530715
List<Polygon> splitPolygonHorizontally(int span) {
List<Polygon> dst = new ArrayList<>();
rotate(iYmax);
//System.out.printf("iYmax=%d\n", iYmax);
int bgn = ((ymin + span) / span) * span;
boolean fSplit = false;
for (int y = bgn; y < ymax; y += span) { // y : 水平分割線のY座標
int cntCross = 0;
int i1 = -1, i2 = -1;
int k = iYmax;
do {
if ((ys[k] - (long)y) * (ys[next(k)] - y) < 0) { // 交差判定
cntCross++;
if (i1 < 0) i1 = k; // 最初の交点
else i2 = k; // 最後の交点
}
k = next(k);
} while (k != iYmax) ; // 一巡するまで
//System.out.printf("%d ", cntCross);
if (cntCross == 2 && i2 - i1 >= 2 && i2+1 < xs.length) { // 水平分割可能
int x1 = crossHorizonX(xs[i1], ys[i1], xs[i1+1], ys[i1+1], y);
int x2 = crossHorizonX(xs[i2], ys[i2], xs[i2+1], ys[i2+1], y);
// (x1,y): 線分i1ーi1+1と水平線yの交点, (x2,y): 線分i2ーi2+1と水平線yの交点
if (x2 > x1) {
System.out.printf("Error x1=%d x2=%d\n", x1, x2);
continue; // 分割しない
}
//分割で生まれるポリゴン 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);
pN.add(x1, y);
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);
set(i2, x2, y);
remove(i1+2, i2); // i1+2, i1+3, ... , i2-1 を削除
setMinMax();
}
//System.out.println();
}
setMinMax();
dst.add(this);
return dst;
}
List<Polygon> splitPolygonVertically(int span) {
List<Polygon> dst = new ArrayList<>();
rotate(iXmax);
//System.out.printf("iYmax=%d\n", iYmax);
int bgn = ((xmin + span) / span) * span;
boolean fSplit = false;
for (int x = bgn; x < xmax; x += span) { // y : 水平分割線のY座標
int cntCross = 0;
int i1 = -1, i2 = -1;
int k = iXmax;
do {
if ((xs[k] - (long)x) * (xs[next(k)] - x) < 0) { // 交差判定
cntCross++;
if (i1 < 0) i1 = k; // 最初の交点
else i2 = k; // 最後の交点
}
k = next(k);
} while (k != iXmax) ; // 一巡するまで
//System.out.printf("%d ", cntCross);
if (cntCross == 2 && i2 - i1 >= 2 && i2+1 < ys.length) { // 垂直分割可能
int y1 = crossVertY(xs[i1], ys[i1], xs[i1+1], ys[i1+1], x);
int y2 = crossVertY(xs[i2], ys[i2], xs[i2+1], ys[i2+1], x);
// (x,y1): 線分i1ーi1+1と水平線yの交点, (x,y2): 線分i2ーi2+1と垂直線xの交点
if (y2 < y1) {
System.out.printf("Error y1=%d y2=%d\n", y1, y2);
continue; // 分割しない
}
//分割で生まれるポリゴン y1, i1+1, ... , i2, y2, y1
Polygon pN = new Polygon(i2 - i1 + 3);
pN.add(x, y1);
for (int i = i1+1; i <= i2; i++) {
pN.add(xs[i], ys[i]);
}
pN.add(x, y2);
pN.add(x, y1);
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, x, y1);
set(i2, x, y2);
remove(i1+2, i2); // i1+2, i1+3, ... , i2-1 を削除
setMinMax();
}
//System.out.println();
}
setMinMax();
dst.add(this);
return dst;
}
// newStart が配列の先頭になるように回転する
void rotate(int newStart) {
int[] xsNew = xs.clone();
int[] ysNew = ys.clone();
for (int i = 0; i < length; i++) {
xsNew[i] = xs[(i+newStart)%length];
ysNew[i] = ys[(i+newStart)%length];
}
xs = xsNew;
ys = ysNew;
iXmax = (iXmax + length - newStart) % length;
iYmax = (iYmax + length - newStart) % length;
}
最初に水平分割を行い、その結果のポリゴンを垂直分割する。
エラーが多く出た。垂直分割にバグがあるかも知れない。吟味しよう。