Interpolation cubique (courbe bézier...)

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Interpolation cubique (courbe bézier...)

Message par blendman »

Salut

J'essaie de créer une sorte de ribon effect en 2D (pour arkeos), pour plusieurs trucs (notamment un truc lié à la souris ^^).
Je crée des points à la volée, de la même manière que pour l'interpolation d'une courbe d'une application graphique.

Donc, j'ai cherché des infos sur l'interpolation (cubique, catmull...), afin d'avoir une courbe plus "smoothée". J'ai trouvé quelques exemples fort sympathiques, mais je n'arrive pas à les adapter à ce que j'essaie de faire.

Pour faire simple, j'ai repris le code du canvas gadget, en lui ajoutant la liaison entre les points pour tracer un "pseudo" trait (je vais faire pareil avec mes sprites3D), mais là, le code est complet, fonctionnel est compact, donc c'est plus simple :D.

Est-ce que vous auriez une idée ou une piste pour "lisser" la courbe que l'on dessine ?
Merci :)

Code : Tout sélectionner

#IMAGE_Content =0

Enumeration
  #GADGET_Canvas
  #GADGET_Brush
  #GADGET_Clear 
EndEnumeration

Global Pas = 2,MouseX_Old,MouseY_Old

; Draw the mouse action result depending on the currently selected mode and event type
Macro point_distance(x1,y1,x2,y2)   
  Int(Sqr((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)) )        
EndMacro
Macro point_direction(x1,y1,x2,y2)
  ATan2((y2- y1),(x2- x1))
EndMacro

Procedure DrawBrush(x1,y1)
  x2 = MouseX_Old
  y2 = MouseY_Old
  flech = point_distance(x1,y1,x2,y2)
  d.d = point_direction(x1,y1,x2,y2)
  
  For i = 1 To flech    
    i+pas
    x_result = x1 + Sin(d) *i
    y_result = y1 + Cos(d) *i
    Circle(x_result,y_result,3,0)
    ;DrawImage(ImageID(#IMAGE_Brush),x_result-brush\size/2,y_result-brush\size/2)
  Next i
EndProcedure

Procedure DrawAction(x, y, EventType)
  If StartDrawing(CanvasOutput(#GADGET_Canvas))
    If EventType = #PB_EventType_LeftButtonDown Or EventType = #PB_EventType_MouseMove
      DrawBrush(x,y)
    EndIf
    StopDrawing()
  EndIf
EndProcedure

CreateImage(#IMAGE_Content, 380, 380, 24)

If OpenWindow(0, 0, 0, 800, 600, "Interpolation", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  CanvasGadget(#GADGET_Canvas, 10, 10, WindowWidth(0)-80, WindowHeight(0)-20, #PB_Canvas_ClipMouse)
  ButtonGadget(#GADGET_Clear,  WindowWidth(0)-60, 100, 50, 25, "Clear")
  SetGadgetAttribute(#GADGET_Canvas, #PB_Canvas_Cursor, #PB_Cursor_Cross)
  
  Repeat
    Event = WaitWindowEvent()
    
    If Event = #PB_Event_Gadget
      
      Select EventGadget()
          
        Case #GADGET_Canvas
          X = GetGadgetAttribute(#GADGET_Canvas, #PB_Canvas_MouseX)
          Y = GetGadgetAttribute(#GADGET_Canvas, #PB_Canvas_MouseY)
          Type = EventType()
          
          Select EventType()
              
            Case #PB_EventType_LeftButtonDown
              If StartDrawing(ImageOutput(#IMAGE_Content))
                DrawImage(GetGadgetAttribute(#GADGET_Canvas, #PB_Canvas_Image), 0, 0)
                StopDrawing()
              EndIf
              
              MouseY_Old = y
              MouseX_Old = x
              DrawAction(X, Y, EventType())
              
              
            Case #PB_EventType_LeftButtonUp
              DrawAction(X, Y, EventType())                        
              
            Case #PB_EventType_MouseMove
              If GetGadgetAttribute(#GADGET_Canvas, #PB_Canvas_Buttons) & #PB_Canvas_LeftButton
                DrawAction(X, Y, EventType()) 
                MouseY_Old = y
                MouseX_Old = x
              EndIf
              
          EndSelect
          
        Case #GADGET_Clear
          If StartDrawing(CanvasOutput(#GADGET_Canvas))
            Box(0, 0, GadgetWidth(#GADGET_Canvas), GadgetHeight(#GADGET_Canvas), $FFFFFF)
            StopDrawing()
          EndIf
          
          
      EndSelect
      
    EndIf
    
  Until Event = #PB_Event_CloseWindow

EndIf
Mesa
Messages : 1126
Inscription : mer. 14/sept./2011 16:59

Re: Interpolation cubique (courbe bézier...)

Message par Mesa »

L'antialiasing peut être une réponse.

Ici http://forum.purebasic.com/english/view ... d03013d3ce

Il y a un exemple multiplateforme qui élimine les pixels en trop mais c'est assez lent. Il faudrait optimiser les calculs. Il y a d'autres exemples plus rapides avec gdi+ mais spécifique à Windows.

Je pense que tu dois connaître ça : http://purebasic.fr/english/viewtopic.php?f=12&t=46987

[Edit] Il y a un autre calcul "manuel" d'antialiasing dans ce code
http://pastebin.com/Ezs6qdKX

Mesa.
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: Interpolation cubique (courbe bézier...)

Message par blendman »

ah, je crois que je me suis mal exprimé ^^.

En fait, ce n'est pas de l'antialiasing que je cherche à faire, mais à lisser la courbe obtenue (car ça doit être valide sur une iamge / un canvas, mais aussi avec des sprites :)).

En gros, moi, j'obtiens ce qui est à gauche (avec des sprites 3D mais c'est pareil qu'un tracé dans un soft de dessin en fait) et je voudrais "lisser" ça avec une courbe type béizer/catmull/lagranfe, etc.. :

Image
(sur la droite c'est fait vite fait en dessinant au dessus mais on comprend l'idée comme ça :))

J'ai trouvé plusieurs codes pour ça (Comtois, cpl Bator, etc..). Mais je n'arrive pas à les adapter au mien ^^ (pour le moment).

Merci :)

EDIT :
et dans le jeu, je pourrais avoir ce genre de choses avec cette technique :
Image

Comme je disais, j'ai déjà trouvé quelques codes qui fonctionnent, mais j'ai aussi besoin du principe des courbes de bézier (ou autre) avec manipulation de la souris, pour faire des effets à la volée (avec la souris ou autre chose) :)
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Interpolation cubique (courbe bézier...)

Message par graph100 »

j'ai un code avec des courbes de bezier. mais je n'ai pas fait d'exemple. donc c'est peut etre moins facile à comprendre.
Je vais essayer de faire un truc clair
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Interpolation cubique (courbe bézier...)

Message par graph100 »

Bon, je poste ce que j'ai sur les courbes de bezier, c'est a mon avis ce que tu cherches, mais toi tu ne veux pas dessiner la courbe, juste avoir les coordonées des points.
Faudra que tu examines la procédure Bezier_recursive() pour cela

1er include : (je ne sais plus pourquoi j'avais fait ca mais bon.. c'est fait)

Code : Tout sélectionner

;{ JR_list ( permet de créer des listes chainées et de les modifier comme on le veut )
; ## module dépendance : none

Procedure JR_Create_linkedlist(taille_type); utiliser la commande SizeOf(type) pour obtenir taille_type
  list_head = AllocateMemory(4 * 5)
  
  PokeL(list_head + 16, taille_type)
  
  ; description de la tete de liste
  
  ; +0 : taille de la liste
  ; +4 : adresse du premier element
  ; +8 : adresse du dernier element
  ; +12 : adresse de l'element courant
  ; +16 : taille des elements de la liste
  
  ; description d'un element
  
  ; +0 : element precedent
  ; +4 : element suivant
  ; +8 : debut des données
  
  ProcedureReturn list_head
EndProcedure

Procedure JR_Add_element(JR_list_id.l) ; ajoute un element en fin de liste et cet element devient celui en cours
  new_element = AllocateMemory(PeekL(JR_list_id + 16) + 8)
  
  ancien_dernier_element = PeekL(JR_list_id + 8)
  
  If PeekL(JR_list_id)
    PokeL(JR_list_id, PeekL(JR_list_id) + 1) ; nb element
    
    PokeL(ancien_dernier_element + 4, new_element) ; mise a jour de l'ancien denier element
    
    PokeL(new_element, ancien_dernier_element) ; adresse de l'element precedent
  Else
    PokeL(JR_list_id, 1) ; nb element
    PokeL(JR_list_id + 4, new_element) ; premier element
    
  EndIf
  
  PokeL(JR_list_id + 8, new_element) ; dernier element
  PokeL(JR_list_id + 12, new_element) ; element courant
EndProcedure

Procedure JR_Select_element(JR_list_id.l, num.l, option.l = 0) ; si option = 1 : l'element courant ne change pas, la fonction retourne l'adresse de l'element à la position num
  nb_elem = PeekL(JR_list_id)
  
  If num > nb_elem Or num < 1: ProcedureReturn 0 : EndIf
  
  dist_first = num - 1
  dist_last = nb_elem - num
  
  If dist_first < dist_last
    adresse = PeekL(JR_list_id + 4)
    
    delta = dist_first
  Else
    adresse = PeekL(JR_list_id + 8)
    
    delta = -dist_last
  EndIf
  
  If delta < 0 : ad = 0 : EndIf
  If delta > 0 : ad = 4 : EndIf
  
  For a = 1 To Abs(delta)
    adresse = PeekL(adresse + ad)
  Next
  
  PokeL(JR_list_id + 12, adresse)
  
  ProcedureReturn adresse
EndProcedure

Procedure JR_Next_element(JR_list_id.l) ; retourne l'adresse de l'élément suivant, et le change en element courant
  adresse_current = PeekL(JR_list_id + 12)
  
  If adresse_current
    If PeekL(adresse_current + 4)
      PokeL(JR_list_id + 12, PeekL(adresse_current + 4))
      
      ProcedureReturn JR_list_id
    EndIf
  Else
    PokeL(JR_list_id + 12, PeekL(JR_list_id + 4))
    
    ProcedureReturn JR_list_id
  EndIf
  
EndProcedure

Procedure JR_Previous_element(JR_list_id.l) ; retourne l'adresse de l'élément précedent, et le change en element courant
  adresse_current = PeekL(JR_list_id + 12)
  
  If adresse_current
    If PeekL(adresse_current)
      PokeL(JR_list_id + 12, PeekL(adresse_current))
      
      ProcedureReturn JR_list_id
    EndIf
  EndIf
  
EndProcedure

Procedure JR_Current_element(JR_list_id.l) ; retourne l'adresse de l'element courant
	ProcedureReturn PeekL(JR_list_id + 12)
EndProcedure

Procedure JR_Set_element(JR_list_id.l, *donne.l, offset.l, taille) ; offset est le decalage de copy (à utilser avec precaution) , taille est la taille des donne a copier (mettre 0 pour taille de la liste)
  ; permet de définir la valeur de l'element courant à partir d'une variable quelconque
  ; (pas d'un résultat direct)
  ; faire attention avec les variables structurées, toute la structure est nécessaire
  
  element = PeekL(JR_list_id + 12)
  
  If element
    If taille
      CopyMemory(*donne, element + 8 + offset, taille)
    Else
      CopyMemory(*donne, element + 8 + offset, PeekL(JR_list_id + 16))
    EndIf
    
    ProcedureReturn JR_list_id
  EndIf
  
EndProcedure

Procedure JR_Get_element(JR_list_id.l, *variable.l) ; copie les données en mémoire dans la variable (de la bonne structure !!!!) d'adresse *variable
  element = PeekL(JR_list_id + 12)
  
  If element
    CopyMemory(element + 8, *variable, PeekL(JR_list_id + 16))
    
    ProcedureReturn JR_list_id
  EndIf
  
EndProcedure

Procedure JR_Delete_element(JR_list_id.l, toujour_un_element.l = 0) ; efface l'élement courant et place l'element précedant en courant
  element = PeekL(JR_list_id + 12)
  
  If element
    previous_element = PeekL(element)
    next_element = PeekL(element + 4)
    
    If previous_element
      PokeL(previous_element + 4, next_element)
      
      PokeL(JR_list_id + 12, previous_element)
    ElseIf toujour_un_element
      PokeL(JR_list_id + 12, next_element)
      
      PokeL(JR_list_id + 4, Next_element)
    Else
      PokeL(JR_list_id + 4, Next_element)
    EndIf
    
    If next_element
      PokeL(next_element, previous_element)
    Else
      PokeL(JR_list_id + 8, previous_element)
    EndIf
    
    PokeL(JR_list_id, PeekL(JR_list_id) - 1)
    
    FreeMemory(element)
  EndIf
EndProcedure

Procedure JR_Delete_linkedlist(JR_list_id.l) ; Efface la liste et libère les ressources en mémoire
  last_element = PeekL(JR_list_id + 8)
  
  If last_element
    Repeat
      previous_element = PeekL(last_element)
      
      FreeMemory(last_element)
      last_element = previous_element
    Until previous_element
  EndIf
  
  FreeMemory(JR_list_id)
EndProcedure

Procedure JR_Reset_linkedlist(JR_list_id.l) ; place l'element courant avant le premier element de la liste
  PokeL(JR_list_id + 12, 0)
EndProcedure

Procedure JR_Change_Current_element(JR_list_id.l, *adresse_element.l) ; l'élement courant deviens celui pointé par *adresse_element
  PokeL(JR_list_id + 12, *adresse_element)
EndProcedure

Procedure JR_Count_element(JR_list_id.l) ; retourne le nombre d'element de la list
  ProcedureReturn PeekL(JR_list_id)
EndProcedure

Procedure JR_Swap_element(JR_list_id, num1.l, num2.l) ; échange deux elements
  nb_elem = PeekL(JR_list_id)
  
  If num1 = num2 Or num1 > nb_elem Or num1 < 1 Or num2 > nb_elem Or num2 < 1 : ProcedureReturn 0 : EndIf
  
  element1 = JR_Select_element(JR_list_id, num1, 1)
  p1 = PeekL(element1)
  n1 = PeekL(element1 + 4)
  
  element2 = JR_Select_element(JR_list_id, num2, 1)
  p2 = PeekL(element2)
  n2 = PeekL(element2 + 4)
  
  If num1 - num2 = 1
    If num2 > 1
      PokeL(p2 + 4, element1)
    EndIf
    
    PokeL(element1, p2)
    PokeL(element1 + 4, element2)
    
    PokeL(element2, element1)
    PokeL(element2 + 4, n1)
    
    If num1 < nb_elem
      PokeL(n1, element2)
    EndIf
  ElseIf num2 - num1 = 1
    If num1 > 1
      PokeL(p1 + 4, element2)
    EndIf
    
    PokeL(element2, p1)
    PokeL(element2 + 4, element1)
    
    PokeL(element1, element2)
    PokeL(element1 + 4, n2)
    
    If num2 < nb_elem
      PokeL(n2, element1)
    EndIf
  Else
    If num1 > 1
      PokeL(p1 + 4, element2)
    EndIf
    If num1 < nb_elem
      PokeL(n1, element2)
    EndIf
    
    PokeL(element2, p1)
    PokeL(element2 + 4, n1)
    
    PokeL(element1, p2)
    PokeL(element1 + 4, n2)
    
    If num2 > 1
      PokeL(p2 + 4, element1)
    EndIf
    If num2 < nb_elem
      PokeL(n2, element1)
    EndIf
  EndIf
  
  If num1 = 1
    PokeL(JR_list_id + 4, element2)
  EndIf
  If num2 = 1
    PokeL(JR_list_id + 4, element1)
  EndIf
  If num1 = nb_elem
    PokeL(JR_list_id + 8, element2)
  EndIf
  If num2 = nb_elem
    PokeL(JR_list_id + 8, element1)
  EndIf
  
  ProcedureReturn JR_list_id
EndProcedure

Procedure JR_Move_element(JR_list_id, num1.l, nouvelle_position.l); deplace un element
  nb_elem = PeekL(JR_list_id)
  
  If num1 = nouvelle_position Or num1 > nb_elem Or num1 < 1 Or nouvelle_position > nb_elem Or nouvelle_position < 1 : ProcedureReturn 0 : EndIf
  
  element1 = JR_Select_element(JR_list_id, num1, 1)
  p1 = PeekL(element1)
  n1 = PeekL(element1 + 4)
  
  element2 = JR_Select_element(JR_list_id, nouvelle_position, 1)
  p2 = PeekL(element2)
  n2 = PeekL(element2 + 4)
  
  If num1 < nouvelle_position
    PokeL(element1, element2)
    PokeL(element1 + 4, n2)
    
    If num1 > 1
      PokeL(p1 + 4, n1)
    EndIf
    
    If num1 < nb_elem
      PokeL(n1, p1)
    EndIf
    
    PokeL(element2 + 4, element1)
    PokeL(n2, element1)
  Else
    PokeL(element1, p2)
    PokeL(element1 + 4, element2)
    
    If num1 > 1
      PokeL(p1 + 4, n1)
    EndIf
    
    If num1 < nb_elem
      PokeL(n1, p1)
    EndIf
    
    PokeL(element2, element1)
    PokeL(p2 + 4, element1)
  EndIf
  
  ProcedureReturn JR_list_id
EndProcedure

Procedure JR_Copy_Linkelist(JR_list_id.l)
  new = JR_Create_linkedlist(PeekL(JR_list_id + 16))
  
  If new
    nb = JR_Count_element(JR_list_id)
    
    ad = PeekL(JR_list_id + 4)
    
    For a = 1 To nb
      JR_Add_element(new)
      
      JR_Set_element(new, ad + 8, 0, 0)
      
      ad = PeekL(ad + 4)
    Next
  EndIf
  
  ProcedureReturn new
EndProcedure


; Procedure Jr_Sort_Linkedlist(JR_list_id.l, mode.l, OffsetDuChamp.l, type.l)
;   
;   For i = 2 To JR_Count_element(JR_list_id)
;     
;     elem = 0
;     
;     CopyMemory(PeekL(JR_list_id + 16) + 8 + OffsetDuChamp, @elem, len)
;     
;     JR_Reset_linkedlist(liste_1)
;     
;     b.point\x = 0
;     
;     While JR_Next_element(liste_1)
;       JR_Get_element(liste_1, @b)
;       
;       
;     Wend
;     
;   Next
;   
; EndProcedure

;}

;{ ## test de démonstration


; liste_1 = JR_Create_linkedlist(SizeOf(point))
; 
; Debug "adresse de la liste = " + Str(liste_1)
; Debug "nb element = " + Str(JR_Count_element(liste_1))
; Debug "## création de 10 elements"
; 
; For a = 1 To 10
;   JR_Add_element(liste_1)
;   
;   e.POINT\y = Random(55)
;   e\x = a
;   
;   JR_Set_element(liste_1, @e, 0, 0)
; Next
; 
; Debug "nb element = " + Str(JR_Count_element(liste_1))
; Debug "## elements :"
; 
; JR_Reset_linkedlist(liste_1)
; 
; b.point\x = 0
; 
; While JR_Next_element(liste_1)
;   JR_Get_element(liste_1, @b)
;   
;   Debug "element x : " + Str(b\x) + "     y : " + Str(b\y)
; 
; Wend
; 
; Debug "## selection de l'element 9"
; 
; JR_Select_element(liste_1, 9, 0)
; 
; JR_Get_element(liste_1, @b)
; Debug "element x : " + Str(b\x) + "     y : " + Str(b\y)
; 
; Debug "## effacement de l'element courant (9)"
; 
; JR_Delete_element(liste_1, 1)
; 
; Debug "nb element = " + Str(JR_Count_element(liste_1))
; 
; JR_Reset_linkedlist(liste_1)
; 
; While JR_Next_element(liste_1)
;   JR_Get_element(liste_1, @b)
;   
;   Debug "element x : " + Str(b\x) + "     y : " + Str(b\y)
; Wend
; 
; Debug "## Echange des elements 1 et 3"
; 
; JR_Swap_element(liste_1, 1, 3)
; 
; JR_Reset_linkedlist(liste_1)
; 
; While JR_Next_element(liste_1)
;   JR_Get_element(liste_1, @b)
;   
;   Debug "element x : " + Str(b\x) + "     y : " + Str(b\y)
; Wend
; 
; Debug "## deplacement de l'element 5 en 2eme position"
; 
; JR_Move_element(liste_1, 5, 2)
; 
; Debug "# test avec les elements suivants"
; JR_Reset_linkedlist(liste_1)
; 
; While JR_Next_element(liste_1)
;   JR_Get_element(liste_1, @b)
;   
;   Debug "element x : " + Str(b\x) + "     y : " + Str(b\y)
; Wend
; 
; Debug "# test avec les elements precedents"
; 
; JR_Select_element(liste_1, JR_Count_element(liste_1), 0)
; 
; Repeat
;   JR_Get_element(liste_1, @b)
;   
;   Debug "element x : " + Str(b\x) + "     y : " + Str(b\y)
;   
;   
; Until JR_Previous_element(liste_1) = 0
; 
; Debug "### Effacement de la liste et creation d'une nouvelle"
; 
; JR_Delete_linkedlist(liste_1)
; 
; liste_1 = JR_Create_linkedlist(SizeOf(point))
; 
; Debug "adresse de la liste = " + Str(liste_1)
; Debug "nb element = " + Str(JR_Count_element(liste_1))
; Debug "## création de 10 elements"
; 
; For a = 1 To 10
;   JR_Add_element(liste_1)
;   
;   e.POINT\y = Random(55)
;   e\x = a
;   
;   JR_Set_element(liste_1, @e, 0, 0)
; Next
; 
; Debug "nb element = " + Str(JR_Count_element(liste_1))
; Debug "## elements :"
; 
; JR_Reset_linkedlist(liste_1)
; 
; b.point\x = 0
; 
; While JR_Next_element(liste_1)
;   JR_Get_element(liste_1, @b)
;   
;   Debug "element x : " + Str(b\x) + "     y : " + Str(b\y)
; 
; Wend
; 
; Debug "## changement de l'element 4 \ y"
; 
; JR_Select_element(liste_1, 4, 0)
; 
; JR_Get_element(liste_1, @b)
; 
; Debug "element 4 :  x : " + Str(b\x) + "     y : " + Str(b\y)
; 
; newdonne.l = 55
; 
; JR_Set_element(liste_1, @newdonne, OffsetOf(POINT\y), SizeOf(Long))
; 
; Debug "nouvelle valeur :"
; 
; JR_Get_element(liste_1, @b)
; 
; Debug "element 4 :  x : " + Str(b\x) + "     y : " + Str(b\y)

;}

2ème include : sur les courbes de bezier, c'est celui ci qu'il faut regarder

Code : Tout sélectionner

;{ include des dépendances

; IncludeFile "MODULE_JR_linkedlist.pbi"

;}


;{ Courbes de Béziers ( permet de créer et manipuler des courbes de bézier )
; ## module dépendance : JR_list

Structure Bezier_Point_d
  x.d
  y.d
EndStructure

Structure quad_point
  x.d
  y.d
  vect_x.d
  vect_y.d
EndStructure

Structure Bezier
  P.Bezier_Point_d[4]
EndStructure

Procedure Bezier_Create(level.l, boucle.l) ; level defini le niveau de lissage de la courbe (5 est un level preferable, mettre plus affecte les performances), retourne l'id de la courbe de bézier créée
  ad = AllocateMemory(12)
  
  PokeL(ad, JR_Create_linkedlist(SizeOf(quad_point)))
  PokeL(ad + 4, level)
  PokeL(ad + 8, boucle)
  
  ProcedureReturn ad
EndProcedure

Procedure Bezier_Add_Part(Bezier_id.l, x.d, y.d, vect_x.d, vect_y.d)
  ad_list = PeekL(Bezier_id)
  JR_Add_element(ad_list)
  
  point.quad_point\x = x
  point\y = y
  point\vect_x = vect_x
  point\vect_y = vect_y
  
  JR_Set_element(ad_list, @point, 0, 0)
EndProcedure

Procedure Bezier_Delete_Part(Bezier_id.l, num.l)
	ad_list = PeekL(Bezier_id)
  
  JR_Select_element(ad_list, num, 0)
  JR_Delete_element(ad_list, 0)
EndProcedure

Procedure RecursiveBezier(*b.Bezier, level.l, color)
  Define.Bezier left, right
  If level <= 0
    ;Dessine un segment
    LineXY(*b\P[0]\x + 0.5, *b\P[0]\y + 0.5, *b\P[3]\x + 0.5, *b\P[3]\y + 0.5, color)
    
;     Circle(*b\P[0]\x + 0.5, *b\P[0]\y + 0.5, 5, color)
;     Circle(*b\P[3]\x + 0.5, *b\P[3]\y + 0.5, 5, color)
  Else
    ;subdivide into 2 Bezier segments
    left\P[0]\x = *b\P[0]\x
    left\P[0]\y = *b\P[0]\y
    left\P[1]\x = (*b\P[0]\x + *b\P[1]\x) / 2
    left\P[1]\y = (*b\P[0]\y + *b\P[1]\y) / 2
    left\P[2]\x = (*b\P[0]\x + 2**b\P[1]\x + *b\P[2]\x) / 4
    left\P[2]\y = (*b\P[0]\y + 2**b\P[1]\y + *b\P[2]\y) / 4
    left\P[3]\x = (*b\P[0]\x + 3**b\P[1]\x + 3**b\P[2]\x + *b\P[3]\x) / 8
    left\P[3]\y = (*b\P[0]\y + 3**b\P[1]\y + 3**b\P[2]\y + *b\P[3]\y) / 8
    ;DrawBezierBase(@left,0,255,0);
    right\P[0]\x = left\P[3]\x;
    right\P[0]\y = left\P[3]\y;
    right\P[1]\x = (*b\P[1]\x + 2**b\P[2]\x + *b\P[3]\x) / 4
    right\P[1]\y = (*b\P[1]\y + 2**b\P[2]\y + *b\P[3]\y) / 4
    right\P[2]\x = (*b\P[2]\x + *b\P[3]\x) / 2
    right\P[2]\y = (*b\P[2]\y + *b\P[3]\y) / 2
    right\P[3]\x = *b\P[3]\x
    right\P[3]\y = *b\P[3]\y
    ;DrawBezierBase(@right,0,0,255)
    ;draw the 2 segments recursively
    RecursiveBezier(@left,level -1, color)
    RecursiveBezier(@right,level -1, color)
  EndIf
EndProcedure

Procedure Bezier_Draw(Bezier_id.l, color.l, base.l)
  Define inter.quad_point
  
  ad_list = PeekL(Bezier_id)
  
  nb = JR_Count_element(ad_list)
  
  JR_Reset_linkedlist(ad_list)
  JR_Next_element(ad_list)
  
  JR_Get_element(ad_list, @inter)
  
  For a = 1 To nb - 1
    b.Bezier\P[0]\x = inter\x
    b.Bezier\P[0]\y = inter\y
    
    If a = 1
      b.Bezier\P[1]\x = inter\x + inter\vect_x
      b.Bezier\P[1]\y = inter\y + inter\vect_y
    Else
      b.Bezier\P[1]\x = inter\x - inter\vect_x
      b.Bezier\P[1]\y = inter\y - inter\vect_y
    EndIf
    
    If base
      Circle(inter\x, inter\y, 3, color)
      Circle(b\P[1]\x, b\P[1]\y, 3, color)
      
      LineXY(inter\x, inter\y, b\P[1]\x, b\P[1]\y, color)
    EndIf
    
    JR_Next_element(ad_list)
    
    JR_Get_element(ad_list, @inter)
    
    b.Bezier\P[3]\x = inter\x
    b.Bezier\P[3]\y = inter\y
    
    b.Bezier\P[2]\x = inter\x + inter\vect_x
    b.Bezier\P[2]\y = inter\y + inter\vect_y
    
    If base = 0
      RecursiveBezier(@b, PeekL(Bezier_id + 4), color)
    Else
      Circle(inter\x, inter\y, 3, color)
      Circle(b\P[2]\x, b\P[2]\y, 3, color)
      
      Line(inter\x, inter\y, inter\vect_x, inter\vect_y, color)
    EndIf
  Next
  
  If PeekL(Bezier_id + 8)
    b.Bezier\P[2]\x = inter\x - inter\vect_x
    b.Bezier\P[2]\y = inter\y - inter\vect_y
    
    JR_Reset_linkedlist(ad_list)
    JR_Next_element(ad_list)
    
    JR_Get_element(ad_list, @inter)
    
    b.Bezier\P[0]\x = inter\x
    b.Bezier\P[0]\y = inter\y
    
    b.Bezier\P[1]\x = inter\x - inter\vect_x
    b.Bezier\P[1]\y = inter\y - inter\vect_y

    If base = 0
      RecursiveBezier(@b, PeekL(Bezier_id + 4), color)
    Else
      Circle(b\P[0]\x, b\P[0]\y, 3, color)
      Circle(b\P[1]\x, b\P[1]\y, 3, color)
      
      LineXY(b\P[0]\x, b\P[0]\y, b\P[1]\x, b\P[1]\y, color)
      
      Circle(b\P[3]\x, b\P[3]\y, 3, color)
      Circle(b\P[2]\x, b\P[2]\y, 3, color)
      
      LineXY(b\P[3]\x, b\P[3]\y, b\P[2]\x, b\P[2]\y, color)
    EndIf
  EndIf
  
EndProcedure

Procedure Bezier_Move_Part(Bezier_id.l, num.l, x.d, y.d, vect_x.d, vect_y.d, option) ; option = 0 : tout les param sont changés, option = 1 : seuls x/y changent, option = 2 : seuls vects changent
  ad_list = PeekL(Bezier_id)
  
  JR_Select_element(ad_list, num, 0)
  
  If option = 0
    point.quad_point\x = x
    point\y = y
    point\vect_x = vect_x
    point\vect_y = vect_y
    
    JR_Set_element(ad_list, @point, 0, 0)
  ElseIf option = 1
    JR_Set_element(ad_list, @x, OffsetOf(quad_point\x), SizeOf(Double))
    JR_Set_element(ad_list, @y, OffsetOf(quad_point\y), SizeOf(Double))
  ElseIf option = 2
    JR_Set_element(ad_list, @vect_x, OffsetOf(quad_point\vect_x), SizeOf(Double))
    JR_Set_element(ad_list, @vect_y, OffsetOf(quad_point\vect_y), SizeOf(Double))
  EndIf
EndProcedure

Procedure Bezier_Get_Part(Bezier_id.l, num.l, *quad_point)
  ad_list = PeekL(Bezier_id)
  
  JR_Select_element(ad_list, num, 0)
  
  JR_Get_element(ad_list, *quad_point)
EndProcedure

Procedure Bezier_Reset_Part(Bezier_id.l) ; fonctionne avec Bezier_Move_Next_Part() et Bezier_Get_Next_Part()
	ad_list = PeekL(Bezier_id)
	
	JR_Reset_linkedlist(ad_list)
EndProcedure

Procedure Bezier_Move_Next_Part(Bezier_id.l, x.d, y.d, vect_x.d, vect_y.d, option) ; option = 0 : tout les param sont changés, option = 1 : seuls x/y changent, option = 2 : seuls vects changent
  ad_list = PeekL(Bezier_id)
  
  JR_Next_element(ad_list)
  
  If option = 0
    point.quad_point\x = x
    point\y = y
    point\vect_x = vect_x
    point\vect_y = vect_y
    
    JR_Set_element(ad_list, @point, 0, 0)
  ElseIf option = 1
    JR_Set_element(ad_list, @x, OffsetOf(quad_point\x), SizeOf(Double))
    JR_Set_element(ad_list, @y, OffsetOf(quad_point\y), SizeOf(Double))
  ElseIf option = 2
    JR_Set_element(ad_list, @vect_x, OffsetOf(quad_point\vect_x), SizeOf(Double))
    JR_Set_element(ad_list, @vect_y, OffsetOf(quad_point\vect_y), SizeOf(Double))
  EndIf
EndProcedure

Procedure Bezier_Get_Next_Part(Bezier_id.l, *quad_point)
  ad_list = PeekL(Bezier_id)
  
  JR_Next_element(ad_list)
  
  JR_Get_element(ad_list, *quad_point)
EndProcedure

Procedure Bezier_Move_Current_Part(Bezier_id.l, x.d, y.d, vect_x.d, vect_y.d, option) ; option = 0 : tout les param sont changés, option = 1 : seuls x/y changent, option = 2 : seuls vects changent
  ad_list = PeekL(Bezier_id)
  
  If option = 0
    point.quad_point\x = x
    point\y = y
    point\vect_x = vect_x
    point\vect_y = vect_y
    
    JR_Set_element(ad_list, @point, 0, 0)
  ElseIf option = 1
    JR_Set_element(ad_list, @x, OffsetOf(quad_point\x), SizeOf(Double))
    JR_Set_element(ad_list, @y, OffsetOf(quad_point\y), SizeOf(Double))
  ElseIf option = 2
    JR_Set_element(ad_list, @vect_x, OffsetOf(quad_point\vect_x), SizeOf(Double))
    JR_Set_element(ad_list, @vect_y, OffsetOf(quad_point\vect_y), SizeOf(Double))
  EndIf
EndProcedure

Procedure Bezier_Get_Current_Part(Bezier_id.l, *quad_point)
  ad_list = PeekL(Bezier_id)
  
  JR_Get_element(ad_list, *quad_point)
EndProcedure

Procedure Bezier_CountPart(Bezier_id.l)
  ProcedureReturn JR_Count_element(PeekL(Bezier_id))
EndProcedure

Procedure Bezier_Free(Bezier_id.l)
  JR_Delete_linkedlist(PeekL(Bezier_id))
  
  FreeMemory(Bezier_id)
EndProcedure

Procedure Bezier_Set_Level(Bezier_id.l, level.l) ; change le niveau de lissage de la courbe
  PokeL(Bezier_id + 4, level)
EndProcedure

Procedure Bezier_Get_Level(Bezier_id.l) ; retourne le niveau de lissage de la courbe
  ProcedureReturn PeekL(Bezier_id + 4)
EndProcedure

Procedure Bezier_Set_Boucle(Bezier_id.l, boucle.l) ; change l'activation de la boucle
  PokeL(Bezier_id + 8, boucle)
EndProcedure

Procedure Bezier_Get_Boucle(Bezier_id.l) ; retourne si l'option boucle est activé ou non
  ProcedureReturn PeekL(Bezier_id + 8)
EndProcedure

Procedure Bezier_Copy(Bezier_id.l) ; duplique la courbe
  ad = AllocateMemory(12)
  
  PokeL(ad, JR_Copy_Linkelist(PeekL(Bezier_id)))
  
  CopyMemory(Bezier_id + 4, ad + 4, 8)
;   PokeL(ad + 4, PeekL(Bezier_id + 4))
;   PokeL(ad + 8, PeekL(Bezier_id + 8))
  
  ProcedureReturn ad
EndProcedure

Procedure Bezier_test_point(Bezier_id.l, sourie_x.l, sourie_y.l, sensibilite.l) ; renvoie l'adresse mémoire de 2 long qui donnent --> +0 : numéro de la partie de courbe | +4 : 1 si c'est le point, 2 si c'est le vecteur | +24 : si c'est un vect, 1 veux dire de prendre la symetrie , ne pas oublier de libérer la mémoire
  Define inter.quad_point
  
  *adresse = AllocateMemory(28)
  
  ad_list = PeekL(Bezier_id)
  
  nb = JR_Count_element(ad_list)
  JR_Reset_linkedlist(ad_list)
  
  For a = 1 To nb
  	JR_Next_element(ad_list)
  	
  	JR_Get_element(ad_list, @inter)
  	
    b.Bezier\P[0]\x = inter\x
    b.Bezier\P[0]\y = inter\y
    
    b.Bezier\P[1]\x = inter\x + inter\vect_x
    b.Bezier\P[1]\y = inter\y + inter\vect_y
    
    b.Bezier\P[2]\x = inter\x - inter\vect_x
    b.Bezier\P[2]\y = inter\y - inter\vect_y
    
    dist.d = Sqr(Pow(b\P[0]\x - sourie_x, 2) + Pow(b\P[0]\y - sourie_y, 2))
    
    If dist <= sensibilite
    	PokeL(*adresse, a)
    	PokeL(*adresse + 4, 1)
    	
    	PokeL(*adresse + 8, b\P[0]\x)
    	PokeL(*adresse + 12, b\P[0]\y)
    	
    	Break
    EndIf
    
    dist.d = Sqr(Pow(b\P[1]\x - sourie_x, 2) + Pow(b\P[1]\y - sourie_y, 2))
    
    If dist <= sensibilite
    	PokeL(*adresse, a)
    	PokeL(*adresse + 4, 2)
    	
    	PokeL(*adresse + 8, b\P[1]\x)
    	PokeL(*adresse + 12, b\P[1]\y)
    	
    	PokeL(*adresse + 16, b\P[0]\x)
    	PokeL(*adresse + 20, b\P[0]\y)
    	
    	Break
    EndIf
    
    dist.d = Sqr(Pow(b\P[2]\x - sourie_x, 2) + Pow(b\P[2]\y - sourie_y, 2))
    
    If dist <= sensibilite
    	PokeL(*adresse, a)
    	PokeL(*adresse + 4, 2)
    	
    	PokeL(*adresse + 8, b\P[2]\x)
    	PokeL(*adresse + 12, b\P[2]\y)
    	
    	PokeL(*adresse + 16, b\P[0]\x)
    	PokeL(*adresse + 20, b\P[0]\y)
    	
    	PokeL(*adresse + 24, 1)
    	Break
    EndIf
  Next
  
  ProcedureReturn *adresse
EndProcedure

;}

;{ ## test de démonstration
; 
; If OpenWindow(0, 0, 0, 800, 600, "Test des courbes de bézier", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
; 	CanvasGadget(0, 0, 0, 800, 600, #PB_Canvas_Keyboard)
; 	
; 	AddKeyboardShortcut(0, #PB_Shortcut_Escape, 0)
; EndIf
; 
; ; on crée la courbe
; ma_bezier = Bezier_Create(5, #False)
; 
; x0 = -1
; y0 = -1
; 
; Repeat
; 	event = WaitWindowEvent()
; 	
; 	If event = #PB_Event_Gadget And EventGadget() = 0
; 		x = GetGadgetAttribute(0, #PB_Canvas_MouseX)
; 		y = GetGadgetAttribute(0, #PB_Canvas_MouseY)
; 		
; 		Select EventType()
; 			Case #PB_EventType_LeftClick
; 				If x0 = -1
; 					x0 = x
; 					y0 = y
; 				Else
; 					Bezier_Add_Part(ma_bezier, x, y, -(x - x0) / 2, -(y - y0) / 2)
; 					
; 					x0 = x
; 					y0 = y
; 				EndIf
; 				
; 		EndSelect
; 		
; 	EndIf
; 	
; 	;{ dessin
; 	
; 	If StartDrawing(CanvasOutput(0))
; 		Box(0, 0, 800, 600, #Black)
; 		
; 		; souris
; 		Circle(x, y, 2, #Red)
; 		
; 		; dessin de la courbe
; 		Bezier_Draw(ma_bezier, #Green, #False)
; 		
; 		StopDrawing()
; 	EndIf
; 	
; 	;}
; 	
; Until event = #PB_Event_CloseWindow
; 
; End
; 
; 
;}


code de test pour montrer un résultat graphique :

Code : Tout sélectionner

InitSprite()
InitKeyboard()

OpenScreen(1280, 1024, 32, "Bezier")

IncludeFile "Librairie Sources\MODULE_JR_linkedlist.pbi"

IncludeFile "Librairie Sources\MODULE_Bezier_Courbes.pbi"

bezier = Bezier_Create(5, 1)

#nb = 6
nb1.d = 60

col = #Green

red.d = Red(col)
green.d = Green(col)
blue.d = Blue(col)

Structure listedepoint
  P.POINT[#nb]
EndStructure

Define az.listedepoint, acc.listedepoint, time.listedepoint

size = SizeOf(listedepoint)

For a = 0 To #nb - 1
  az\P[a]\x = Random(1280 - 100) + 50
  az\P[a]\y = Random(1024 - 100) + 50
Next

NewList bezier.l()

For a = 0 To nb1
  AddElement(bezier())
  
  bezier() = Bezier_Create(5, 1)
Next

FirstElement(bezier())

For a = 0 To #nb - 1 Step 2
  Bezier_Add_Part(bezier(), (az\P[a]\x + az\P[a + 1]\x) / 2, (az\P[a]\y + az\P[a + 1]\y) / 2, az\P[a]\x - (az\P[a]\x + az\P[a + 1]\x) / 2, az\P[a]\y - (az\P[a]\y + az\P[a + 1]\y) / 2)
Next

; aze = Bezier_Copy(

base = -1

it = -1

Repeat
  it = -it
  
  Delay(10)
  
  ExamineKeyboard()
  
  FirstElement(bezier())
  
  If KeyboardReleased(#PB_Key_F1) : base = -base : EndIf
  If KeyboardReleased(#PB_Key_Up) : Bezier_Set_Level(bezier(), Bezier_Get_Level(bezier()) + 1) : EndIf
  If KeyboardReleased(#PB_Key_Down) : Bezier_Set_Level(bezier(), Bezier_Get_Level(bezier()) - 1) : EndIf
  
  a = 0
  ForEach bezier()
    
    If a
      da = ad
    EndIf
    
    ad = Bezier_Copy(bezier())
    
    If a
      Bezier_Free(bezier())
      bezier() = da
    EndIf
    
    a + 1
  Next
  
  FirstElement(bezier())
  
  b = 1
  For a = 0 To #nb - 1
    b = -b
    
    If time\P[a]\x <= 0
      time\P[a]\x = Random(80) + 50
      
      acc\P[a]\x = Random(10) - 5
      acc\P[a]\y = Random(10) - 5
    Else
      time\P[a]\x - 1
    EndIf
    
    az\P[a]\x + acc\P[a]\x
    az\P[a]\y + acc\P[a]\y
    
    If az\P[a]\x < 0 Or az\P[a]\x > 1280 : acc\P[a]\x = -acc\P[a]\x : EndIf
    If az\P[a]\y < 0 Or az\P[a]\y > 1024 : acc\P[a]\y = -acc\P[a]\y : EndIf
    
    If b = 1
      Bezier_Move_Part(bezier(), a / 2 + 1, (az\P[a]\x + az\P[a - 1]\x) / 2, (az\P[a]\y + az\P[a - 1]\y) / 2, az\P[a - 1]\x - (az\P[a]\x + az\P[a - 1]\x) / 2, az\P[a - 1]\y - (az\P[a]\y + az\P[a - 1]\y) / 2, 0)
    EndIf
  Next
  
  ClearScreen(0)
  
  If StartDrawing(ScreenOutput())
      
      j.d = 0
      ForEach bezier()
        j + 1
        
        If (j/2 - Int(j/2) And it = 1) Or (j/2 - Int(j/2)  = 0 And it = -1)
          
          If j < nb1 / 2
            color1.d = j / nb1
          Else
            color1.d = 1 - j / nb1
          EndIf
          
          Bezier_Draw(bezier(), RGB(red * color1, green * color1, blue * color1), 0)
          If base = 1 : Bezier_Draw(bezier(), #Red, 1) : EndIf
        EndIf
      Next
      
    StopDrawing()
  EndIf
  FlipBuffers()
  
Until KeyboardPushed(#PB_Key_Escape)

End
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Interpolation cubique (courbe bézier...)

Message par graph100 »

et un autre code , plus simple.

tu te déplace entre les points avec les touches du pavnum (je sais que c'est moisi, mais je dois avoir repris ca de qqun ;)

Code : Tout sélectionner

InitSprite()
InitKeyboard()
InitMouse()

; OpenScreen(800, 600, 32, "Bezier")
OpenScreen(1280, 1024, 32, "Bezier")

IncludeFile "Librairie Sources\MODULE_JR_linkedlist.pbi"

IncludeFile "Librairie Sources\MODULE_Bezier_Courbes.pbi"

bezier = Bezier_Create(5, 1)

Structure listedepoint
  P.POINT[6]
EndStructure

Define az.listedepoint

az\P[0]\x = 500
az\P[0]\y = 510
az\P[1]\x = 250
az\P[1]\y = -490

az\P[2]\x = 348
az\P[2]\y = 400
az\P[3]\x = -200
az\P[3]\y = 100

az\P[4]\x = 500
az\P[4]\y = 200
az\P[5]\x = 100
az\P[5]\y = -90

Bezier_Add_Part(bezier, az\P[0]\x, az\P[0]\y, az\P[1]\x, az\P[1]\y)
Bezier_Add_Part(bezier, az\P[2]\x, az\P[2]\y, az\P[3]\x, az\P[3]\y)
Bezier_Add_Part(bezier, az\P[4]\x, az\P[4]\y, az\P[5]\x, az\P[5]\y)

Repeat
  Delay(10)
  
  ExamineKeyboard()
  ExamineMouse()
  
  t$ = KeyboardInkey()
  If Val(t$) And Val(t$) < 7
    i = Val(t$) - 1
  EndIf
  
  j.d = i
  
  az\P[i]\x + MouseDeltaX()
  az\P[i]\y + MouseDeltaY()
  
  
  If (j/2) - Int(j/2)
    Bezier_Move_Part(bezier, i / 2 + 1, 0, 0, az\P[i]\x, az\P[i]\y, 2)
    
    x = az\P[i]\x + az\P[i - 1]\x
    y = az\P[i]\y + az\P[i - 1]\y
  Else
    Bezier_Move_Part(bezier, i / 2 + 1, az\P[i]\x, az\P[i]\y, 0, 0, 1)
    
    x = az\P[i]\x
    y = az\P[i]\y
  EndIf
  
  ClearScreen(0)
  
  If StartDrawing(ScreenOutput())
      Bezier_Draw(bezier, #White, 0)
      Bezier_Draw(bezier, #Red, 1)
      
      DrawingMode(#PB_2DDrawing_Outlined)
      Circle(x, y, 5, #Green)
      
    StopDrawing()
  EndIf
  FlipBuffers()
  
Until KeyboardPushed(#PB_Key_Escape)

End
je crois pas que le déplacement entre les points soit de Comtois,
mais en tout cas, le code initial sur les courbes de bezier est de lui. Moi j'ai fait un include pour le manipuler
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Interpolation cubique (courbe bézier...)

Message par graph100 »

le truc de bezier, c'est que tu règles un point et la tangente à la courbe en ce point.
Du coup tu peux avoir le genre d'effet que tu recherches, en ajustant correctement les tangentes,
ensuite il faut que tu récupère les coordonnées de chaque point intermédiaires pour les exploiter.
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Re: Interpolation cubique (courbe bézier...)

Message par Backup »

voir sommaire des Tutos :
http://www.purebasic.fr/french/viewtopi ... ier#p65087

le Tuto numero 5 rubrique "Utilisateur Expert"

tuto fait par G-rom (Cpl-bator) d'apres un source de Comtois lui meme adapté d'un code en Blitz basic .... de mémoire :)
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: Interpolation cubique (courbe bézier...)

Message par blendman »

salut

J'avais déjà regardé le code de comtois :).

Je l'ai simplifié au maximum pour essayer de l'utiliser dans mon exemple.
Mais j'ai encore quelques bugs, même si ça se rapproche ^^.

Code : Tout sélectionner

;{ constantes, enum,
#IMAGE_Content =0

Enumeration
  #GADGET_Canvas
  #GADGET_Brush
  #GADGET_Clear
EndEnumeration

;}

;{ structure
Structure Pointf
  x.f
  y.f
EndStructure

Structure Bezier
  P.Pointf[4]
EndStructure

Global Global_Bezier.Bezier, level.a =5
Global Pas=2,point0.point,point1.point,point2.point,point3.point
;}


;{ macros et procedures
Macro point_distance(x1,y1,x2,y2)   
  Int(Sqr((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)) )       
EndMacro
Macro point_direction(x1,y1,x2,y2)
  ATan2((y2- y1),(x2- x1))
EndMacro


Procedure DrawBezierRecursive ( *b.Bezier, level.l)
  Define.Bezier left, right
  If level <= 0;    
     Circle(*b\P[0]\x , *b\P[0]\y ,5, 0) ;Dessine un segment
   Else
    ;subdivide into 2 Bezier segments
    left\P[0]\x = *b\P[0]\x
    left\P[0]\y = *b\P[0]\y
    left\P[1]\x = (*b\P[0]\x + *b\P[1]\x) / 2
    left\P[1]\y = (*b\P[0]\y + *b\P[1]\y) / 2
    left\P[2]\x = (*b\P[0]\x + 2**b\P[1]\x + *b\P[2]\x) / 4
    left\P[2]\y = (*b\P[0]\y + 2**b\P[1]\y + *b\P[2]\y) / 4
    left\P[3]\x = (*b\P[0]\x + 3**b\P[1]\x + 3**b\P[2]\x + *b\P[3]\x) / 8
    left\P[3]\y = (*b\P[0]\y + 3**b\P[1]\y + 3**b\P[2]\y + *b\P[3]\y) / 8
    
    right\P[0]\x = left\P[3]\x;
    right\P[0]\y = left\P[3]\y;
    right\P[1]\x = (*b\P[1]\x + 2**b\P[2]\x + *b\P[3]\x) / 4
    right\P[1]\y = (*b\P[1]\y + 2**b\P[2]\y + *b\P[3]\y) / 4
    right\P[2]\x = (*b\P[2]\x + *b\P[3]\x) / 2
    right\P[2]\y = (*b\P[2]\y + *b\P[3]\y) / 2
    right\P[3]\x = *b\P[3]\x
    right\P[3]\y = *b\P[3]\y
    ;draw the 2 segments recursively
    DrawBezierRecursive (@left,level -1)
    DrawBezierRecursive (@right,level -1)
  EndIf
EndProcedure

Procedure DrawBrush(x1,y1)
  x2 = point1\x
  y2 = point1\y
  flech = point_distance(x1,y1,x2,y2)
  d.d = point_direction(x1,y1,x2,y2)
  
     

  For i = 1 To flech   
    i+pas
    x_result = x1 + Sin(d) *i
    y_result = y1 + Cos(d) *i
    Global_Bezier\P[0]\x = x_result
    Global_Bezier\P[0]\y = y_result
    DrawBezierRecursive(@Global_Bezier,level) ; bézier bug... 
    ;Circle(x_result,y_result,3,0) ; normal, ok
  Next i
EndProcedure

Procedure DrawAction(x, y, EventType)
  If StartDrawing(CanvasOutput(#GADGET_Canvas))
    If EventType = #PB_EventType_LeftButtonDown Or EventType = #PB_EventType_MouseMove
      DrawBrush(x,y)
    EndIf
    StopDrawing()
  EndIf
EndProcedure



;}

;{ window & loop
CreateImage(#IMAGE_Content, 800, 600, 24)

If OpenWindow(0, 0, 0, 800, 600, "Interpolation", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  CanvasGadget(#GADGET_Canvas, 10, 10, WindowWidth(0)-80, WindowHeight(0)-20, #PB_Canvas_ClipMouse)
  ButtonGadget(#GADGET_Clear,  WindowWidth(0)-60, 100, 50, 25, "Clear")
  SetGadgetAttribute(#GADGET_Canvas, #PB_Canvas_Cursor, #PB_Cursor_Cross)
  
  Repeat
    Event = WaitWindowEvent()
    
    If Event = #PB_Event_Gadget
      
      Select EventGadget()
          
        Case #GADGET_Canvas
          point0\X = GetGadgetAttribute(#GADGET_Canvas, #PB_Canvas_MouseX)
          point0\Y = GetGadgetAttribute(#GADGET_Canvas, #PB_Canvas_MouseY)
          Global_Bezier\P[0]\x = point0\x
          Global_Bezier\P[0]\y = point0\y
          Type = EventType()
          
          Select EventType()
              
            Case #PB_EventType_LeftButtonDown
              If StartDrawing(ImageOutput(#IMAGE_Content))
                DrawImage(GetGadgetAttribute(#GADGET_Canvas, #PB_Canvas_Image), 0, 0)
                StopDrawing()
              EndIf
              
              
              point3\x = point2\x
              point3\y = point2\y
              point2\x = point1\x
              point2\y = point1\y
              point1\x = point0\x
              point1\y = point0\y
  
              Global_Bezier\P[1]\x = point1\x
              Global_Bezier\P[1]\y = point1\y
              Global_Bezier\P[2]\x = point2\x
              Global_Bezier\P[2]\y = point2\y
              Global_Bezier\P[3]\x = point3\x
              Global_Bezier\P[3]\y = point3\y
              
              DrawAction(point0\X, point0\Y, EventType())
              
              
            Case #PB_EventType_LeftButtonUp
              DrawAction(point0\X, point0\Y, EventType())                       
              
            Case #PB_EventType_MouseMove
              If GetGadgetAttribute(#GADGET_Canvas, #PB_Canvas_Buttons) & #PB_Canvas_LeftButton
                Global_Bezier\P[0]\x = point0\x
                Global_Bezier\P[0]\y = point0\y
                DrawAction(point0\X, point0\Y, EventType())
                
                point3\x = point2\x
                point3\y = point2\y
                point2\x = point1\x
                point2\y = point1\y
                point1\x = point0\x
                point1\y = point0\y
                
                
                Global_Bezier\P[1]\x = point1\x
                Global_Bezier\P[1]\y = point1\y
                Global_Bezier\P[2]\x = point2\x
                Global_Bezier\P[2]\y = point2\y
                Global_Bezier\P[3]\x = point3\x
                Global_Bezier\P[3]\y = point3\y
                
              EndIf
              
          EndSelect
          
        Case #GADGET_Clear
          If StartDrawing(CanvasOutput(#GADGET_Canvas))
            Box(0, 0, GadgetWidth(#GADGET_Canvas), GadgetHeight(#GADGET_Canvas), $FFFFFF)
            StopDrawing()
          EndIf
          
          
      EndSelect
      
    EndIf
    
  Until Event = #PB_Event_CloseWindow
  
EndIf
;}
Je ne sais pas si je dois l'utiliser comme ça, si vous avez des pistes pour corriger ça je suis preneur ;).
Mesa
Messages : 1126
Inscription : mer. 14/sept./2011 16:59

Re: Interpolation cubique (courbe bézier...)

Message par Mesa »

Juste une idée :
Si on déplace la souris et que l'on garde en mémoire la position du curseur n-2, n-1 et n. (en x et y)

On calcul l'angle entre n-2 et n-1 = angle1
On calcul l'angle entre n-1 et n = angle2

On pose une condition : si angle2 > à 20% de angle1 alors le tournant est trop prononcé et on pose finalement angle2= angle1+ 20%

On peut remplacer 20% par autre chose.

Le but est d'arrondir un tournant, si l'écart entre les 2 angles est trop grand alors cela afficherait un angle trop fort, un angle droit par exemple alors on force angle2 à une valeur plus faible , ce qui arrondit le tournant, on calcul les valeurs x et y de n à partir de l'angle2 recalculé à 20%.

Je ne sais pas si je suis assez clair.

Mesa.
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: Interpolation cubique (courbe bézier...)

Message par blendman »

Salut

Ca semble être une idée pas mal.
Tu aurais un pitit exemple ? :D

ça marcherait avec le système de points créés entre 2 points dessinés (pour faire des dessins avec lignes (comme dans mon exemple) et non par points) ?
Mesa
Messages : 1126
Inscription : mer. 14/sept./2011 16:59

Re: Interpolation cubique (courbe bézier...)

Message par Mesa »

Le code de LSI peut peut-être t'inspirer
http://www.purebasic.fr/french/viewtopi ... =6&t=11923

Mesa.
Frenchy Pilou
Messages : 2194
Inscription : jeu. 27/janv./2005 19:07

Re: Interpolation cubique (courbe bézier...)

Message par Frenchy Pilou »

Je viens de voir cela ;)
http://www.mit.edu/~ibaran/curves/

Peut-être est-ce adaptable ou cela colle-t-il trop à la courbe de départ?
Est beau ce qui plaît sans concept :)
Speedy Galerie
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: Interpolation cubique (courbe bézier...)

Message par blendman »

Frenchy Pilou a écrit :Je viens de voir cela ;)
http://www.mit.edu/~ibaran/curves/

Peut-être est-ce adaptable ou cela colle-t-il trop à la courbe de départ?
ça a l'air pas mal, mais par contre, pour l'adapter, je n'ai pas le niveau je pense ^^.
Je vais étudier ça en tout cas, merci pour le lien ;).
G-Rom
Messages : 3641
Inscription : dim. 10/janv./2010 5:29

Re: Interpolation cubique (courbe bézier...)

Message par G-Rom »

"smoothé" une ligne est assez simple , je m'explique :

Image

Il te faut 3 points minimum , ces 3 points forment 2 segments. ( figure de gauche )
- pour chaque segment , tu divises leurs longueur en 2 , ce qui te donne 3 segments ( figure centrale )
- tu recommences l'opération autant de fois que tu veut ( figure de droite )


@++
Répondre