トップPC版地図アプリGIS > 折れ線に沿って小さな画像を並べて描画する

折れ線に沿って小さな画像を並べて描画する

はじめに

標準OSM地図では、 崖(natural=cliff)は下図に示すように、折れ線に沿って、小さな三角画像(▲)を高い方から低い方に向けて 描き並べる。

Javaでこれに相当することを行う。

三角と三角の間は少し隙間があり、この間隔は多少調整できる。折れ線は短い直線がつながったものである。

画像幅より短い線分には画像は描かず、それより長い線分には隙間を調整して、整数個の画像を描くものと する。

標準OSM地図ではもっと細かい処理が行われているようであり、画像の描画が途中で終わり、次の線分では 残りの描画を行っているケースもあるようだ。その場合、隣り合う線分は平行ではないため、 小さな三角は形が崩れる。

標準OSM地図より多少見栄えは落ちてもいいので、プログラムを簡単にしたい。

現スマホ(Android Java)プログラム

Android Java では次のようにしている。 まずは、これを本家Javaに置き換えたい。

イメージの回転は Matrix が AffineTransform に代わるが、本質的には大差がないであろう。

void drawIconMulti(Canvas canvas, Renderer r, Bitmap bmp, float space) {
    if (bmp == null) return;
    float width = bmp.getWidth();
    float height = bmp.getHeight();
    Matrix matrix = r.matrixMultiIcon;
    float prv_x = points[0], prv_y = points[1];
    for (int k = 1; k < points.length/2; k++) {
        float x = points[k * 2];
        float y = points[k * 2 + 1];
        double dist = distance(x, y, prv_x, prv_y);
        int num_icons = (int)(dist / (width + space) + 0.5);
        float dx = (x - prv_x) / num_icons;
        float dy = (y - prv_y) / num_icons;
        float deg = (float)degree(prv_x, prv_y, x, y);
        float x1 = prv_x, y1 = prv_y;
        for (int n = 0; n++ < num_icons; x1 += dx, y1 += dy) {
            matrix.reset();
            matrix.postRotate(deg, width/2, height/2);
            matrix.postTranslate(x1+dx/2-width/2, y1+dy/2-height/2);
            canvas.drawBitmap(bmp, matrix, null);
        }
        prv_x = x1;
        prv_y = y1;
    }
}

スクショを下に示す。パソコンの場合タイル画像のサイズは 256x256画素であるが、スマホは解像度が高いため 縦横3倍の768x768画素としている。このため、画像はパソコンよりも鮮明である。

本家Javaプログラム

void drawIconMulti(Graphics2D g, Image img, float space) {
    if (img == null) return;
    float width = img.getWidth(null);
    float height = img.getHeight(null);
    if (width <= 0 || height <= 0) return;
    float prv_x = xpoints[0], prv_y = ypoints[0];
    for (int k = 1; k < xpoints.length; k++) {
        float x = xpoints[k];
        float y = ypoints[k];
	float dx = x - prv_x;
	float dy = y - prv_y;
        double dist = Math.hypot(dx, dy);
	double angle = Math.atan2(dy, dx);
        int num = (int)(dist / (width + space) + 0.5);
        float x1 = prv_x, y1 = prv_y;
        for (int n = 0; n++ < num; x1 += dx/num, y1 += dy/num) {
	    AffineTransform affin = new AffineTransform();
	    affin.translate(x1-width/2, y1-height/2); //イメージの移動
	    affin.rotate(angle, width/2, height/2);   //画像の中心に回転
	    g.drawImage(img, affin, null);            //イメージの描画
        }
        prv_x = x1;
        prv_y = y1;
    }
}

リファレンス

[1] Shape上に文字列を配置する
[2] Fun with Java2D - Strokes