Graphic: Cubic bezier through four (or multiple) points (solved)

Just starting out? Need help? Post your questions and find answers here.
acreis
Enthusiast
Enthusiast
Posts: 232
Joined: Fri Jun 01, 2012 12:20 am

Graphic: Cubic bezier through four (or multiple) points (solved)

Post by acreis »

Hi everyone,
I’m looking for a previously published PureBasic code (or example) that displays a graph with multiple points, where:
• A smooth curve passes through the points
• The points can be dragged interactively with the mouse
• The curve updates dynamically as the points move
Has anyone seen something like this shared before? I’d really appreciate a link or any hints on where to find it. Thanks in advance!

Solved:

Code: Select all

;
; https://www.purebasic.fr/english/viewtopic.php?p=646693#p646693
; https://apoorvaj.io/cubic-bezier-through-four-points
; function vec2_dist(a, b) {
;     return Math.sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
; }
; 
; function refit_bezier(
;     passthru_0, passthru_1, passthru_2, passthru_3,
;     out_tangent_1, out_tangent_2
; ) {
;     let d1 = Math.pow(vec2_dist(passthru_1, passthru_0), alpha);
;     let d2 = Math.pow(vec2_dist(passthru_2, passthru_1), alpha);
;     let d3 = Math.pow(vec2_dist(passthru_3, passthru_2), alpha);
;     // Modify tangent 1
;     {
;         let a = d1 * d1;
;         let b = d2 * d2;
;         let c = (2 * d1 * d1) + (3 * d1 * d2) + (d2 * d2);
;         let d = 3 * d1 * (d1 + d2);
;         out_tangent_1.x = (a * passthru_2.x - b * passthru_0.x + c * passthru_1.x) / d;
;         out_tangent_1.y = (a * passthru_2.y - b * passthru_0.y + c * passthru_1.y) / d;
;     }
;     // Modify tangent 2
;     {
;         let a = d3 * d3;
;         let b = d2 * d2;
;         let c = (2 * d3 * d3) + (3 * d3 * d2) + (d2 * d2);
;         let d = 3 * d3 * (d3 + d2);
;         out_tangent_2.x = (a * passthru_1.x - b * passthru_3.x + c * passthru_2.x) / d;
;         out_tangent_2.y = (a * passthru_1.y - b * passthru_3.y + c * passthru_2.y) / d;
;     }
; 
; }

EnableExplicit


; -Structures
Structure POINTF
  x.f
  y.f
EndStructure


Structure TREFITTEDBEZIER  
  *window
  *canvas
  *text
  width.i
  height.i
  alpha.f
  Array p.POINTF(11)
  ptMouseMovePoint.POINT
  ptMouseDownPoint.POINT
  ptInitPosPoint.POINTF 
  hotpoint.i
  smalldistance.f
  LButtonDown.i
EndStructure

;- Globals
Global *app.TREFITTEDBEZIER = AllocateStructure(TREFITTEDBEZIER)




;- Macros

Macro CanvasMouseX(_canvas_)
  
  GetGadgetAttribute(_canvas_, #PB_Canvas_MouseX) 
  
EndMacro


Macro CanvasMouseY(_canvas_)
  
  GetGadgetAttribute(_canvas_, #PB_Canvas_MouseY) 
  
EndMacro


Macro vec2_dist(_point_a_, _point_b_)
  
  Sqr(Pow(_point_a_\x - _point_b_\x, 2) + Pow(_point_a_\y - _point_b_\y, 2))
  
EndMacro   



Macro AddPathCirclePT(_point_, _size_ = 8)
  
  AddPathCircle(_point_\x, _point_\y, _size_)
  
EndMacro 




Procedure refit_bezier(*passthru_0.POINTF, *passthru_1.POINTF, *passthru_2.POINTF, *passthru_3.POINTF, alpha.f, *out_tangent_1.POINTF, *out_tangent_2.POINTF)
  Define d1.f, d2.f, d3.f
  Define a.f, b.f, c.f, d.f
  
  d1 = Pow(vec2_dist(*passthru_1, *passthru_0), alpha)
  d2 = Pow(vec2_dist(*passthru_2, *passthru_1), alpha)
  d3 = Pow(vec2_dist(*passthru_3, *passthru_2), alpha)
  
  ; Modify tangent 1
  a = d1 * d1
  b = d2 * d2
  c = (2 * d1 * d1) + (3 * d1 * d2) + (d2 * d2)
  d = 3 * d1 * (d1 + d2)
  *out_tangent_1\x = (a * *passthru_2\x - b * *passthru_0\x + c * *passthru_1\x) / d
  *out_tangent_1\y = (a * *passthru_2\y - b * *passthru_0\y + c * *passthru_1\y) / d
  
  ; Modify tangent 2
  a = d3 * d3
  b = d2 * d2
  c = (2 * d3 * d3) + (3 * d3 * d2) + (d2 * d2)
  d = 3 * d3 * (d3 + d2)
  *out_tangent_2\x = (a * *passthru_1\x - b * *passthru_3\x + c * *passthru_2\x) / d
  *out_tangent_2\y = (a * *passthru_1\y - b * *passthru_3\y + c * *passthru_2\y) / d
EndProcedure






Procedure Bezier_Draw(*passthru_0.POINTF, *passthru_1.POINTF, *passthru_2.POINTF, *passthru_3.POINTF)
  
  
  Define out_tangent_1.POINTF, out_tangent_2.POINTF
  
  refit_bezier(*passthru_0, *passthru_1, *passthru_2, *passthru_3, *app\alpha, out_tangent_1, out_tangent_2)
  
  
  VectorSourceColor(RGBA(100, 255, 0, 255))
  
  ;AddPathCirclePT(out_tangent_1)
  ;AddPathCirclePT(out_tangent_2)
  
  VectorSourceColor(RGBA(255, 100, 100, 255))
  
  AddPathCirclePT(*passthru_0)
  AddPathCirclePT(*passthru_3)
  
  
  MovePathCursor(*passthru_1\x,*passthru_1\y)
  VectorSourceColor(RGBA(0, 0, 0, 255))
  AddPathCurve(out_tangent_1\x, out_tangent_1\y, out_tangent_2\x, out_tangent_2\y, *passthru_2\x, *passthru_2\y)
  StrokePath(1)
  
  
  
  ; Draw original points
  AddPathCirclePT(*passthru_1)
  AddPathCirclePT(*passthru_2)
  VectorSourceColor(RGBA(0, 0, 0, 255))
  StrokePath(1)
  
  
  ; Draw tangents
  ;     VectorSourceColor(RGBA(0, 0, 0, 255))
  ;     MovePathCursor(*passthru_1\x,*passthru_1\y)
  ;     AddPathLine(p1\x, p1\y)
  ;     MovePathCursor(passthru_2\x,*passthru_2\y)
  ;     AddPathLine(p2\x, p2\y)
  ;     StrokePath(1)
  
  
  
EndProcedure



Procedure Canvas_Draw()
  
  
  If StartVectorDrawing(CanvasVectorOutput(*app\Canvas))
    
    
    With *app
      
      Protected i 
      VectorSourceColor(RGBA(255,255,255,255))
      Protected r.rect
      GetClientRect_(GadgetID(\canvas), r)
      AddPathBox(0,0, r\right, r\bottom)
      FillPath()
      
      
      
      If \hotpoint > -1
        VectorSourceColor(RGBA(255,0,0,100))
        AddPathCirclePT(\p(\hotpoint))
        StrokePath(8)
      EndIf   
      
      
      Protected n = ArraySize(\p())-3
      For i = 0 To n
        Bezier_Draw(\p(0+i), \p(1+i), \p(2+i), \p(3+i))
      Next
      
    EndWith   
    
    
    
    StopVectorDrawing()
    
  EndIf  
  
  
EndProcedure




Procedure Canvas_GetHotPoint()
  
  With *app
    \hotpoint = -2
    Protected i, n = ArraySize(\p())
    For i = 0 To n
      If vec2_dist(\ptMouseMovePoint, \p(i)) < \smalldistance
        \hotpoint = i
        ProcedureReturn #True
      EndIf
    Next   
  EndWith
  
  ProcedureReturn #False 
  
EndProcedure  




Procedure Canvas_LeftButtonUp()
  
  With *app
    \LButtonDown = #False
  EndWith
  
  
  Canvas_Draw()
  
EndProcedure



Procedure Canvas_LeftButtonDown()
  
  With *app
    
    \LButtonDown = #True
    
    \ptMouseDownPoint\x = CanvasMouseX(\canvas)
    \ptMouseDownPoint\y = CanvasMouseY(\canvas)
    
    If Canvas_GetHotPoint()
      \ptInitPosPoint = \p(\hotpoint)
    EndIf  
    
  EndWith
  
EndProcedure



Procedure Canvas_DragPoint()
  
  With *app
    
    If \hotpoint > -1
      
      \p(\hotpoint)\x = \ptInitPosPoint\x + (\ptMouseMovePoint\x - \ptMouseDownPoint\x)
      \p(\hotpoint)\y = \ptInitPosPoint\y + (\ptMouseMovePoint\y - \ptMouseDownPoint\y)
      
    EndIf 
    
  EndWith
  
  
EndProcedure



Procedure Canvas_MouseMove()
  
  With *app
    
    \ptMouseMovePoint\x = CanvasMouseX(\canvas)
    \ptMouseMovePoint\y = CanvasMouseY(\canvas) 
    SetGadgetText(\text, "" + \ptMouseMovePoint\x + ", " + \ptMouseMovePoint\y )
    
    
    If \LButtonDown And \hotpoint > -1
      Canvas_DragPoint()
      Canvas_Draw()
      ProcedureReturn 
    EndIf 
    
    Canvas_GetHotPoint()
    
    
  EndWith
  
  Canvas_Draw()
  
  
EndProcedure




Procedure Main()
  
  
  
  With *app
    
    \width = 800
    \height = 600
    \alpha = 0.5
    \smalldistance = 8
    \hotpoint = -2
    
    \window = OpenWindow(#PB_Any, 100, 100, \width, \height, "Refitted Bezier Curve")
    \Canvas = CanvasGadget(#PB_Any, 0, 0, \width, \height, #PB_Canvas_Container)
    \Text = TextGadget(#PB_Any,0,0, \width, 16, "")
    
    BindGadgetEvent(\Canvas, @Canvas_MouseMove(), #PB_EventType_MouseMove)
    BindGadgetEvent(\Canvas, @Canvas_LeftButtonUp(), #PB_EventType_LeftButtonUp)
    BindGadgetEvent(\Canvas, @Canvas_LeftButtonDown(), #PB_EventType_LeftButtonDown)
    
    
    Protected i, n = ArraySize(\p())
    For i = 0 To n
      \p(i)\x = i*50 + 50
      \p(i)\y = i*40 + 40
    Next   
    
    Canvas_Draw()
    
  EndWith 
  
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
        Break
    EndSelect
  ForEver
  
  
EndProcedure


Main()
Last edited by acreis on Mon Oct 20, 2025 12:17 am, edited 4 times in total.
User avatar
STARGÅTE
Addict
Addict
Posts: 2258
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: Graphic: Curve throug points

Post by STARGÅTE »

Probably you are looking for Spline curves or Bézier curve.
I just linked them to the forum search here.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4991
Joined: Sun Apr 12, 2009 6:27 am

Re: Graphic: Curve throug points

Post by RASHAD »

Hi acreis
Next code by NULL for sprite
Modified by RASHAD for windows
Take it as start :)

Code: Select all

ww=400
wh=400

hWin=OpenWindow(0, 0,0,ww,wh, "Spline",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
CanvasGadget(0,0,0,ww,wh)
StartDrawing(CanvasOutput(0))
Box(0,0,ww,wh,#Black)
StopDrawing()

NewList p.POINT()               ; waypoints
x.f = ww/2                      ; object x
y.f = wh/2                      ; object y
angle.f                         ; object angle
speed_move.f = 0.4              ; movement speed
speed_rotate.f = speed_move*0.1 ; rotation speed
distance_tolerance.f = 3.0      ; pixel tolerance to reach waypoint
angle_needed.f                  ; angle from object to next waypoint
angle_diff.f                    ; rotation needed to point straight to next waypoint


Repeat
  Select WindowEvent()
    Case #PB_Event_CloseWindow
      quit=1
      
    Case #WM_LBUTTONDOWN            ; add point
      LastElement(p())
      AddElement(p())
      p()\x = WindowMouseX(0)
      p()\y = WindowMouseY(0)
      
    Case #WM_RBUTTONDOWN             ; clear points
      ClearList(p())
      StartDrawing(CanvasOutput(0))
      Box(0,0,ww,wh,#Black)
      StopDrawing()
      
  EndSelect
  If ListSize(p())
    FirstElement(p())
    ; distance check only axis-based. you could use real distance calculation here if prefered
    If Abs(p()\x-x) < distance_tolerance And Abs(p()\y-y) < distance_tolerance
      DeleteElement(p())
    EndIf
  EndIf  
  
  If ListSize(p())
    FirstElement(p())
    angle_needed = ATan2( p()\x-x, p()\y-y )
    
    If angle_needed < 0
      angle_needed + 2*#PI ;
    EndIf
    
    If angle_needed > angle
      If (angle_needed-angle) < #PI
        angle_diff = (angle_needed - angle)
      Else
        angle_diff = -(2*#PI - (angle_needed - angle))
      EndIf
    Else
      If (angle-angle_needed) < #PI
        angle_diff = - (angle - angle_needed)
      Else
        angle_diff =  (2*#PI - (angle - angle_needed))
      EndIf
    EndIf
    
    angle + angle_diff*speed_rotate
    
    While angle > 2*#PI : angle - 2*#PI : Wend
    While angle < 0     : angle + 2*#PI : Wend
    
    x + speed_move*Cos(angle)
    y + speed_move*Sin(angle)
  EndIf
  
  
  StartDrawing(CanvasOutput(0))
  ForEach p()
    Circle(p()\x,p()\y,2,#Red) 
  Next
  DrawingMode(#PB_2DDrawing_Default )
  Plot(x,y,#White)                                      ; position
                                                        ;LineXY(x,y,x+20*Cos(angle_needed),y+20*Sin(angle_needed),#Red)  ; angle needed
                                                        ;LineXY(x,y,x+10*Cos(angle),y+10*Sin(angle),#Green)              ; current angle
  StopDrawing()
  
  
Until quit = 1
Edit : Uncheck DPI for now :)
Egypt my love
acreis
Enthusiast
Enthusiast
Posts: 232
Joined: Fri Jun 01, 2012 12:20 am

Re: Graphic: Curve throug points

Post by acreis »

STARGÅTE wrote: Fri Oct 17, 2025 6:27 pm Probably you are looking for Spline curves or Bézier curve.
I just linked them to the forum search here.
That's right STARGÅTE!

I've been tracking the posts about spline, bezier, curve interpolation the last 15 years.

There's a lot of very good examples, but one I saw, I don't remember when, fits my present needs.

If it is not a false memory or hallucination, it's like I said, "smooth curves by points", "points draggable", and not strange loops when general direction of points change.

I googled the forum before posting about it, but had no success.

So I asked, maybe the author or someone with same need could remember.

Many thanks!
acreis
Enthusiast
Enthusiast
Posts: 232
Joined: Fri Jun 01, 2012 12:20 am

Re: Graphic: Curve throug points

Post by acreis »

RASHAD wrote: Fri Oct 17, 2025 9:31 pm Hi acreis
Next code by NULL for sprite
Modified by RASHAD for windows
Take it as start :)

Code: Select all

ww=400
wh=400

hWin=OpenWindow(0, 0,0,ww,wh, "Spline",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
CanvasGadget(0,0,0,ww,wh)
StartDrawing(CanvasOutput(0))
Box(0,0,ww,wh,#Black)
StopDrawing()

NewList p.POINT()               ; waypoints
x.f = ww/2                      ; object x
y.f = wh/2                      ; object y
angle.f                         ; object angle
speed_move.f = 0.4              ; movement speed
speed_rotate.f = speed_move*0.1 ; rotation speed
distance_tolerance.f = 3.0      ; pixel tolerance to reach waypoint
angle_needed.f                  ; angle from object to next waypoint
angle_diff.f                    ; rotation needed to point straight to next waypoint


Repeat
  Select WindowEvent()
    Case #PB_Event_CloseWindow
      quit=1
      
    Case #WM_LBUTTONDOWN            ; add point
      LastElement(p())
      AddElement(p())
      p()\x = WindowMouseX(0)
      p()\y = WindowMouseY(0)
      
    Case #WM_RBUTTONDOWN             ; clear points
      ClearList(p())
      StartDrawing(CanvasOutput(0))
      Box(0,0,ww,wh,#Black)
      StopDrawing()
      
  EndSelect
  If ListSize(p())
    FirstElement(p())
    ; distance check only axis-based. you could use real distance calculation here if prefered
    If Abs(p()\x-x) < distance_tolerance And Abs(p()\y-y) < distance_tolerance
      DeleteElement(p())
    EndIf
  EndIf  
  
  If ListSize(p())
    FirstElement(p())
    angle_needed = ATan2( p()\x-x, p()\y-y )
    
    If angle_needed < 0
      angle_needed + 2*#PI ;
    EndIf
    
    If angle_needed > angle
      If (angle_needed-angle) < #PI
        angle_diff = (angle_needed - angle)
      Else
        angle_diff = -(2*#PI - (angle_needed - angle))
      EndIf
    Else
      If (angle-angle_needed) < #PI
        angle_diff = - (angle - angle_needed)
      Else
        angle_diff =  (2*#PI - (angle - angle_needed))
      EndIf
    EndIf
    
    angle + angle_diff*speed_rotate
    
    While angle > 2*#PI : angle - 2*#PI : Wend
    While angle < 0     : angle + 2*#PI : Wend
    
    x + speed_move*Cos(angle)
    y + speed_move*Sin(angle)
  EndIf
  
  
  StartDrawing(CanvasOutput(0))
  ForEach p()
    Circle(p()\x,p()\y,2,#Red) 
  Next
  DrawingMode(#PB_2DDrawing_Default )
  Plot(x,y,#White)                                      ; position
                                                        ;LineXY(x,y,x+20*Cos(angle_needed),y+20*Sin(angle_needed),#Red)  ; angle needed
                                                        ;LineXY(x,y,x+10*Cos(angle),y+10*Sin(angle),#Green)              ; current angle
  StopDrawing()
  
  
Until quit = 1
Edit : Uncheck DPI for now :)
Hi RASHAD,

Thanks a lot!

It's a really good start, I'll try fit it to my needs!
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4991
Joined: Sun Apr 12, 2009 6:27 am

Re: Graphic: Curve throug points

Post by RASHAD »

Hi acreis
I think you mean Bézier by OpenCV-JHPJHP
You can drag the point but it is limited to 2 points
Maybe you can adapt it for your needs
Egypt my love
acreis
Enthusiast
Enthusiast
Posts: 232
Joined: Fri Jun 01, 2012 12:20 am

Re: Graphic: Curve throug points

Post by acreis »

Hi RASAHD

I'm trying to adapt this too: https://apoorvaj.io/cubic-bezier-through-four-points
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4991
Joined: Sun Apr 12, 2009 6:27 am

Re: Graphic: Curve throug points

Post by RASHAD »

Hi acreis
It is good to start from scratch for learning
But NM has a fantastic piece of code using PB Vector lib
You can ask him for more or collaborate with him OR adapt it for your needs by yourself
In any case I will be very happy with the result :mrgreen:
have a good time mate
viewtopic.php?t=75326
Egypt my love
acreis
Enthusiast
Enthusiast
Posts: 232
Joined: Fri Jun 01, 2012 12:20 am

Re: Graphic: Curve throug points

Post by acreis »

yeap, I replied there in Wed Oct 15, 2025 2:40 pm, good time to you [all]!
acreis
Enthusiast
Enthusiast
Posts: 232
Joined: Fri Jun 01, 2012 12:20 am

Re: Graphic: Curve throug points

Post by acreis »

acreis wrote: Sun Oct 19, 2025 12:15 am Hi RASAHD

I'm trying to adapt this too: https://apoorvaj.io/cubic-bezier-through-four-points
Done! (see first post for interactive solution)
That's all, folks!

Code: Select all

; function vec2_dist(a, b) {
;     return Math.sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
; }
; 
; function refit_bezier(
;     passthru_0, passthru_1, passthru_2, passthru_3,
;     out_tangent_1, out_tangent_2
; ) {
;     let d1 = Math.pow(vec2_dist(passthru_1, passthru_0), alpha);
;     let d2 = Math.pow(vec2_dist(passthru_2, passthru_1), alpha);
;     let d3 = Math.pow(vec2_dist(passthru_3, passthru_2), alpha);
;     // Modify tangent 1
;     {
;         let a = d1 * d1;
;         let b = d2 * d2;
;         let c = (2 * d1 * d1) + (3 * d1 * d2) + (d2 * d2);
;         let d = 3 * d1 * (d1 + d2);
;         out_tangent_1.x = (a * passthru_2.x - b * passthru_0.x + c * passthru_1.x) / d;
;         out_tangent_1.y = (a * passthru_2.y - b * passthru_0.y + c * passthru_1.y) / d;
;     }
;     // Modify tangent 2
;     {
;         let a = d3 * d3;
;         let b = d2 * d2;
;         let c = (2 * d3 * d3) + (3 * d3 * d2) + (d2 * d2);
;         let d = 3 * d3 * (d3 + d2);
;         out_tangent_2.x = (a * passthru_1.x - b * passthru_3.x + c * passthru_2.x) / d;
;         out_tangent_2.y = (a * passthru_1.y - b * passthru_3.y + c * passthru_2.y) / d;
;     }
; 
; }

EnableExplicit




Structure Vector2
  x.f
  y.f
EndStructure




Procedure.f vec2_dist(*a.Vector2, *b.Vector2)
  ProcedureReturn Sqr(Pow(*a\x - *b\x, 2) + Pow(*a\y - *b\y, 2))
EndProcedure




Procedure refit_bezier(*passthru_0.Vector2, *passthru_1.Vector2, *passthru_2.Vector2, *passthru_3.Vector2, alpha.f, *out_tangent_1.Vector2, *out_tangent_2.Vector2)
  Define d1.f, d2.f, d3.f
  Define a.f, b.f, c.f, d.f
  
  d1 = Pow(vec2_dist(*passthru_1, *passthru_0), alpha)
  d2 = Pow(vec2_dist(*passthru_2, *passthru_1), alpha)
  d3 = Pow(vec2_dist(*passthru_3, *passthru_2), alpha)
  
  ; Modify tangent 1
  a = d1 * d1
  b = d2 * d2
  c = (2 * d1 * d1) + (3 * d1 * d2) + (d2 * d2)
  d = 3 * d1 * (d1 + d2)
  *out_tangent_1\x = (a * *passthru_2\x - b * *passthru_0\x + c * *passthru_1\x) / d
  *out_tangent_1\y = (a * *passthru_2\y - b * *passthru_0\y + c * *passthru_1\y) / d
  
  ; Modify tangent 2
  a = d3 * d3
  b = d2 * d2
  c = (2 * d3 * d3) + (3 * d3 * d2) + (d2 * d2)
  d = 3 * d3 * (d3 + d2)
  *out_tangent_2\x = (a * *passthru_1\x - b * *passthru_3\x + c * *passthru_2\x) / d
  *out_tangent_2\y = (a * *passthru_1\y - b * *passthru_3\y + c * *passthru_2\y) / d
EndProcedure



Macro AddPathCirclePT(_point_)
    AddPathCircle(_point_\x, _point_\y, 8)
EndMacro  



Global gCanvas
Global width = 800, height = 600


Procedure Draw(*passthru_0.Vector2, *passthru_1.Vector2, *passthru_2.Vector2, *passthru_3.Vector2)
  
  Define alpha.f = 0.5
  
  Define out_tangent_1.Vector2, out_tangent_2.Vector2
  
  refit_bezier(*passthru_0, *passthru_1, *passthru_2, *passthru_3, alpha, out_tangent_1, out_tangent_2)
  
  
  If StartVectorDrawing(CanvasVectorOutput(gCanvas))
    
    
    ; Cls
    ;AddPathBox(0, 0, width, height)
    ;VectorSourceColor(RGBA(245, 255, 255, 255))
    ;FillPath()
    
    
    ; Draw original points
    VectorSourceColor(RGBA(0, 0, 0, 255))
    AddPathCirclePT(*passthru_1)
    AddPathCirclePT(*passthru_2)
    FillPath()
    
    VectorSourceColor(RGBA(100, 100, 100, 255))
    
    AddPathCirclePT(out_tangent_1)
    AddPathCirclePT(out_tangent_2)
    
    AddPathCirclePT(*passthru_0)
    AddPathCirclePT(*passthru_3)
    
    
    MovePathCursor(*passthru_1\x,*passthru_1\y)
    ;AddPathCurve( p1\x, p1\y, p2\x, p2\y,*passthru_3\x,*passthru_3\y)
    AddPathCurve(out_tangent_1\x, out_tangent_1\y, out_tangent_2\x, out_tangent_2\y, *passthru_2\x, *passthru_2\y)
    StrokePath(1)
    
    
    ; Draw tangents
;     VectorSourceColor(RGBA(0, 0, 0, 255))
;     MovePathCursor(*passthru_1\x,*passthru_1\y)
;     AddPathLine(p1\x, p1\y)
;     MovePathCursor(passthru_2\x,*passthru_2\y)
;     AddPathLine(p2\x, p2\y)
;     StrokePath(1)
    
    EndIf 
    
    StopVectorDrawing()
    

  
EndProcedure




; Main procedure
Procedure Main()
  
  
  
  Define hWnd = OpenWindow(#PB_Any, 100, 100, width, height, "Refitted Bezier Curve")
  gCanvas = CanvasGadget(#PB_Any, 0, 0, width, height)
  
  
  Protected.Vector2 passthru_0, passthru_1, passthru_2, passthru_3
 
  
  passthru_0\x = 200: passthru_0\y = 300
  passthru_1\x = 400: passthru_1\y = 300
  passthru_2\x = 600: passthru_2\y = 100
  passthru_3\x = 610: passthru_3\y = 80
  
  draw(passthru_0, passthru_1,  passthru_2,  passthru_3)
  
  passthru_0\x = 100: passthru_0\y = 100
  passthru_1\x = 200: passthru_1\y = 300
  passthru_2\x = 400: passthru_2\y = 300
  passthru_3\x = 600: passthru_3\y = 100
  
  draw(passthru_0, passthru_1,  passthru_2,  passthru_3)
  
  passthru_0\x = 90: passthru_0\y = 70
  passthru_1\x = 100: passthru_1\y = 100
  passthru_2\x = 200: passthru_2\y = 300
  passthru_3\x = 400: passthru_3\y = 300
  
  draw(passthru_0, passthru_1,  passthru_2,  passthru_3)
  
  
  
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
        Break
    EndSelect
  ForEver
  
  
EndProcedure



Main()

User avatar
idle
Always Here
Always Here
Posts: 6022
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Graphic: Cubic bezier through four (or multiple) points (solved)

Post by idle »

I was just looking at doing this for the AVGSceneGraph.
Do you mind if I nick it.
acreis
Enthusiast
Enthusiast
Posts: 232
Joined: Fri Jun 01, 2012 12:20 am

Re: Graphic: Cubic bezier through four (or multiple) points (solved)

Post by acreis »

Hi Idle!

Of course, it’s all yours.
User avatar
idle
Always Here
Always Here
Posts: 6022
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Graphic: Cubic bezier through four (or multiple) points (solved)

Post by idle »

acreis wrote: Wed Oct 22, 2025 11:37 pm Hi Idle!

Of course, it’s all yours.
Thanks, think you can change like this RightClick

Code: Select all

;
; https://www.purebasic.fr/english/viewtopic.php?p=646693#p646693
; https://apoorvaj.io/cubic-bezier-through-four-points
; function vec2_dist(a, b) {
;     return Math.sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
; }
; 
; function refit_bezier(
;     passthru_0, passthru_1, passthru_2, passthru_3,
;     out_tangent_1, out_tangent_2
; ) {
;     let d1 = Math.pow(vec2_dist(passthru_1, passthru_0), alpha);
;     let d2 = Math.pow(vec2_dist(passthru_2, passthru_1), alpha);
;     let d3 = Math.pow(vec2_dist(passthru_3, passthru_2), alpha);
;     // Modify tangent 1
;     {
;         let a = d1 * d1;
;         let b = d2 * d2;
;         let c = (2 * d1 * d1) + (3 * d1 * d2) + (d2 * d2);
;         let d = 3 * d1 * (d1 + d2);
;         out_tangent_1.x = (a * passthru_2.x - b * passthru_0.x + c * passthru_1.x) / d;
;         out_tangent_1.y = (a * passthru_2.y - b * passthru_0.y + c * passthru_1.y) / d;
;     }
;     // Modify tangent 2
;     {
;         let a = d3 * d3;
;         let b = d2 * d2;
;         let c = (2 * d3 * d3) + (3 * d3 * d2) + (d2 * d2);
;         let d = 3 * d3 * (d3 + d2);
;         out_tangent_2.x = (a * passthru_1.x - b * passthru_3.x + c * passthru_2.x) / d;
;         out_tangent_2.y = (a * passthru_1.y - b * passthru_3.y + c * passthru_2.y) / d;
;     }
; 
; }

EnableExplicit


; -Structures
Structure POINTF
  x.f
  y.f
EndStructure


Structure TREFITTEDBEZIER  
  *window
  *canvas
  *text
  width.i
  height.i
  alpha.f
  Array p.POINTF(0)
  ptMouseMovePoint.POINT
  ptMouseDownPoint.POINT
  ptInitPosPoint.POINTF 
  hotpoint.i
  smalldistance.f
  LButtonDown.i
EndStructure

;- Globals
Global *app.TREFITTEDBEZIER = AllocateStructure(TREFITTEDBEZIER)
ReDim *app\p(3) 



;- Macros

Macro CanvasMouseX(_canvas_)
  
  GetGadgetAttribute(_canvas_, #PB_Canvas_MouseX) 
  
EndMacro


Macro CanvasMouseY(_canvas_)
  
  GetGadgetAttribute(_canvas_, #PB_Canvas_MouseY) 
  
EndMacro


Macro vec2_dist(p1,p2)
  
  Sqr((p1\x-p2\x)*(p1\x-p2\x) + (p1\y-p2\y)*(p1\y-p2\y))*0.5
  ;Sqr(Pow(_point_a_\x - _point_b_\x, 2) + Pow(_point_a_\y - _point_b_\y, 2))
  
EndMacro   



Macro AddPathCirclePT(_point_, _size_ = 8)
  
  AddPathCircle(_point_\x, _point_\y, _size_)
  
EndMacro 




Procedure refit_bezier(*passthru_0.POINTF, *passthru_1.POINTF, *passthru_2.POINTF, *passthru_3.POINTF, alpha.f, *out_tangent_1.POINTF, *out_tangent_2.POINTF)
  Define d1.f, d2.f, d3.f
  Define a.f, b.f, c.f, d.f
  
  d1 = (vec2_dist(*passthru_1, *passthru_0));, alpha)
  d2 = (vec2_dist(*passthru_2, *passthru_1));, alpha)
  d3 = (vec2_dist(*passthru_3, *passthru_2));, alpha)
  
  ; Modify tangent 1
  a = d1 * d1
  b = d2 * d2
  c = (2 * d1 * d1) + (3 * d1 * d2) + (d2 * d2)
  d = 3 * d1 * (d1 + d2)
  *out_tangent_1\x = (a * *passthru_2\x - b * *passthru_0\x + c * *passthru_1\x) / d
  *out_tangent_1\y = (a * *passthru_2\y - b * *passthru_0\y + c * *passthru_1\y) / d
  
  ; Modify tangent 2
  a = d3 * d3
  b = d2 * d2
  c = (2 * d3 * d3) + (3 * d3 * d2) + (d2 * d2)
  d = 3 * d3 * (d3 + d2)
  *out_tangent_2\x = (a * *passthru_1\x - b * *passthru_3\x + c * *passthru_2\x) / d
  *out_tangent_2\y = (a * *passthru_1\y - b * *passthru_3\y + c * *passthru_2\y) / d
EndProcedure




Procedure Bezier_Draw(*passthru_0.POINTF, *passthru_1.POINTF, *passthru_2.POINTF, *passthru_3.POINTF)
  
  
  Define out_tangent_1.POINTF, out_tangent_2.POINTF
  
  refit_bezier(*passthru_0, *passthru_1, *passthru_2, *passthru_3, *app\alpha, out_tangent_1, out_tangent_2)
  
  
  VectorSourceColor(RGBA(100, 255, 0, 255))
  VectorSourceColor(RGBA(255, 100, 100, 255))
  
  AddPathCirclePT(*passthru_0)
  AddPathCirclePT(*passthru_3)
  
  
  MovePathCursor(*passthru_1\x,*passthru_1\y)
  VectorSourceColor(RGBA(0, 0, 0, 255))
  AddPathCurve(out_tangent_1\x, out_tangent_1\y, out_tangent_2\x, out_tangent_2\y, *passthru_2\x, *passthru_2\y)
  StrokePath(1)
    
  ; Draw original points
  AddPathCirclePT(*passthru_1)
  AddPathCirclePT(*passthru_2)
  VectorSourceColor(RGBA(0, 0, 0, 255))
  StrokePath(1)
  
  
  ; Draw tangents
  ;     VectorSourceColor(RGBA(0, 0, 0, 255))
  ;     MovePathCursor(*passthru_1\x,*passthru_1\y)
  ;     AddPathLine(p1\x, p1\y)
  ;     MovePathCursor(passthru_2\x,*passthru_2\y)
  ;     AddPathLine(p2\x, p2\y)
  ;     StrokePath(1)
  
  
  
EndProcedure



Procedure Canvas_Draw()
  
  
  If StartVectorDrawing(CanvasVectorOutput(*app\Canvas))
    
    
    With *app
      
      Protected i 
      VectorSourceColor(RGBA(255,255,255,255))
      Protected r.rect
      GetClientRect_(GadgetID(\canvas), r)
      AddPathBox(0,0, r\right, r\bottom)
      FillPath()
      
      
      
      If \hotpoint > -1
        VectorSourceColor(RGBA(255,0,0,100))
        AddPathCirclePT(\p(\hotpoint))
        StrokePath(8)
      EndIf   
      
      
      Protected n = ArraySize(\p())-3
      For i = 0 To n
        Bezier_Draw(\p(0+i), \p(1+i), \p(2+i), \p(3+i))
      Next
      If n 
      MovePathCursor(\p(n+2)\x,\p(n+2)\y)
      AddPathLine(\p(n+3)\x,\p(n+3)\y) 
      VectorSourceColor(RGBA(255,0,0,255))
      StrokePath(1)
      EndIf 
    EndWith   
    
    
    
    StopVectorDrawing()
    
  EndIf  
  
  
EndProcedure




Procedure Canvas_GetHotPoint()
  
  With *app
    \hotpoint = -2
    Protected i, n = ArraySize(\p())
    For i = 0 To n
      If vec2_dist(\ptMouseMovePoint, \p(i)) < \smalldistance
        \hotpoint = i
        ProcedureReturn #True
      EndIf
    Next   
  EndWith
  
  ProcedureReturn #False 
  
EndProcedure  




Procedure Canvas_LeftButtonUp()
  
  With *app
    \LButtonDown = #False
  EndWith
  
  
  Canvas_Draw()
  
EndProcedure



Procedure Canvas_LeftButtonDown()
  
  With *app
    
    \LButtonDown = #True
    
    \ptMouseDownPoint\x = CanvasMouseX(\canvas)
    \ptMouseDownPoint\y = CanvasMouseY(\canvas)
    
    If Canvas_GetHotPoint()
      \ptInitPosPoint = \p(\hotpoint)
    EndIf  
    
  EndWith
  
EndProcedure

Procedure canvas_RightCLick() 
  Protected size = ArraySize(*app\p())+1 
  ReDim *app\p(size) 
  *app\p(size)\x = CanvasMouseX(*app\canvas)
  *app\p(size)\y = CanvasMousey(*app\canvas)
  
EndProcedure   
  
Procedure Canvas_DragPoint()
  
  With *app
    
    If \hotpoint > -1
      
      \p(\hotpoint)\x = \ptInitPosPoint\x + (\ptMouseMovePoint\x - \ptMouseDownPoint\x)
      \p(\hotpoint)\y = \ptInitPosPoint\y + (\ptMouseMovePoint\y - \ptMouseDownPoint\y)
      
    EndIf 
    
  EndWith
  
  
EndProcedure



Procedure Canvas_MouseMove()
  
  With *app
    
    \ptMouseMovePoint\x = CanvasMouseX(\canvas)
    \ptMouseMovePoint\y = CanvasMouseY(\canvas) 
    SetGadgetText(\text, "" + \ptMouseMovePoint\x + ", " + \ptMouseMovePoint\y )
    
    
    If \LButtonDown And \hotpoint > -1
      Canvas_DragPoint()
      Canvas_Draw()
      ProcedureReturn 
    EndIf 
    
    Canvas_GetHotPoint()
    
    
  EndWith
  
  Canvas_Draw()
  
  
EndProcedure




Procedure Main()
  
  
  
  With *app
    
    \width = 800
    \height = 600
    \alpha = 0.5
    \smalldistance = 8
    \hotpoint = -2
    
    \window = OpenWindow(#PB_Any, 100, 100, \width, \height, "Refitted Bezier Curve")
    \Canvas = CanvasGadget(#PB_Any, 0, 0, \width, \height, #PB_Canvas_Container)
    \Text = TextGadget(#PB_Any,0,0, \width, 16, "")
    
    BindGadgetEvent(\Canvas, @Canvas_MouseMove(), #PB_EventType_MouseMove)
    BindGadgetEvent(\Canvas, @Canvas_LeftButtonUp(), #PB_EventType_LeftButtonUp)
    BindGadgetEvent(\Canvas, @Canvas_LeftButtonDown(), #PB_EventType_LeftButtonDown)
    BindGadgetEvent(\Canvas, @canvas_RightCLick(), #PB_EventType_RightClick)
    
    Protected i, n = ArraySize(\p())
    For i = 0 To n
      \p(i)\x = i*50 + 50
      \p(i)\y = i*40 + 40
    Next   
    
    Canvas_Draw()
    
  EndWith 
  
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
        Break
    EndSelect
  ForEver
  
  
EndProcedure


Main()

User avatar
idle
Always Here
Always Here
Posts: 6022
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Graphic: Cubic bezier through four (or multiple) points (solved)

Post by idle »

This isn't quite right I added code to make star shape polygons
no idea how to fill the shape at the moment.

Code: Select all



EnableExplicit

; -Structures
Structure POINTF
  x.f
  y.f
EndStructure

Structure TREFITTEDBEZIER  
  *window
  *canvas
  *text
  width.i
  height.i
  alpha.f
  Array p.POINTF(0)
  ptMouseMovePoint.POINT
  ptMouseDownPoint.POINT
  ptInitPosPoint.POINTF 
  hotpoint.i
  smalldistance.f
  LButtonDown.i
EndStructure

;- Globals
Global *app.TREFITTEDBEZIER = AllocateStructure(TREFITTEDBEZIER)
ReDim *app\p(3) 

;- Macros

Macro CanvasMouseX(_canvas_)
  
  GetGadgetAttribute(_canvas_, #PB_Canvas_MouseX) 
  
EndMacro


Macro CanvasMouseY(_canvas_)
  
  GetGadgetAttribute(_canvas_, #PB_Canvas_MouseY) 
  
EndMacro


Macro vec2_dist(p1,p2)
  
  Sqr((p1\x-p2\x)*(p1\x-p2\x) + (p1\y-p2\y)*(p1\y-p2\y))*0.5
  ;Sqr(Pow(_point_a_\x - _point_b_\x, 2) + Pow(_point_a_\y - _point_b_\y, 2))
  
EndMacro   


Macro AddPathCirclePT(_point_, _size_ = 8)
  
  AddPathCircle(_point_\x, _point_\y, _size_)
  
EndMacro 

Procedure _AVGRefit_Bezier(*p0.pointf,*p1.pointf,*p2.pointf,*p3.pointf,*t0.pointf,*t1.pointf)
    
  Protected d1.f, d2.f, d3.f
  Protected a.f, b.f, c.f, d.f
  Protected tx1.f,ty1.f,tx2.f,ty2.f
    
  d1 = Sqr((*p1\x-*p0\x)*(*p1\x-*p0\x) + (*p1\y-*p0\y)*(*p1\y-*p0\y))*0.5
  d2 = Sqr((*p2\x-*p1\x)*(*p2\x-*p1\x) + (*p2\y-*p1\y)*(*p2\y-*p1\y))*0.5 
  d3 = Sqr((*p3\x-*p2\x)*(*p3\x-*p2\x) + (*p3\y-*p2\y)*(*p3\y-*p2\y))*0.5 
  
  a = d1 * d1
  b = d2 * d2
  c = (2 * d1 * d1) + (3 * d1 * d2) + (d2 * d2)
  d = 3 * d1 * (d1 + d2)
  
  *t0\x = (a * *p2\x - b * *p0\x + c * *p1\x) / d
  *t0\y = (a * *p2\y - b * *p0\y + c * *p1\y) / d
    
  a = d3 * d3
  b = d2 * d2
  c = (2 * d3 * d3) + (3 * d3 * d2) + (d2 * d2)
  d = 3 * d3 * (d3 + d2)
  
  *t1\x = (a * *p1\x - b * *p3\x + c * *p2\x) / d
  *t1\y = (a * *p1\y - b * *p3\y + c * *p2\y) / d
    
EndProcedure

Procedure Canvas_Draw()
  
  
  If StartVectorDrawing(CanvasVectorOutput(*app\Canvas))
        
    With *app
      
      Protected i 
      VectorSourceColor(RGBA(255,255,255,255))
      Protected r.rect
      GetClientRect_(GadgetID(\canvas), r)
      AddPathBox(0,0, r\right, r\bottom)
      FillPath()
      
      If \hotpoint > -1
        VectorSourceColor(RGBA(255,0,0,100))
        AddPathCirclePT(\p(\hotpoint))
        StrokePath(8)
      EndIf   
      
      Protected j,n = ArraySize(\p())
      For i = 0 To n
               
        Define out_tangent_1.POINTF, out_tangent_2.POINTF
        
        _AVGRefit_Bezier(*app\p(i%n),*app\p((i+1)%n),*app\p((i+2)%n),*app\p((i+3)%n),out_tangent_1,out_tangent_2)
                
        MovePathCursor(*app\p((i+1)%n)\x,*app\p((i+1)%n)\y)
        AddPathCurve(out_tangent_1\x, out_tangent_1\y, out_tangent_2\x, out_tangent_2\y, *app\p((i+2)%n)\x,*app\p((i+2)%n)\y)
               
      Next
           
    EndWith   
    
    VectorSourceColor(RGBA(0, 0, 0, 255))
    StrokePath(4)
        
    StopVectorDrawing()
    
  EndIf  
  
EndProcedure

Procedure Canvas_GetHotPoint()
  
  With *app
    \hotpoint = -2
    Protected i, n = ArraySize(\p())
    For i = 0 To n
      If vec2_dist(\ptMouseMovePoint, \p(i)) < \smalldistance
        \hotpoint = i
        ProcedureReturn #True
      EndIf
    Next   
  EndWith
  
  ProcedureReturn #False 
  
EndProcedure  

Procedure Canvas_LeftButtonUp()
   With *app
    \LButtonDown = #False
  EndWith
   Canvas_Draw()
 EndProcedure
 
 Procedure Canvas_LeftButtonDown()
  With *app
   
    \LButtonDown = #True
    
    \ptMouseDownPoint\x = CanvasMouseX(\canvas)
    \ptMouseDownPoint\y = CanvasMouseY(\canvas)
    
    If Canvas_GetHotPoint()
      \ptInitPosPoint = \p(\hotpoint)
    EndIf  
    
  EndWith
  
EndProcedure

Procedure canvas_RightCLick() 
  Protected size = ArraySize(*app\p())+1 
  ReDim *app\p(size) 
  *app\p(size)\x = CanvasMouseX(*app\canvas)
  *app\p(size)\y = CanvasMousey(*app\canvas)
  
EndProcedure   
  
Procedure Canvas_DragPoint()
  With *app
     If \hotpoint > -1
   
      \p(\hotpoint)\x = \ptInitPosPoint\x + (\ptMouseMovePoint\x - \ptMouseDownPoint\x)
      \p(\hotpoint)\y = \ptInitPosPoint\y + (\ptMouseMovePoint\y - \ptMouseDownPoint\y)
      
    EndIf 
    
  EndWith
   
EndProcedure

Procedure Canvas_MouseMove()
 
  With *app
    
    \ptMouseMovePoint\x = CanvasMouseX(\canvas)
    \ptMouseMovePoint\y = CanvasMouseY(\canvas) 
    SetGadgetText(\text, "" + \ptMouseMovePoint\x + ", " + \ptMouseMovePoint\y )
    
    
    If \LButtonDown And \hotpoint > -1
      Canvas_DragPoint()
      Canvas_Draw()
      ProcedureReturn 
    EndIf 
    
    Canvas_GetHotPoint()
    
    
  EndWith
  
  Canvas_Draw()
  
  
EndProcedure

Procedure AVGAddPathPolygonBezier(x,y,sides.i,majoraxis.i,minoraxis.i=0,orient.i=0,Stars=0)
     
  Protected xx, yy, px, py, inc.f, ang.f, fin.f
  Protected ndx.f,ndy.f,dy.f,dx.f,dx1,dy1,cosOrient.f,SinOrient.f
  Protected start.i,finish.i,dz.f,i.i
    
  start = 0 
  If stars 
    sides*2 
  EndIf   
  
  ReDim *app\p(sides) 
     
  dz=1.0
  finish = sides 
  If finish < 3 : finish = 3 : EndIf
  If finish > 64 : finish = 64 : EndIf
  inc = Radian(360 / finish)
  finish = start + 360
   
  ang = Radian(start)
  fin = Radian(finish)
  cosOrient = Sin(Radian(orient-180)) ;0 To 360
  sinOrient = Cos(Radian(orient-180))  
  dx = x + (Cos(ang) * majoraxis * dz) 
  dy = y + (Sin(ang) * minoraxis * dz) 
  dx1 = dx - x 
  dy1 = dy - y
  px = x + (dx1 * sinOrient - dy1 * cosOrient) ;rotate coordinates
  py = y + (dx1 * cosOrient + dy1 * sinOrient) 
  If stars 
    dz = 0.5 
  EndIf   
    
  Protected first=0  
  i=0
  Repeat 
    
    ang + inc  
    If ang > fin : ang = fin : EndIf
    dx = x + (Cos(ang) * majoraxis * dz) 
    dy = y + (Sin(ang) * minoraxis * dz) 
    dx1 = dx - x 
    dy1 = dy - y
    ndx = x + (dx1 * sinOrient - dy1 * cosorient) 
    ndy = y + (dx1 * cosOrient + dy1 * sinorient)
     
    *app\p(i)\x = ndx 
    *app\p(i)\y = ndy 
    i+1
    
    first=1 
    px = ndx
    py = ndy
    
    If stars 
      If dz = 0.5 
        dz = 1.0 
      Else 
        dz = 0.5 
      EndIf   
    EndIf 
  Until ang = fin
    
 EndProcedure  

Procedure Main()
    
  With *app
    
    \width = 800
    \height = 600
    \alpha = 0.5
    \smalldistance = 8
    \hotpoint = -2
    
    \window = OpenWindow(#PB_Any, 100, 100, \width, \height, "Refitted Bezier Curve")
    \Canvas = CanvasGadget(#PB_Any, 0, 0, \width, \height, #PB_Canvas_Container)
    \Text = TextGadget(#PB_Any,0,0, \width, 16, "")
    
    BindGadgetEvent(\Canvas, @Canvas_MouseMove(), #PB_EventType_MouseMove)
    BindGadgetEvent(\Canvas, @Canvas_LeftButtonUp(), #PB_EventType_LeftButtonUp)
    BindGadgetEvent(\Canvas, @Canvas_LeftButtonDown(), #PB_EventType_LeftButtonDown)
    BindGadgetEvent(\Canvas, @canvas_RightCLick(), #PB_EventType_RightClick)
        
    AVGAddPathPolygonBezier(500,350,6,90,90,15,1)
        
    Canvas_Draw()
    
  EndWith 
  
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
        Break
    EndSelect
  ForEver
  
  
EndProcedure


Main()


Post Reply