トップPC地図システム > 道路や川に沿って文字列を描画する

道路や川に沿って文字列を描画する

一方通行の道路に矢印(→)を描画する

まず、前C#版地図システムGISを踏襲したプログラムを試す。

    public void DrawArrows(Graphics g, TileToRender tile, string arrow, bool fName=false) {
        Brush br = new SolidBrush(Color.FromArgb(255,0,0,0));

        float prv_x = float.MinValue, prv_y = float.MinValue;
        float xlast = float.MinValue, ylast = float.MinValue;

        Font fnt = new Font("Arial", tile.zoom>=17 ? 12 : 9);
        SizeF size = g.MeasureString(arrow, fnt);

        PointF[] points = GetPointArray(tile, 0, num_nodes);
        for (int k = 0; k < points.Length; k++) {
            PointF point = points[k];
            float x = point.X;
            float y = point.Y;
            if (prv_x > float.MinValue && (k%2==0 || !fName)) {
                if (xlast==float.MinValue || Distance(x,y,xlast,ylast) > 300) {
                    float deg = (float)Degree(x, y, prv_x, prv_y);
                    g.ResetTransform();
                    g.TranslateTransform((x+prv_x)/2, (y+prv_y)/2);
                    g.RotateTransform(deg);
                    g.DrawString(arrow, fnt, br, -size.Width/2, -size.Height/2);
                    g.ResetTransform();
                    xlast = (x+prv_x)/2;
                    ylast = (y+prv_y)/2;
                }
            }
            prv_x = x;
            prv_y = y;
        }
    }

    double Distance(double x, double y, double x2, double y2) {
        return Math.Sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y));
    }

    double Degree(double x, double y, double x2, double y2) {
        return Math.Atan2(y2 - y, x2 - x) * 180 / Math.PI;
    }

このプログラムの実行結果を下に示す。矢印は文字 '→' を使っている。 もう少し見栄えのよいフォントがあるかも知れない。

線分 (x, y) - (prv_x, prv_y) の中央に、角度を同じにして 文字 '→' を描画している。 線分の長さが文字の幅よりも大きい場所を選んだ方がよいかも知れない。


クリックすると拡大します

道路の中心に道路名を描画する

矢印とは異なり、複数文字となるが、線分の長さが文字列全体の長さより大きい線分に限定すれば、 矢印描画プログラムを少し修正するだけで済む。

単独の道路としては、道路名同士の描画のぶつかりは起きないが、十字路をまたぐ描画では、 交差点で道路名同士のぶつかりが起きるかも知れない。

道路名は間隔を空けて複数描画されるため、道路と同じで、その上に、 後からアイコンや店名などが描画されて、一部が読めなくなってもよいとする。

しかし、平行に走る鉄道路線名と道路名のぶつかりが起こりうるため、 描画の重なりを回避する仕組みが必要となる。

前C#版地図システムGISでは、文字列幅より長い線分を探して、そこに、道路名を描画している。 数年以上使って不便を感じていないので、とりあえず、これを踏襲する。

代替案としては、線分の長さに条件は付けず、一文字ずつ線分の角度に合わせて描画する方法である。 頂点近くでは、より近い方の線分の角度に合わせるか、平均角度にするかであるが、 見栄えを確認して、調整することになろう。

A.リファレンス

[0] 縁取り文字を描く
[1] 【C#】文字列の回転描画
[2] 文字列を描画したときの大きさを計測する
[3] Graphics.MeasureString メソッド
[4] 2点間の距離と角度と座標の求め方

B.来歴およびノート

2023.3.22