Page 1 sur 2

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

Publié : mer. 22/avr./2009 4:15
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 !

Publié : jeu. 23/avr./2009 18:01
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 :)

Publié : jeu. 23/avr./2009 18:32
par cha0s
pour les courbes bezier il y a sa http://www.developpez.net/forums/d49723 ... prites-3d/ en plus c'est en pure.

Publié : ven. 24/avr./2009 3:10
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 !

Publié : ven. 24/avr./2009 23:10
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...

Publié : jeu. 25/juin/2009 9:09
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

Publié : jeu. 25/juin/2009 10:33
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

Publié : jeu. 25/juin/2009 10:55
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:

Publié : jeu. 25/juin/2009 12:53
par kernadec
je pense que c'est une fonction à ajouter dans Purebasic

Publié : jeu. 25/juin/2009 23:03
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 !

Publié : ven. 26/juin/2009 11:18
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

Publié : ven. 26/juin/2009 18:00
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

Publié : ven. 26/juin/2009 19:31
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

Publié : ven. 26/juin/2009 19:38
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 !

Publié : ven. 26/juin/2009 19:43
par kernadec
moi j'ai raté le bac, je suis tombé a l'eau