langage python

a marqué ce sujet comme résolu.

Bonjour,

J’ai écrit un programme en langage python qui me permet de créer une boucle, qui passe par 4 points, maintenant j’aimerai écrire un programme qui me permeterai de placer sur les lignes de la boucle n points rouges se déplacant ( j’essaye de modéliser un réseau de transports). Ce deuxième programme me pose problème auriez vous des pistes, ou un programme similaire a me conseiller .

Merci bcp

je met mon programme ci dessous:

from tkinter import Tk, Canvas



x_min = -5000
x_max =  5000
y_min = -5000
y_max =  5000

from random import random
def Aléa(a = 0, b = 1) :
   return a + (b - a) * random()

from numpy import cos, sin, pi as π
def CréerLigne(n) :

   Θ = sorted([Aléa(0, 2 * π) for _ in range(n)])
   Stations = []
   for k in range(n) :
       θ = Θ[k] % (π / 2)
       if θ > π / 4 :
           θ = π / 2 - θ
       r_max = x_max / cos(θ)
       r = Aléa(0.3 * r_max, 0.9 * r_max)
       Stations.append( (r * cos(Θ[k]), r * sin(Θ[k])) )
   return Stations


n = 4


DIM = 600

def PixelVersCoordonnées(px, py) :
   x = x_min + (x_max - x_min) * px / (DIM - 1)
   y = y_max - (y_max - y_min) * py / (DIM - 1)
   return (x, y)
def CoordonnéesVersPixel(x, y) :
   px = int((x - x_min) / (x_max - x_min) * (DIM - 1))
   py = int((y_max - y) / (y_max - y_min) * (DIM - 1))
   return (px, py)


def Simulation() :

   F = Tk() ; F.title("Métropolitain miniature")
   C = Canvas(F, width = DIM, height = DIM, background = "#aaa")
   C.pack()

   Stations = [(2484.2051465742793, 4036.0330629760906), (-2520.221328393551, -501.45504151300406), (-1915.9534272380367, -3147.810933949548), (1534.818374770701, -4468.517925592077)]
   for k in range(n) :
       (px1, py1) = CoordonnéesVersPixel(*Stations[ k-1])
       (px2, py2) = CoordonnéesVersPixel(*Stations[3])
       C.create_line(px1, py1, px2, py2, fill = "#000")
   for k in range(n) :
       (px, py) = CoordonnéesVersPixel(*Stations[k])
       C.create_oval(px - 5, py - 5, px + 5, py + 5, fill = "#fff")

 
   F.mainloop() ```  
       
       
+0 -0

Bonjour, pour déplacer des éléments sur un segment, il te sera nécessaire de calculer la fonction affine qui relie les deux extrémités. Une fois que tu as les deux paramètres a et b, tu n’as plus qu’à les utiliser comme vecteur et réaliser une boucle (ou non) de tes objets sur le segment (penser à vérifier les bornes). Nature of Code peut te donner des idées. Si tu cales à nouveau, n’hésites pas - je/on te donnera d’autres infos.

Voici un exemple de simulation:

J’ai quelque remarque sur ton code:

  • Si il est possible en python d’utliser presque tous les caractères pour le nom des variables, il est préférable d’eviter les caractères accentués (à, é, ..) et les caractères spéciaux (ex π) qui risquent de poser des problème sur certains postes qui n’ont pas la police adaptée.
  • Ta fonction simulation ne doit pas contenir l’appel à mainloop(), par principe une simulation est une boucle et il la fonction mainloop ne doit être appelée qu’uen fois.
  • tu dispatche les imports au fil de code il est plus lisible des les mettre tous en début de code.
  • tu utilise le style CamelCase pour nommer tes fonctions et variables, en python le style snake_case est préconisé.
  • L’utlisation des splat * pour des fonctions simple avec un nombre d’argument fixe alourdi inutilement la lecture , j’ai légèrement transformé CoordonnéesVersPixel pour éviter ca.
  • J’ai utilisé un dictionnaire pour représenter un train , mais creer une classe Train serait plus adapté sur ce type de problème.

Nota : J’ai utilisé directement les positions sur la fenêtre dans ma simulation et non les vraies coordonnées des trains, ce n’est pas une bonne pratique pour de la simulation mais ca m’evitais de conversion peu utile pour montrer le principe de la boucle de de simulation avec Tkinter.

from tkinter import Tk, Canvas


x_min = -5000
x_max =  5000
y_min = -5000
y_max =  5000

from random import random
def Aléa(a = 0, b = 1) :
   return a + (b - a) * random()

from numpy import cos, sin, pi as π
def CréerLigne(n) :

   Θ = sorted([Aléa(0, 2 * π) for _ in range(n)])
   Stations = []
   for k in range(n) :
       θ = Θ[k] % (π / 2)
       if θ > π / 4 :
           θ = π / 2 - θ
       r_max = x_max / cos(θ)
       r = Aléa(0.3 * r_max, 0.9 * r_max)
       Stations.append( (r * cos(Θ[k]), r * sin(Θ[k])) )
   return Stations


n = 4
Stations = [(2484.2051465742793, 4036.0330629760906), (-2520.221328393551, -501.45504151300406), (-1915.9534272380367, -3147.810933949548), (1534.818374770701, -4468.517925592077)]

DIM = 600

def PixelVersCoordonnées(px, py) :
   x = x_min + (x_max - x_min) * px / (DIM - 1)
   y = y_max - (y_max - y_min) * py / (DIM - 1)
   return (x, y)
def CoordonnéesVersPixel(coord) :
    x, y = coord    
    px = int((x - x_min) / (x_max - x_min) * (DIM - 1))
    py = int((y_max - y) / (y_max - y_min) * (DIM - 1))
    return (px, py)


# creer la fenetre TK en dehors de la boucle de simulation (on en la crée qu'une seule fois)
F = Tk() ; F.title("Métropolitain miniature")
C = Canvas(F, width = DIM, height = DIM, background = "#aaa")
C.pack()
for k in range(n) :
    (px1, py1) = CoordonnéesVersPixel(Stations[ k-1])
    (px2, py2) = CoordonnéesVersPixel(Stations[3])
    C.create_line(px1, py1, px2, py2, fill = "#000")
for k in range(n) :
    (px, py) = CoordonnéesVersPixel(Stations[k])
    C.create_oval(px - 5, py - 5, px + 5, py + 5, fill = "#fff")

def creer_train(start,end):
    """
    creer un train parcourant le chemin entre les stations start et end
    pos -> position relative entre les stations start et end
    sens -> dans quel sens le train se déplace , -1 pour le retour  
    """    
    (x0, y0), (x1, y1) = map(CoordonnéesVersPixel, (Stations[start],Stations[end]))
    train = dict(start=(x0,y0), end=(x1,y1), pos=0, sens=1)
    # l'identifiant du point du train doit etre sauvegardé, afin de modifier 
    # sa position lors de la simumation, un identifiant est retourné lors de
    # l'appel des fonctions C.create_*
    train['id'] = C.create_oval(x0-3,y0-3,x1+3,y1+3, fill='#f00')
    return train


def simule_train(train, vitesse=1):
    pos = train['pos'] 
    pos += vitesse * train['sens']
    pos = min(100, max(0, pos))
    if pos in (0,100):
        train['sens'] *= -1
    train['pos'] = pos
    (x0, y0), (x1, y1) = train['start'], train['end']
    tx, ty = x0 + (x1-x0) * pos / 100, y0 + (y1 - y0) * pos / 100 
    #on utlise l'id du train pour mettre sa position à jour
    C.coords(train['id'], tx-3, ty-3, tx+3, ty+3)
    # F.after permet de faire touner la simulation ici tous les 100ms
    # mais il faut appeler une fonction sans parametre, 
    # pour passer des arguments on peut utliser une lambda
    F.after(100, lambda :simule_train(train, vitesse)) 
    
   
simule_train(train=creer_train(3,0) , vitesse=2)
simule_train(train=creer_train(3,1), vitesse=1)
# la boucle principale de l'appli Tkinter ne doit surtout pas etre lancée dans une boucle de simulation
F.mainloop()
+0 -0

Bonjour

Ta fonction simulation ne doit pas contenir l’appel à mainloop(), par principe une simulation est une boucle et il la fonction mainloop ne doit être appelée qu’uen fois.

Pas trop en accord avec cette remarque. Je veux dire, que c’est l’endroit où il crée son instance Tk et l’endroit où il termine la boucle événementielle, donc on pourrait considérer que c’est comme une fonction principale (main) qu’il nommerait Simulation, non ?

Pour le reste je suis d’accord, quoique le dispatch * ne me paraît pas choquant plus que ça, mais bon, je dirais que les goûts et les couleurs…

+0 -0

Je n’ai pas été assez clair, le but de cette remarque était surtout pour ne pas faire plusieurs appel de mainloop ce qui poserait des problèmes, effectivement si la fonction principale s’appelle simulation et que ce n’est pas une boucle ca marchera aussi bien, j’aime bien séparer la partie interface des calculs/simulations, mais bon les gouts et les couleurs …. ;)

Nota: mon code est un truc vite faits il n’est vraiment pas efficace, et avait surtout pour but de monter comment on peut faire une boucle de "simulation" avec after et comment gérer les objet du canvas avec leur ID.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte