casteljau algorithm (courbe de bezier)

Partagez votre expérience de PureBasic avec les autres utilisateurs.
Avatar de l’utilisateur
microdevweb
Messages : 1798
Inscription : mer. 29/juin/2011 14:11
Localisation : Belgique

casteljau algorithm (courbe de bezier)

Message par microdevweb »

Bonjour à tous,

Voici un algorithme qui peut vous être utile pour dessiner une courbe de bezier ou tester la présence de la souris sur un courbe existante

Image

Code : Tout sélectionner

Procedure cubicBezier(Array p(2),t.f,*x,*y)
  ; this procedure return the dot of curve
  ; base on the casteljau algorithm
  ; p is a array (2,4) one as x,y second is p0,p1,p2,p3
  ; t is a float batween 0 and 1
  Protected Dim dot(2),i
  For i = 0 To 1
    dot(i) = Pow(1 - t,3) * p(i,0) + Pow(1 - t,2) * 3 * t * p(i,1) + 
             (1 - t) * 3 * t * t * p(i,2) + t * t* t * p(i,3)
  Next
  PokeL(*x,dot(0))
  PokeL(*y,dot(1))
EndProcedure


Exemple complet :

Code : Tout sélectionner

Global Dim p(2,4)
#X = 0
#Y = 1
#MAIN_FORM = 0
Enumeration 
  #CANVAS 
  #BT_DRAW
  #P0X
  #P0Y
  #P1X
  #P1Y
  #P2X
  #P2Y
  #P3X
  #P3Y
EndEnumeration


; cursor pos
p(#X,0) = 50
p(#Y,0) = 50
; p1 pos
p(#X,1) = 100
p(#Y,1) = 10
; p2 pos
p(#X,2) = 300
p(#Y,2) = 250
; p3 pos
p(#X,3) = 400
p(#Y,3) = 150
Declare drawDots()
Declare cubicBezier(Array p(2),t.f,*x,*y)

Procedure drawCurve()
  StartVectorDrawing(CanvasVectorOutput(#CANVAS))
  VectorSourceColor($FFD2FAFA)
  FillVectorOutput()
  ; draw curve
  MovePathCursor(p(#x,0),p(#Y,0))
  AddPathCurve(p(#x,1),p(#Y,1),p(#x,2),p(#Y,2),p(#x,3),p(#Y,3))
  VectorSourceColor($FF0000FF)
  StrokePath(2)
  ; draw control dots
  VectorSourceColor($8D0000FF)
  AddPathBox(p(#x,1),p(#Y,1),10,10)
  AddPathBox(p(#x,2),p(#Y,2),10,10)
  FillPath()
  StopVectorDrawing()
EndProcedure

Procedure hoverCurve(mx,my)
  Protected t.f = 0,n,x,y
  For n = 0 To 1 / 0.01
    cubicBezier(p(),t,@x,@y)
    If mx >= x - 1 And mx <= x + 1
      If my >= y - 1 And my <= y + 1
        ProcedureReturn #True
      EndIf
    EndIf
    t + 0.01
  Next
  ProcedureReturn #False
EndProcedure

Procedure cubicBezier(Array p(2),t.f,*x,*y)
  ; this procedure return the dot of curve
  ; base on the casteljau algorithm
  ; p is a array (2,4) one as x,y second is p0,p1,p2,p3
  ; t is a float batween 0 and 1
  Protected Dim dot(2),i
  For i = 0 To 1
    dot(i) = Pow(1 - t,3) * p(i,0) + Pow(1 - t,2) * 3 * t * p(i,1) + 
             (1 - t) * 3 * t * t * p(i,2) + t * t* t * p(i,3)
  Next
  PokeL(*x,dot(0))
  PokeL(*y,dot(1))
EndProcedure

Procedure drawDots()
  Protected x,y,t.f = 0,n
  For n = 0 To 1 / 0.01
    StartVectorDrawing(CanvasVectorOutput(#CANVAS))
    VectorSourceColor($FF00FF00)
    cubicBezier(p(),t,@x,@y)
    AddPathCircle(x,y,3)
    t + 0.01
    FillPath()
    StopVectorDrawing()
    Delay(50)
  Next
EndProcedure

Procedure evGadget()
  Select EventGadget()
    Case #P0X
      p(#X,0) = GetGadgetState(EventGadget())
      drawCurve()
    Case #P0Y
      p(#Y,0) = GetGadgetState(EventGadget())
      drawCurve()
    Case #P1X
      p(#X,1) = GetGadgetState(EventGadget())
      drawCurve()
    Case #P1Y
      p(#Y,1) = GetGadgetState(EventGadget()) 
      drawCurve()
    Case #P2X
      p(#X,2) = GetGadgetState(EventGadget())
      drawCurve()
    Case #P2Y
      p(#Y,2) = GetGadgetState(EventGadget())
      drawCurve()
    Case #P3X
      p(#X,3) = GetGadgetState(EventGadget())
      drawCurve()
    Case #P3Y
      p(#Y,3) = GetGadgetState(EventGadget()) 
      drawCurve()
    Case #BT_DRAW
      drawDots()
    Case #CANVAS
      If EventType() = #PB_EventType_MouseMove
        Protected mx = GetGadgetAttribute(#CANVAS,#PB_Canvas_MouseX)
        Protected my = GetGadgetAttribute(#CANVAS,#PB_Canvas_MouseY)
        If hoverCurve(mx,my)
          SetGadgetAttribute(#CANVAS,#PB_Canvas_Cursor,#PB_Cursor_Hand)
        Else
          SetGadgetAttribute(#CANVAS,#PB_Canvas_Cursor,#PB_Cursor_Default)
        EndIf
      EndIf
  EndSelect
  
EndProcedure

OpenWindow(#MAIN_FORM,0,0,800,600,"Event curve",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
CanvasGadget(#CANVAS,0,0,800,530)
; PO
y = 540
x = 10
TextGadget(#PB_Any,X,Y,60,20,"P0 X :")
X + 60
SpinGadget(#P0X,X,Y,60,20,0,1000,#PB_Spin_Numeric)
SetGadgetState(#P0X,p(#x,0))
Y + 30
X = 10
TextGadget(#PB_Any,X,Y,60,20,"P0 Y :")
X + 60
SpinGadget(#P0Y,X,Y,60,20,0,1000,#PB_Spin_Numeric)
SetGadgetState(#P0Y,p(#Y,0))
; P1
y = 540
x = 150
TextGadget(#PB_Any,X,Y,60,20,"P1 X :")
X + 60
SpinGadget(#P1X,X,Y,60,20,0,1000,#PB_Spin_Numeric)
SetGadgetState(#P1X,p(#x,1))
Y + 30
X = 150
TextGadget(#PB_Any,X,Y,60,20,"P1 Y :")
X + 60
SpinGadget(#P1Y,X,Y,60,20,0,1000,#PB_Spin_Numeric)
SetGadgetState(#P1Y,p(#Y,1))
; P2
y = 540
x = 300
TextGadget(#PB_Any,X,Y,60,20,"P2 X :")
X + 60
SpinGadget(#P2X,X,Y,60,20,0,1000,#PB_Spin_Numeric)
SetGadgetState(#P2X,p(#x,2))
Y + 30
X = 300
TextGadget(#PB_Any,X,Y,60,20,"P2 Y :")
X + 60
SpinGadget(#P2Y,X,Y,60,20,0,1000,#PB_Spin_Numeric)
SetGadgetState(#P2Y,p(#Y,2))
; P3
y = 540
x = 450
TextGadget(#PB_Any,X,Y,60,20,"P3 X :")
X + 60
SpinGadget(#P3X,X,Y,60,20,0,1000,#PB_Spin_Numeric)
SetGadgetState(#P3X,p(#x,3))
Y + 30
X = 450
TextGadget(#PB_Any,X,Y,60,20,"P3 Y :")
X + 60
SpinGadget(#P3Y,X,Y,60,20,0,1000,#PB_Spin_Numeric)
SetGadgetState(#P3Y,p(#Y,3))
y = 540
x + 70
ButtonGadget(#BT_DRAW,x,y,60,30,"DRAW")
drawCurve()

BindEvent(#PB_Event_Gadget,@evGadget())

Repeat
  WaitWindowEvent()
Until Event() = #PB_Event_CloseWindow

Windows 10 64 bits PB: 5.70 ; 5.72 LST
Work at Centre Spatial de Liège
Avatar de l’utilisateur
venom
Messages : 3071
Inscription : jeu. 29/juil./2004 16:33
Localisation : Klyntar
Contact :

Re: casteljau algorithm (courbe de bezier)

Message par venom »

Sympa, merci microdevweb du partage. 8)






@++
Windows 10 x64, PureBasic 5.73 x86 & x64
GPU : radeon HD6370M, CPU : p6200 2.13Ghz
Répondre