2

ダイアグラム エディターをコーディングし、二次ベジエ セグメントから完全に機能するいくつかの曲線リンクを描画します (図を参照)。

BezierLink

「スパイク」曲線リンクを描画するための最良の方法 (および可能であれば) を検索します。おおよそこのように(青で):

スパイクライン

どこから始めればいいのかわかりません。drawingbrush や「湾曲したテキストを描く方法」に関する記事をいくつか読みましたが、必要なものではないようです...

あなたの助けやアドバイスをありがとう! :)

いくつかの発言を完了するために、ベジエは 3 ポイントから quadrametricBezier クラスで作成されます。皆さんのお陰で !

4

3 に答える 3

5

それを行うための組み込みの方法が WPF にあるとは思いません。自分で座標を計算し、自分で線を引く必要があります (例: DrawingVisual を使用)。

座標を計算するには、次のことを行う必要があります。

ステップ 1 ベジエ曲線に沿ってポイントをサンプリングします。

4 つの制御点を持つベジェ曲線の式は次のとおりです。

curve(t) = t^3 p1 + 3 t^2 (1-t) p2 + 3 t (1-t)^2 p3 + (1-t)^3 p4

d/dt curve(t) = 3 p3 - 3 p4 + 6 p2 t - 12 p3 t + 6 p4 t + 3 p1 t^2 - 9 p2 t^2 + 9 p3 t^2 - 3 p4 t^2

これらの式を使用して、曲線上の点とその接線方向を計算できます。接線方向を 90° 回転させる (つまり、X/Y を入れ替えて Y の符号を変更する) と、法線方向になります。

ただし、これらの点は等距離ではありません。

ここに画像の説明を入力

したがって、これらの点を直接使用すると、一部の「スパイク」が他のものよりも短い曲線が得られます。

ここに画像の説明を入力

ステップ 2: 曲線に沿って等距離のポイントを取得する

これで、曲線に沿った点のリストができました。各点と次の点の間のユークリッド距離を計算できます。これらの距離をすべて合計すると、曲線の全長が得られます。

(およそ) 10 ピクセル幅のスパイクが必要だとしましょう。n=round(TotalLength / 10)それからポイントが必要です。ポイントは にありs(i) = TotalLength / n * iます。

tしたがって、たとえば3 番目の等距離点のの値を見つけたい場合は、 を計算しs(3) = TotalLength / n * 3ます。次に、曲線に沿った合計距離が s(3) を超えるポイントに到達するまで、サンプリングされたポイントのセットを繰り返し、移動しながら距離を合計します。これで、探しているポイントの直前と直後のポイントがわかったので、3 の法則を使用してその間の t を計算できます。

これで、曲線に沿って同じ距離だけ離れた点のセットができました。

ここに画像の説明を入力

ステップ 3: スパイクを描く

これは最も簡単な部分です: 等距離の各ポイントで、法線を計算します (上記の微分式を使用)。その法線をその長さで割り、法線の単位を取得します。次に、各偶数ポイント+d * UnitNormalと各奇数ポイント-d * UnitNormalに を追加します。ここdで、 はスパイクの「深さ」、つまり先端から曲線までの距離です。

ここに画像の説明を入力

于 2012-08-20T08:35:05.060 に答える
1

QuadraticBezierSegmentWPFソリューションに関心がある人のために、私は最終的にとPathGeometryクラスに基づいてこれをコーディングします(あまり最適化されていません) 。

皆様、本当にありがとうございました。:)

public partial class MainWindow : Window
{
    int orientation = 1;
    int compt = 0;
    int SpikeWidth = 5;
    int SpikeHeigth = 3;

    public MainWindow()
    {

        InitializeComponent();

        Polyline wave = new Polyline();
        wave.Stroke = Brushes.Blue;
        wave.StrokeThickness = 2;

        PathGeometry pg = BezierPath.Data.GetFlattenedPathGeometry();
        double CurveLenght = GetLength(pg, PathFigure.StartPoint);
        double NbrPoint = (Math.Round(CurveLenght / SpikeWidth));
        for (int i = 0; i <= NbrPoint; i++)
        {
            //Calcul de T
            double t = SpikeWidth * i / CurveLenght;

            Point TangentPoint;
            Point PointToDraw;
            pg.GetPointAtFractionLength(t, out PointToDraw, out TangentPoint);


            // Calcul de l'angle
            double a = Math.Atan2(TangentPoint.Y, TangentPoint.X);
            a += Math.PI / 2;

            //Alterner un point sur deux de chaque coté de la courbe
            if (compt % 2 == 0)
                orientation = 1;
            else
                orientation = -1;

            //Calcul du point et ajout à la polyligne.
            //Point calculation and added to the polyline.
            wave.Points.Add(new Point(Math.Cos(a) * SpikeHeigth * orientation + PointToDraw.X, Math.Sin(a) * SpikeHeigth * orientation + PointToDraw.Y));


            //Compte le nombre de passage pour l'orientation
            compt += 1;
        }
        //Traçage sur la canvas
        cv.Children.Add(wave);
    }           

    private double GetLength(PathGeometry pg, Point startPoint)
    {
        PolyLineSegment pls = pg.Figures[0].Segments[0] as PolyLineSegment;

        double distance = 0;
        foreach (Point pt in pls.Points)
        {
            distance += Math.Sqrt((startPoint.X - pt.X).Pow(2) + (startPoint.Y - pt.Y).Pow(2));
            startPoint = pt;
        }
        return distance;
    }
}
<Canvas x:Name="cv">
    <Path Stroke="Black" x:Name="BezierPath">
        <Path.Data>
            <PathGeometry>
                <PathGeometry.Figures>
                    <PathFigureCollection>
                        <PathFigure x:Name="PathFigure" StartPoint="10,400">
                        <PathFigure.Segments>
                            <PathSegmentCollection>
                                <QuadraticBezierSegment x:Name="BezierSegment" Point1="50,80" Point2="400,400">
                                </QuadraticBezierSegment>
                            </PathSegmentCollection>
                        </PathFigure.Segments>
                    </PathFigure>
                    </PathFigureCollection>
                </PathGeometry.Figures>
            </PathGeometry>                    
        </Path.Data>
    </Path>               
</Canvas>
于 2012-08-25T17:49:59.583 に答える
1

既にベジェ曲線を計算していると仮定すると、目的の曲線は、ベジェ曲線とベジェ曲線に法線ベクトルを掛けた三角波の和です。tベジエ曲線はパラメータが [0, 1]のパラメトリック曲線であることを考慮する必要があります。次に、ベジエ曲線の長さ関数が必要でありL(t)、それを の代わりに三角波方程式にプラグインしtます。

三角波もモジュロ演算で表現可能

TW(t) = M * abs(mod(q * L(t), n * 2 - 2) - n + 1) + 1

どこ

M- 波の大きさ、

q- パスに沿った倍率

n- 曲線の期間、

t- ベジエ曲線のパラメータ、

L(t)- ベジエ曲線の長さ関数。

結果の曲線:

C(t) = TW(t) * B_normal(t) + B(t)

ここB_normal(t)で、 は点 におけるベジエ曲線の法線ベクトルtです。

于 2012-08-20T07:12:43.070 に答える