Page 1 sur 1

Cinématique inverse

Publié : ven. 06/juil./2018 20:50
par Fig
Vous pouvez modifier les constantes correspondantes au nombre d'os et leur longueur.

En dépit des apparences, cela n'a rien à voir avec le double pendule.

C'est ce qui est utilisé (dans le principe) en modélisation 3D pour bouger un squelettes ou pour animer un bras robotique en le déplaçant par son extrémité.

Code : Tout sélectionner

#x=600:#y=400
#nbBones=5 ;nombres de segments
#lengthBone=50 ;longueur des segments
#FixX=#X/2:#FixY=#Y/2 ;Coordonnées du point fixe

If InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0 Or OpenWindow(0, 0, 0, #X, #Y, "Backward kinematic", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)=0 Or OpenWindowedScreen(WindowID(0),0,0,#X,#Y,0,0,0,#PB_Screen_WaitSynchronization)=0
    MessageRequester("Error", "Can't open the sprite system", 0)
    End
EndIf
Structure Bone
    x1.i
    y1.i
    x2.i
    y2.i
    length.i
    Angle.f
EndStructure
NewList Bone.Bone()

Procedure AddBone(List Bone.Bone(),length.i,angle.f)
    If ListIndex(Bone())=-1
        AddElement(Bone())
        Bone()\x1=#FixX
        Bone()\y1=#FixY
    Else
        xold.i=Bone()\x2
        yold.i=Bone()\y2
        AddElement(Bone())
        Bone()\x1=xold
        Bone()\y1=yold
    EndIf
    Bone()\Angle=angle:Bone()\length=length
    Bone()\x2=Bone()\x1+Bone()\length*Cos(angle)
    Bone()\y2=Bone()\y1+Bone()\length*Sin(angle)
EndProcedure

Procedure follow(List Bone.Bone(),targetX.i,targetY.i)
    Bone()\Angle=ATan2(targetX-Bone()\x1,targetY-Bone()\y1)
    Bone()\x2=Bone()\x1+Bone()\length*Cos(Bone()\Angle)
    Bone()\y2=Bone()\y1+Bone()\length*Sin(Bone()\Angle)
    a.i=Bone()\x2-Bone()\x1
    b.i=Bone()\y2-Bone()\y1
    Bone()\x2=targetx
    Bone()\y2=targety
    Bone()\x1=targetx-a
    Bone()\y1=targety-b
EndProcedure

Procedure Update(List Bone.Bone(),xold.i,yold.i)
    If LastElement(Bone())
        Repeat
            follow(Bone(),xold,yold)
            xold=Bone()\x1
            yold=Bone()\y1
        Until PreviousElement(Bone())=0
        ;shift back to fix point
        deltax.i=Bone()\x1-#FixX
        deltay.i=Bone()\y1-#FixY
        ForEach Bone()
            Bone()\x1-deltax
            Bone()\y1-deltay
            Bone()\x2-deltax
            Bone()\y2-deltay
        Next
    EndIf
EndProcedure

;create some bones...
For i=1 To #nbBones
    AddBone(Bone(),#lengthBone,Radian(-90))
Next i

Dx.i=2:Dy.i=2:x.i=Random(#X):y.i=Random(#Y)
Repeat
    FlipBuffers()
    ClearScreen(RGB(0,0,0))
    ExamineKeyboard()
    ;bouncing box
    If x>#x Or x<0:Dx=-Dx:EndIf
    If y>#y Or y<0:Dy=-Dy:EndIf
    x+Dx:y+Dy
    
    Update(Bone(),x,y)
    StartDrawing(ScreenOutput())
    Circle(x,y,10,#Red)
    ForEach Bone()
        LineXY(Bone()\x1,Bone()\y1,Bone()\x2,Bone()\y2,#Blue)
        Circle(Bone()\x2,Bone()\y2,2,#White)
    Next    
    Circle(#FixX,#FixY,3,#Green)
    StopDrawing()
     Repeat:Event = WindowEvent():If event= #PB_Event_CloseWindow:End:EndIf:Until event=0
Until KeyboardPushed(#PB_Key_Escape)

Re: Cinématique inverse

Publié : sam. 07/juil./2018 9:59
par Kwai chang caine
C'est vraiment joli, j'y connais rien, mais c'est un peu comme les aquariums ou le feu, on se surprend à regarder ça pendant un certain temps
Merci 8)

Re: Cinématique inverse

Publié : sam. 07/juil./2018 16:29
par celtic88
8O

TOI,
tu dois travailler chez google :)

Re: Cinématique inverse

Publié : lun. 09/juil./2018 8:02
par Guillot
joli code
tres propre

Re: Cinématique inverse

Publié : lun. 09/juil./2018 8:49
par Ar-S
Concis et beau rendu. Bravo.

Re: Cinématique inverse

Publié : mar. 28/août/2018 22:15
par threedslider
cool, beaucoup d'inspiration pour mon projet :)

Re: Cinématique inverse

Publié : mer. 13/mai/2020 15:38
par omega
salut

Je reçois toujours ce message: "Can't open the sprite system"

Re: Cinématique inverse

Publié : mer. 13/mai/2020 16:40
par SPH
Pas mal (femelle donc) :mrgreen:

Re: Cinématique inverse

Publié : jeu. 14/mai/2020 21:28
par venom
Sympa ce code, j'etais passé a coté. Merci Fig. 8)
omega a écrit :salut
Je reçois toujours ce message: "Can't open the sprite system"
j'ai séparer les initialisations dans le code de fig, essaie a nouveau pour voir ce qui cloche (le retour d'erreur est propre a chaque initialisation)

Code : Tout sélectionner

#x=600:#y=400
#nbBones=5 ;nombres de segments
#lengthBone=50 ;longueur des segments
#FixX=#X/2:#FixY=#Y/2 ;Coordonnées du point fixe

    ;- Initialisation environnement sprite
    If InitSprite() = 0
     MessageRequester("Erreur", "Impossible d'ouvrir l'écran & l'environnement nécessaire aux sprites !", 0)
      End
    EndIf

    ; Initialisation environnement clavier
    If InitKeyboard() = 0
     MessageRequester("Erreur", "Impossible d'initialisé le clavier !", 0)
      End
    EndIf
  
    ; Initialisation environnement souris
    If InitMouse() = 0
     MessageRequester("Erreur", "Impossible d'initialisé la souris !", 0)
      End
    EndIf
    
    
    OpenWindow(0, 0, 0, #X, #Y, "Backward kinematic", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
     OpenWindowedScreen(WindowID(0),0,0,#X,#Y,0,0,0,#PB_Screen_WaitSynchronization)

Structure Bone
    x1.i
    y1.i
    x2.i
    y2.i
    length.i
    Angle.f
EndStructure
NewList Bone.Bone()

Procedure AddBone(List Bone.Bone(),length.i,angle.f)
    If ListIndex(Bone())=-1
        AddElement(Bone())
        Bone()\x1=#FixX
        Bone()\y1=#FixY
    Else
        xold.i=Bone()\x2
        yold.i=Bone()\y2
        AddElement(Bone())
        Bone()\x1=xold
        Bone()\y1=yold
    EndIf
    Bone()\Angle=angle:Bone()\length=length
    Bone()\x2=Bone()\x1+Bone()\length*Cos(angle)
    Bone()\y2=Bone()\y1+Bone()\length*Sin(angle)
EndProcedure

Procedure follow(List Bone.Bone(),targetX.i,targetY.i)
    Bone()\Angle=ATan2(targetX-Bone()\x1,targetY-Bone()\y1)
    Bone()\x2=Bone()\x1+Bone()\length*Cos(Bone()\Angle)
    Bone()\y2=Bone()\y1+Bone()\length*Sin(Bone()\Angle)
    a.i=Bone()\x2-Bone()\x1
    b.i=Bone()\y2-Bone()\y1
    Bone()\x2=targetx
    Bone()\y2=targety
    Bone()\x1=targetx-a
    Bone()\y1=targety-b
EndProcedure

Procedure Update(List Bone.Bone(),xold.i,yold.i)
    If LastElement(Bone())
        Repeat
            follow(Bone(),xold,yold)
            xold=Bone()\x1
            yold=Bone()\y1
        Until PreviousElement(Bone())=0
        ;shift back to fix point
        deltax.i=Bone()\x1-#FixX
        deltay.i=Bone()\y1-#FixY
        ForEach Bone()
            Bone()\x1-deltax
            Bone()\y1-deltay
            Bone()\x2-deltax
            Bone()\y2-deltay
        Next
    EndIf
EndProcedure

;create some bones...
For i=1 To #nbBones
    AddBone(Bone(),#lengthBone,Radian(-90))
Next i

Dx.i=2:Dy.i=2:x.i=Random(#X):y.i=Random(#Y)
Repeat
    FlipBuffers()
    ClearScreen(RGB(0,0,0))
    ExamineKeyboard()
    ;bouncing box
    If x>#x Or x<0:Dx=-Dx:EndIf
    If y>#y Or y<0:Dy=-Dy:EndIf
    x+Dx:y+Dy
   
    Update(Bone(),x,y)
    StartDrawing(ScreenOutput())
    Circle(x,y,10,#Red)
    ForEach Bone()
        LineXY(Bone()\x1,Bone()\y1,Bone()\x2,Bone()\y2,#Blue)
        Circle(Bone()\x2,Bone()\y2,2,#White)
    Next   
    Circle(#FixX,#FixY,3,#Green)
    StopDrawing()
     Repeat:Event = WindowEvent():If event= #PB_Event_CloseWindow:End:EndIf:Until event=0
Until KeyboardPushed(#PB_Key_Escape)





@++