VB: trigonométrie [Résolu]

Signaler
-
Messages postés
61
Date d'inscription
dimanche 26 janvier 2014
Statut
Membre
Dernière intervention
6 décembre 2020
-
Bonsoir,

Je suis en train de tourner en bourrique avec VB.
Je suis face à un exercice de dessin, et je suis infichu de réussir à créer ne serait-ce que le début de ma figure géométrique.

Le concept pourtant est relativement simple:
dessiner un segment à des coordonnées (x, y, xPrim, yPrim)
lui infliger un raccourcissement par un facteur k
puis dessiner le nouveau segment au point de coordonnées initiales (xPrim, yPrim) avec une rotation de teta degrés (et répéter ce processus jusqu'à ce que la Terre s'effondre mais pas tout à fait).

Le "détail" qui, pêche concerne d'après moi la manipulation des fonctions cos et sin.
Sur calculatrice j'obtiens un résultat cohérent pour mes futures coordonnées.
Sur cet algorithme en revanche... c'est l'équivalent d'un slip un soir de gastro. Le respect des angles n'a aucune corrélation avec l'angle lui-même.
Malgré la conversion des degrés en radians, l'appel à C'thulhu et aux poupées vaudou, l'incohérence reste la référence.
J'en déduis que c'est la version VB de cos et sin que j'utilise comme un manche.

Je vous propose si vous l'acceptez, de jeter un œil sur ma progression du moment _ nb: j'ai désactivé certains fragments à cause de la faute de base et il me reste 2 paramètres à traiter (limite de la future boucle notamment).

        Dim longueur, angle, x, y, xPrim, yPrim, j As Integer
        Dim coeff, k As Double
        longueur = LengthBox.Text()                     '// valeurs utilisateur
        angle = AngleUpDown.Value()
        angle = angle * Math.PI / 180                   '//angle en RAD
        k = CoeffUpDown.Value()
        x = PictureBox1.Width / 2 - longueur / 2        '//dessin autour du centre
        y = PictureBox1.Height / 2 + longueur / 2
        xPrim = x + longueur                            '//coordonnees temporaires B du sgt [AB]
        yPrim = y
        j = 1
        coeff = 1                                       '//coeff temporaire avant boucle
        'For i = longueur To 0 Step -1
        g.DrawLine(Pens.Black, x, y, xPrim, yPrim)
        coeff = k
        longueur = longueur * coeff
        x = xPrim                                        '// coordonnees A deviennent B
        y = yPrim
        xPrim = (Math.Cos(angle) * longueur)     '// B devient C - formule trigo x = hypothenuse . cos angle
        yPrim = yPrim - (Math.Sin(angle) * longueur)     '// y = hypothenuse . sin angle
        'Next
        g.DrawLine(Pens.Black, x, y, xPrim, yPrim)
        Label1.Text = ((Math.Cos(angle) * longueur))


J'ai enlevé un compteur entre temps (j) dont le but à la base était d'incrémenter l'angle (angle = angle x j)
Mes 2 dernières lignes sont des vérifications dans l'optique "débogage".
Auriez-vous une solution pour résoudre mes équations de xPrim et yPrim qui sont définitivement fausses? et probablement le nœud du problème?
Merci d'avance pour votre temps
A voir également:

9 réponses

Messages postés
15400
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
18 janvier 2021
643
Bonsoir

ce n'est de toute façon pas un problème de développement, mais de maths.



Connaissant l'angle Alpha et la longueur L, c'est Dx et Dy que tu peux calculer.
Les coordonnées de B, ça vient après.
Messages postés
15400
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
18 janvier 2021
643
Il faut faire par étape.
D'abord on calcule la longueur du futur segment, ce que tu as fait.
Ensuite on détermine son angle par rapport à l'horizontale (on peut aussi par rapport à la verticale, mais ça inverse les calculs), ce que tu as fait.

J'ai donc un segment de longueur L et d'angle Alpha, avec un point connu => c'est un vecteur.
Avec la trigonométrie on peut calculer les coordonnées du vecteur Dx et Dy.

cos(Alpha) = Dx / L => Dx = L * cos(Alpha)
sin(Alpha) = Dy / L => Dy = L * sin(Alpha)

Ce que tu as fait aussi.

Pour déterminer les coordonnées du point B, il faut translater les coordonnées du point A de la valeur du vecteur.

Dans ton premier code
        xPrim = (Math.Cos(angle) * longueur)     '// B devient C - formule trigo x = hypothenuse . cos angle
        yPrim = yPrim - (Math.Sin(angle) * longueur)     '// y = hypothenuse . sin angle

il n'y avait pas de translation de X.

Dans le second, je pense que c'est un problème de signe.
On a fait le calcul avec des longueurs positives donc Dx et Dy sont positifs.

Le repère que j'ai montré à son axe des X positif à droite et son axe des Y positifs vers le haut, car j'ai utilisé Géogebra (un logiciel de Maths utilisé au collège).
Dans ce cas, il faudrait effectivement ajouter Dx à xA et soustraire Dy à yA.

Mais je ne suis pas sûr dans une pictureBox le repère soit dans ce sens. Je ne code plus en winform depuis un moment et je n'ai que rarement utiliser des picturebox. Je crois me souvenir que comme pour un image, les Y sont positifs vers le bas.
Il faudrait donc ajouter Dy à yA.
Messages postés
31087
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
18 janvier 2021
3 192
hello,
de mémoire, le point aux coordonnées 0,0 se situe dans l'angle haut gauche.
et donc, en effet, le Y est positif vers le bas.
Messages postés
15400
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
18 janvier 2021
643
Bonjour

j'ai fait un essai chez moi.

J'ai d'abord écrit une méthode dont le rôle est de retourner le 2eme point en fonction du premier, de la norme du vecteur et de l'angle directeur

    ''' <summary>
    ''' Calcule le point de fin d'un segment en fonction du point de départ, de la norme et de l'angle
    ''' </summary>
    ''' <param name="Depart">Point de départ</param>
    ''' <param name="Rho">Norme</param>
    ''' <param name="Teta">Angle en radians</param>
    ''' <returns></returns>
    Private Function FinSegment(Depart As Point, Rho As Double, Teta As Double) As Point
        Dim vecteur As Size

        vecteur.Width = Convert.ToInt32(Math.Round(Rho * Math.Cos(Teta)))
        vecteur.Height = Convert.ToInt32(Math.Round(Rho * Math.Sin(Teta)))

        FinSegment = Depart + vecteur

    End Function


J'ai écrit une seconde méthode qui dessine un trait sur une Picturebox à partir des 2 extrémités
    ''' <summary>
    ''' Dessine un trait sur le pictureBox 
    ''' </summary>
    ''' <param name="Depart">Début du trait</param>
    ''' <param name="Fin">Fin du trait</param>
    ''' <param name="Pc">PictureBox à dessiner</param>
    Private Sub DessineTrait(Depart As Point, Fin As Point, Pc As PictureBox)
        Dim BMP As Bitmap = New Bitmap(Pc.Image)
        Dim G As Graphics = Graphics.FromImage(BMP)

        G.DrawLine(Pens.Black, Depart, Fin)

        Pc.Image = BMP

    End Sub


J'ai ensuite mis en musique avec 2 boucles, la première remplit une liste de points et la seconde dessine les traits à partir de la liste.

        PictureBox1.Image = New Bitmap(400, 400)
        Using graph As Graphics = Graphics.FromImage(PictureBox1.Image)
            Dim ImageSize As Rectangle = New Rectangle(0, 0, PictureBox1.Image.Width, PictureBox1.Image.Height)
            graph.FillRectangle(Brushes.White, ImageSize)
        End Using

        Dim lesPoints As New List(Of Point)
        Dim rho As Double = 80
        Dim teta As Double = 0
        Dim deltaTeta As Double = -10.0 * Math.PI / 180 'angle négatif pour que ça tourne dans le sens trigo

        lesPoints.Add(New Point(10, 380))

        For i As Integer = 0 To 4
            lesPoints.Add(FinSegment(lesPoints.Last(), rho, teta))
            rho *= 4 / 5
            teta += deltaTeta
        Next

        For i As Integer = 0 To 3
            DessineTrait(lesPoints(i), lesPoints(i + 1), PictureBox1)
        Next




Quand j'étais petit, la mer Morte n'était que malade.
George Burns
Messages postés
15400
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
18 janvier 2021
643
j'ai oublié la capture
Messages postés
15400
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
18 janvier 2021
643
Bonsoir

mais ma frustration demeure intacte, parce que je suis convaincu que ma méthode a du sens, sauf que je suis infichu d'utiliser la formule correctement sur VB.
Donc ta méthode résout mon exercice,
mais ne répond pas à ma question initiale concernant les formules de xPrim et yPrim ^^


ben si, j'ai appliqué exactement la même chose....

        vecteur.Width = Convert.ToInt32(Math.Round(Rho * Math.Cos(Teta))) 'le décalage en X est bien le produit de la longueur par le cosinus
        vecteur.Height = Convert.ToInt32(Math.Round(Rho * Math.Sin(Teta)))'le décalage en Y est bien le produit de la longueur par le sinus

        FinSegment = Depart + vecteur 'là ça fait bien x' = x + dX et y' = y + dY, mais en une ligne puisque les objets existent, autant s'en servir


Donc juste en passant l'angle en Double je viens de faire le test pour les valeurs qui fâchent (ex: 30°), et j'ai des segments pertinents :-)
ha oui, forcément, 1 radian c'est 57.3° environ

En fait, ton problème est que tu n'as pas su/pensé débogguer correctement.
En exécutant en pas à pas et espionnant le contenu des variables, tu aurais du voir le symptôme assez rapidement.
Je te conseille ce petit tuto https://openclassrooms.com/fr/courses/1526901-apprenez-a-developper-en-c/2867766-utilisez-le-debogueur les exemples de code sont en C# mais c'est bien fait avec Visual Studio

Messages postés
13943
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
18 janvier 2021
785
bonjour,
il est préférable de déclarer le type de chaque variable.
peux-tu plutôt partager un programme plus simple qui se concentre sur ce qui ne fonctionne pas?
Messages postés
13943
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
18 janvier 2021
785
Messages postés
13943
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
18 janvier 2021
785
n'hésite pas, non plus, à préciser quelles sont les valeurs de tes variables, quel résultat tu obtiens, et quel résultat tu souhaites.
>
Messages postés
13943
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
18 janvier 2021

ok. Je vais supprimer mon post et revenir en plus concis dans ce cas (le petit geste pour la planète)
Messages postés
50571
Date d'inscription
mardi 8 janvier 2008
Statut
Modérateur
Dernière intervention
18 janvier 2021
6 687 > arscy
Salut,

Heu ? Pourquoi ? Continue ici, il n'y a aucune raison de supprimer les réponses de yg_be, n'est-ce pas ?
Bonsoir,
Je suis d'accord avec la première partie de la phrase faute d'avoir compris à quoi fait allusion D.
Dans ma formule j'envoie pour un segment [AB] les coordonnées du point A en B,
puis les coordonnées de B en un C qui correspond à AB + un angle alpha.
C'est donc de la trigonométrie de base.
→ cos alpha = (longueur xC)/(longueur AB)
→ sin alpha = (longueur yC)/(longueur AB)
donc
longueur xC = cos alpha x longueur AB
longueur yC = sin alpha x longueur AB
Et si je n'ai pas écrit n'importe quoi, pour avoir xC et yC
il faut que j'additionne ces longueurs aux coordonnées préexistantes
soit xC= xB + cos alpha x longueur AB
yC = yB - sin alpha x longueur AB (repère inversé dans VB d'où la soustraction)

soit, dans ma formule:
xPrim = x + (Math.Cos(angle) * longueur)
 yPrim = y - (Math.Sin(angle) * longueur) 


mais ça
C'est faux.
Pourquoi?
Messages postés
61
Date d'inscription
dimanche 26 janvier 2014
Statut
Membre
Dernière intervention
6 décembre 2020
1
Comme le dit jordane45, le (0,0) se trouve dans l'angle supérieur gauche du pictureBox.
Pour ma part je souhaite une rotation dans le sens trigonométrique, donc je pense que la soustraction est la bonne idée.
Au point où j'en étais j'ai quand même tenté la version par addition, et à part avoir l'erreur dans le sens horaire, je n'ai pas de résolution de mon problème.
Quand je procède au calcul avec une calculatrice tout se tient, par contre sur VB c'est l'hécatombe. J'ai pris 2 captures d'image juste pour l'illustration, à 10° près.
nb: n'oublions pas que j'ai bloqué mon algorithme initial (pas de boucle): je suis censé avoir
2 vecteurs dessinés, reliés entre eux et différents d'un angle alpha.


angle= 20° → les deux vecteurs sont colinéaires (wtf?)


ange= 30°. Ça ressemble d'avantage à 60° mais bon...

Et entre ces deux angles j'ai droit à des longueurs "figées" (la valeur en bas de l'icône me permettait de voir la taille du vecteur ajouté histoire d'essayer de trouver d'où venait l'erreur.
Cette valeur est fixe jusqu'à des points bascule qui n'ont pas de cohérence à mes yeux :-( ex: angle 0 à 28° : le 2e vecteur est colinéaire, le suivant restera figé au même angle jusque 85°, ...).
Il y a du plomb dans ma formule que je n'arrive pas à saisir... Or mathématiquement parlant, il me semblait que c'était correct...
Et bien quoi qu'il en soit ta méthode fonctionne,
mais ma frustration demeure intacte, parce que je suis convaincu que ma méthode a du sens, sauf que je suis infichu d'utiliser la formule correctement sur VB.
Donc ta méthode résout mon exercice,
mais ne répond pas à ma question initiale concernant les formules de xPrim et yPrim ^^

J'ai essayé de recommencer mon système, pour comprendre ce qui partait en cacahuète.
But: dessiner un seul vecteur, avec d'emblée un angle teta
--> point de départ en (0;0);
point xPrim et yPrim correspondant aux abscisse et ordonnée du point d'arrivée du vecteur de longueur lon (qui a été soumis à un angle teta)
        Dim x, y, xPrim, yPrim, angle As Integer
        Dim k, lon As Double
        lon = LengthBox.Text()
        angle = (AngleUpDown.Value) * (Math.PI) / 180       '// conversion en RAD
        k = CoeffUpDown.Value                                  '//on ne s'en sert pas ici
        x = 0
        y = 0
        xPrim = x + (Math.Cos(angle)) * lon
        yPrim = y - (Math.Sin(angle)) * lon
        g.DrawLine(Pens.Black, x, y, xPrim, yPrim)
        Label1.Text = "( " & xPrim & " ; " & yPrim & " )"    '//recuperer les coordonnees de xPrim et                                                                                                                                                        '//yPrim pour avoir une idee 



Pour une longueur de 1, ça m'a l'air très cohérent:
pour teta = 0 j'ai le point d'arrivée en (1;0)
pour teta = 90 j'ai le point d'arrivée en (0;1)
pour teta = 180 j'ai le point d'arrivée en (-1;0)
pour teta = 270 j'ai le point d'arrivée en (0;-1)
→ les fonctions cos et sin semblent fonctionner comme sur une calculatrice standard.
MAIS (car on ne pouvait se passer d'un mais) si j'augmente la valeur de mon vecteur, tout part de travers:
ex: longueur de 5
Pour téta = 0; point d'arrivée en (5;0)
pour téta = 180: point d'arrivée en (-5;1) ← et si ma fonction marchait correctement, je n'ai aucune raison de voir un y en -1 bon sang de bon soir!
Messages postés
13943
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
18 janvier 2021
785
tu veux dire que avec AngleUpDown.Value = 180, tu obtiens, pour (xPrim; Yprim),
(-1;0) quand lon = 1
(-5;1) quand lon = 5

je ne vois pas la déclaration de xPrim et yPrim.
Messages postés
13943
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
18 janvier 2021
785 >
Messages postés
13943
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
18 janvier 2021

ceci donne quoi?
Dim lon As Double, xprim As Double, yPrim As Double, teta As Double, Angle As Double
teta = 180
lon = 5
Angle = teta * 4 * Atn(1) / 180     '// conversion en RAD
xprim = (Math.Cos(Angle)) * lon
yPrim = -(Math.Sin(Angle)) * lon
MsgBox "( " + CStr(xprim) + " ; " + CStr(yPrim) + " )"
>
Messages postés
13943
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
18 janvier 2021

Désolé yg_be, j'ai fait un copier/coller un peu court sur ma dernière formule (il manquait x, y, xPrim, yPrim et angle en Integer
mais
Bingo Jeannie Longo:
mon erreur: déclaration de variable angle → j'ai déclaré angle en un entier parce que je le demandais en degrés dans mon interface ... mais je le convertis en radians dans ma formule ... et donc en un Réel.
Ce qui explique que dans ma PictureBox le vecteur était figé de 0 à 28° par exemple (l'entier était toujours arrondi à une valeur quelconque, et à 29 on passait à l'entier supérieur).
Donc juste en passant l'angle en Double je viens de faire le test pour les valeurs qui fâchent (ex: 30°), et j'ai des segments pertinents :-)
Tu as corrigé mon erreur/horreur sur ce point d'ailleurs
Je retourne sur ma formule initiale et je reviens pour confirmer que ça fonctionne.
Messages postés
61
Date d'inscription
dimanche 26 janvier 2014
Statut
Membre
Dernière intervention
6 décembre 2020
1


Quand l'erreur basique est résolue, voici à quoi ça ressemble...
Merci pour votre mobilisation et vos suggestions :-)