Bezier curves Gadget

Share your advanced PureBasic knowledge/code with the community.
zapman*
Enthusiast
Enthusiast
Posts: 115
Joined: Wed Jun 02, 2004 10:17 pm
Location: New Caledonia (South Pacific)
Contact:

Bezier curves Gadget

Post by zapman* »

Code updated For 5.20+

Code: Select all

; Bezier Gadget
; By Zapman


#PaleYellow=255+ (250*256) + (220*256*256)
#PaleBlue  =220+ (255*256) + (255*256*256)
#Violet    =240 + (30*256) + (170*256*256)
#WM_MOUSEWHEEL=522

;
#MaxBPoints = 100
;
Structure BezierPoint
  x.l
  y.l
  t1x.l
  t1y.l
  t2x.l
  t2y.l
EndStructure
;
Dim DBPoints.BezierPoint(#MaxBPoints)
;
Structure BezierArea
  RefNumber.l
  leftP.l
  topP.l
  RightP.l
  BottomP.l
  BPoints.BezierPoint[#MaxBPoints]
  SelectedPoint.l
  OutOfAreaCursor.l
  InsideAreaCursor.l
  MoveCursor.l
  Image.l
  SDrawing.l
  BezierCallBack.l
  TimeType.l
  OnPoint.l
  OnLTangeante.l
  OnRTangeante.l
  SymTangeante.l
  ForgetBS.l
EndStructure

Declare AddBezierPoint (*Area.BezierArea,x,y,t1x,t1y,t2x,t2y)
Declare BezierGadget (NRef,*Area.BezierArea,vleft,vtop,vright,vbottom,TimeType,BezierCallBack)
Declare RedrawBezier (*Area.BezierArea)
Declare BezierCurve(x1,y1,x2,y2,x3,y3,x4,y4,DWide,color)
Declare ManageBezierEvents (*Area.BezierArea,WE)
Declare DestroyBezierGadget (*Area.BezierArea)


;
Procedure BezierCallBack1 (*Area.BezierArea)
  ; modify this procedure or create another one if you want to draw something behind the curve
  Box(0,0,*Area\RightP-*Area\LeftP,*Area\BottomP-*Area\TopP,#PaleYellow)
  Line (0,((*Area\BottomP-*Area\TopP)/2),*Area\RightP-*Area\LeftP,0,#Violet)
EndProcedure
;
;
Procedure BezierCallBack2 (*Area.BezierArea)
  ; modify this procedure or create another one if you want to draw something behind the curve
  Box(0,0,*Area\RightP-*Area\LeftP,*Area\BottomP-*Area\TopP,#PaleBlue)
  Circle(150,100,30,#PaleYellow)
  Circle(350,130,30,255)
EndProcedure

#NoWindow = 1
hwd = OpenWindow(#NoWindow, 0, 0, 510, 510 ,"BezierGadget Demo",  #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_TitleBar| #PB_Window_TitleBar | #PB_Window_ScreenCentered)
If hwd
  ;- Gadget Constants
  
  #WDrawing = 479
  #HDrawing = 188
  
  #THelp      = 2
  #BSaw       = 3
  #BSinus     = 4
  #BRTime     = 5
  #BRNormal   = 6
  #TTitle1    = 7
  #TTitle2    = 8
  
  #Bezier1     = 10
  #Bezier2     = 11
  ;
  
  
  ButtonGadget(#BSaw     ,  13, 225, 70, 20, "Saw")
  ButtonGadget(#BSinus   ,  13, 250, 70, 20, "Sinus")
  OptionGadget(#BRTime   , 183, 225, 70, 20, "Time")
  OptionGadget(#BRNormal , 280, 225, 70, 20, "Normal")
  SetGadgetState (#BRTime,1)
  TimeOrNormal = 1
  
  BezierGadget (#Bezier1,BezierArea1.BezierArea,13,27,#WDrawing+13,#HDrawing+27,TimeOrNormal,@BezierCallBack1())
  tx.s= "Right Button : create/modify tangeantes - MouseWheel : scrolling"
  tx + Chr(13)+ "Use Shift to get symetric tangeantes."
  tx + Chr(13)+ "Move a selected point with the arrows keys."
  tx + Chr(13)+ "<- (backspace) delete a selected point."
  TextGadget(#THelp, 83, #HDrawing+55, #WDrawing, 60, tx, #PB_Text_Center)
  TextGadget(#TTitle1, 13, 5, 80, 20, "Time/Normal")
  TextGadget(#TTitle2, 13, 290, 80, 20, "Normal")
  
  AddBezierPoint (BezierArea1,0,-#HDrawing*1/4,-#WDrawing*1/4,0,#WDrawing*1/4,0)
  AddBezierPoint (BezierArea1,#WDrawing/2,#HDrawing*1/4,-#WDrawing*1/4,0,#WDrawing*1/4,0)
  
  RedrawBezier(BezierArea1)
  
  BezierGadget (#Bezier2,BezierArea2.BezierArea,13,310,#WDrawing+13,#HDrawing+310,0,@BezierCallBack2())
  AddBezierPoint (BezierArea2,#WDrawing/2,-#HDrawing*1/4,-#WDrawing*1/4,0,#WDrawing*1/4,0)
  AddBezierPoint (BezierArea2,#WDrawing/2-150,#HDrawing*1/4,-#WDrawing*1/4,0,#WDrawing*1/4,0)
  AddBezierPoint (BezierArea2,#WDrawing/2+150,-#HDrawing*1/4,0,0,0,0)
  AddBezierPoint (BezierArea2,#WDrawing/2+150,#HDrawing*1/4,0,0,0,0)
  RedrawBezier(BezierArea2)
  
  ;
  QuitWSynthetiser = 0
  cont = 0
  
  Repeat
    Delay(10)
    WE = WindowEvent()
    If EventWindow()<>#NoWindow
      WE = 0
    Else
      ManageBezierEvents (BezierArea1,WE)
      ManageBezierEvents (BezierArea2,WE)
    EndIf
    
    If WE = #PB_Event_CloseWindow
      Quit = 1
    EndIf
    If WE = #PB_Event_Gadget
      
      Select EventGadget()
          
        Case #BSinus
          BHigh = BezierArea1\BottomP-BezierArea1\TopP
          BWide = BezierArea1\RightP -BezierArea1\LeftP
          BezierArea1\BPoints[1]\x=-1
          AddBezierPoint (BezierArea1,0,-BHigh *1/4,-BWide*1/4,0,BWide*1/4,0)
          AddBezierPoint (BezierArea1,BWide/2,BHigh *1/4,-BWide*1/4,0,BWide*1/4,0)
          RedrawBezier (BezierArea1)
        Case #BSaw
          BHigh = BezierArea1\BottomP-BezierArea1\TopP
          BWide = BezierArea1\RightP -BezierArea1\LeftP
          BezierArea1\BPoints[1]\x=-1
          AddBezierPoint (BezierArea1,BWide/2,-BHigh *1/4,0,0,0,0)
          AddBezierPoint (BezierArea1,BWide/2+1,BHigh *1/4,0,0,0,0)
          RedrawBezier (BezierArea1)
        Case #BRTime
          TimeOrNormal = 1
          DestroyBezierGadget (BezierArea1)
          BezierGadget (#Bezier1,BezierArea1,13,27,#WDrawing+13,#HDrawing+27,TimeOrNormal,@BezierCallBack1())
          
          AddBezierPoint (BezierArea1,0,-#HDrawing*1/4,-#WDrawing*1/4,0,#WDrawing*1/4,0)
          AddBezierPoint (BezierArea1,#WDrawing/2,#HDrawing*1/4,-#WDrawing*1/4,0,#WDrawing*1/4,0)
          RedrawBezier (BezierArea1)
        Case #BRNormal
          TimeOrNormal = 0
          DestroyBezierGadget (BezierArea1)
          BezierGadget (#Bezier1,BezierArea1,13,27,#WDrawing+13,#HDrawing+27,TimeOrNormal,@BezierCallBack2())
          
          AddBezierPoint (BezierArea1,#WDrawing/2,-#HDrawing*1/4,-#WDrawing*1/4,0,#WDrawing*1/4,0)
          AddBezierPoint (BezierArea1,#WDrawing/2,#HDrawing*1/4,-#WDrawing*1/4,0,#WDrawing*1/4,0)
          RedrawBezier (BezierArea1)
      EndSelect
    EndIf
    
  Until Quit
  
  CloseWindow(#NoWindow)
EndIf






Procedure AddBezierPoint (*Area.BezierArea,x,y,t1x,t1y,t2x,t2y)
  ct = 1
  While *Area\BPoints[ct]\x<>-1 And ct<#MaxBPoints
    ct + 1
  Wend
  If *Area\BPoints[ct]\x=-1
    *Area\BPoints[ct]\x=x
    *Area\BPoints[ct]\y=y
    *Area\BPoints[ct]\t1x=t1x
    *Area\BPoints[ct]\t1y=t1y
    *Area\BPoints[ct]\t2x=t2x
    *Area\BPoints[ct]\t2y=t2y
    If ct<#MaxBPoints
      *Area\BPoints[ct+1]\x=-1
    EndIf
    *Area\SelectedPoint = x
    result = 1
  Else
    result = 0
  EndIf
  ProcedureReturn result
EndProcedure
;
Procedure BezierGadget (NRef,*Area.BezierArea,vleft,vtop,vright,vbottom,TimeType,BezierCallBack)
  *Area\RefNumber = NRef
  *Area\LeftP = vleft
  *Area\topP    = vtop
  *Area\RightP  = vright
  *Area\BottomP = vbottom
  *Area\BPoints[1]\x=-1
  *Area\SelectedPoint=-1
  *Area\OutOfAreaCursor=LoadCursor_(0, #IDC_ARROW)
  *Area\InsideAreaCursor=LoadCursor_(0, #IDC_CROSS)
  *Area\MoveCursor=LoadCursor_(0, #IDC_SIZEALL)
  *Area\Image = CreateImage(NRef,vright-vleft,vbottom-vtop)
  *Area\SDrawing = ImageGadget(NRef, vleft, vtop, vright-vleft, vbottom-vtop,*Area\Image, #PB_Image_Border)
  *Area\BezierCallBack=BezierCallBack
  *Area\TimeType = TimeType
  *Area\OnPoint = 0
  *Area\OnLTangeante = 0
  *Area\OnRTangeante = 0
  *Area\SymTangeante = 0
  *Area\ForgetBS = 0
  #BViolet    =240 + (30*256) + (170*256*256)
  ProcedureReturn 1
EndProcedure
;
Procedure DestroyBezierGadget (*Area.BezierArea)
  DestroyCursor_(*Area\OutOfAreaCursor)
  DestroyCursor_(*Area\InsideAreaCursor)
  DestroyCursor_(*Area\MoveCursor)
  FreeGadget (NRef)
EndProcedure
;
Procedure BezierCurve(x1,y1,x2,y2,x3,y3,x4,y4,DWide,color)
  ; D'aprés une procédure de Rob, du Robsite German forum
  ; From a procedure of Rob - Robsite German forum
  i.f = 0
  oldx=x1
  oldy=y1
  cx.f=3*x2
  bx.f=3*(x4+x3-x2-x1)-cx
  ax.f=x4-x1-cx-bx
  cy.f=3*y2
  by.f=3*(y4+y3-y2-y1)-cy
  ay.f=y4-y1-cy-by
  While i.f < 1
    i+0.05
    x=((ax*i+bx)*i+cx)*i+x1
    y=((ay*i+by)*i+cy)*i+y1
    If i>0
      If x>DWide
        If oldx<DWide
          LineXY(oldx,oldy,x,y,color)
        EndIf
        xb=x-DWide
        oldxb=oldx-DWide
      Else
        xb=x
        oldxb=oldx
      EndIf
      yb=y
      oldyb=oldy
      If xb<0
        xb=0
      EndIf
      If oldxb<0
        If x<>oldx
          ps=oldxb*(y-oldy)/(x-oldx)
          oldyb=oldyb-ps
        Else
          oldyb=yb
        EndIf
        oldxb=0
      EndIf
      LineXY(oldxb,oldyb,xb,yb,color)
    EndIf 
    oldx=x
    oldy=y
  Wend
EndProcedure
;
Procedure RedrawBezier (*Area.BezierArea)
  change = *Area\TimeType
  While change                ; Sort the array - Trie le tableau
    change = 0
    For ct=1 To #MaxBPoints-1
      If *Area\BPoints[ct+1]\x=-1 Or *Area\BPoints[ct]\x=-1
        If *Area\BPoints[ct]\x=-1 : ctend = ct : Else : ctend = ct+1 : EndIf
        ct=#MaxBPoints
      Else
        If *Area\BPoints[ct+1]\x<*Area\BPoints[ct]\x
          change = 1
          mempoint.BezierPoint\x=*Area\BPoints[ct]\x
          mempoint\y  =*Area\BPoints[ct]\y
          mempoint\t1x=*Area\BPoints[ct]\t1x
          mempoint\t1y=*Area\BPoints[ct]\t1y
          mempoint\t2x=*Area\BPoints[ct]\t2x
          mempoint\t2y=*Area\BPoints[ct]\t2y
          *Area\BPoints[ct]\x  = *Area\BPoints[ct+1]\x
          *Area\BPoints[ct]\y  = *Area\BPoints[ct+1]\y
          *Area\BPoints[ct]\t1x= *Area\BPoints[ct+1]\t1x
          *Area\BPoints[ct]\t1y= *Area\BPoints[ct+1]\t1y
          *Area\BPoints[ct]\t2x= *Area\BPoints[ct+1]\t2x
          *Area\BPoints[ct]\t2y= *Area\BPoints[ct+1]\t2y
          *Area\BPoints[ct+1]\x  = mempoint\x
          *Area\BPoints[ct+1]\y  = mempoint\y
          *Area\BPoints[ct+1]\t1x= mempoint\t1x
          *Area\BPoints[ct+1]\t1y= mempoint\t1y
          *Area\BPoints[ct+1]\t2x= mempoint\t2x
          *Area\BPoints[ct+1]\t2y= mempoint\t2y
          If *Area\SelectedPoint = ct
            *Area\SelectedPoint = ct + 1
            *Area\OnPoint = ct + 1
            *Area\OnLTangeante = ct + 1
            *Area\OnRTangeante = ct + 1
          Else
            If *Area\SelectedPoint = ct+1
              *Area\SelectedPoint = ct
              *Area\OnPoint = ct
              *Area\OnLTangeante = ct
              *Area\OnRTangeante = ct
            EndIf
          EndIf
        EndIf
      EndIf
    Next
  Wend
  DWide = *Area\RightP-*Area\LeftP
  DHigh = *Area\BottomP-*Area\TopP
  If *Area\TimeType
    For ct=1 To #MaxBPoints-1 ; limit tangeantes lenght
      If *Area\BPoints[ct]\x<>-1
        If ct>1
          If *Area\BPoints[ct]\t1x+*Area\BPoints[ct]\x<*Area\BPoints[ct-1]\x
            *Area\BPoints[ct]\t1x=*Area\BPoints[ct-1]\x-*Area\BPoints[ct]\x
          EndIf
        Else
          If *Area\BPoints[1]\t1x+*Area\BPoints[1]\x<*Area\BPoints[ctend-1]\x-DWide
            *Area\BPoints[1]\t1x=*Area\BPoints[ctend-1]\x-DWide -*Area\BPoints[1]\x
          EndIf
        EndIf
        If *Area\BPoints[ct+1]\x<>-1
          If *Area\BPoints[ct]\t2x+*Area\BPoints[ct]\x>*Area\BPoints[ct+1]\x
            *Area\BPoints[ct]\t2x=*Area\BPoints[ct+1]\x-*Area\BPoints[ct]\x
          EndIf
        Else
          If *Area\BPoints[ct]\t2x+*Area\BPoints[ct]\x>*Area\BPoints[1]\x+DWide
            *Area\BPoints[ct]\t2x=*Area\BPoints[1]\x+DWide -*Area\BPoints[ct]\x
          EndIf
          ct=#MaxBPoints
        EndIf
      EndIf
    Next
  EndIf
  
  StartDrawing(ImageOutput(*Area\RefNumber))
  If *Area\BezierCallBack
    CallFunctionFast(*Area\BezierCallBack,*Area)
  Else
    Box(0,0,*Area\RightP-*Area\LeftP,*Area\BottomP-*Area\TopP,#White)
  EndIf
  For ct=1 To #MaxBPoints
    If *Area\BPoints[ct]\x=-1
      ctend=ct-1
      ct=#MaxBPoints
    Else
      If ct=*Area\SelectedPoint
        DrawingMode(0)
      Else
        DrawingMode(4)
      EndIf
      Box(*Area\BPoints[ct]\x-2,*Area\BPoints[ct]\y+(DHigh/2)-2,5,5,0)
      If *Area\BPoints[ct]\t1x Or *Area\BPoints[ct]\t1y
        DrawingMode(4)
        Circle (*Area\BPoints[ct]\x+*Area\BPoints[ct]\t1x,*Area\BPoints[ct]\y+*Area\BPoints[ct]\t1y+(DHigh/2),3,#Red)
        xt = *Area\BPoints[ct]\x+*Area\BPoints[ct]\t1x
        yt = *Area\BPoints[ct]\y+*Area\BPoints[ct]\t1y+(DHigh/2)
        If xt<0
          ps=xt**Area\BPoints[ct]\t1y/(*Area\BPoints[ct]\x-xt)
          yt=yt+ps
          xt=0
        EndIf
        LineXY(*Area\BPoints[ct]\x,*Area\BPoints[ct]\y+(DHigh/2),xt,yt,#BViolet)
      EndIf
      If *Area\BPoints[ct]\t2x Or *Area\BPoints[ct]\t2y
        DrawingMode(4)
        Circle (*Area\BPoints[ct]\x+*Area\BPoints[ct]\t2x,*Area\BPoints[ct]\y+*Area\BPoints[ct]\t2y+(DHigh/2),3,#Red)
        LineXY(*Area\BPoints[ct]\x,*Area\BPoints[ct]\y+(DHigh/2),*Area\BPoints[ct]\x+*Area\BPoints[ct]\t2x,*Area\BPoints[ct]\y+*Area\BPoints[ct]\t2y+(DHigh/2),#BViolet)
      EndIf
      If ct>1
        BezierCurve(*Area\BPoints[ct-1]\x,*Area\BPoints[ct-1]\y+(DHigh/2),*Area\BPoints[ct-1]\t2x,*Area\BPoints[ct-1]\t2y,*Area\BPoints[ct]\t1x,*Area\BPoints[ct]\t1y,*Area\BPoints[ct]\x,*Area\BPoints[ct]\y+(DHigh/2),DWide,0)
      EndIf
    EndIf
  Next
  If ctend And *Area\TimeType
    BezierCurve(*Area\BPoints[ctend]\x,*Area\BPoints[ctend]\y+(DHigh/2),*Area\BPoints[ctend]\t2x,*Area\BPoints[ctend]\t2y,*Area\BPoints[1]\t1x,*Area\BPoints[1]\t1y,*Area\BPoints[1]\x+DWide,*Area\BPoints[1]\y+(DHigh/2),DWide,0)
  EndIf
  StopDrawing()
  SetGadgetState(*Area\RefNumber, ImageID(*Area\RefNumber))
EndProcedure
;
Procedure ManageBezierEvents (*Area.BezierArea,WE)
  GetCursorPos_(@MP.Point)
  MP\x = MP\x-2
  MP\y = MP\y-2
  GetWindowRect_(*Area\SDrawing,@re.RECT)
  BHigh = *Area\BottomP-*Area\TopP
  BWide = *Area\RightP -*Area\LeftP
  re\right  =re\left  + BWide
  re\bottom =re\top   + BHigh
  If PtInRect_(re,@MP)
    MO = 1
  Else
    MO = 0
  EndIf
  MP\x = MP\x - re\left
  MP\y = MP\y - re\top
  If GetAsyncKeyState_(#VK_LBUTTON) Or GetAsyncKeyState_(#VK_RBUTTON)
    If GetAsyncKeyState_(#VK_LBUTTON) And GetAsyncKeyState_(#VK_CONTROL)=0
      LBUTTONDOWN = 1
      RBUTTONDOWN = 0
    Else
      RBUTTONDOWN = 1
    EndIf
    If MO
      *Area\ForgetBS = 0
    Else
      *Area\ForgetBS = 1
    EndIf
  Else
    RBUTTONDOWN = 0
    LBUTTONDOWN = 0
    *Area\OnPoint = 0
    *Area\OnLTangeante = 0
    *Area\OnRTangeante = 0
    *Area\SymTangeante = 0
  EndIf
  ;
  mp\y=mp\y-(BHigh /2)
  ;
  If MO
    NCurs = *Area\InsideAreaCursor
    ct = 0
    If *Area\OnPoint=0 And *Area\OnLTangeante=0 And *Area\OnRTangeante=0
      While *Area\BPoints[ct]\x<>-1 And ct<#MaxBPoints
        If Abs(mp\x-*Area\BPoints[ct]\x)<5 And Abs(mp\y-*Area\BPoints[ct]\y)<5
          NCurs = *Area\MoveCursor
          If LBUTTONDOWN
            *Area\OnPoint = ct
          ElseIf RBUTTONDOWN
            *Area\OnLTangeante = ct ; will reset the both tangeantes to zero
            *Area\OnRTangeante = ct
          EndIf
        EndIf
        If Abs(mp\x-(*Area\BPoints[ct]\x+*Area\BPoints[ct]\t1x))<5 And Abs(mp\y-(*Area\BPoints[ct]\y+*Area\BPoints[ct]\t1y))<5
          NCurs = *Area\MoveCursor
          If LBUTTONDOWN Or RBUTTONDOWN
            *Area\OnLTangeante = ct
          EndIf
        EndIf
        If Abs(mp\x-(*Area\BPoints[ct]\x+*Area\BPoints[ct]\t2x))<5 And Abs(mp\y-(*Area\BPoints[ct]\y+*Area\BPoints[ct]\t2y))<5
          NCurs = *Area\MoveCursor
          If LBUTTONDOWN Or RBUTTONDOWN
            *Area\OnRTangeante = ct
          EndIf
        EndIf
        ct + 1
      Wend
    EndIf
    If *Area\OnPoint Or *Area\OnLTangeante Or *Area\OnRTangeante
      If *Area\OnLTangeante = *Area\OnRTangeante
        *Area\SymTangeante = 1
        If mp\x>*Area\BPoints[*Area\OnLTangeante]\x+*Area\BPoints[*Area\OnLTangeante]\t1x
          *Area\OnLTangeante = 0
        Else
          *Area\OnRTangeante = 0
        EndIf
      EndIf
      If *Area\TimeType
        If *Area\OnLTangeante And mp\x>*Area\BPoints[*Area\OnLTangeante]\x
          *Area\OnRTangeante = *Area\OnLTangeante
          *Area\OnLTangeante = 0
        EndIf
        If *Area\OnRTangeante And mp\x<*Area\BPoints[*Area\OnRTangeante]\x
          *Area\OnLTangeante = *Area\OnRTangeante
          *Area\OnRTangeante = 0
        EndIf
      EndIf
      If *Area\OnPoint
        *Area\BPoints[*Area\OnPoint]\x=mp\x
        *Area\BPoints[*Area\OnPoint]\y=mp\y
        *Area\SelectedPoint = *Area\OnPoint
        RedrawBezier (*Area)
      ElseIf *Area\OnLTangeante
        *Area\BPoints[*Area\OnLTangeante]\t1x=mp\x-*Area\BPoints[*Area\OnLTangeante]\x
        *Area\BPoints[*Area\OnLTangeante]\t1y=mp\y-*Area\BPoints[*Area\OnLTangeante]\y
        If *Area\SymTangeante Or GetAsyncKeyState_(#VK_SHIFT)
          *Area\BPoints[*Area\OnLTangeante]\t2x=-*Area\BPoints[*Area\OnLTangeante]\t1x
          *Area\BPoints[*Area\OnLTangeante]\t2y=-*Area\BPoints[*Area\OnLTangeante]\t1y
        EndIf
        *Area\SelectedPoint = OnLTangeante
        RedrawBezier (*Area)
      ElseIf *Area\OnRTangeante
        *Area\BPoints[*Area\OnRTangeante ]\t2x=mp\x-*Area\BPoints[*Area\OnRTangeante ]\x
        *Area\BPoints[*Area\OnRTangeante ]\t2y=mp\y-*Area\BPoints[*Area\OnRTangeante ]\y
        If *Area\SymTangeante Or GetAsyncKeyState_(#VK_SHIFT)
          *Area\BPoints[*Area\OnRTangeante]\t1x=-*Area\BPoints[*Area\OnRTangeante]\t2x
          *Area\BPoints[*Area\OnRTangeante]\t1y=-*Area\BPoints[*Area\OnRTangeante]\t2y
        EndIf
        *Area\SelectedPoint = *Area\OnRTangeante
        RedrawBezier (*Area)
      EndIf
    Else
      If (LBUTTONDOWN Or RBUTTONDOWN)
        ct = 0
        While *Area\BPoints[ct]\x<>-1 And ct<#MaxBPoints : ct+1 : Wend
        If *Area\BPoints[ct]\x=-1
          NCurs = *Area\MoveCursor
          *Area\BPoints[ct]\x=mp\x
          *Area\BPoints[ct]\y=mp\y
          *Area\BPoints[ct]\t1x=0
          *Area\BPoints[ct]\t1y=0
          *Area\BPoints[ct]\t2x=0
          *Area\BPoints[ct]\t2y=0
          *Area\SelectedPoint = ct
          If LBUTTONDOWN
            *Area\OnPoint = ct
          Else
            *Area\OnLTangeante = ct
            *Area\OnRTangeante = ct
          EndIf
          If ct<#MaxBPoints
            *Area\BPoints[ct+1]\x=-1
          EndIf
          RedrawBezier (*Area)
        EndIf
      EndIf
    EndIf
  Else
    NCurs = *Area\OutOfAreaCursor
  EndIf
  If NCurs<>*Area\OutOfAreaCursor
    SetCursor_(NCurs)
  EndIf
  ;
  If WE = #WM_MOUSEWHEEL And *Area\TimeType And *Area\ForgetBS=0
    s.l=-(EventwParam() >> 16)/20
    For ct=1 To #MaxBPoints-1
      If *Area\BPoints[ct]\x=-1
        ct=#MaxBPoints
      Else
        mx = *Area\BPoints[ct]\x
        *Area\BPoints[ct]\x=*Area\BPoints[ct]\x+s
        If *Area\BPoints[ct]\x<0
          *Area\BPoints[ct]\x=*Area\BPoints[ct]\x+BWide
        EndIf
        If *Area\BPoints[ct]\x>BWide
          *Area\BPoints[ct]\x=*Area\BPoints[ct]\x-BWide
        EndIf
      EndIf
    Next
    RedrawBezier (*Area)
  EndIf
  If WE = #WM_KEYDOWN
    ; Shortcuts - Gestion des touches rapides flèches et Backspace
    If *Area\ForgetBS=0 And *Area\SelectedPoint>-1
      If GetAsyncKeyState_(#VK_UP)
        *Area\BPoints[*Area\SelectedPoint]\y-1
        If *Area\BPoints[*Area\SelectedPoint]\y<(-BHigh/2+1)
          *Area\BPoints[*Area\SelectedPoint]\y = -BHigh/2
        EndIf
        RedrawBezier(*Area)
      EndIf
      If GetAsyncKeyState_(#VK_DOWN)
        *Area\BPoints[*Area\SelectedPoint]\y+1
        If *Area\BPoints[*Area\SelectedPoint]\y>(BHigh/2-1)
          *Area\BPoints[*Area\SelectedPoint]\y = BHigh/2
        EndIf
        RedrawBezier(*Area)
      EndIf
      If GetAsyncKeyState_(#VK_RIGHT)
        *Area\BPoints[*Area\SelectedPoint]\x+1
        If *Area\BPoints[*Area\SelectedPoint]\x>(BWide-1)
          *Area\BPoints[*Area\SelectedPoint]\x =BWide
        EndIf
        RedrawBezier(*Area)
      EndIf
      If GetAsyncKeyState_(#VK_LEFT)
        *Area\BPoints[*Area\SelectedPoint]\x-1
        If *Area\BPoints[*Area\SelectedPoint]\x<1
          *Area\BPoints[*Area\SelectedPoint]\x = 0
        EndIf
        RedrawBezier(*Area)
      EndIf
      If GetAsyncKeyState_(#VK_BACK) Or GetAsyncKeyState_(#VK_CLEAR)
        ;- ClearPoint
        For ct=*Area\SelectedPoint To #MaxBPoints-1
          If ct >1 Or *Area\TimeType=0 Or *Area\BPoints[ct+1]\x>0
            *Area\BPoints[ct]\x=*Area\BPoints[ct+1]\x
            *Area\BPoints[ct]\y=*Area\BPoints[ct+1]\y
            *Area\BPoints[ct]\t1x=*Area\BPoints[ct+1]\t1x
            *Area\BPoints[ct]\t1y=*Area\BPoints[ct+1]\t1y
            *Area\BPoints[ct]\t2x=*Area\BPoints[ct+1]\t2x
            *Area\BPoints[ct]\t2y=*Area\BPoints[ct+1]\t2y
            If *Area\BPoints[ct]\x=-1
              ct = #MaxBPoints
            EndIf
          EndIf
        Next
        RedrawBezier(*Area)
      EndIf
    EndIf
  EndIf
EndProcedure



; BONUS : Get Y from X. This is usable (and makes sens) only with "Time Bezier" curves

Procedure CalcYFromXTimeBezier(xr,*area.BezierArea)
  DWide = *Area\RightP-*Area\LeftP
  DHigh = *Area\BottomP-*Area\TopP
  If *Area\BPoints[1]\x<>-1 And xr>-1 And xr<(DWide+1)
    For ct=1 To #MaxBPoints
      If *Area\BPoints[ct+1]\x=-1
        xend=*Area\BPoints[ct]\x
        ctend = ct
        ct = #MaxBPoints
      EndIf
    Next
    ct = 1
    While *Area\BPoints[ct]\x<xr And ct<ctend : ct + 1 : Wend
    If ct = 1
      ctd = ctend
      ctf = ct
    ElseIf *Area\BPoints[ct]\x<xr
      ctd = ctend
      ctf = 1
    Else
      ctd = ct-1
      ctf = ct
    EndIf
    x1 = *Area\BPoints[ctd]\x
    y1 = *Area\BPoints[ctd]\y+(DHigh/2)
    x2 = *Area\BPoints[ctd]\t2x
    y2 = *Area\BPoints[ctd]\t2y
    x3 = *Area\BPoints[ctf]\t1x
    y3 = *Area\BPoints[ctf]\t1y
    x4 = *Area\BPoints[ctf]\x
    y4 = *Area\BPoints[ctf]\y+(DHigh/2)
    If ct = 1
      x1 = DWide - x1
    ElseIf *Area\BPoints[ct]\x<xr
      x4 + DWide
    EndIf
    cx.f=3*x2
    bx.f=3*(x4+x3-x2-x1)-cx
    ax.f=x4-x1-cx-bx
    cy.f=3*y2
    by.f=3*(y4+y3-y2-y1)-cy
    ay.f=y4-y1-cy-by
    lowlim.f=0
    Highlim.f = 1
    cont = 1
    While cont
      i.f=(Highlim-lowlim)/2+lowlim
      x=((ax*i+bx)*i+cx)*i+x1
      If xr>x
        lowlim=i
      ElseIf xr<x
        Highlim=i
      Else
        cont = 0
        y=((ay*i+by)*i+cy)*i+y1
      EndIf
    Wend
    ProcedureReturn y
  EndIf
EndProcedure
Don't try - DO it !
User avatar
J. Baker
Addict
Addict
Posts: 2188
Joined: Sun Apr 27, 2003 8:12 am
Location: USA
Contact:

Post by J. Baker »

Nice work zapman! :D Do you have plans for this?
www.posemotion.com

PureBasic Tools for OS X: PureMonitor, plist Tool, Data Maker & App Chef


Even the vine knows it surroundings but the man with eyes does not.
GreenGiant
Enthusiast
Enthusiast
Posts: 252
Joined: Fri Feb 20, 2004 5:43 pm

Post by GreenGiant »

Wow, I'd been looking at some curve routines, but this is a lot more impressive than anything I'd got working. Nice going.
zapman*
Enthusiast
Enthusiast
Posts: 115
Joined: Wed Jun 02, 2004 10:17 pm
Location: New Caledonia (South Pacific)
Contact:

Post by zapman* »

J. Baker wrote:Nice work zapman! :D Do you have plans for this?
Yes. It will be included in SoundEditor and will be used to manage, for exemple, sound modulation (freq./volume, etc...)
Don't try - DO it !
User avatar
NoahPhense
Addict
Addict
Posts: 1999
Joined: Thu Oct 16, 2003 8:30 pm
Location: North Florida

Re: Bezier curves Gadget

Post by NoahPhense »

Wow.. thats freakin sweet.. nice work!

- np
User avatar
eddy
Addict
Addict
Posts: 1479
Joined: Mon May 26, 2003 3:07 pm
Location: Nantes

Post by eddy »

wow !

Math or not math that is the question 8O
Imagewin10 x64 5.72 | IDE | PB plugin | Tools | Sprite | JSON | visual tool
Dare2
Moderator
Moderator
Posts: 3321
Joined: Sat Dec 27, 2003 3:55 am
Location: Great Southern Land

Post by Dare2 »

Floored. 8O
@}--`--,-- A rose by any other name ..
Fred
Administrator
Administrator
Posts: 18254
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Post by Fred »

Nice piece of code.
Post Reply