Announcement

Collapse
No announcement yet.

Draw Smooth Curve from Series of Points - Discussion

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Draw Smooth Curve from Series of Points - Discussion

    This thread is to discuss the code I just posted, showing how to create a smooth curve by connecting points using a series of Bezier curves. It was posted in the Source Code forum, here.

    In the code, you just click to create points. Once 4 points are generated, the smooth curve is built. Additional clicks generate additional segments to the curve.




    As with the other Bezier code I posted, credit goes to Rod Stephens, whose code was the basis for the code I've posted.

    Comments and questions are welcome!
    Last edited by Gary Beene; 11 Oct 2013, 08:05 PM.

  • #2
    Hey Frank!
    Nice work! Was your original code points, to which you applied the Bezier curve code?

    Comment


    • #3
      Frank,
      So, your idea of generating/moving points (gravity manipulated in your example) is very straight forward. Based on that idea, I wrote the code below, where I have just 20 points which are randomly moved around - connecting all the points (plus first to last) with the Bezier cure code I posted earlier and that you used in your demo.

      I like what you did. My own example (picture below) was pretty weak, but it shows how easily you can plop in an algorithm of your choice - just drop in a single function (MovePoints - which both initializes and moves points) and you can get an entirely new look!

      Very cool. Thanks for sharing the idea.

      In this compilable example, I used the updated/simplified DrawBezier function that I posted with in the Source forum.



      Code:
      'Compilable Example:
      #Compiler PBWin 10
      #Compile Exe
      #Dim All
      %Unicode = 1
      #Include "Win32API.inc"
      
      %IDC_Graphic = 500
      %ID_Timer    = 501
      
      Global hDlg As Dword, P() As Point, pCount As Long
      
      Function PBMain() As Long
         Dialog New Pixels, 0, "Smooth Curve from Series of Points",300,300,400,400, %WS_OverlappedWindow To hDlg
         Control Add Graphic, hDlg, %IDC_Graphic, "", 0, 0, 400,400, %SS_Notify
         Graphic Attach hDlg, %IDC_Graphic, ReDraw
         Dialog Show Modal hDlg Call DlgProc
      End Function
      
      CallBack Function DlgProc() As Long
         Select Case Cb.Msg
            Case %WM_InitDialog
               Randomize Timer
               MovePoints(1)     'initialize points
               SetTimer hDlg, %ID_Timer, 20, 0
            Case %WM_Command
               Select Case Cb.Ctl
                  Case %IDC_Graphic
                     KillTimer hDlg, %ID_Timer
                     MovePoints(1)  'initialize points
                     SetTimer hDlg, %ID_Timer, 20, 0
               End Select
            Case %WM_Timer
               MovePoints(0)     'non-zero means change all point locations
               DrawCurves 0.01, 0.5
         End Select
      End Function
      
      Sub MovePoints(Initialize As  Long)
         Local i As Long
         If Initialize Then
            'initialize points
            pCount = 20 : ReDim P(19)
            For i = 0 To 18 : P(i).x = Rnd(100,300) : P(i).y = Rnd(100,300) : Next i : P(19) = P(0)
         Else
            'move points
            For i = 0 To 18
               P(i).x += Rnd(-1,1) : P(i).y += Rnd(-1,1)
            Next i
            P(19) = P(0)
         End If
      End Sub
      
      Sub DrawBezier(ByVal dt As Single, pt0 As Point, pt1 As Point, pt2 As Point, pt3 As Point)
          Local t,x0,y0,x1,y1 As Single
          t = 0
          x1 = pt0.x * (1 - t) ^ 3  + pt1.x * 3 * t * (1 - t) ^ 2 + pt2.x * 3 * t ^ 2 * (1 - t) + pt3.x * t ^ 3
          y1 = pt0.y * (1 - t) ^ 3  + pt1.y * 3 * t * (1 - t) ^ 2 + pt2.y * 3 * t ^ 2 * (1 - t) + pt3.y * t ^ 3
          t = t + dt
          Do While t < 1
              x0 = x1 : y0 = y1
              x1 = pt0.x * (1 - t) ^ 3  + pt1.x * 3 * t * (1 - t) ^ 2 + pt2.x * 3 * t ^ 2 * (1 - t) + pt3.x * t ^ 3
              y1 = pt0.y * (1 - t) ^ 3  + pt1.y * 3 * t * (1 - t) ^ 2 + pt2.y * 3 * t ^ 2 * (1 - t) + pt3.y * t ^ 3
              Graphic Line  (x0, y0)-(x1, y1), %Blue
              t = t + dt
          Loop
          ' Connect to the final point.
          t = 1
          x0 = x1 : y0 = y1 : x1 = pt3.x : y1 = pt3.y
          Graphic Line (x0, y0)-(x1, y1), %Blue
      End Sub
      
      Sub DrawCurves(ByVal dt As Single, ByVal tension As Single)
         Local control_scale As Single, i As Integer
         Local pt,pt_before, pt_after, pt_after2, Di, DiPlus1, p1, p2, p3, p4 As Point
      
         Graphic Clear
          control_scale = CSng(tension / 0.5 * 0.175)
          For i = 0 To UBound(P) - 1
              pt_before = P(Max(i - 1, 0))
              pt = P(i)
              pt_after = P(i + 1)
              pt_after2 = P(Min(i + 2, UBound(P)))
      
              p1 = P(i)
              p4 = P(i + 1)
      
              Di.X = pt_after.X - pt_before.X
              Di.Y = pt_after.Y - pt_before.Y
              p2.X = pt.X + control_scale * Di.X
              p2.Y = pt.Y + control_scale * Di.Y
      
              DiPlus1.X = pt_after2.X - P(i).X
              DiPlus1.Y = pt_after2.Y - P(i).Y
              p3.X = pt_after.X - control_scale * DiPlus1.X
              p3.Y = pt_after.Y - control_scale * DiPlus1.Y
      
              DrawBezier dt, p1, p2, p3, p4
          Next i
          Graphic ReDraw
      End Sub
      Last edited by Gary Beene; 14 Oct 2013, 10:47 PM.

      Comment


      • #4
        See posts #2 and #3 in this thread:
        Forum: http://www.jose.it-berater.org/smfforum/index.php

        Comment


        • #5
          Jose!
          Thanks for pointing out the GDIP Bezier posts.

          One of the things I'm enjoying is looking at the different options on how to get a graphics results. I especially like it when I've done something the long way, and find out that there's a much more minimal way to do the same thing - as your GDIP code appears to be!

          I knew that GDIP had some Bezier and line-smoothing capabilities. But I just hadn't gotten around to looking more closely. But now that you've pointed them out, I'll be giving it a try - in the morning 'cause it's just about midnight here and I'm about to crash for the evening!

          Thanks again!

          Comment


          • #6
            I was playing around again (years later) with the Bezier code and compared the results to Jose's suggested GDI+ approach. I'm generally interested in the best looking results, with anti-aliasing if possible.



            The blue is the manual code and the green is the GDI+ code.

            At line width = 1 the manual code gives a much less "smooth" result as compared to the GDI+. At wider lines, it looks some better, as in this image ...



            Unfortunately the anti-aliasing code I published recently doesn't support wide lines and I'm not sure how to do it myself. I'll go looking for something existing that I can convert. If anyone has it already, please speak up.

            I also need to add antialiasing to the example Jose posted, to see how well GDI handles it.

            Comment

            Working...
            X