Déplacement visuel d'un point sur une suite de segments

Résolu
Renaud974 Messages postés 15 Date d'inscription mardi 29 août 2006 Statut Membre Dernière intervention 17 novembre 2012 - 28 sept. 2012 à 14:56
Renaud974 Messages postés 15 Date d'inscription mardi 29 août 2006 Statut Membre Dernière intervention 17 novembre 2012 - 29 sept. 2012 à 16:34
Bonjour,

Malgré pas mal de recherches, je n'arrive pas à trouver un fort coup de pouce pour écrire un algo me permettant de faire la représentation grapique d'un point qui se déplace à vitesse constante sur une trajectoire constituée de segments (tableau de points).
L'idée est de mettre un timer (VB6) et de lui faire afficher régulièrement un point qui se situe sur la trajectoire et qui est à une distance fixe (cumulée sur trajectoire) du point précédemment affiché.
Sur un seul segment, je m'en sors.
Au-delà, j'ai des nœuds au cerveau. Je n'arrive pas à gérer la succession des segments et le fait qu'il faille éventuellement sauter plusieurs segments s'ils sont petits (en ajoutant leur longueur).
J'ai l'idée, mais transformer ça en boucles et en conditions est trop rude pour moi.
Quelqu'un a quand même bien dû mettre ça en ligne quelque part, nom de nom!

Voudriez-vous me filer un coup de main par le biais d'un lien (français ou anglais), ou d'un bout de pseudo-code?

Bien cordialement,
Renaud.

16 réponses

Bonjour Renaud.

Je vous propose l'algorithme suivant

Option Explicit
Private Type Point
    x As Single
    y As Single
End Type
Private Type Segment
    Point1 As Point
    Point2 As Point
    Longueur As Single
End Type


Private Sub Procéder(Lst() As Point, Pas As Single)
Dim i As Long, n As Long, Sgm As Segment, Sgms() As Segment
Dim x1 As Single, x2 As Single, dx As Single, y1 As Single, y2 As Single, dy As Single
Dim L() As Single, a As Long, b As Long, c As Long
Dim u As Single, k As Single, d As Single
Dim xa As Single, ya As Single, xb As Single, yb As Single, x As Single, y As Single
Dim a0 As Long

'Récupération du nombre de segments
n = UBound(Lst) - 1

'Construction et dessin des segments
ReDim Sgms(0 To n)
For i = 1 To n
    With Sgm
        .Point1 Lst(i): .Point2 Lst(i + 1)
        x1 .Point1.x: x2 .Point2.x: dx = x1 - x2
        y1 .Point1.y: y2 .Point2.y: dy = y1 - y2
        .Longueur = Sqr(dx * dx + dy * dy)
        Accueil.Line (x1, y1)-(x2, y2)
        Accueil.PSet (x2, y2)
    End With
    Sgms(i) = Sgm
Next i

'Construction de la fonction de linéarisation
ReDim L(0 To n + 1)
L(1) = 0
For i = 2 To n + 1
    L(i) = L(i - 1) + Sgms(i - 1).Longueur
Next i

'Calcul et affichage des points
i 0: a0 1
Do
    d = i * Pas
    If d > L(n + 1) Then
        Exit Do
    Else
        'Calcul et affichage du point
        If d = L(n + 1) Then
            a n: u Sgms(n).Longueur
        Else
            a a0: b n + 1
            Do
                If b - a = 1 Then
                    Exit Do
                Else
                    c = Int((a + b) / 2)
                    If d < L(c) Then b c Else a c
                End If
            Loop
        End If
        Sgm = Sgms(a)
        u = d - L(a)
        k = u / Sgm.Longueur
        With Lst(a)
            xa .x: ya .y
        End With
        With Lst(b)
            xb .x: yb .y
        End With
        x = xa + k * (xb - xa)
        y = ya + k * (yb - ya)
        Accueil.Circle (x, y), 2, RGB(255, 0, 0)
        
        'Itération
        i i + 1: a0 a
    End If
Loop
End Sub

Il a été testé sur une feuille nommée "Accueil", avec

AutoRedraw True, ScaleMode 3 (Pixel)


Pour l'utiliser, il faut préparer un tableau Lst() As Point. Il s'agit d'un tableau dynamique redimensionné de 0 à n, où n est le nombre de points décrivant la trajectoire, le point Lst(0) étant ignoré. Vous pourrez alors appeler la méthode Procéder, en prenant comme premier argument ce tableau Lst(), et comme second argument Pas l'intervalle de distance entre deux marques successives.

En espérant que cela vous sera utile.


Étant illettré, je signe d'une croix : ×
3
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
28 sept. 2012 à 17:11
Bonjour,
Je comprends ('sinon je ne vois pas comment) que tu as les coordonnées des extrémités des segments successifs.
Tu peuix alors t'inspirer du source que j('ai déposé là ===>
Tapez le texte de l'url ici.
La procédure allons traite, à chaque fois, un segment nouveau.
________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
0
Renaud974 Messages postés 15 Date d'inscription mardi 29 août 2006 Statut Membre Dernière intervention 17 novembre 2012
28 sept. 2012 à 18:19
Bonjour,

Oui, j'ai les coordonnées de tous les points constitutifs de ma trajectoire (qui est une succession de segments).

J'ai exécuté le source que vous me proposez et je l'ai regardé, mais mon principal problème n'est pas traité : le saut du segment n au segment n+1, voire carrément le saut du segment n au segment n+2 ou n+x quand les segments sont très petits et que la vitesse est élevée (en effet, la distance parcourue entre deux affichages successifs de mon point mobile - disons que c'est un cercle - peut être supérieure à la taille d'un segment).
Ces sauts sont nécessaires pour avoir une vitesse constante visuellement (ce qui n'est pas le cas dans votre exemple où la vitesse varie en fonction de l'angle du segment).

Bien cordialement,
Renaud.
0
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
28 sept. 2012 à 19:31
Il te suffit alors de ne pas utiliser duree comme constante, mais de le faire varier en fonction de la distance réelle parcourue dans chaque tour de la boucle.
Cette distance se mesure par application du théorème de Pythagore.


________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Renaud974 Messages postés 15 Date d'inscription mardi 29 août 2006 Statut Membre Dernière intervention 17 novembre 2012
28 sept. 2012 à 20:57
J'avais plus dans l'idée un truc du genre suivant :
Je choisis une vitesse V d'avancement du point (par exemple 20mm/s)
Je choisis un nombre d'images par secondes n (idéalement 24, on va prendre 20 pour simplifier)
D'où ma fréquence d'affichage du point en ms : DeltaT=1000/n=1000/20=50ms
Entre chaque affichage du point, je dois déplacer celui-ci sur mon trajet de la distance d=V*DeltaT=20*0.05=1mm

Imaginons que j'ai 3 segments, délimités par P1, P2, P3, P4 avec
P1P2=2.4mm
P2P3=0.2mm
P3P4=2mm

Au début de mon mouvement, je vais afficher mon cercle sur P1
50ms plus tard, je vais l'afficher entre P1 et P2, à 1mm de P1
50ms plus tard, je vais l'afficher entre P1 et P2, à 2mm de P1
50ms plus tard, je ne l'affiche pas sur P2P3, car il faut que mon point parcoure 1mm en plus, je vais donc l'afficher entre P3 et P4, à 0.4mm de P3.
50ms plus tard, je vais l'afficher entre P3 et P4, à 1.4mm de P3
Il ne me reste alors plus que 0.6mm sur [P3P4]. Je vais donc afficher mon cercle sur P4 un peu plus tôt que 50ms : 0.6*50/1=30ms.

C'est tout ça que je voudrais coder.
0
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
28 sept. 2012 à 21:06
Tu as ton idée ?
Applique-la, si tu pense qu'elle est la bonne.
Je persiste et signe : si tu veux une vitesse constante, il te faut algébriquement parlant passer par le calcul de la distance parcourue (et donc : théorème de Pythagore). Tout le reste ne serait que pure fantaisie.
Mais fais donc, fais donc ... et montre.


________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
0
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
28 sept. 2012 à 21:12
Enfin quoi !
Comment peux-tu penser à calculer/définir une vitesse sans les deux paramètres qui sont à la base même de sa définition (durée et distance) ???


________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
0
Renaud974 Messages postés 15 Date d'inscription mardi 29 août 2006 Statut Membre Dernière intervention 17 novembre 2012
28 sept. 2012 à 21:13
Oui, oui, je suis bien conscient qu'il faut que je calcule des distances parcourues, et ça ne me pose aucun problème mathématique d'ailleurs, je sais faire. Ce qu'il y a, c'est que je souhaiterais un clignotement du point régulier (sauf pour la toute fin du mouvement), donc je ne souhaite pas faire varier la période du timer. Si c'est possible, bien entendu.

Je ne suis pas bloqué sur cette idée, c'est seulement la description de ma façon d'envisager la chose pour le moment. Si tu as des explication un peu plus précises sur ce que tu suggères, je pourrais peut-être mieux l'appréhender et le développer.
0
Renaud974 Messages postés 15 Date d'inscription mardi 29 août 2006 Statut Membre Dernière intervention 17 novembre 2012
28 sept. 2012 à 21:23
Comment peux-tu penser à calculer/définir une vitesse sans les deux paramètres qui sont à la base même de sa définition (durée et distance) ???


Je ne cherche pas à calculer la vitesse de déplacement, c'est une donnée de départ.
0
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
28 sept. 2012 à 21:27
Bref ...
Bonne chance dans tes approches. Elles m'échappent, personnellement. Mais apparemment, pas à toi ... Vas-y donc. Reviens si tu échoues et on reviendra à celle définition de la vitesse (qu'elle soit à établir ou à constater).
Je te laisse là.


________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
0
Renaud974 Messages postés 15 Date d'inscription mardi 29 août 2006 Statut Membre Dernière intervention 17 novembre 2012
28 sept. 2012 à 21:33
Merci (sincèrement) d'avoir essayé. Je vais essayer de comprendre ta suggestion.

Au plaisir.
Renaud.
0
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
29 sept. 2012 à 08:29
Résumons donc :
Je ne cherche pas à calculer la vitesse de déplacement, c'est une donnée de départ.

c'est que je souhaiterais un clignotement du point régulier (sauf pour la toute fin du mouvement), donc je ne souhaite pas faire varier la période du timer. Si c'est possible, bien entendu.

Si tu as des explication un peu plus précises sur ce que tu suggères, je pourrais peut-être mieux l'appréhender et le développer

Ce qui se traduit donc, puisque vitesse régulière, d'une part, et fréquence régulère de "cliché", d'autre part, par :
--- faire clignoter à chaque fois qu'une certaine distance a été parcourue ----
et ce : quelle que soit le "regard" que tu portes sur les choses.
Non ?
Quant à :
(sauf pour la toute fin du mouvement)

- compréhensible uniquement en toute fin de "course" (extrémité du parcours total)
- pas du tout compréhensible en ce qui concerne les "portions" de chemin.
Rien à faire, ami ===>> il te faudra réellement attendre que la distance "tempo" ait été parcourue, ce qui signifie qu'en cas de passage d'un segment à l'autre la distance devra être calculée, lorsque inférieure à celle correspondant au "tempo", par addition avec une fraction du segment suivant.

Et ma conclusion, maintenant, après tes précisions nouvelles sur le résultat souhaitée :
comme il te faudra calculer avec précision le moment où "faire clignoter" le point, tu n'échapperas pas (si tu veux être rigoureux), à l'utilisation d'un timer à intervalle très court, où il te faudra :
--- faire avancer en boucle ton point sur une infime distance (la plus infime possible)
--- à chaque tour de cette boucle : calculer et attendre que le sous-parcours soit immédiatement égal ou supérieur à la distance "longueur d'onde" décidée.
Il est clair que ce calcul prendra lui-même du temps. Si ce temps de calcul est supérieur à celui de l'intervalle du timer, toute ta "visualisation" s'en trouvera forcément faussée.

________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
0
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
29 sept. 2012 à 08:40
Je crois par ailleurs commencer à deviner que tu n'es pas face à un parcours dont le dessin t'a été communiqué, mais face à un parcours résultant de "relevés" faits (sur port série, par exemple).
La solution la moins farfelue serait alors, au moment même des relevés, d'alimenter un tableau selon la fréquence que tu veux.
il te suffira alors ensuite, si tu veux "revisualiser" l'avancement : d'utiliser les données de ce tableau, à la même fréquence de relevés.


________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
0
Renaud974 Messages postés 15 Date d'inscription mardi 29 août 2006 Statut Membre Dernière intervention 17 novembre 2012
29 sept. 2012 à 14:27
On se rejoint sur presque tout, j'ai dû mal m'exprimer.
Pas trop le temps ces jours-ci, je fais ma tambouille dans mon coin et je poste mes élucubrations plus tard.

Bien cordialement,
Renaud.
0
Renaud974 Messages postés 15 Date d'inscription mardi 29 août 2006 Statut Membre Dernière intervention 17 novembre 2012
29 sept. 2012 à 14:30
Désolé, ma réponse ci-dessus (14h27) s'adressait à ucfoutu, je n'avais pas rafraîchi la page.

Merci pour votre code Zermelo, je regarde ça ce soir.

Bien cordialement,
Renaud.
0
Renaud974 Messages postés 15 Date d'inscription mardi 29 août 2006 Statut Membre Dernière intervention 17 novembre 2012
29 sept. 2012 à 16:34
Bonjour,

Entre la promenade familiale digestive et les occupations de l'après-midi, j'ai trouvé un petit moment pour étudier le code ci-dessus.
Zermelo a bien compris ce qui me tracassait : cette imbrication de boucles et de conditions que j'ai vraiment du mal à mettre en œuvre, tous les calculs m'étant par ailleurs familiers.
Son code permet de définir les positions successives du "flash" à faire apparaître pour simuler le mouvement. Comme je dispose à l'origine de la trajectoire complète, je peux construire un tableau de ces positions et utiliser ensuite un timer pour faire l'affichage, sans temps de calcul. A charge pour moi de redimensionner le tableau à la fin du mouvement pour libérer de la mémoire si besoin est.

J'ai mis tout ça en œuvre à partir d'une succession de points entrés au hasard dans le Form_Load. Et ça fonctionne très bien!
Pour tester, vous devez créer une form "Accueil" avec AutoRedraw True, ScaleMode 3 (Pixel), sur laquelle vous placez deux textbox, un bouton, et un timer avec Enabled=false en conservant les noms par défaut.
Text1 sert à définir le pas, Text2 sert à définir l'intervalle de temps. Vous pouvez mettre deux labels pour préciser. Ci-dessous une capture pour préciser tout ça.

http://www.casimages.com/img.php?i=120929042918976010374637.gif

Voici ensuite le code à coller (bon, une ou deux variables intermédiaires le rendraient probablement plus lisible) :
Option Explicit

Private Type Point
    x As Single
    y As Single
End Type

Private Type Segment
    Point1 As Point
    Point2 As Point
    Longueur As Single
End Type

Dim Points() As Point
Dim PointsDuFilm() As Point
Dim IterationAffichage As Integer

Private Sub Form_Load()
   ReDim PointsDuFilm(0 To 0)
   ReDim Points(0 To 6)
   Points(0).x = 0 ' ignoré
   Points(0).y = 0 'ignoré
   Points(1).x = 100
   Points(1).y = 220
   Points(2).x = 100
   Points(2).y = 300
   Points(3).x = 120
   Points(3).y = 300
   Points(4).x = 500
   Points(4).y = 130
   Points(5).x = 510
   Points(5).y = 140
   Points(6).x = 500
   Points(6).y = 340
End Sub

Private Sub Proceder(Lst() As Point, Pas As Single)
   Dim i As Long, n As Long, Sgm As Segment, Sgms() As Segment
   Dim x1 As Single, x2 As Single, dx As Single, y1 As Single, y2 As Single, dy As Single
   Dim L() As Single, a As Long, b As Long, c As Long
   Dim u As Single, k As Single, d As Single
   Dim xa As Single, ya As Single, xb As Single, yb As Single, x As Single, y As Single
   Dim a0 As Long
   
   'Récupération du nombre de segments
   n = UBound(Lst) - 1
   
   'Construction et dessin des segments
   ReDim Sgms(0 To n)
   For i = 1 To n
       With Sgm
           .Point1 Lst(i): .Point2 Lst(i + 1)
           x1 .Point1.x: x2 .Point2.x: dx = x1 - x2
           y1 .Point1.y: y2 .Point2.y: dy = y1 - y2
           .Longueur = Sqr(dx * dx + dy * dy)
           Accueil.Line (x1, y1)-(x2, y2)
           Accueil.PSet (x2, y2)
       End With
       Sgms(i) = Sgm
   Next i
   
   'Construction de la fonction de linéarisation
   ReDim L(0 To n + 1)
   L(1) = 0
   For i = 2 To n + 1
       L(i) = L(i - 1) + Sgms(i - 1).Longueur
   Next i
   
   'Calcul et affichage des points
   i 0: a0 1
   Do
       d = i * Pas
       If d > L(n + 1) Then
           Exit Do
       Else
           'Calcul et affichage du point
           If d = L(n + 1) Then
               a n: u Sgms(n).Longueur
           Else
               a a0: b n + 1
               Do
                   If b - a = 1 Then
                       Exit Do
                   Else
                       c = Int((a + b) / 2)
                       If d < L(c) Then b c Else a c
                   End If
               Loop
           End If
           Sgm = Sgms(a)
           u = d - L(a)
           k = u / Sgm.Longueur
           With Lst(a)
               xa .x: ya .y
           End With
           With Lst(b)
               xb .x: yb .y
           End With
           x = xa + k * (xb - xa)
           y = ya + k * (yb - ya)
           
           ReDim Preserve PointsDuFilm(0 To UBound(PointsDuFilm) + 1)
           PointsDuFilm(UBound(PointsDuFilm)).x = x
           PointsDuFilm(UBound(PointsDuFilm)).y = y
           
           'Accueil.Circle (x, y), 2, RGB(255, 0, 0)
           
           'Itération
           i i + 1: a0 a
       End If
   Loop
End Sub

Private Sub Command1_Click()
   Accueil.Cls
   Call Proceder(Points(), CSng(Text1.Text))
   IterationAffichage = 1
   Timer1.Interval = CSng(Text2.Text)
   Timer1.Enabled = True
End Sub

Private Sub Timer1_Timer()
   Accueil.AutoRedraw = False
   Accueil.Cls
   Accueil.Circle (PointsDuFilm(IterationAffichage).x, PointsDuFilm(IterationAffichage).y), 2, RGB(255, 0, 0)
   If IterationAffichage UBound(PointsDuFilm) Then Timer1.Enabled False
   IterationAffichage = IterationAffichage + 1
End Sub


En mettant par exemple un pas de 5 et un timer de 25, on visualise le mouvement en cliquant sur le bouton.
Bon, il y a un petit bug si on fait la manip' plusieurs fois, mais le principe est là.

Mille mercis!!! Je vais imprimer ce bout de code et lire tout ça à tête reposée avec un crayon et un papier pour tout décortiquer et être moins bête dans quelques jours!

Bien cordialement,
Renaud.
0
Rejoignez-nous