Subdivisions d'une courbe(création d'un circuit)+screenshots

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Avatar de l’utilisateur
Huitbit
Messages : 940
Inscription : jeu. 08/déc./2005 5:19
Localisation : Guadeloupe

Subdivisions d'une courbe(création d'un circuit)+screenshots

Message par Huitbit »

Petite récréation...

Depuis que j'ai redécouvert grabsprite()
(voir http://www.purebasic.fr/french/viewtopic.php?t=9256)
ça m'a donné envie de l'utiliser pour un jeu de voiture !

Avant cela, il fallait un circuit.
Ca faisait un moment que j'entendais parler des courbes de bézier (Comtois, Cpl Bator), je n'avais pas envie de mettre le nez dedans car je voyais des équations à priori inhospitalières et manquant de souplesse :lol: .

Je n'ai pas mis le nez dedans mais j'ai repris le principe sur le papier, purebasic a fait le reste ! Je ne sais pas si c'est la bonne méthode mais c'est ce que je voulais obtenir :P .

A chaque subdivision, je découpe le segment [AB] en trois bouts [AM],[MN] et [NB] avec au niveau vectoriel |AM>=rapport*|AB> et |AN>=(1-rapport)*|AB>. Les anciens points sont remplacés par les nouveaux.

Image

Au bout de 4 subdivisions, on obtient déjà une courbe bien lisse :P
Ce n'est donc pas la peine d'aller plus loin en modifiant la ligne!

Code : Tout sélectionner

#generation=3; génération 0,1, 2 et 3

J'ai pris un exemple avec 5 points de contrôle et 4 subdivisions (5*2^4=80 points au final).
J'ai mis une petite boule qui se déplace sans tenir compte de sa vitesse, juste pour voir !

Pour voir d'autres circuits, il suffit de supprimer la création des points non aléatoires et d'activer la création aléatoire:(déjà en commentaires dans le code!)

Code : Tout sélectionner

;-initialisation des 5 points de contrôle

;aléatoire
 For n=0 To #nbre_de_pts_de_ctrl-1
 points(n)\x=Random(#largeur_ecran)
 points(n)\y=Random(#hauteur_ecran)
 Next n


et de modifier éventuellement :

Code : Tout sélectionner

#nbre_de_pts_de_ctrl=5
#generation=3; génération 0,1, 2 et 3
Ca ne change rien pour le reste du code :P !
Essayez, ça marche tout seul :wink: , la boule est bien dressée!
Exemple:

Code : Tout sélectionner

#nbre_de_pts_de_ctrl=20
#generation=4
Image

Je n'avais pas saisi la portée de cette méthode mais c'est impressionnant vu la simplicité et la souplesse du code (circuit, jeux de plateformes...etc!!).
En effet, on travaille avec des droites affines :P !

Il ne reste plus qu'à coupler ça avec la mécanique, grabsprite(), les rotations et autres...

Prochaine mise à jour déplacement à vitesse constante(ou autre !).

Code : Tout sélectionner

;subdivision
;Auteur Huitbit
;PureBasic 4.30 (Windows - x86)
;*********************************
#largeur_ecran=1024
#hauteur_ecran=768
#nbre_de_pts_de_ctrl=5
#generation=3; génération 0,1, 2 et 3
#spr_decor=0
#spr=1
rapport.f=0.25
nbre_de_pts_final.l=#nbre_de_pts_de_ctrl*Pow(2,#generation+1)-1

Structure infos
  x.l
  y.l
  a.f
  b.f
EndStructure

Dim points.infos (nbre_de_pts_final)

Macro affine(a,b,xA,yA,xB,yB)
a=(yB-yA)/(xB-xA)
b=(yA*xB-yB*xA)/(xB-xA)
EndMacro

;-initialisation des 5 points de contrôle

;aléatoire
; For n=0 To #nbre_de_pts_de_ctrl-1
; points(n)\x=Random(#largeur_ecran)
; points(n)\y=Random(#hauteur_ecran)
; Next n

;non aléatoire
points(0)\x=20
points(0)\y=20

points(1)\x=1004
points(1)\y=20

points(2)\x=900
points(2)\y=748

points(3)\x=512
points(3)\y=20

points(4)\x=20
points(4)\y=748

;-subdivisions de la courbe
For generation_en_cours=0 To #generation
  nbre_de_pts_provisoires.l=#nbre_de_pts_de_ctrl*Pow(2,generation_en_cours)-1
  For n=nbre_de_pts_provisoires To 0 Step -1
    ;A, B extremités du segment à découper
    xA.l=points(n)\x
    yA.l=points(n)\y
    If n<nbre_de_pts_provisoires
      xB.l=points(n+1)\x
      yB.l=points(n+1)\y
    Else
      xB.l=points(0)\x
      yB.l=points(0)\y
    EndIf
    points(2*n+1)\x=xA+(xB-xA)*(1-rapport)
    points(2*n+1)\y=yA+(yB-yA)*(1-rapport)
    points(2*n)\x=xA+(xB-xA)*rapport
    points(2*n)\y=yA+(yB-yA)*rapport
  Next n
Next generation_en_cours

x_spr.l=points(0)\x
y_spr.l=points(0)\y

;-calculs des équations affines de chaque segment
For n=0 To nbre_de_pts_final
  If n<nbre_de_pts_final
    affine(points(n)\a,points(n)\b,points(n)\x,points(n)\y,points(n+1)\x,points(n+1)\y)
  Else
    affine(points(n)\a,points(n)\b,points(n)\x,points(n)\y,points(0)\x,points(0)\y)
  EndIf
Next n

;-######################################
;-PROGRAMME PRINCIPAL
;-######################################
InitSprite()
InitKeyboard()
OpenWindow(0,0,0,#largeur_ecran,#hauteur_ecran,"Subdivision ",#PB_Window_ScreenCentered|#PB_Window_SystemMenu  )
OpenWindowedScreen(WindowID(0),0,0,#largeur_ecran,#hauteur_ecran,0,0,0)

CreateSprite(#spr_decor,#largeur_ecran,#hauteur_ecran)
StartDrawing(SpriteOutput(#spr_decor))
For n=0 To nbre_de_pts_final
  If n<nbre_de_pts_final
    LineXY(points(n)\x,points(n)\y,points(n+1)\x,points(n+1)\y,RGB(255,255,0))
  Else
    LineXY(points(0)\x,points(0)\y,points(nbre_de_pts_final)\x,points(nbre_de_pts_final)\y,RGB(255,255,0))
  EndIf
  DrawText(points(n)\x,points(n)\y,Str(n))
Next n
StopDrawing()

CreateSprite(#spr,16,16)
StartDrawing(SpriteOutput(#spr))
Plot(8,8,RGB(255,0,0))
Circle(8,8,8,RGB(0,0,255))
StopDrawing()

numero.l=0
;-BOUCLE PRINCIPALE

Repeat
  FlipBuffers() 
  DisplaySprite(#spr_decor,0,0)
  
  If numero=nbre_de_pts_final; permet de "boucler" un tour
    If  points(numero)\x<points(0)\x
      x_spr=x_spr+1
      If  x_spr>=points(0)\x
        numero=0
      EndIf
    Else
      x_spr=x_spr-1
      If  x_spr<=points(0)\x
        numero=0
      EndIf
    EndIf
    
  ElseIf points(numero)\x<points(numero+1)\x
    x_spr=x_spr+1
    If  x_spr>=points(numero+1)\x
      numero=numero+1
    EndIf
  Else
    x_spr=x_spr-1
    If  x_spr<=points(numero+1)\x
      numero=numero+1
    EndIf
  EndIf
  
  y_spr=points(numero)\a*x_spr+points(numero)\b
  
  DisplayTransparentSprite(#spr,x_spr-8,y_spr-8)
  
  
  Repeat
    Event = WindowEvent()      
    If  Event = #PB_Event_CloseWindow
      End 
    EndIf
  Until Event = 0
  
  Delay(1)
ForEver
Hasta la vista !
Frenchy Pilou
Messages : 2194
Inscription : jeu. 27/janv./2005 19:07

Message par Frenchy Pilou »

J'ai trouvé çà il y a un tut sur la courbe de bezier mais aussi plein de trucs rigolos!
La transformée de Fourier en s'amusant çà passe bien mieux :)
Et tout pour la 3D :)
ETC...
Bon c'est pas spécialement pour du basic, mais çà s'adapte facilement :)
cha0s
Messages : 681
Inscription : sam. 05/mars/2005 16:09

Message par cha0s »

pour les courbes bezier il y a sa http://www.developpez.net/forums/d49723 ... prites-3d/ en plus c'est en pure.
Avatar de l’utilisateur
Huitbit
Messages : 940
Inscription : jeu. 08/déc./2005 5:19
Localisation : Guadeloupe

Message par Huitbit »

@Chaos
Merci quand même mais...

Huitbit a dit :
je n'avais pas envie de mettre le nez dedans
:mrgreen:

J'adore réinventer le fil à couper la roue beurrée.

Avec purebasic, on crayonne deux trois trucs sur un bout de papier et zou :P !

En plus, vu la simplicité du code, je vais pouvoir appliquer sans problème tout ce que j'avais fait pour le solide guidé sur un rail!

A l'époque, le Caporal m'en avait parlé si je l'avais écouté :roll: , j'aurais tracé le sol avec quelques points de contrôle et en plus, j'aurais travaillé avec des droites
( :D cadeau bonux :D aucun calcul de dérivé à faire car dérivé=coefficient directeur de la droite!)

Hasta la vista !
beauregard
Messages : 1307
Inscription : dim. 08/juil./2007 18:32
Localisation : Toulouse

Message par beauregard »

joli code :) et je confirme, cà ne sort pas du circuit... et n'hésite pas à te plonger aussi dans l'Alphablending, pour magnifier un jeu il n'y a pas mieux...
config de mon ordi: seven, directx11, Pentium(R) DualCore E5700, RadeonHD 4550 512MB, PureBasic 4.61 x86
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

Avec un autre algo que Bezier et les subdivisions, j'ai fait ce code.

Code : Tout sélectionner

Structure PointInfo
   x.F
   y.F
   Level.I
   *Before
   *After
EndStructure

Structure Vertex2
   x.F
   y.F
EndStructure

Structure LineInfo
   x1.F
   y1.F
   x2.F
   y2.F
EndStructure

   Global NewList Pt.PointInfo()
   Global LevelMax.I = 2
   Global MarkQty.I = 20
   Global Dim Ln.LineInfo(999)
   Global MaxLine.I
   Global Dim Lb.Vertex2(999)
   Global MaxPoint.I

Procedure Inter(xA1.F, yA1.F, xA2.F, yA2.F, xB1.F, yB1.F, xB2.F, yB2.F, *A.Vertex2)

   Protected dxA.F
   Protected dyA.F   
   Protected dxB.F
   Protected dyB.F   
   Protected mA.F
   Protected pA.F   
   Protected mB.F
   Protected pB.F   
   Protected x.F
   Protected y.F

   dxA = xA1 - xA2
   dyA = yA1 - yA2
   dxB = xB1 - xB2
   dyB = yB1 - yB2
   
   If dxA = 0.0
      mB = dyB / dxB
      pB = yB1 - (mB * xB1)
      x = xA1
      y = mB * x + pB
   Else
      If dxB = 0.0
         mA = dyA / dxA
         pA = yA1 - (mA * xA1)
         x = xB1
         y = mA * x + pA
      Else
         mA = dyA / dxA
         pA = yA1 - (mA * xA1)

         mB = dyB / dxB
         pB = yB1 - (mB * xB1)

         x = (pB - pA) / (mA - mB)
         y = mA * x + pA
      EndIf
   EndIf

   
   *A\x = x
   *A\y = y
   
EndProcedure

Procedure InsertPoints(Level)
   Protected x1.F
   Protected y1.F
   Protected x2.F
   Protected y2.F
   SelectElement(Pt(), 0)
   *Start = Pt()
   ForEach(Pt() )
      If Pt() = *Start
         *After = *Start
         x2 = Pt()\x
         y2 = Pt()\y
      Else
         If Pt()\Level < Level
            *Before = *After
            x1 = x2
            y1 = y2
            *After = Pt()
            x2 = Pt()\x
            y2 = Pt()\y
            InsertElement(Pt() )
            Pt()\Level = Level
            Pt()\x = (x1 + x2) / 2.0
            Pt()\y = (y1 + y2) / 2.0
            Pt()\Before = *Before
            Pt()\After = *After
            NextElement(Pt() )
         EndIf
      EndIf
   Next
EndProcedure

Procedure UpdatePoints()
   Protected x1.F
   Protected y1.F
   Protected x2.F
   Protected y2.F
   For I = 1 To LevelMax
      ForEach(Pt() )
         If Pt()\Level = I
            *Normal = Pt()
            *Before = Pt()\Before
            *After =  Pt()\After
            ChangeCurrentElement(Pt(), *Before)
            x1 = Pt()\x
            y1 = Pt()\y
            ChangeCurrentElement(Pt(), *After)
            x2 = Pt()\x
            y2 = Pt()\y
            ChangeCurrentElement(Pt(), *Normal)
            Pt()\x = (x1 + x2) / 2.0
            Pt()\y = (y1 + y2) / 2.0         
         EndIf
      Next
   Next
EndProcedure

Procedure CalculateLines()
   Protected x1.F
   Protected y1.F
   Protected x2.F
   Protected y2.F
   Protected x3.F
   Protected y3.F
   Protected vxA.F
   Protected vyA.F
   Protected vxB.F
   Protected vyB.F
   Protected xA.F
   Protected yA.F
   Protected xB.F
   Protected yB.F
   Protected Pas.F
   Pas = 10.0
   MaxLine = -1
   OpStep = 0
   MaxPoint = -1
   ForEach Pt()
      Select OpStep
         Case 0
            If Pt()\Level = 1
               x1 = Pt()\x
               y1 = Pt()\y
               OpStep = 1
            EndIf
         Case 1
            If Pt()\Level = 0
               x2 = Pt()\x
               y2 = Pt()\y
               OpStep = 2
            EndIf   
         Case 2
            If Pt()\Level = 1
               x3 = Pt()\x
               y3 = Pt()\y
               vxA = (x2 - x1) / (Pas + 1.0)
               vyA = (y2 - y1) / (Pas + 1.0)
               vxB = (x3 - x2) / (Pas + 1.0)
               vyB = (y3 - y2) / (Pas + 1.0)
               xA = x1
               yA = y1
               xB = x2
               yB = y2
               For I = 0 To Pas
                  MaxLine + 1
                  Ln(MaxLine)\x1 = xA
                  Ln(MaxLine)\y1 = yA
                  Ln(MaxLine)\x2 = xB
                  Ln(MaxLine)\y2 = yB
                  P.Vertex2
                  If MaxLine > 0
                     With Ln(MaxLine - 1)
                        Inter(\x1, \y1, \x2, \y2, xA, yA, xB, yB, @P)
                     EndWith
                     MaxPoint + 1
                     Lb(MaxPoint)\x = P\x
                     Lb(MaxPoint)\y = P\y
                  EndIf
                  xA + vxA
                  yA + vyA
                  xB + vxB
                  yB + vyB
               Next
               OpStep = 1
               x1 = x3
               y1 = y3
            EndIf
      EndSelect
   Next
EndProcedure

Procedure DispLines()
   For I = 0 To MaxLine
      LineXY(Ln(I)\x1, Ln(I)\y1, Ln(I)\x2, Ln(I)\y2, #White)
   Next I
EndProcedure

Procedure DispLines2()
   For I = 1 To MaxPoint
      LineXY(Lb(I - 1)\x, Lb(I - 1)\y, Lb(I)\x, Lb(I)\y, #White)
   Next I
EndProcedure

   For I = 1 To MarkQty
      Angle.F = (I - 1) * 2.0 * #PI / MarkQty
      AddElement(Pt() )
      Pt()\x = 512 + Sin(Angle) * 200.0
      Pt()\y = 384 + Cos(Angle) * 200.0
   Next

   For I = 1 To LevelMax
      InsertPoints(I)
   Next
   InitSprite()
   InitMouse()
   OpenScreen(1024, 768, 32, "")
   
   Repeat
      Delay(1)
      ExamineMouse()
      MX = MouseX()
      MY = MouseY()
      MDX = MouseDeltaX()
      MDY = MouseDeltaY()
      MB1 = MouseButton(1)
      If MB1 = 0
         If MovePoint
            MovePoint = 0
            CalculateLines()
         EndIf
      Else
         UpdatePoints()
      EndIf
      ClearScreen(0)
      StartDrawing(ScreenOutput() )
         ForEach(Pt() )
            If Pt()\Level = 0
               If MB1
                  If (Abs(MX - Pt()\x) <= 8) And (Abs(MY - Pt()\y) <= 8)
                     MovePoint = 1
                     PointToMove = Pt()
                  EndIf
               EndIf
               Box(Pt()\x-8, Pt()\y-8, 16, 16, #Red)         
            EndIf
            If Pt()\Level = 1
               ;Box(Pt()\x-8, Pt()\y-8, 16, 16, #Blue)
            EndIf
            If Pt()\Level = 2
               ;Box(Pt()\x-8, Pt()\y-8, 16, 16, #Green)
            EndIf
         Next
         CalculateLines()
         UpdatePoints()
         DispLines2()
         If MovePoint
            ChangeCurrentElement(Pt(), PointToMove)
            Pt()\x + MDX
            Pt()\y + MDY
         EndIf
         Line(MX, MY, 16, 16, #White)
      StopDrawing()
      FlipBuffers()
   Until MouseButton(2)
   End
Avatar de l’utilisateur
kernadec
Messages : 1606
Inscription : ven. 25/avr./2008 11:14

Message par kernadec »

bonjour
pour le 1er post très très bien,
je pense que l'on va pouvoir appeler cet algo :courbe de "huitbit"

bon travail, merci,

cordialement
Avatar de l’utilisateur
Cool Dji
Messages : 1126
Inscription : ven. 05/sept./2008 11:42
Localisation : Besançon
Contact :

Message par Cool Dji »

Yaouh, jolis codes. Bravo !
C'est bien vu ces algos pour faire differement qu'avec Bezier et bien plus simple, génial.

Bordel, droites affines : j'ai pas utilisé ce terme depuis au moins 20 ans !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Au secours :lol:
Only PureBasic makes it possible
Avatar de l’utilisateur
kernadec
Messages : 1606
Inscription : ven. 25/avr./2008 11:14

Message par kernadec »

je pense que c'est une fonction à ajouter dans Purebasic
Avatar de l’utilisateur
Huitbit
Messages : 940
Inscription : jeu. 08/déc./2005 5:19
Localisation : Guadeloupe

Message par Huitbit »

Hello,

Merci pour les réponses,

Je suis complètement débordé en ce moment :x mais c'est promis, ce post ira beaucoup plus loin :wink:

Hasta la vista !
Avatar de l’utilisateur
kernadec
Messages : 1606
Inscription : ven. 25/avr./2008 11:14

Message par kernadec »

bonjour Huitbit
je viens de comparer ton tracer de circuit
avec un tracer identique en B-Spline et lignes curves,
mais peut être que tu as déjà comparer toi aussi?

alors, je remarque que les trois mode de tracé se chevauches,
et par rapport à ton tracé il y a seulement des différences de lissage
voila l'algo de la B-Spline et une doc des lignes curves "bentley Microstation"

http://fr.wikipedia.org/wiki/B-spline#Liens_internes
http://communities.bentley.com/Wiki/vie ... ge_Dans_MX

cordialement
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

Salut Kernadec,

Je ne sais pas comment tu fais pour comparer ces courbes mais si tu y arrives, c'est nickel!

Est-ce que tu pourrais comparer une courbe avec les code que j'ai pondu? Je pense d'ailleurs que vous n'avez point remarqué le petit batônnet en haut à gauche de l'écran au démarrage qui sert de curseur de souris et qui permet de déplacer les bornes rouge en cliquant sur ces dernières pour modifier la courbe en temps réel...

Ollivier
Avatar de l’utilisateur
kernadec
Messages : 1606
Inscription : ven. 25/avr./2008 11:14

Message par kernadec »

bonjour olivier
voila c'est facile
tu transfère l'image de la courbe sous Microstation
que l' on peut se procurer dans une version démo et c'est un logiciel de ouf.
qui fonctionne entre 10 et 15 minutes, puis s'arrête et revient sous windows
mais on peut relancer Microstation et il n'a rien perdu de ton dessin puisqu'il fonctionne en overlay,
il sauvegarde sur le fichier creer tout tes essais, il suffit d' importer l'image dans ton plan de travail et de tracer une courbe de Bézier, une ligne curve, une Bspline, par les point marqués sur l'image du dessin de Huitbit, onl trace la courbe, et de visu on peut se rendre compte des différences, bien que ce soit à l'oeil sur ce genre de logiciel le zoom et pratiquement infini. alors voila!
j'ai une expérience professionnelle avec ce logiciel, j'espère avoir répondu a ta question

et pour ton code je le ferais, mais il faut que je fasse plusieurs images pour cela.
sous Microstation, il n'y a pas de courbe combinée il y à les trois citées. Mais il n'est pas précisé dans la doc si ce sont des bezier curve, beziers bspline, et en plus il y plusieurs algo dérivés de ces couples de tracés, voila les limites de mon investigations
cordialement
Dernière modification par kernadec le ven. 26/juin/2009 19:40, modifié 1 fois.
Avatar de l’utilisateur
Cool Dji
Messages : 1126
Inscription : ven. 05/sept./2008 11:42
Localisation : Besançon
Contact :

Message par Cool Dji »

Sisi Ollivier,
j'ai bien vu kon pouvait déplacer les points rouges in real time..
Les 2 codes me bluffent car j'ai toujours eu du mal avec la géométrie...ps 3/20 en maths au bac coef 5. Je l'ai eu sans passer par les rattrapages !
Only PureBasic makes it possible
Avatar de l’utilisateur
kernadec
Messages : 1606
Inscription : ven. 25/avr./2008 11:14

Message par kernadec »

moi j'ai raté le bac, je suis tombé a l'eau
Répondre