DOBON.NETプログラミング道掲示板

ツリー一括表示

Nomalアイコン DrawBezierの使い方について /つばさ (20/07/31(Fri) 17:38) #34510 2020-07-31.jpg/17KB
Nomalアイコン Re[1]: DrawBezierの使い方について /魔界の仮面弁士 (20/08/01(Sat) 04:08) #34513 DrawBezier.gif/18KB
  └Nomalアイコン Re[2]: DrawBezierの使い方について /つばさ (20/08/01(Sat) 09:42) #34514 解決み!
    └Nomalアイコン Re[3]: DrawBezierの使い方について /魔界の仮面弁士 (20/08/02(Sun) 16:55) #34515
      └Nomalアイコン Re[4]: DrawBezierの使い方について /つばさ (20/08/03(Mon) 08:14) #34516 2020-07-30.png/7KB
        └Nomalアイコン Re[5]: DrawBezierの使い方について /魔界の仮面弁士 (20/08/03(Mon) 15:00) #34518
          └Nomalアイコン Re[6]: DrawBezierの使い方について /つばさ (20/08/04(Tue) 07:49) #34519 解決み!
            └Nomalアイコン Re[7]: DrawBezierの使い方について /つばさ (20/08/04(Tue) 08:10) #34520 解決み! 2020-08-04.jpg/16KB


親記事 / ▼[ 34513 ]
■34510 / 親階層)  DrawBezierの使い方について
□投稿者/ つばさ 一般人(1回)-(2020/07/31(Fri) 17:38:42)
  • アイコン環境/言語:[Win10 VB2017] 
    分類:[.NET] 

     はじめまして、よろしくお願いします。
    Win10でVB2017を使用しています。

    現在、ベジェ曲線をPivtureBox表示に挑戦しています。

    Dim Bezier_1 As New Point(66, 663)
    Dim Bezier_2 As New Point(96, 784)
    Dim Bezier_3 As New Point(96, 784)
    Dim Bezier_4 As New Point(236, 731)

    g.DrawBezier(Pen_Red, Bezier_1, Bezier_2, Bezier_3, Bezier_4)

    と、記述した時の描画が、添付画像になります。
    赤色ラインがVB出力ですが、実際のイラストレーターのライン(黒色ライン)と
    かなり違った結果になります。

    始点終点、制御点が2点の時は問題ないのですが
    制御点が1点の時の3点ベジェ曲線の時にこうなります。

    3点ベジェ曲線の記述方法のアドバイスを頂けたら嬉しいのですが
    よろしくお願いします。(うまく説明できてないと思いますが、すみません。)

191×140
イメージ
2020-07-31.jpg
/17KB
違反を報告
[ □ Tree ] 返信 削除キー/

▲[ 34510 ] / ▼[ 34514 ]
■34513 / 1階層)  Re[1]: DrawBezierの使い方について
□投稿者/ 魔界の仮面弁士 大御所(1289回)-(2020/08/01(Sat) 04:08:58)
  • アイコン
    No34510に返信(つばささんの記事)
    > と、記述した時の描画が、添付画像になります。
    
    座標指定と画像の内容が一致していないように見えます。
    もしかして、左上原点の左手系座標ではなく、右手系座標に変換しているのでしょうか。
    
    g.TranslateTransform(0, PictureBox1.Height - 1)
    g.ScaleTransform(1, -1)
    
    
    
    > 始点終点、制御点が2点の時は問題ないのですが
    > 制御点が1点の時の3点ベジェ曲線の時にこうなります。
    
    赤い方は、Graphics.DrawBezier メソッドで描かれた 3 次ベジエ曲線で
    黒い方は、始点・オフカーブ点・終点からなる 2 次のベジエ曲線に見えます。
    
    
    
    > Dim Bezier_2 As New Point(96, 784)
    > Dim Bezier_3 As New Point(96, 784)
    
    同じ座標を指定したところで、2 次にはならないですね。
    
    
    ベジエの軌跡を確認するためのサンプルを作ってみました。
    
    
    Imports System.Drawing.Drawing2D
    
    Public Class Form1
    
        Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Button1.Enabled = False
            Drawing = True
            Using bc = BufferedGraphicsManager.Current
                Dim bg = bc.Allocate(PictureBox1.CreateGraphics(), PictureBox1.ClientRectangle)
                bg.Graphics.SmoothingMode = SmoothingMode.HighQuality
                bg.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic
    
                Dim points() = {New PointF(12.0F, 155.0F), New PointF(42.0F, 28.0F), New PointF(190.0F, 81.0F)}
    
                Dim bezierPoints2(100) As PointF
                Dim bezierPoints3(100) As PointF
                For t = 0 To 100
                    bg.Graphics.Clear(Color.White)
    
                    '指定のノットを灰色線で描く
                    bg.Graphics.DrawLines(Pens.Silver, points)
                    For Each p In points
                        bg.Graphics.DrawEllipse(Pens.Silver, GetSquare(p, 6.0F))
                    Next
    
                    '★ Graphics.DrawBezier は、赤い破線で描いておく
                    Using bezierPen As New Pen(Color.Red, 2.0F) With {.DashStyle = DashStyle.Dash}
                        '制御点が一つ足りないので、points(1) を 2 回指定している
                        bg.Graphics.DrawBezier(bezierPen, points(0), points(1), points(1), points(2))
                    End Using
    
    
                    '移動点のパーセンテージを表示する
                    bg.Graphics.DrawString($"t = {t / 100:0.00}", Font, Brushes.Black, PointF.Empty)
    
    
                    '★ 2次の軌跡を水色で描く
                    Dim m2_0 = GetMovePoint(points(0), points(1), t)
                    Dim m2_1 = GetMovePoint(points(1), points(2), t)
                    bg.Graphics.FillEllipse(Brushes.DarkSlateGray, GetSquare(m2_0, 6.0F))
                    bg.Graphics.FillEllipse(Brushes.DarkSlateGray, GetSquare(m2_1, 6.0F))
    
                    bezierPoints2(t) = GetMovePoint(m2_0, m2_1, t)
                    Using bezierBrush As New SolidBrush(Color.FromArgb(100, Color.Cyan))
                        For Each b In bezierPoints2.Take(t + 1)
                            bg.Graphics.FillEllipse(bezierBrush, GetSquare(b, 6.0F))
                        Next
                        bg.Graphics.DrawLine(Pens.Blue, m2_0, m2_1)
                        bg.Graphics.DrawEllipse(Pens.Blue, GetSquare(bezierPoints2(t), 6.0F))
                    End Using
    
    
                    '★ 3次の軌跡を黄色で描く
                    Dim p2_0 = GetMovePoint(points(0), points(1), t)
                    Dim p2_1 = GetMovePoint(points(1), points(1), t)    '同じ座標なので計算するまでもないけれど一応
                    Dim p2_2 = GetMovePoint(points(1), points(2), t)
    
                    Dim m3_0 = GetMovePoint(p2_0, p2_1, t)
                    Dim m3_1 = GetMovePoint(p2_1, p2_2, t)
                    bg.Graphics.FillEllipse(Brushes.Green, GetSquare(m3_0, 6.0F))
                    bg.Graphics.FillEllipse(Brushes.Green, GetSquare(m3_1, 6.0F))
                    bg.Graphics.DrawLine(Pens.Green, m3_0, m3_1)
    
                    bezierPoints3(t) = GetMovePoint(m3_0, m3_1, t)
                    Using bezierBrush As New SolidBrush(Color.FromArgb(100, Color.Yellow))
                        For Each b In bezierPoints3.Take(t + 1)
                            bg.Graphics.FillEllipse(bezierBrush, GetSquare(b, 6.0F))
                        Next
                    End Using
                    bg.Graphics.DrawEllipse(Pens.Green, GetSquare(bezierPoints3(t), 6.0F))
    
                    If ClosingRequired Then
                        Drawing = False
                        Close()
                        Return
                    End If
    
                    bg.Render()
                    Await Task.Delay(60)
                Next
    
            End Using
            Button1.Enabled = True
            Drawing = False
        End Sub
    
        Private Function GetMovePoint(p0 As PointF, p1 As PointF, percent As Byte) As PointF
            Return New PointF((p1.X - p0.X) * percent / 100.0F + p0.X, (p1.Y - p0.Y) * percent / 100.0F + p0.Y)
        End Function
    
        Private Function GetSquare(center As PointF, length As Single) As RectangleF
            Dim topLeft = center - New SizeF(length / 2.0F, length / 2.0F)
            Return New RectangleF(topLeft, New SizeF(length, length))
        End Function
    
        Private Drawing As Boolean = False
        Private ClosingRequired As Boolean = False
        Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
            If Drawing Then
                ClosingRequired = True
                e.Cancel = True
            End If
        End Sub
    End Class

225×229
イメージ
DrawBezier.gif
/18KB
違反を報告
[ 親 34510 / □ Tree ] 返信 削除キー/

▲[ 34513 ] / ▼[ 34515 ]
■34514 / 2階層)  Re[2]: DrawBezierの使い方について
□投稿者/ つばさ 一般人(2回)-(2020/08/01(Sat) 09:42:37)
  • アイコン魔界の仮面弁士さま、ありがとうございます。

    ご指摘通りY軸を反転しております。
    説明不足で申し訳ありません。

    また、ご回答のコードをVBに張り付けて実行してみました。
    能力不足のため細かく理解することはできませんが
    3点ベジェの曲線を表示するのは、座標計算をしなければ
    思ったような曲線は、得られないようですね。

    AIデータの表示プルグラムを進めていく場合
    「3点ベジェ曲線」の箇所が出てきた場合、教えていただいたコードを
    引用しながら完成を目指してまいります。

    この度は、ありがとうございました。
    初めてのVB投稿だったので助かりました。
    また、質問が発生した時には、よろしくお願いします。

解決み!
違反を報告
[ 親 34510 / □ Tree ] 返信 削除キー/

▲[ 34514 ] / ▼[ 34516 ]
■34515 / 3階層)  Re[3]: DrawBezierの使い方について
□投稿者/ 魔界の仮面弁士 大御所(1290回)-(2020/08/02(Sun) 16:55:03)
  • アイコン
    No34514に返信(つばささんの記事)
    > 3点ベジェの曲線を表示するのは、座標計算をしなければ
    > 思ったような曲線は、得られないようですね。
    
    …あれ?
    
    質問内容は「DrawBezier メソッドの使い方について」であって、
    黒色ラインを描く方法についてでは無いと思ったのですが。
    
    
    曲線の細かい話については、この辺りに書かれていますが、それはさておき。
    http://www.f.waseda.jp/moriya/PUBLIC_HTML/education/classes/infomath6/applet/fractal/spline/
    
    2 次ベジエを 3 次ベジエに変換したいのであれば、2次における
    「始点〜制御点までの 2/3 の位置」と
    「終点〜制御点までの 2/3 の位置」を
    3 次の第一制御点・第二制御点として指定してみてください。
    
    
    > 実際のイラストレーターのライン(黒色ライン)と
    イラストレーター(Illustrator?)を見たことが無いので
    黒色ラインが 2 次ベジエであるという、
    当方の予想が正しいのかは分かりません。
    そちらの仕様確認はご自身で行ってください。
    
    
    
    Module GraphicsExtension
      <System.Runtime.CompilerServices.Extension>
      Public Sub DrawQuadCurve(this As Graphics, pen As Pen, pt1 As PointF, pt2 As PointF, pt3 As PointF)
        Dim p1 As New PointF((pt1.X + 2.0F * pt2.X) / 3.0F, (pt1.Y + 2.0F * pt2.Y) / 3.0F)
        Dim p2 As New PointF((2.0F * pt2.X + pt3.X) / 3.0F, (2.0F * pt2.Y + pt3.Y) / 3.0F)
        this.DrawBezier(pen, pt1, p1, p2, pt3)
      End Sub
    End Module
    
    
    とりあえず上記を貼り付けたうえで、先の
     .DrawBezier(bezierPen, points(0), points(1), points(1), points(2))
    の結果を
     .DrawQuadCurve(bezierPen, points(0), points(1), points(2))
    と比較してみてください。

違反を報告
[ 親 34510 / □ Tree ] 返信 削除キー/

▲[ 34515 ] / ▼[ 34518 ]
■34516 / 4階層)  Re[4]: DrawBezierの使い方について
□投稿者/ つばさ 一般人(3回)-(2020/08/03(Mon) 08:14:24)
  • アイコン説明不足にも関わらづ、追加の解説ありがとうございます。
    最初の投稿画像ですが、説明を加えたものを添付致します。
    DrawBezierの3点での使い方を検索したのですが
    4点での使い方しか無いように思い試してみると違う形の結果でした。

    そこで制御点を作ることを考えたのですが、参考ページがなかったので
    数値を変化させながら結果を重ねて表示することを繰り返しました。
    元の制御点から60%の位置が丁度イラストレーターの画像と
    一致するような結果になりました。

    いくつかテストAIデータを作って、試したのですが問題なさそうです。
     しかし「ベジェ曲線」の描画方法が、誤差を考えると
    こんなやり方のはずがないと思い質問をしました。

    たとえば
      DrawBezier(Color、始点、制御点1、制御点2、終点、描画形式)
        の、ような記述で
    描画形式(ラインの種類)を指定した場合にその指定で描画してくれるのでは?
    この答えは分かりませんでしたので、今回こちらで質問させていただきました。

    2度に渡ってわかりやすい解説、ありがとうございます。

225×206
イメージ
2020-07-30.png
/7KB
違反を報告
[ 親 34510 / □ Tree ] 返信 削除キー/

▲[ 34516 ] / ▼[ 34519 ]
■34518 / 5階層)  Re[5]: DrawBezierの使い方について
□投稿者/ 魔界の仮面弁士 大御所(1292回)-(2020/08/03(Mon) 15:00:00)
  • アイコンNo34516に返信(つばささんの記事)
    > DrawBezierの3点での使い方を検索したのですが
    > 4点での使い方しか無いように思い試してみると違う形の結果でした。

    ベジエ曲線の考え方は、下記のアニメーションを見ると分かりやすいかと思います。
    https://postd.cc/bezier-curves/


    なお、.NET Framework のヘルプで DrawBezier について調べてみると、
    ベジェではなくベジエと表記されているわけですが、Be'zier の発音は
    ベジェよりはベジエの方が原音に近いようです。(ベズィエといった感じ?)



    > 元の制御点から60%の位置が丁度イラストレーターの画像と
    > 一致するような結果になりました。

    2 次 → 3 次変換を、数学的証明した記事がありました。
    60% ではなく、2/3 の位置ですね。
    https://nowokay.hatenablog.com/entry/20070623/1182556929


    3 次 → 2 次はもう少し複雑です。次数を落としている分、
    1 つの 2 次ベジエで表現できるとは限らないので、
    複数の 2 次ベジエ曲線を並べて近似曲線にするなどして対応します。
    http://nutsu.com/blog/2008/021520_as_bezierconvert.html
違反を報告
[ 親 34510 / □ Tree ] 返信 削除キー/

▲[ 34518 ] / ▼[ 34520 ]
■34519 / 6階層)  Re[6]: DrawBezierの使い方について
□投稿者/ つばさ 一般人(4回)-(2020/08/04(Tue) 07:49:18)
  • アイコン お世話になります。
    新たな情報、ありがとうございます。

    制御点の値を3つほど作ってラインを書いてみました。
    その後、AIのラインとVBのラインを重ねての画像です。

    制御点60%でほぼ一致することから、数式から導かれるBezier曲線と
    A社、M社の3点Bezier曲線は独自のものと思われます。

    3点Bezier曲線に関しては、ユーザーが必要な係数を
    探し出しセットする仕様なのかもしれませんね?

    この問題は、最初あまり気にならなかったのですが
    これから先に進めていく過程で、座標計算にて曲線の通過ポイントを
    割り出さなければいけない場面が出てくるのですが
    今の時点で、遭遇できたことは幸いです。

    幾度もの解説、並びにアドバイスいただき感謝しています。
    ありがとうございました。

解決み!
違反を報告
[ 親 34510 / □ Tree ] 返信 削除キー/

▲[ 34519 ] / 返信無し
■34520 / 7階層)  Re[7]: DrawBezierの使い方について
□投稿者/ つばさ 一般人(5回)-(2020/08/04(Tue) 08:10:50)
  • アイコン画像が大きくて、添付できていませんね?
    もう一度、投稿です。
解決み!
158×112
イメージ
2020-08-04.jpg
/16KB
違反を報告
[ 親 34510 / □ Tree ] 返信 削除キー/


Mode/  Pass/


- Child Tree -