低ズーム用はノードを間引くことによりポリゴンデータのサイズを小さくできるが、 高ズーム用の場合、そのままでは、スマホのメモリには載らないほどの大きなポリゴン(ユーラシア大陸など)がある。
このため、ポリゴンの分割が必須となる。また、メモリに載るとしても分割した方がレンダリング時間か短くなる。
まず、水平分割プログラム 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; }
最初に水平分割を行い、その結果のポリゴンを垂直分割する。
エラーが多く出た。垂直分割にバグがあるかも知れない。吟味しよう。