3

破線(PointF[])、いくつかstring、およびGraphicsオブジェクトがあります。今度はこの文字列を自分の線に描きたいと思います。

次に例を示します。

ここに画像の説明を入力してください

最も簡単な方法でそれを行うためのアルゴリズムはありますか?

[編集] わかりました。@endofzeroのコードを試し、少し変更しました。これが全体の解決策です(角度と距離の計算を含む):

private static void DrawBrokenString(Graphics g, IList<PointF> line, string text, Font font)
{
    g.SmoothingMode = SmoothingMode.AntiAlias;
    g.TextRenderingHint = TextRenderingHint.AntiAlias;
    Pen pen = new Pen(Brushes.Black);

    for (int index = 0; index < line.Count - 1; index++)
    {
        float distance = GetDistance(line[index], line[index + 1]);

        if (text.Length > 0)
        {
            for (int cIndex = text.Length; cIndex >= 0; cIndex--)
            {
                SizeF textSize = g.MeasureString(text.Substring(0, cIndex).Trim(), font);
                if (textSize.Width <= distance)
                {
                    float rotation = GetAngle(line[index], line[index + 1]);

                    g.TranslateTransform(line[index].X, line[index].Y);
                    g.RotateTransform(rotation);

                    if (index != line.Count - 2)
                    {
                        g.DrawString(text.Substring(0, cIndex).Trim(), font, new SolidBrush(Color.Black),
                                 new PointF(0, -textSize.Height));
                    }
                    else
                    {
                        g.DrawString(text.Trim(), font, new SolidBrush(Color.Black),
                                 new PointF(0, -textSize.Height));
                    }

                    g.RotateTransform(-rotation);
                    g.TranslateTransform(-line[index].X, -line[index].Y);

                    text = text.Remove(0, cIndex);
                    break;
                }
            }    
        }
        else
        {
            break;
        }

        g.DrawLine(pen, line[index].X, line[index].Y, line[index + 1].X, line[index + 1].Y);
    }
}

private static float GetDistance(PointF p1, PointF p2)
{
    return (float) Math.Sqrt(Math.Pow(p2.X - p1.X, 2) + Math.Pow(p2.Y - p1.Y, 2));
}

private static float GetAngle(PointF p1, PointF p2)
{
    float c = (float) Math.Sqrt(Math.Pow(p2.X - p1.X, 2) + Math.Pow(p2.Y - p1.Y, 2));

    if (c == 0)
        return 0;

    if (p1.X > p2.X)
        return (float) (Math.Asin((p1.Y - p2.Y)/c)*180/Math.PI - 180);

    return (float) (Math.Asin((p2.Y - p1.Y)/c)*180/Math.PI);
}

今、私は私の問題を終わらせるためにただ一つのことを必要としています。文字列が重ならないようにします。何か案は?ああ、パスに文字列を描画できない場合(ブレークが多すぎるため、線の上(中央上部)に描画する必要があります。

不要なオーバーラップの例を次に示します。

ここに画像の説明を入力してください

4

1 に答える 1

1

破線に沿ってテキストを描画する方法の簡単な例を次に示します。

    private static void DrawBrokenLine(PointF[] line, string text, Graphics g, Font font)
    {
        for (int index = 0; index < line.Length - 1; index++)
        {
            float distance = distanceBetween(line[index], line[index + 1]);

            if (text.Length > 0)
            {
                for (int cIndex = text.Length; cIndex >= 0; cIndex--)
                {
                    SizeF textSize = g.MeasureString(text.Substring(0, cIndex).Trim(), font);
                    if (textSize.Width <= distance)
                    {
                        float rotation = angleBetween(line[index], line[index + 1]);

                        g.TranslateTransform(line[index].X, line[index].Y);
                        g.RotateTransform(rotation);

                        g.DrawString(text.Substring(0, cIndex).Trim(), font, new SolidBrush(Color.Black),
                            new PointF(0, -textSize.Height));

                        g.RotateTransform(-rotation);
                        g.TranslateTransform(-line[index].X, -line[index].Y);

                        text = text.Remove(0, cIndex);
                        break;
                    }
                }
            }
            else
                break;
        }
    }

単語間のスペースでのみ改行したい場合は、測定時に文字列を短くする方法を変更する必要があります。

編集

コーナーでのテキストの重なりを修正するために、計算を追加しました。

    private static void DrawBrokenLine(PointF[] line, string text, Graphics g, Font font)
    {
        float lastOverlap = 0;

        for (int index = 0; index < line.Length - 1; index++)
        {
            float distance = distanceBetween(line[index], line[index + 1]);

            float angleOfLines = 180;
            if (index < line.Length - 2)
            {
                angleOfLines = angleBetweenLines(line[index], line[index + 1], line[index + 2]);
            }

            if (text.Length > 0)
            {
                SizeF textSize = g.MeasureString(text, font);
                float overlap = 0;
                if (angleOfLines < 180)
                {
                    if (angleOfLines <= 90)
                    {
                        overlap = (textSize.Height / 1.5f) / (
                            Convert.ToSingle(Math.Tan((angleOfLines / 2) * Math.PI / 180))
                            );
                    }
                    else
                    {
                        overlap = Convert.ToSingle(
                            Math.Sin(angleOfLines * Math.PI / 180) * (textSize.Height / 1.5f));
                    }
                }

                for (int cIndex = text.Length; cIndex >= 0; cIndex--)
                {
                    textSize = g.MeasureString(text.Substring(0, cIndex).Trim(), font);

                    if (textSize.Width <= distance - overlap - lastOverlap)   //notice the subtraction of overlap
                    {
                        float rotation = angleBetween(line[index], line[index + 1]);

                        g.TranslateTransform(line[index].X, line[index].Y);
                        g.RotateTransform(rotation);

                        g.DrawString(text.Substring(0, cIndex).Trim(), font, new SolidBrush(Color.Black),
                            new PointF(lastOverlap, -textSize.Height));

                        g.RotateTransform(-rotation);
                        g.TranslateTransform(-line[index].X, -line[index].Y);

                        text = text.Remove(0, cIndex);
                        break;
                    }
                }

                lastOverlap = overlap;
            }
            else
                break;
        }
    }

    private static float angleBetweenLines(PointF A, PointF B, PointF C)
    {
        float angle1 = 360 - angleBetween(A, B);
        float angle2 = 360 - angleBetween(B, C);

        if (angle1 < 0)
            angle1 += 360;
        if (angle2 < 0)
            angle2 += 360;

        float delta = 180 + angle1 - angle2;

        if (delta < 0)
            delta += 360;
        if (delta > 360)
            delta -= 360;

        return delta;
    }

ここに画像の説明を入力

私の例には注意点があります。お気付きのように、テキストの高さを特別な数値で割っています。テキストの正確な高さを返さないことに問題があったMeasureStringため、これを手動で修正しようとしました。

線の上に文字列を描画する場合 (切れ目が多すぎるため) は、その状況をどのように検出するかによって異なります (何が多すぎるのか、テキストをどこに配置する必要があるのか​​、角度を付けるべきかなど)。おそらく、この状況の例の画像を提供できれば、明確にするのに役立つでしょう。

于 2012-11-01T19:52:04.077 に答える