Manuel de référence de la bibliothèque VPython

Guigui_

VPython est le langage de programmation Python ajouté d'un module graphique 3D appelé "Visual" créée originellement par David Scherer en 2000. Cette documentation décrit toutes les possibilités de Visual. La traduction de la documentation a été réalisée par Yoann et Guillaume Duriaud. Cette traduction est conforme à la version 5.0.3 de VPython. ♪

- Titre : Manuel de référence de la bibliothèque VPython

- Auteur : Guigui_

- Parution : 23 février 2009

- Licence :

Sommaire

- Introduction

- Vpython : l'environnement Python/ Visual / IDLE

- Entités visuelles

- Éléments simples de programmation en Python

- Les objets 3D

- La flèche (arrow)

- La boîte (box)

- Le cône (cone)

- L'object convexe (convex)

- La courbe (curve)

- Le cylindre (cylinder)

- L'ellipsoïde (ellipsoid)

- Les faces (faces)

- La structure (frame)

- L'hélice (helix)

- L'étiquette (label)

- Le nuage de points (points)

- La pyramide (pyramid)

- L'anneau (ring)

- La sphère (sphere)

- Travailler avec les objets

- Couleur et opacité

- Éclairage

- Matériaux et Textures

- Valeurs par défaut

- Vitesse d'animation

- Rotation d'un objet

- Attributs supplémentaires

- Suppression d'un objet

- 3/4 = 0 ?

- Fenêtres, évènements, fichiers

- Contrôler une ou plusieurs fenêtres d'affichage visual

- Interactions Souris

- Mouse Click

- Mouse Drag

- Interactions Clavier

- Contrôles: boutons (button), glissières (slider), interrupteurs à bascule (toggle), et menus déroulants (menu)

- Lecture et Écriture de fichiers

- Calculs vectoriels

- Tracer des graphes, des fonctions ou des données

- Les fonctions factorielle (factorial) et combinaison (combin)

- Licence

Introduction

Vpython : l'environnement Python/ Visual / IDLE

L'environnement de développement interactif que vous utiliserez est appelé "IDLE."

La fenêtre d'affichage

Lors de l'utilisation de VPython, la fenêtre graphique montre des objets en 3D.

(0,0,0) est le centre de la fenêtre graphique. L'axe +x est dirigé vers la droite, l'axe +y est dirigé vers le haut et l'axe +z pointe en direction de l'extérieur de l'écran, vers vous.

x, y et z sont mesurées dans n'importe quelle unité que vous choisissez ; la scène est automatiquement redimensionnée convenablement. (Vous pourriez, par exemple, créer une sphère de rayon 1E-15 m pour représenter un noyau, ou une sphère de rayon 1E6 m pour représenter une planète, quoique cela n'aurait pas de sens de poser ces deux objets dans une même fenêtre graphique !) .

La fenêtre de sortie

La sortie de chaque instruction -print- que vous exécutez dans votre programme va dans la fenêtre de sortie, qui est une fenêtre à texte déroulant. Vous pouvez utiliser cette fenêtre pour afficher des valeurs de variables, afficher des listes, des messages, etc. Placez-la là où vous pouvez y voir des messages.

La fenêtre de code

Si vous tapez le simple programme suivant dans la fenêtre de code de IDLE et que vous le lancez (appuyez sur F5 ou utilisez le menu Run), vous verrez un affichage comme celui montré sur la figure en dessous.

from visual import *
redbox=box(pos=vector(4,2,3),
size=(8,4,6),color=color.red)
ball=sphere(pos=vector(4,7,3),radius=2,color=color.green)

Visual est le nom du module graphique 3D utilisé par le langage Python. VPython est le nom de la combinaison du langage Python, du module Visual et de l'environnement de développement IDLE.

Visualisation de la scène

Dans la fenêtre d'affichage, cliquez et déplacez avec le bouton droit de la souris (laissez appuyer la touche shift sur Macintosh). Déplacez à gauche ou à droite et vous tournez autour de la scène. Pour tourner autour de l'axe horizontal, déplacez la souris vers le haut ou le bas avec le bouton droit de la souris maintenu appuyé. Cliquez et déplacez vers le haut ou le bas la souris avec le bouton du milieu maintenu appuyé pour vous rapprocher ou vous éloignez de la scène (sur une souris à deux boutons, maintenez appuyé le bouton gauche et droit de la souris; sur une souris à un bouton, maintenez appuyée la touche CTRL).

Entités visuelles

Objets, noms et attributs

Les objets graphiques que vous créez, tels que les sphères, les boîtes, les courbes continuent d'exister pendant toute la durée d'exécution de votre programme, et le module graphique 3D de Visual continuera de les afficher partout où ils sont. Vous devez donner un nom à chaque objet (tel que redbox ou greenball dans l'exemple au-dessus) si vous souhaitez vous y référer de nouveau plus loin dans votre programme. Tous les objets ont des attributs: propriétés comme greenball.pos (la position de la sphère), greenball.color, et radius ou d'autres paramètres de taille. Si vous changez un attribut d'un objet, tel que sa position ou sa couleur, Visual affichera automatiquement l'objet dans sa nouvelle localisation ou avec sa nouvelle couleur.

Vous pouvez définir des valeurs des attributs dans le "constructeur" (le code utilisé pour créer un objet), et vous pouvez aussi modifier les attributs plus tard:

ball.radius = 2.2

En plus de la définition de base des attributs, vous pouvez créer de nouveaux attributs. Par exemple, vous pouvez créer une sphère nommée moon; en plus de son rayon et de sa position, vous pouvez lui donner des attributs tels que sa masse (moon.mass) et son moment (moon.momentum).

Vecteurs

Les objets dans Visual ne sont pas tous des objets visibles. Par exemple, Visual permet de créer des quantités vectorielles 3D, et exécute des opérations vectorielles sur eux. Si vous créez une quantité vectorielle appelée a, vous pouvez vous référer à ses composantes telles que a.x, a.y, et a.z. Cependant, pour ajouter deux vecteurs a et b, vous n'avez pas besoin d'ajouter les composantes une à une; Visual effectuera l'addition vectorielle pour vous:

a = vector(1,2,3)
b = vector(4,5,6)
c=a+b

Si vous affichez c , vous verrez que c'est un vecteur de composantes (5, 7, 9).

Multiplication scalaire

d = 3*a # d est un vecteur de composantes (3, 6, 9)

Norme vectorielle

s = mag(c) # s est un scalaire
z = mag(c)**2 # vous pouvez élever au carré la norme d'un vecteur

Calculs vectoriels

f = cross(a,b) # produit vectoriel
g = dot(a,b) # produit scalaire
h = norm(a) # vecteur normé (unitaire); a/mag(a)

Les attributs des objets Visual peuvent être des vecteurs, comme la vitesse ou le moment.

Éléments simples de programmation en Python

Importation du module graphique 3D (Visual)

La première ligne de votre programme doit être :

from visual import *

Commentaires

Un commentaire dans un programme Python commence par "#"

# cette ligne est un commentaire

Variables

Des variables peuvent être créées n'importe où dans un programme Python, simplement en assignant un nom de variable à une valeur. Le type de la variable est déterminé par l'instruction d'affectation.

a = 3 # un entier
b = -2. # un nombre à virgule flottante
c = vector(0.4, 3e3, -1e1) # un vecteur
Earth = sphere(pos=(0,0,0), radius=6.4e6) # un objet
bodies = [ship, Earth, Moon] # une liste d'objets

Les objets basiques Visual tels que sphere() et box() ont un panel d'attributs tel que la couleur, et vous pouvez définir des attributs supplémentaires tels que la masse ou le moment. D'autres objets, tels que vector(), ont des attributs intégrés, mais vous ne pouvez pas créer d'attributs supplémentaires.

Avertissement à propos des divisions

La division d'entiers ne prendra pas le chemin que l'on attend, car le résultat est arrondi au plus proche entier inférieur. Ainsi :

a = 3/4
print a # a vaut 0

Pour éviter ceci, placez le point des décimaux après chaque nombre, comme ceci :

b = 3./4.
print b # b vaut 0.75, comme attendu

Nous recommandons d'écrire l'instruction suivante au début de votre programme, dans ce cas 3/4 vaudra 0.75, il y a deux underscores avant et après le mot "future" :

from __future__ import division

Élévation à une puissance

x**2 # et non x^2 qui est une opération sur les bits en Python

Tests de logique

If, elif ("else if"), else :

if a == b: # regardez la table des expressions logiques ci-dessous
c = 3.5 # code indenté exécuté si le test est vrai
elif a < b:
c = 0. # c sera remis à zéro si a < b
else:
c = -23.2

Expressions logiques

==

égal

!=

différent de

plus petit que

plus grand que

plus petit ou égal

plus grand ou égal

or

ou logique

and

et logique

in

membre d'une séquence

not in

non membre d'une séquence

Listes

Une liste est une séquence ordonnée de n'importe quelle sorte d'objets. Elle est délimitée par des crochets.

moons = [Io, Europa, Ganymede, Callisto]

La fonction "arange" (raccourci de "arrayrange") crée une séquence de nombres :

angles = arange (0., 2.*pi, pi/100)
# nombres de 0. à 2.*pi-(pi/100.) dans un pas de (pi/100)

numbers = arange(10) # argument entier -> entiers
print numbers # [0,1,2,3,4,5,6,7,8,9]

Boucles

La plus simple des boucles en Python est la boucle "while". La boucle continue aussi longtemps que l'expression logique spécifiée est vraie :

while x < 23:
x = x + vx*dt

Pour écrire une boucle infinie, utilisez simplement une expression logique qui sera toujours vraie :

while 1==1:
ball.pos = ball.pos + (ball.momentum/ball.mass)*dt

Comme la valeur assignée à l'expression logique VRAI vaut 1, la suite produira aussi une boucle infinie :

while 1:
a = b+c

Les boucles infinies conviennent parce que vous pouvez toujours interrompre le programme en choisissant "Stop Program" dans le menu Run de IDLE.

Il est aussi possible de boucler sur les membres d'une séquence :

moons = [Io, Europa, Ganymede, Callisto]
for a in moons:
r = a.pos - Jupiter.pos

for x in arange(10):
# voir "listes" au-dessus
...

for theta in arange(0., 2.*pi, pi/100.):
# voir "listes" au-dessus

Vous pouvez redémarrer une boucle ou la terminer avant son terme :

if a == b: continue # retourne au début de la boucle
if a > b: break # sort de la boucle

Afficher des résultats

Pour afficher un nombre, un vecteur, une liste, ou autre chose utilisez la commande "print" :

print Europa.momentum

Pour afficher un message texte, encadrez-le par des quotes :

print "We have just crashed on the Moon with speed", v, "m/s."

Python offre aussi la possibilité d'un affichage formaté. Ici, price sera affiché avec trois chiffres avant la partie décimale et deux chiffres après, et num sera affiché en tant qu'entier :

print "It's $%3.2f dollars for %d copies" % (price,num)

Plus d'informations sur Python

Nous avons résumé un très petit sous-ensemble du langage de programmation Python. Une documentation plus intensive est fournie dans le menu d'aide de IDLE et il y a des informations supplémentaires sur le site web de Python, mais beaucoup de ces informations supposent que vous ayez déjà une bonne expérience de la programmation dans d'autres langages. Nous recommandons le livre suivant à ceux qui veulent en apprendre plus sur Python: Python Programming: An Introduction to Computer Science by John M. Zelle (Franklin Beedle & Associates, 2003).

Les objets 3D

La flèche (arrow)

La flèche a une hampe en forme de boîte avec une pointe de flèche à une de ses extrémités. L'instruction suivante affichera une flèche pointant parallèlement à l'axe x :

pointer = arrow(pos=(0,2,1), axis=(5,0,0), shaftwidth=1)

La flèche a les attributs suivants et les valeurs par défaut identiques à ceux du cylindre : pos (0,0,0), x (0), y(0), z(0), axis (1,0,0), length (1), color (1,1,1) qui est la couleur color.white, red (1), green (1), blue (1), opacity (1), material, et up (0,1,0). Comme pour la boîte (box), l'attribut up est important pour la flèche, car la hampe et la tête ont une section transverse carrée et définir l'attribut up tourne la flèche selon son axe. Attributs supplémentaires de la flèche :

shaftwidth : par défaut, shaftwidth = 0.1*(longueur de la flèche) ;

headwidth : par défaut, headwidth = 2*shaftwidth ;

headlength : par défaut, headlength = 3*shaftwidth.

Assigner n'importe lequel de ces attributs à 0 fait que l'objet utilisera les valeurs par défaut basées sur la taille de la flèche. Si headlength devient plus grand que la moitié de la longueur de la flèche, ou que la hampe devient plus fine que 1/50 de la longueur, la flèche entière est redimensionnée en conséquence.

Ce comportement par défaut rétrécit les largeurs des très courtes flèches, et grandit les largeurs des très longues flèches (tout en affichant correctement la longueur totale). Si vous préférez que shaftwidth et headwidth ne changent pas lorsque la flèche devient très courte ou très longue, définissez fixedwidth = 1. Dans ce cas, le seul ajustement qui est fait est que headlength est ajusté pour qu'il ne devienne jamais plus long que la moitié de la longueur totale, ainsi la longueur totale de la flèche reste correcte. Cela signifie que des flèches épaisses très courtes ressembleront à une punaise, avec une tête presque plate.

Notez que l'attribut pos pour le cylindre, la flèche, le cône et la pyramide correspond à une des extrémités de l'objet, alors que pour la boîte, sphère ou anneau, il correspond au centre de l'objet.

Voir la description des attributs supplémentaires disponibles pour tous les objets 3D

La boîte (box)

Sur le premier schéma, nous montrons un simple exemple de création d'une boîte :

mybox = box(pos=(x0,y0,z0), length=L, height=H, width=W)

La position donnée est le centre de la boîte (x0, y0, z0). C'est une différence avec le cylindre, dont l'attribut pos est une des extrémités du cylindre. Comme pour le cylindre, nous pouvons faire référence aux composantes vectorielles individuelles de la boîte comme mybox.x, mybox.y, et mybox.z. La longueur (le long de l'axe x) vaut L, la hauteur (le long de l'axe y) vaut H, et la largeur vaut W (le long de l'axe z). Pour cette boîte, nous avons mybox.axis = (L, 0, 0) . Notez que l'axe de la boîte est semblable à l'axe du cylindre.

Pour une boîte qui n'est pas alignée avec l'axe des coordonnées, des problèmes supplémentaires entrent en jeu. L'orientation de la longueur de la boîte est donnée par l'axe (voir le second schéma) :

mybox = box(pos=(x0,y0,z0), axis=(a,b,c), length=L, height=H, width=W)

L'attribut axis donne une direction pour la longueur de la boîte, et la longueur, la hauteur et la largeur de la boîte sont données comme avant (si l'attribut length n'est pas donné, la longueur est définie par la norme du vecteur axis).

Il reste à savoir comment orienter la boîte tournant autour de l'axe spécifié. La règle que Visual utilise est d'orienter la largeur soit dans le plan orthogonal à la direction "up" de l'affichage, qui est par défaut l'axe y. Cependant sur le schéma, vous voyez que la largeur est dans le plan x-z. La hauteur de la boîte est orientée perpendiculairement à la largeur et à l'axe spécifié de la boîte. Cela aide de penser à la longueur initialement comme allant le long de l'axe x, la hauteur le long de l'axe y, et la largeur le long de l'axe z, et quand l'axe est incliné, la largeur reste dans le plan x-z.

Vous pouvez tourner la boîte selon son propre axe en changeant le vecteur "up" de la boîte, en spécifiant un attribut up pour la boîte qui est différent du vecteur up du système de coordonnées :

mybox = box(pos=(x0,y0,z0), axis=(a,b,c), length=L, height=H, width=W, up=(q,r,s))

Avec cette instruction, la largeur de la boîte sera dans le plan perpendiculaire au vecteur (q,r,s), et la hauteur de la boîte sera perpendiculaire à la largeur et au vecteur (a,b,c).

La boîte a les attributs suivants et des valeurs par défaut comme ceux du cylindre: pos (0,0,0), x (0), y(0), z(0), axis (1,0,0), length (1), color (1,1,1) qui est la couleur color.white, red (1), green (1), blue (1) opacity (1), material, et up (0,1,0). Attributs supplémentaires de la boîte :

height : dans la direction y dans les cas simples, par défaut vaut 1 ;

width : dans la direction z dans les cas simples, par défaut vaut 1 ;

size : (longueur, hauteur, largeur), par défaut vaut (1,1,1) ;

myell.size=(20,10,12) définit length=20, height=10, width=12.

Notez que l'attribut pos pour le cylindre, la flèche, le cône et la pyramide correspond à une des extrémités de l'objet, alors que pour la boîte, sphère ou anneau, il correspond au centre de l'objet.

Voir la description des attributs supplémentaires disponibles pour tous les objets 3D.

Le cône (cone)

Le cône a une section transverse circulaire et se termine en pointe. L'instruction suivante affichera un cône dont le centre de la base circulaire est à la position (5,2,0) et dont l'axe principal est parallèle à l'axe x et d'une longueur de 12, la base du cône a un rayon de 1 :

cone(pos=(5,2,0), axis=(12,0,0), radius=1)

Le cône a les attributs suivants et des valeurs par défaut identiques à ceux du cylindre: pos (0,0,0), x (0), y(0), z(0), axis (1,0,0), length (1), color (1,1,1) qui est la couleur color.white, red (1), green (1), blue (1), opacity (1), material, et up (0,1,0). Comme pour le cylindre, up n'a qu'un effet subtil sur l'apparence en 3D du cône, sauf si un matériau non lisse est spécifié. Les attributs supplémentaires du cône :

radius Rayon de la base du cône, par défaut = 1

Notez que l'attribut pos pour le cylindre, la flèche, le cône et la pyramide correspond à une des extrémités de l'objet, alors que pour la boîte, sphère ou anneau, il correspond au centre de l'objet.

Voir la description des attributs supplémentaires disponibles pour tous les objets 3D.

L'object convexe (convex)

L'objet convexe prend une liste de points (attribut pos), comme la courbe. Un objet est généré qui est en tout point convexe (c'est-à-dire bombement à l'extérieur). Tout point qui formerait une portion concave de l'objet (bombement à l'intérieur) est écarté. Si tous les points sont dans un même plan, l'objet est une surface plane.

Actuellement, il n'est pas possible de spécifier l'opacité d'un objet convexe.

Voir la description des attributs supplémentaires disponibles pour tous les objets 3D.

La courbe (curve)

La courbe affiche des lignes droites entre des points et si les points sont suffisamment proches les uns des autres, vous obtiendrez l'apparence d'une courbe lisse. En plus de son usage basique pour l'affichage de courbes, la courbe a de puissantes capacités pour d'autres usages, comme le tracé efficace de fonctions.

Plusieurs attributs, tels que pos et color, peuvent être différents pour chaque point de la courbe. Ces attributs sont stockés en tant que tableaux NumPy. Le module NumPy pour Python fournit des possibilités de traitements puissants sur les tableaux; par exemple, deux tableaux peuvent être ajoutés. Les tableaux NumPy sont accessibles en utilisant les règles standard de Python pour faire référence au nième item d'une séquence (ainsi, seq[0] est le premier item de seq, seq[1] est le deuxième, seq[2] est le troisième, etc.). Par exemple, anycurve.pos[0] est la position du premier point dans anycurve.

Vous pouvez donner à la courbe une liste explicite de coordonnées sous forme de tuples comme toutes les séquences Python. Voici un exemple d'un carré 2D :

square = curve(pos=[(0,0),(0,1),(1,1),(1,0),(0,0)])

Essentiellement, (1,1) est l'abréviation de (1,1,0). Cependant, vous ne pouvez pas mélanger des points 2D et 3D dans une même liste.

Les courbes peuvent avoir une épaisseur spécifiée par le rayon de la section transverse de la courbe (la courbe a une épaisseur ou un diamètre qui est le double du rayon) :

curve(pos=[(0,0,0), (1,0,0), (2,1,0)], radius=0.05)

Le rayon par défaut vaut 0, ce qui dessine une courbe fine. Un rayon non nul donne une "épaisseur" à la courbe, mais une très petite valeur pour le rayon peut donner une courbe qui sera trop fine pour être visible.

Dans l'exemple suivant, la fonction arange() (fournie par le module Numeric Python, qui est importé par le module Visual, donne une séquence de valeurs de 0 à 20 avec un pas de 0.1 (n'incluant pas la dernière valeur 20).

c = curve( x = arange(0,20,0.1) ) # Dessine une hélice
c.y = sin( 2.0*c.x )
c.z = cos( 2.0*c.x )

Les attributs x, y, et z permettent aux courbes d'être utilisées pour dessiner facilement des fonctions :

curve( x=arange(100), y=arange(100)**0.5, color=color.red)

Une fonction de traçage ressemble à ceci (un programme complet!), où "raw_input" est une fonction Python qui accepte une entrée typée dans le shell de Python :

eqn = raw_input('Equation in x: ')
x = arange( 0, 10, 0.1 )
curve( x=x, y=eval(eqn) )

Le tracé d'une fonction paramétrique est aussi facile :

t = arange(0, 10, 0.1)
curve( x = sin(t), y = 1.0/(1+t), z = t**0.5,
red = cos(t), green = 0, blue = 0.5*(1-cos(t)) )

Voici les attributs de la courbe :

pos[] : tableau des positions des points dans la courbe: pos[0], pos[1], pos[2]….
Le nombre courant de points est donné par len(curve.pos) ;

x[ ], y[ ], z[ ] : composantes de pos, chacune vaut par défaut [0,0,0,0,…] ;

color[ ] : couleur des points dans la courbe ;

red[ ], green[ ], blue[ ] : composantes de couleur des points dans la courbe ;

radius : rayon de la section transverse de la courbe. Par défaut, radius=0 rend la courbe mince ;

material : matériau pour l'épaisseur de la courbe; voir Matériaux pour les options disponibles actuellement.

Actuellement, il n'est pas possible de spécifier l'opacité d'un object courbe.

Ajout de plus de points à une courbe

Les courbes peuvent être créées par incrémentation par la fonction append(). Un nouveau point partage par défaut les caractéristiques du dernier point.

spiral = curve( color = color.cyan )
for t in arange(0, 2*pi, 0.1):
spiral.append( pos=(t,sin(t),cos(t)) )

Un des nombreux usages de la courbe est de laisser une trainée derrière un objet en mouvement. Par exemple, si ball est une sphère en mouvement, ceci ajoutera un point à la trainée :

trail = curve()
ball = sphere()
# .... Chaque fois que vous mettez à jour la position de la balle:
trail.append(pos=ball.pos)

Lors de l'ajout à une courbe, vous pouvez choisir de ne conserver que les N derniers points, y compris celui que vous êtes en train d'ajouter :

trail.append(pos=ball.pos, retain=50) # last 50 points

Interpolation

Le mécanisme de tracé de la courbe est l'interpolation d'un point au suivant. Par exemple, supposons que les trois premiers points soient rouges, mais que le quatrième point soit bleu, comme dans l'exemple suivant. Les lignes connectant les trois premiers points sont tous rouges, mais la ligne allant du troisième point (rouge) au quatrième point (bleu) est affiché avec un dégradé du rouge au bleu.

c = curve( pos=[(0,0,0), (1,0,0)], color=color.red )
c.append( pos=(1,1,0) ) # ajoute un point rouge
c.append( pos=(0,1,0), color=color.blue) # ajoute un point bleu

Si vous voulez un changement brusque dans la couleur ou l'épaisseur, ajoutez un autre point à la même position. Dans l'exemple suivant, ajouter un point bleu à la même position que le troisième point (rouge) rend la ligne finale d'un bleu pur.

c = curve( pos=[(0,0,0), (1,0,0)], color=color.red)
c.append( pos=(1,1,0) ) # ajoute un point rouge
c.append( pos=(1,1,0), color=color.blue) # même point, bleu
c.append( pos=(0,1,0) ) # ajoute un point bleu

Note technique: Peu importe le nombre de points dans la courbe, seuls 1000 seront affichés, choisis uniformément parmi l'ensemble des points afin que l'affichage d'une courbe très longue ne soit pas ralenti de façon inacceptable.

Voir la description des attributs supplémentaires disponibles pour tous les objets 3D.

Le cylindre (cylinder)

Étudier la description de l'objet cylindre offre un aperçu des principaux aspects communs à l'ensemble des objets 3D de Visual comme la boîte, sphère, pyramide, etc.

Voici un exemple qui montre comment créer un cylindre, on le nomme "rod" pour les prochaines références :

rod = cylinder(pos=(0,2,1), axis=(5,0,0), radius=1)

Le centre d'une des extrémités du cylindre est à la position x=0, y=2, et z=1. Son axe principal est le long de l'axe x, d'une longueur de 5, ainsi l'autre extrémité du cylindre est à la position (5,2,1) comme le montre le diagramme à droite.

Vous pouvez modifier la position du cylindre après l'avoir créé, ceci aura l'effet de le déplacer immédiatement à sa nouvelle position :

rod.pos = (15,11,9) # modifie la position (x,y,z)
rod.x = 15 # modifie uniquement la composante pos.x

Si vous créez un objet tel qu'un cylindre, mais sans donner de nom comme rod, vous ne pourrez plus vous y référer plus tard. Cela n'a pas d'importance si vous n'avez pas l'intention de modifier cet objet.

Comme nous n'avons pas spécifié de couleur, le cylindre sera de la couleur courante du "premier plan" (voir Contrôler une ou plusieurs Fenêtres d'Affichage Visual). La couleur par défaut du premier plan est le blanc. Après avoir créé le cylindre, vous pouvez changer sa couleur :

rod.color = (0,0,1) # rend l'objet rod bleu

Ceci rendra immédiatement le cylindre bleu, en utilisant le système RGB pour la spécification des couleurs en terme de fraction de rouge, vert et bleu. (Pour plus de détails sur le choix des couleurs, voir Spécification des couleurs.) Vous pouvez sélectionner individuellement les quantités de rouge, vert et bleu comme ceci :

rod.red = 0.4
rod.green = 0.7
rod.blue = 0.8

Le cylindre peut être créé avec d'autres attributs optionnels qui peuvent être listés dans n'importe quel ordre. Voici une liste exhaustive des attributs, la plupart de ceux-ci s'appliquant également à d'autres objets :

pos : position : le centre de l'une des extrémités du cylindre; par défaut = (0,0,0)
Un triplet, entre parenthèses, tel que (3,2,5) ;

axis : l'axe pointe de la position pos vers l'autre extrémité du cylindre, par défaut = (1,0,0) ;

x, y, z : essentiellement la même chose que pos.x, pos.y, pos.z, par défaut, tous sont à 0 ;

radius : rayon du cylindre, par défaut = 1 ;

length : longueur de l'axe, si non spécifiée, le vecteur axis détermine la longueur, par défaut = 1.
Si length est spécifié, il est prioritaire sur la longueur donnée par axis ;

color : couleur de l'objet, en tant qu'un triplet rouge-vert-bleu (RGB/RVB): (1,0,0) est un rouge pur, par défaut = (1,1,1), qui est la couleur color.white ;

red, green, blue : (vous pouvez déterminer individuellement les attributs de couleur), par défaut, tous sont à 1 ;

opacity : l'opacité de l'object, par défaut = 1, 0 pour la complète transparence ;

material : le matériau de l'objet, voir Matériaux pour les options actuellement disponibles :

up : côté du cylindre qui est tourné vers le "haut"; celui-ci n'a qu'un effet subtil sur l'apparence 3D du cylindre à moins qu'un matériau non lisse soit spécifié; par défaut (0,1,0).

Notez que l'attribut pos pour le cylindre, la flèche, le cône et la pyramide correspond à une des extrémités de l'objet, alors que pour la boîte, sphère ou anneau, il correspond au centre de l'objet.

Voir la description des attributs supplémentaires disponibles pour tous les objets 3D.

Quand vous lancez un programme VPython, par commodité Visual crée une fenêtre d'affichage et la nomme scene. Par défaut, les objets que vous créez vont dans cette fenêtre. Voir Contrôler une ou plusieurs Fenêtres d'Affichage Visual plus loin dans ce manuel pour comprendre comment vous pouvez créer une fenêtre d'affichage supplémentaire et y placer des objets.

L'ellipsoïde (ellipsoid)

Un long ellipsoïde ressemble à un cigare, un court ressemble un peu à une pilule. Ses sections transverses sont circulaires ou elliptiques. L'ellipsoïde a les mêmes attributs que la boîte et il peut être pensé en tant que l'ajustement au mieux de l'intérieur d'une boîte de mêmes dimensions :

myell = ellipsoid(pos=(x0,y0,z0), length=L, height=H, width=W)

La position donnée est le centre de l'ellipsoïde à (x0, y0, z0). C'est une différence avec le cylindre, dont l'attribut pos est à une des extrémités du cylindre. Comme pour le cylindre, vous pouvez faire référence individuellement aux composantes vectorielles de l'ellipsoïde avec myell.x, myell.y, et myell.z. La longueur de bout en bout (le long de l'axe x) vaut L , la hauteur (le long de l'axe y) vaut H , et la largeur vaut W (le long de l'axe z). Pour cet ellipsoïde, nous avons myell.axis = (L, 0, 0) . Notez que l'axe d'un ellipsoïde fonctionne comme l'axe d'un cylindre.

Pour un ellipsoïde qui n'est pas aligné avec l'axe des coordonnées, des problèmes supplémentaires entrent en jeu. L'orientation de la longueur de l'ellipsoïde est donnée par l'axe (voir le schéma visible avec la documentation de la boîte (box)) :

myell = ellipsoid(pos=(x0,y0,z0), axis=(a,b,c), length=L, height=H, width=W)

L'attribut axis donne une direction pour la longueur de l'ellipsoïde, et la longueur, hauteur et largeur de l'ellipsoïde sont données comme avant (si l'attribut de longueur n'est pas donné, la longueur est définie par la norme du vecteur de l'axe).

L'ellipsoïde a les attributs suivants et des valeurs par défaut identiques à ceux du cylindre : pos (0,0,0), x (0), y(0), z(0), axis (1,0,0), length (1), color (1,1,1) qui est la couleur color.white, red (1), green (1), blue (1), opacity (1), material, et up (0,1,0). Attributs supplémentaires, semblables à ceux de la boîte :

height : dans la direction y dans les cas simples, par défaut vaut 1 ;

width:dans la direction z dans les cas simples, par défaut vaut 1 ;

size : (longueur, hauteur, largeur), par défaut vaut (1,1,1).
myell.size=(20,10,12) définit length=20, height=10, width=12.

Notez que l'attribut pos pour le cylindre, la flèche, le cône et la pyramide correspond à une des extrémités de l'objet, alors que pour la boîte, sphère ou anneau, il correspond au centre de l'objet.

Voir la description des attributs supplémentaires disponibles pour tous les objets 3D.

Les faces (faces)

La primitive "faces" prend une liste de triangles (position, couleur, et la normale pour chaque vertex). Ceci est utile pour l'écriture de routines en Python pour importer des modèles 3D faits avec d'autres outils de modélisation 3D. Vous aurez toujours besoin de faire beaucoup de calculs de normales et autres, mais vous n'aurez pas besoin de faire du codage en C pour importer des fichiers de modèles arbitraires.

Les faces sont une primitive de tableau (comme la courbe, l'objet convexe, etc.), ainsi vous devez utiliser une structure pour le déplacer. Cela se compose d'un ensemble de triangles à une seule face avec des sommets, couleurs et normales spécifiés par l'utilisateur. Les attributs pos, color, et normal ressemblent à ceci :

pos = [ t0v0, t0v1, t0v2,
t1v0, t1v1, t1v2,
t2v0, t2v1, t2v2, ... ]

où t0v0 est la position du sommet 0 du triangle 0, t0v1 est celle du sommet 1 du triangle 1, etc.

Chaque face est une surface à un seul côté. Le côté qui est éclairé est déterminé par l'ordre d'enroulement de la face. Quand vous regardez la face, celle-ci est éclairée si l'ordre des sommets dans la liste pos va dans le sens contraire des aiguilles d'une montre. Si vous soulez que le triangle soit visible des deux côtés, vous devez créer un autre triangle avec un ordre d'enroulement opposé.

Si vous ne spécifiez pas de normales au niveau des sommets, la face est éclairée seulement par la lumière "ambiant". Pour que l'éclairage principal affecte l'apparence, vous devez spécifier des normales à la surface au niveau des sommets. Dans le cas le plus simple, une normale à un sommet est perpendiculaire à la face et les faces contigües se joignent par une arête vive. Un bord doux peut être produit en moyennant les normales à deux faces à leur sommet commun. La luminosité d'une face est proportionnelle au cosinus de l'angle entre la normale et la lumière.

Si vous spécifiez des couleurs différentes aux sommets d'une face triangulaire, VPython interpole à partir de la face, dans ce cas, la face ne sera pas unicolore. Il y a une interpolation similaire pour les normales s'il y a différentes normales aux sommets, dans ce cas, la face n'est pas d'une seule luminosité.

L'objet faces a été conçu pour faciliter l'écriture d'importateurs de modèles, ou l'écriture de nouvelles primitives Python, et non pour être manipulé par des programmes classiques. Cet objet est considérablement d'un plus bas niveau que n'importe quel autre objet de Visual (quoiqu'il n'est pas nécessairement plus rapide, au moins en ce moment). Il est assez facile d'implémenter des lissages ou de facetter des ombres, des colorations par sommet, des éclairages d'un ou des deux côtés, etc., mais tous ces calculs doivent être faits par le programmeur (lors de la définition de pos, color, normal).

Vous pouvez spécifier un matériau, mais actuellement vous ne pouvez pas spécifier l'opacité pour les faces.

Voir la description des attributs supplémentaires disponibles pour tous les objets 3D

Pour des exemples d'utilisation des faces, se référer aux programmes de démonstration sur les faces.

La structure (frame)

Des objets composites avec une structure (frame)

Vous pouvez grouper des objets ensemble pour créer un objet composite qui peut être déplacé et tourné comme si c'était un unique objet. Créez une structure, et associez des objets à cette structure :

f = frame()
cylinder(frame=f, pos=(0,0,0), radius=0.1, length=1, color=color.cyan)
sphere(frame=f, pos=(1,0,0), radius=0.2, color=color.red)
f.axis = (0,1,0) # modifie l'orientation des deux objets
f.pos = (-1,0,0) # modifie la position des deux objets

Par défaut, frame() est à la position (0,0,0) et les axes sont dans la direction x (1,0,0). Le cylindre et la sphère sont créés dans la structure. Lorsque n'importe lequel des attributs de la structure est modifié (pos, x, y, z, axis, ou up), l'objet composite est réorienté et repositionné.

Vous pouvez rendre tous les objets de la structure visible ou invisible en définissant l'attribut visible de la structure.

Un autre attribut de la structure est objects, qui est une liste des objets actuellement visibles et contenus dans la structure (la liste ne comprend pas les objets qui sont actuellement non visibles, ni les lumières, qui se trouvent dans scene.lights). Si vous voulez rendre tous les objets rouges dans la structure, appliquez les instructions suivantes (on suppose que la structure est nommée f) :

for obj in f.objects:
obj.color = color.red

Si vous utilisez cette méthode pour rendre tous les objets invisibles, la liste f.objects sera vide. Si vous avez besoin d'une liste contenant tous les objets, aussi bien visibles qu’invisibles, vous devez maintenir votre propre liste d'objets.

Si ball est un objet de la structure, ball.pos est la position locale à la structure, et non la position actuelle dans "l'espace monde". Voici une routine qui calcule la position d'un vecteur tel que ball.pos dans l'espace entier :

def world_space_pos(frame, local):
"""Returns the position of local in world space."""
x_axis = norm(frame.axis)
z_axis = norm(cross(frame.axis, frame.up))
y_axis = norm(cross(z_axis, x_axis))
return

frame.pos+local.x*x_axis+local.y*y_axis+local.z*z_axis

L'hélice (helix)

L'instruction suivante affichera une hélice qui sera parallèle à l'axe x :

spring = helix(pos=(0,2,1), axis=(5,0,0), radius=0.5)

L'hélice a les attributs et les valeurs par défaut suivants : pos (0,0,0), x (0), y(0), z(0), axis (1,0,0), length (1), radius (1), coils (5), thickness (radius/20), color (1,1,1) qui est la couleur color.white, red (1), green (1), blue (1), material and up (0,1,0).

Notez que l'attribut pos pour le cylindre, la flèche, le cône et la pyramide correspond à une des extrémités de l'objet, alors que pour la boîte, sphère ou anneau, il correspond au centre de l'objet.

Actuellement, il n'est pas possible de spécifier l'opacité d'un objet hélice (helix), qui est sur l'objet courbe (curve).

Voir la description des attributs supplémentaires disponibles pour tous les objets 3D.

L'étiquette (label)

Avec l'étiquette, vous pouvez afficher un texte dans une boîte, reliée par une ligne à un point spécifié. Voici des exemples simples (dans la deuxième instruction sur l'étiquette, notez le schéma standard en Python pour le formatage des valeurs numériques, où 1.5f signifie un chiffre avant le point décimal et cinq après) :

box(pos=(0,0,0), color=color.red)
label(pos=(0,0.25,0), text='This is a box')
label(pos=(0,-0.25,0), text='pi = %1.5f' % pi)

Il y a plusieurs options supplémentaires pour l'étiquette. Dans le schéma ci-contre, une sphère représentant la Terre (dont le centre est à la position earth.pos) a été associée à un label contenant le texte "Earth" dans sa boîte, reliée à la sphère par une ligne qui s'arrête à la surface de celle-ci :

earthlabel = label(pos=earth.pos, text='Earth', xoffset=20, yoffset=12, space=earth.radius, height=10, border=6, font='sans')

Une caractéristique unique de l'étiquette est que plusieurs de ses attributs sont donnés en pixels au lieu des coordonnées traditionnelles de "l'espace". Par exemple, la hauteur du texte est donnée en pixels; ce qui permet d'avoir un texte toujours lisible même si la sphère est déplacée loin de l'étiquette. Les autres attributs définis en pixels comprennent xoffset, yoffset, et border. Les attributs de l'étiquette sont :

pos; x,y,z : le point de l'espace qui est étiqueté. S’il n'y a pas d'offset (voir le schéma), le centre du text est positionné à pos ;

xoffset, yoffset : les coordonnées x et y de l'extrémité de la ligne, en pixels (voir le schéma). Vous pouvez justifier à gauche le texte en paramétrant xoffset = 1 et line = 0 (ainsi la ligne de 1 pixel ne sera pas visible), ou justifier à droite le texte en paramétrant xoffset = -1 et line = 0 ;

text : le texte à afficher, tel que 'Earth'.
(Des retours à la ligne peuvent être rajoutés avec \n, comme dans label.text = "Three lines of text") ;

font : nom de la fonte souhaité, par exemple, 'sans', 'serif', ou 'monospace' (largeur fixe)
Les chaînes de caractères Unicode sont supportées ;

height : hauteur de la fonte en pixels, par défaut de 13 pixels ;

color, red, green, blue : couleur du texte ;

opacity : opacité de l'arrière-plan de la boîte, par défaut 0.66
(0 transparent, 1 opaque, pour les objets derrière la boîte) ;

border : distance en pixels du texte à la boîte environnante, par défaut 5 pixels ;

box : 1 si la boîte doit être dessinée (par défaut), 0 sinon ;

line : 1 si la ligne de la boîte à la position pos doit être dessinée (par défaut), 0 sinon ;

linecolor : couleur de la ligne et de la boîte ;

space : rayon définissant une sphère environnante de centre pos, sur laquelle la ligne n'est pas tracée.

Voir la description des attributs supplémentaires disponibles pour tous les objets 3D.

Le nuage de points (points)

L'objet points prend une liste de points pour l'attribut pos comme l'objet curvet. L'instruction suivante va dessiner deux points, chacun d'un rayon de 50 pixels.

points(pos=[(-1,0,0), (1,0,0)], size=50, color=color.red)

Un nouvel objet points est similaire à un objet curve, mais avec des points déconnectés. Comme pour l'objet curve, l'attribut pos est un tableau de points et l'attribut color peut être alors un tableau. Si vous écrivez shape="round", les points sont ronds, ce qui est le cas par défaut, shape="square" rend les points carrés. La taille des points est spécifiée par l'attribut size, et par défaut size vaut 5 (moyenne d'un carré de 5 par 5, ou d'un disque compris dans un carré de 5 par 5. L'attribut size représente les pixels de l'écran si size_units="pixels" (défaut), mais si size_units="world", l'attribut size représente les coordonnées usuelles. La taille maximale d'un point est d'environ 50 par 50 pixels; spécifier une taille plus grande que le maximum n'augmentera pas la taille.

L'éclairage n'affecte pas l'apparence, qui est seulement déterminée par la couleur. Vous ne pouvez pas spécifier un matériau pour les points, et actuellement, ce n'est pas possible de spécifier l'opacité d'un object points.

Voir la description des attributs supplémentaires disponibles pour tous les objets 3D.

Mise en garde technique: size_units="world" peut ne pas fonctionner sur de très vieux drivers vidéo qui ne supportent pas OpenGL 1.4 ou l'extension ARB_POINT_PARAMETERS. Si vous avez des problèmes, mettez à jour vos pilotes vidéo.

La pyramide (pyramid)

La pyramide a une section transverse rectangulaire et se termine en pointe. L'instruction suivante affichera une pyramide dont le centre de la base rectangulaire est à la position (5,2,0), et dont l'axe principal est parallèle à l'axe x avec une base de hauteur 6 (en y) et de largeur 4 (en z), et de longueur 12 de la base au sommet :

pyramid(pos=(5,2,0), size=(12,6,4))

La pyramide a les attributs suivants et des valeurs par défaut identiques à ceux du cylindre: pos qui est le centre de la base rectangulaire (0,0,0), x (0), y(0), z(0), axis (1,0,0), length (1), color (1,1,1) qui est la couleur color.white, red (1), green (1), blue (1), opacity (1), material, et up (0,1,0). Attributs supplémentaires de la pyramide:

height : dans la direction y dans le cas par défaut, 1 par défaut ;

width : dans la direction z dans le cas par défaut, 1 par défaut ;

size : (longueur, hauteur, largeur), (1,1,1) par défaut mypyramid.size=(20,10,12) règle length=20, height=10, width=12.

Notez que l'attribut pos pour le cylindre, la flèche, le cône et la pyramide correspond à une des extrémités de l'objet, alors que pour la boîte, sphère ou anneau, il correspond au centre de l'objet.

Voir la description des attributs supplémentaires disponibles pour tous les objets 3D.

L'anneau (ring)

L'anneau est circulaire, d'un rayon et d'une épaisseur externe spécifiés et son centre est donné par l'attribut pos :

ring(pos=(1,1,1), axis=(0,1,0), radius=0.5, thickness=0.1)

L'anneau a les attributs suivants et des valeurs par défaut identiques à ceux du cylindre: pos (0,0,0), x (0), y(0), z(0), axis (1,0,0), length (1), color (1,1,1) qui est la couleur color.white, red (1), green (1), blue (1), opacity (1), material, et up (0,1,0). Comme pour le cylindre, up a un effet subtil sur l'apparence 3D de l'anneau à moins qu'un matériau non lisse n'ait été spécifié. L'attribut axis n'a qu'un effet sur l'orientation de l'anneau, la norme du vecteur de l'attribut axis est non pertinente. Attributs supplémentaires de l'anneau :

radius : rayon de la partie centrale de l'anneau, par défaut 1, ainsi
rayon externe = radius+thickness,

rayon interne = radius-thickness ;

thickness : le rayon de la section transverse de l'anneau (1/10e du rayon si non spécifié), et non le diamètre entier comme on pouvait l'attendre.

Notez que l'attribut pos pour le cylindre, la flèche, le cône et la pyramide correspond à une des extrémités de l'objet, alors que pour la boîte, sphère ou anneau, il correspond au centre de l'objet.

Voir la description des attributs supplémentaires disponibles pour tous les objets 3D.

La sphère (sphere)

Voici un exemple qui montre comment créer une sphère :

ball = sphere(pos=(1,2,1), radius=0.5)

Ceci crée une sphère centrée à la position (1,2,1) de rayon 0.5, avec la couleur courante du premier plan.

La sphère a les attributs suivants et des valeurs par défaut identiques à ceux du cylindre excepté qu'il n'y a pas d'attribut de longueur (length) : pos (0,0,0), x (0), y(0), z(0), axis (1,0,0), color (1,1,1) qui est la couleur color.white, red (1), green (1), blue (1), opacity (1), material et up (0,1,0). Comme pour les cylindres, les attributs up et axis affectent l'orientation de la sphère, mais n'ont qu'un effet subtil sur l'apparence à moins qu'un matériau non lisse n'ait été spécifié, la norme du vecteur axis est non pertinente. Attributs supplémentaires de la sphère :

radius : rayon de la sphère, par défaut = 1.

Notez que l'attribut pos pour le cylindre, la flèche, le cône et la pyramide correspond à une des extrémités de l'objet, alors que pour la boîte, sphère ou anneau, il correspond au centre de l'objet.

Voir la description des attributs supplémentaires disponibles pour tous les objets 3D.

Travailler avec les objets

Couleur et opacité

Couleur

Dans le système de couleur RGB (RVB), vous spécifiez une couleur en terme d'une fraction de rouge, vert et bleu, correspondant à la luminance de chaque point rouge, vert, bleu de l'écran de l'ordinateur. Dans le schéma RGB, le blanc est la couleur avec le maximum de rouge, bleu et vert (1, 1, 1). Le noir en a une quantité minimale (0, 0, 0). Le rouge le plus vif est représenté par (1, 0, 0). Autrement dit, il a une quantité pleine de rouge, nulle en vert et en bleu.

Voici quelques exemples de couleurs RGB, avec les noms que vous pouvez utiliser dans Visual:

(1,0,0) color.red

(1,1,0) color.yellow

(0,0,0) color.black

(0,1,0) color.green

(1,0.5,0) color.orange

(1,1,1) color.white

(0,0,1) color.blue

(0,1,1) color.cyan

(1,0,1) color.magenta

Vous pouvez aussi créer vos propres couleurs telles que celles-ci :

(0.5, 0.5, 0.5) un gris assez foncé, ou vous pouvez écrire color=color.gray(0.5) qui signifie (0.5,0.5,0.5) ;

(1,0.7,0.2) une couleur cuivrée.

Les couleurs peuvent apparaître différemment selon l'ordinateur, et sous différentes conditions d'éclairage 3D. Les couleurs nommées ci-dessus sont très probablement affichées convenablement, parce que les valeurs RGB de 0 ou 1 ne sont pas affectées par les différentes corrections sur la couleur (corrections "gamma").

Le programme de démo VPython colorsliders.py vous permet d'ajuster des glissières RGB pour visualiser des couleurs et afficher les triplets de couleur que vous pouvez copier dans votre programme. Il fournit également des glissières HSV pour ajuster la teinte, la saturation (la quantité de blanc ajoutée pour diluer la teinte), et la valeur (luminosité), qui est une autre façon de décrire une couleur.

Actuellement, Visual n'accepte que les descriptions de couleurs RGB, mais il existe des fonctions pour convertir un triplet de couleur de RGB en HSV :

c = (1,1,0)
c2 = color.rgb_to_hsv(c) # convertie RGB en HSV
print hsv # (0.16667, 1, 1)
c3 = color.hsv_to_rgb(c2) # conversion inverse en RGB
print c3 # (1, 1, 0)

Autre exemple : sphere(radius=2, color=hsv_to_rgb( (0.5,1,0.8) ).

Opacité

Vous pouvez rendre la plupart des objets transparents en spécifiant un valeur entre 0 et 1 compris pour l'attribut "opacity". Par exemple, box(color=color.red, opacity=0.8) est d'un transparent léger. Une valeur d'opacité de 0 signifie une transparence totale, et de 1 signifie une opacité totale. Actuellement, les objets courbes (curve), convexes (convex), faces (faces), points (points) et hélices (helix) n'acceptent pas la transparence.

Vous aurez parfois un rendu incorrect chaque fois qu'il y a un object translucide (opacity < 1.0) qui n'est pas convexe (par exemple, l'anneau (ring)), ou deux objects translucides qui se chevauchent sur l'écran et aussi selon leur profondeur (distances de la caméra au plus proche et plus éloigné des plans perpendiculaires à scene.forward qui intersectent l'objet). Les objets n'ont pas besoin en réalité se chevaucher dans l'espace pour avoir des problèmes. Le rendu incorrect aura habituellement pour effet de faire disparaître l'objet le plus lointain (échec l'objet très proche). Le rendu précis de scènes ad hoc avec de la translucidité est difficile et coûteux, et nous ne voulions pas attendre une solution parfaite avant d'introduire cette amélioration utile.

Éclairage

Contrôler une ou plusieurs fenêtres d'affichage visual

Au début, il y a déjà une fenêtre d'affichage nommée scene. Les objets fenêtre d'affichage ne créent pas de fenêtre à l'écran, à moins qu'ils soient utilisés. Si vous créez votre propre objet fenêtre d'affichage tôt dans votre programme, vous n'aurez pas à vous soucier de l'objet scene. Si vous commencez simplement en créant des objets tels que la sphère, ils iront dans l'objet scene.

Display() : crée une scène avec des attributs spécifiés, cette scène devient la scène sélectionnée et est retournée par la fonction. Par exemple, les lignes suivantes créent une autre fenêtre d'affichage Visual 600 par 200, avec son coin haut gauche au coin en haut à gauche de l'écran (y est mesuré à partir du haut de l'écran), avec 'Examples of Tetrahedrons' dans la barre de titre, centrée à la position (5,0,0) et avec un arrière-plan de couleur cyan remplissant la fenêtre.

scene2 = display(title='Examples of Tetrahedrons',
x=0, y=0, width=600, height=200,
center=(5,0,0), background=(0,1,1))

Options d'usage universel

select() : sélectionne la scène spécifiée, ainsi les objets seront dessinés dans cette scène par défaut; par exemple scene.select().

Exécuter myscene = display.get_selected() retourne une référence à la scène dans laquelle les objets sont actuellement créés.

Foreground : définit la couleur utilisée par défaut lors de la création de nouveaux objets tels que la sphère, par défaut c'est le blanc. Exemple : scene.foreground = (1,0,0).

background : définit la couleur utilisée pour remplir la fenêtre d'affichage; par défaut c'est le noir.

Ambient ; couleur de la lumière non directionnelle ("ambiante"). Par défaut, elle vaut color.gray(0.2). Pour une compatibilité avec les versions antérieures de Visual, ceci peut être exprimé comme scene.ambient=0.2. Voir aussi l'attribut suivant lights.

Ligths : liste d'objets lumière créés pour cette scène. Par défaut, une scène a deux lumières lointaines :
distant_light(direction=(0.22, 0.44, 0.88), color=color.gray(0.8)) ;
distant_light(direction=(-0.88, -0.22, -0.44), color=color.gray(0.3)).
Ceci est équivalent aux lumières par défaut dans Visual pour une version antérieure à la 5. Vous pouvez vous débarrasser de ces lumières par défaut avec scene.lights = []. La couleur d’objets lumière et la quantité de scene.ambient doivent être précisées avec attention, parce que si le total de l'intensité lumineuse excède 1 quelque part dans la scène les résultats seront imprévisibles. scene.lights est une liste de toutes les lumières que vous avez créées.

Vous pouvez créer des lumières qui sont locales, à proximité d'autres objets. La déclaration suivante crée une lumière jaune positionnée à (x, y, z), et si vous mettez à jour constamment lamp.pos à jour, la lumière se déplacera. Vous pouvez placer une sphère (sphere) ou une boîte (box) avec material=materials.emissive au même endroit, de sorte que la lampe ressemble à une lampe incandescente.

lamp = local_light(pos=(x,y,z), color=color.yellow)

Une lumière lointaine rouge localisée dans la direction (x, y, z) est créée comme ceci :

distant_light(direction=(x,y,z), color=color.red)

Précédemment à la version 5 de Visual, vous définissiez une lumière en spécifiant un vecteur dans la direction de la lumière depuis l'origine et la norme du vecteur définissait l'intensité. Par exemple, scene.lights = [vecteur (1,0,0)] avec scene.ambient = 0, allumera la scène avec une intensité maximale depuis le côté droit, avec aucune lumière ambiante sur la gauche. Dans la version 5 de Visual et plus tard, cette façon de spécifier les lumières continuera de fonctionner, mais il sera préférable de créer des objets lumière.

Pour obtenir la position de la caméra, voir Interactions Souris.

Objects : une liste de tous les objets visibles à l'écran, les objets non visibles et les lumières ne sont listés (scene.lights est une liste des lumières existantes). Par exemple, la suite rend visibles et rouges toutes les boîtes dans la scène :

for obj in scene2.objects:
if obj.__class__ == box # on peut écrire box ou 'box'
obj.color = color.red

show_rendertime : si vous définissez scene.show_rendertime = 1, dans le coin inférieur gauche de l'écran, vous verrez quelque chose comme "cycle: 27 render: 5", c'est-à-dire 27 millisecondes entre les rendus de la scène, en prenant cinq millisecondes pour l'affichage, auquel cas 22 des 27 millisecondes, ont été consacrées à l'exécution de vos instructions Python.

Stereo : option stéréoscopique, scene.stereo = 'redcyan' permet de générer une vue pour l'œil gauche et une vue pour l'œil droit, à regarder avec des lunettes rouge et cyan, avec des verres rouges pour l'œil gauche (il y a aussi les options 'redblue' et 'yellowblue', on notera que les objets qui n'étaient pas blancs initialement seront quelque peu moins lumineux).

L'option scene.stereo = 'crosseyed' produit des images côte à côte qui, si elles sont suffisamment petites, peuvent être vues en 3D en louchant, mais en faisant la mise au point sur l'écran (cela requiert un peu d'entraînement). L'option scene.stereo = 'passive' produit des images côte à côte qui, si elles sont suffisamment petites, peuvent être vues en 3D en regardant "face à un mur", c'est-à-dire en regardant au loin, mais en faisant la mise au point sur l'écran (cela aussi nécessite un peu d'entraînement).

scene.stereo = 'active' permettra d'alterner des images pour l'œil gauche et pour l'œil droit, à regarder avec des lunettes stéréoscopiques, si le système graphique supporte les pages stéréo quadruples. Si l'équipement stéréo n'est pas disponible, régler l'option n'a pas d'effet et scene.stereo aura la valeur 'nostereo'. Le réglage scene.stereo = 'passive' donnera une vue d'une largeur de deux fenêtres pour l'affichage utilisant deux projecteurs polarisés (pour être regardée avec de simples lunettes passives polarisées pour voir le relief). ( les pages stéréo quadruple 'actives' sont disponibles seulement sur des systèmes graphiques spécialisés qui ont le matériel nécessaire et un connecteur pour les lunettes stéréoscopiques, comme les PC munis d'affichage CRT et de cartes graphiques nVidia Quadro. Cela génère l'illusion de profondeur en rendant chaque image deux fois depuis des angles légèrement différents correspondant aux yeux gauche et droit. Les lunettes stéréoscopiques sont synchronisées avec les images en alternance de sorte que chaque œil ne voit que l'image qui lui est destinée, et notre cerveau fait le reste. Cela s'appelle 'page vidéo quadruple' parce qu'il y a un tampon OpenGL par œil, et chaque tampon est dédoublé pour une mise à jour plus fluide. L'option stéréo 'Passive' nécessite une carte vidéo qui peut piloter deux moniteurs ou deux projecteurs.)

cursor.visible : en définissant scene.cursor.visible = 0, le curseur de la souris deviendra insivible. Ceci est souvent approprié lorsqu'on fait glisser un objet avec la souris. On fait réapparaître le curseur avec scene.cursor.visible = 1. NON ENCORE IMPLANTE DANS VISUAL 5.

Contrôler la fenêtre

Les attributs de fenêtre x, y, width, height, title et fullscreen ne peuvent pas être modifiés pendant que la fenêtre est active; ils sont utilisés pour créer la fenêtre, pas pour la modifier. Si vous souhaitez modifier l'un de ces attributs de fenêtre, d'abord rendez invisible la fenêtre, faites les changements, et ensuite rendez de nouveau la fenêtre visible. Cela crée une nouvelle fenêtre avec les nouveaux attributs, tous les objets existants font toujours partie de la nouvelle fenêtre.

x, y : position de la fenêtre à l'écran (pixel en haut à gauche); scene.y = 200 positionne la fenêtre standard 200 pixels en dessous du haut de l'écran.

width, height : largeur et hauteur de la zone d'affichage en pixels: scene.height = 200 (barre de titre incluse).

Title : texte dans la barre de titre de la fenêtre: scene.title = 'Planetary Orbit'.

fullscreen Option de plein écran, scene2.fullscreen = 1 fait passer la scène appelée scene2 en plein écran. Dans ce cas il n'y a pas de croix de fermeture visible, pressez Escape pour quitter. (Il y a un bogue en ce moment dans l'option fullscreen sur Linux, la touche Escape n'a aucun effet. Si vous utilisez l'option fullscreen sur Linux, soyez sûr d'avoir programmé une entrée souris pour quitter le programme.

Visible : assure que la scène est visible; scene2.visible = 1 rend la scène nommée scene2 visible. Cette fonction est automatiquement appelée lorsque de nouvelles primitives sont ajoutées à la scène, ou si la souris est référencée. Définir visible à 0 cache la scène.

Exit : si scene2.exit = 0, le programme ne quitte pas lorsque la croix de fermeture de la fenêtre scene2 est cliquée. Par défaut, sceneb.exit = 1, dans ce cas cliquer sur la croix de fermeture quittera le programme.

Contrôler la vue

center : position à partir de laquelle la caméra regarde continuellement, même lorsque l'utilisateur tourne la position de la caméra. Si vous changez center, la caméra bouge pour continuer de regarder dans les mêmes directions "limites" à partir du nouveau centre, à moins que vous changiez aussi forward (voir le prochain attribut). Par défaut (0,0,0).

autocenter : scene.center est continuellement mis à jour pour être le centre de la plus petite boîte contenant la scène et alignée sur l'axe. Cela signifie que si votre programme déplace la scène entière, le centre de cette scène continuera d'être centré dans la fenêtre.

Forward : vecteur pointant dans la même direction que le regard de la caméra (c'est-à-dire, de la position courante de la caméra donnée par scene.mouse.camera vers scene.center). Les contrôles de rotation de l'utilisateur, lorsqu'ils sont actifs, changeront ce vecteur continuellement. Quand forward est modifié, la position de la caméra change pour continuer de regarder depuis center. Par défaut (0,0,-1).

fov : champ de visualisation de la caméra en radians. Ceci est défini comme le maximum des champs horizontaux et verticaux de la vue. Vous pouvez le penser comme la taille angulaire d'un objet de taille range, ou comme la taille angulaire du plus long axe de la fenêtre vue par l'utilisateur. Par défaut pi/3.0 radians (60 degrés).

Range : l'étendue de la région d'intérêt depuis center le long de chaque axe. Cet attribut vaut toujours 1.0/scale, si bien que vous utiliserez soit range soit scale en fonction de ce qui donnera le plus de sens à votre programme. Définir range à 10 est équivalent à le définir à (10,10,10). Définir range à (10,0,0) signifie que scene.center+scene.range sera au bord droit d'une fenêtre carrée. Une sphère de rayon 10 remplira la fenêtre. Une boîte cubique dont la demi-largeur vaut 10 débordera de la fenêtre, parce que l'avant de la boîte en 3D apparaît plus large que le plan xy traversant scene.center, à moins que le champ de vision soit très faible.

Scale : un facteur d'échelle qui dimensionne la région d'intérêt dans la sphère avec un rayon unitaire. Ceci vaut toujours 1.0/range, si bien que vous utiliserez soit range soit scale en fonction de ce qui donnera le plus de sens à votre programme. Définir scale à 0.1 est équivalent à le définir à (0.1,0.1,0.1) ou définir range à (10,10,10).

up : un vecteur représentant le haut de l'espace-monde. Ce vecteur est le long de la ligne verticale de l'écran (pensez à la caméra ayant un "plomb à plomb" qui garde le haut de l'écran orienté vers up). La caméra tourne aussi autour de cet axe quand l'utilisateur tourne "horizontalement". Par défaut l'axe y est le vecteur up.

Il y a une interaction entre up et forward, la direction que la caméra pointe. Par défaut, la caméra pointe dans la direction -z (0,0,-1). Dans ce cas, vous pouvez faire que l'axe x ou y (ou n'importe quelle direction comprise entre ces deux axes) soit le vecteur up, mais vous ne pouvez pas faire que l'axe z soit le vecteur up, parce que c'est l'axe autour duquel la caméra tourne lorsque vous définissez l'attribut up. Si vous voulez que l'axe z pointe dans la direction up, définissez d'abord forward à quelque chose d'autre que l'axe -z, par exemple (1,0,0).

autoscale = 0 : pas de redimensionnement automatique (définissez range ou scale explicitement), autoscale = 1 Redimensionnement automatique (scene.autoscale = 1 par défaut). Il est souvent utile de permettre à Visual de faire un affichage initial avec une échelle automatique, puis de couper le redimensionnement automatique pour empêcher plus tard les modifications automatiques.

Userzoom = 0 : l'utilisateur ne peut pas zoomer ou dézoomer dans la scène.

Userzoom = 1 : l'utilisateur peut zoomer (par défaut).

Userspin = 0 : l'utilisateur ne peut pas tourner la scène.

Userspin = 1 : l'utilisateur peut la tourner (par défaut).

Matériaux et Textures

Vous pouvez spécifier un matériau tel que le bois pour n'importe quel objet autre que le nuage de points (points) :

sphere(color=color.orange, material=materials.wood)

Parmi les matériaux actuellement disponibles, on trouve :

- materials.wood ;

- materials.rough ;

- materials.marble ;

- materials.plastic ;

- materials.earth ;

- materials.diffuse ;

- materials.emissive (comme si cela brillait) ;

- materials.unshaded (non affecté par l'éclairage).

Le programme d'exemple material_test.py affiche tous ces matériaux. Le matériau émissif (emissive) est particulièrement approprié pour simuler le rendu d'une lumière d'une couleur donnée. Cette lumière apparente n'illumine pas les autres objets, mais vous pouvez souhaiter placer une lumière locale au même endroit, comme cela est fait avec le pendule lumineux dans le programme d'exemple texture_and_lighting.py. Le rendu d'un matériau non ombré (unshaded) n'est pas affecté par l'éclairage et est utile lorsque vous voulez afficher un objet dont l'apparence est déterminée uniquement par ses attributs propres.

Les matériaux fonctionneront avec les cartes graphiques qui supportent le Pixel Shader 3.0 ("PS 3.0"). Pour plus de détails, voir http://en.wikipedia.org/wiki/Pixel_shader#Hardware. Certains matériaux peuvent fonctionner avec des cartes graphiques qui supportent PS 2.0, mais d'autres matériaux doivent être désactivés manuellement; voir les instructions dans le module site-settings.py dans le paquet Visual de votre dossier site-packages. Si le matériel graphique ne supporte pas les pixels shaders, la propriété matériau est ignoré. Si vous pensez que vous devriez pouvoir utiliser les matériaux, mais que vous rencontrez des problèmes d'affichage ou de performance, nous vous recommandons vivement de mettre à jour vos pilotes de carte vidéo avec la dernière version.

Certains matériaux comme le bois sont orientés selon l'axe spécifié. Par exemple, une boîte en bois avec par défaut axis = (1,0,0) présente des cernes sur ses surfaces yz et des bandes sur les autres faces. Changer d'axe modifie le côté où vous voyez les cernes.

Créer votre propre texture

Vous pouvez créer un objet texture et ensuite l'appliquer à la surface d'un objet. Une texture surfacique est une matrice M par N dont chaque emplacement contient 1, 2, 3, ou 4 valeurs numériques. M et N doivent être des puissances de 2 (1, 2, 4, 8, 16, 32, 64, 128, 256, 512, etc.). Les valeurs numériques peuvent représenter la couleur, la luminance (luminosité ou nuances de gris), ou l'opacité.

Voici les possibilités de chaque emplacement dans la matrice :

- une valeur : luminance par défaut, ou spécifier channels=["opacity"] pour représenter l'opacité ;

- deux valeurs : luminance et opacité ;

- trois valeurs : rouge, vert, bleu ;

- quatre valeurs: rouge, vert, bleu, opacité.

Voici un exemple de programme dans lequel une texture en damier 4 par 4 par 1 est créée et appliquée à une boîte :

from visual import *
checkerboard = ( (0,1,0,1),
(1,0,1,0),
(0,1,0,1),
(1,0,1,0) )
tex = materials.texture(data=checkerboard,
mapping="rectangular",
interpolate=False)
box(axis=(0,0,1), color=color.cyan, material=tex)

L'exemple ci-dessus utilise un mapping rectangulaire (rectangular), ce qui place la texture sur les deux faces opposées d'une boîte, avec des bandes sur les côtés. Par défaut, l'une des faces est dans la direction (1,0,0), mais cela peut être modifié en spécifiant un autre axe pour la boîte, comme cela a été fait dans l'exemple ci-dessus. Un mapping signe (sign) est semblable au mapping rectangulaire, mais n'est pas affecté par la couleur de l'objet et apparaît sur une seule face d'une boîte (déterminé par l'axe de la boîte). Un mapping sphérique (spherical) recouvre l'ensemble de l'objet. Dans l'exemple texture_and_lighting.py, vous pouvez trouver la réalisation d'une balle de plage en utilisant un mapping sphérique.

Par défaut, interporlate vaut True, mais pour obtenir un damier plus net, il a été défini à False dans l'exemple précédent.

Vous pouvez sauver la texture dans un fichier pour une utilisation ultérieure :

materials.saveTGA("checks", checkerboard)

Ceci sauvegarde le motif en damier dans un fichier "checks.tga", un fichier targa que beaucoup d'applications graphiques peuvent afficher. Plus loin dans votre programme, vous pouvez utiliser ces données sans les recréer :

data = materials.loadTGA("checks")

Plus généralement, n'importe quel fichier targa dont la largeur et la hauteur sont toutes deux des puissances de 2 peut être lu comme données en utilisant materials.loadTGA(filename). Si le nom du fichier en question est "checks.tga", vous pouvez donner le nom complet du fichier ou simplement "checks".

Une manière de créer un motif consiste à créer un tableau numpy de zéros puis à assigner des valeurs aux emplacements individuels :

pattern = zeros((4,8,3)) # un tableau numpy de 4 par 8 par 3 de 0
pattern[0][0] = (1,.5,.7) # assigne un triplet rgb au premier emplacement

Autre exemple

Voici un exemple pour placer un "sign" sur l'une des faces de la boîte (box), consistant en une grille de composantes de couleurs de 2 par 2 par 3 :

from visual import *
grid = ( (color.red, (1, 0.7 ,0)),
((0, 1, 0.3), color.magenta) )
tgrid = materials.texture(data=grid,
mapping="sign",
interpolate=False)
box(axis=(0,0,1), material=tgrid)

Créer une texture à partir d'une photo

Une texture peut être créée à partir d'un fichier targa, et diverses applications graphiques peuvent convertir des photos en jpeg ou d'autres formats en fichier targa. Ceci peut être fait avec PIL, la Python Imaging Library, qui peut être téléchargée et installée (vous pouvez la trouver avec une recherche sur le web). Voici un exemple de code PIL qui convertit une photo jpeg en un fichier targa qui peut être utilisé pour créer une texture pour afficher l'image, comme dans le programme d'exemple stonehenge.py.

from visual import *
import Image # PIL doit être installée
name = "flower"
width = 128 # doit être une puissance de 2
height = 128 # doit être une puissance de 2
im = Image.open(name+".jpg")
#print im.size # optionnel, voir la taille d'une image
# Optional cropping:
#im = im.crop((x1,y1,x2,y2)) # (0,0) est en haut à gauche
im = im.resize((width,height), Image.ANTIALIAS)
materials.saveTGA(name,im)

Par la suite, vous pourrez écrire data = materials.loadTGA(name) pour récupérer les données de l'image d'un fichier targa.

Par commodité, une texture peut aussi être créée directement depuis les données d'une image de PIL, comme ceci :

tex = materials.texture(data=im, mapping="sign")

Les problèmes d'efficacité

Normalement, vous créer des données pour une définition de texture qui contiennent des valeurs entre 0.0 et 1.0, la gamme standard des composantes de couleur et d'opacité dans Visual. Toutefois, la machinerie graphique sous-jacente fonctionne avec des valeurs dans la plage de 0 à 255, ce qui peut être exprimé dans un octet de 8 bits de la mémoire de l'ordinateur. Si vous avez affaire avec de larges textures et que le temps est critique, vous devrez éviter les conversions de la gamme 0-1 vers la gamme 0-255 en construisant les données de la texture depuis un tableau numpy d'octets de 8 bits non signés. Un byte non signé est dénommé ubyte. Voici un exemple simple :

checkers = array( ( (0,255,0,255),
(255,0,255,0),
(0,255,0,255),
(255,0,255,0) ), ubyte)

La fonction array convertit une séquence de valeurs dans un tableau numpy. Dans ce cas, les valeurs sont des octets de 8 bits.

Les canaux

Les données "channels" forment une partie de la définition d'une texture. La plupart du temps, ces canaux sont automatiquement assignés pour vous, de la manière suivante:

- 1 valeur : channels=["luminance"] par défaut, channels=["opacity"] pour représenter l'opacité ;

- 2 valeurs : channels=["luminance","opacity"] ;

- 3 valeurs : channels=["red","green","blue"] ;

- 4 valeurs : channels=["red","green","blue","opacity"].

Sauf dans le cas où le modèle représente l'opacité plutôt que la luminance (luminosité ou la nuance de gris), il n'est pas nécessaire de préciser les canaux lors de la construction d'une texture, car les options channel ci-dessus sont actuellement les seuls ensembles de canaux valides. Toutefois, il est prévu que dans le futur, il puisse y avoir des canaux supplémentaires disponibles, tels que la brillance.

mipmap

Quand un objet dans la scène est petit et très loin, il n'y a pas besoin d'afficher sa texture en détail. Avec la valeur par défaut mipmap = True , Visual prépare une série de petites textures à utiliser le cas échéant. Ces textures supplémentaires prennent un peu de temps de préparation pour un usage ultérieur, et nécessitent un espace de stockage d'un tiers plus élevé, mais elles peuvent accélérer le rendu de la scène. Vous devriez rarement vous trouver dans des situations où vous auriez besoin de paramétrer mipmap = False.

Créer vos propres matériaux

Créer ses propres matériaux (par opposition à la création de textures) est techniquement un peu difficile. Le programme materials.py, un composant du module Visual, contient des modèles de nuance pour le bois et d'autres matériaux, et il contient également des instructions sur la façon de construire vos propres matériaux. Des modèles de nuance sont écrits dans un langage ressemblant au C, GLSL (OpenGL Shader Language).

Valeurs par défaut

Valeurs pratiques par défaut

Les objets peuvent être définis avec des valeurs par défaut assez pratiques :

arrow() est équivalent à arrow(pos=(0,0,0), axis=(1,0,0), radius=1) ;

box() est équivalent à box(pos=(0,0,0), size=(1,1,1)) ;

cone() est équivalent à cone(pos=(0,0,0), axis=(1,0,0), radius=1) ;

convex() crée un objet "vide" auquel des points peuvent être ajoutés ;

curve() crée une courbe "vide" à laquelle des points peuvent être ajoutés ;

cylinder() est équivalent à cylinder(pos=(0,0,0), axis=(1,0,0), radius=1) ;

ellipsoid() est équivalent à ellipsoid(pos=(0,0,0), size=(1,1,1)) ;

frame() crée une structure avec pos=(0,0,0) et axis=(1,0,0) helix() est équivalent to helix(pos=(0,0,0), axis=(1,0,0), radius=1, thickness=0.05, coils=5) ;

points() crée un ensemble de points vide auquel des points peuvent être ajoutés ;

pyramid() est équivalent à pyramid(pos=(0,0,0), size=(1,1,1), axis=(1,0,0)) ;

ring() est équivalent à ring(pos=(0,0,0), axis=(1,0,0), radius=1) ;

sphere() est équivalent à sphere(pos=(0,0,0), radius=1 ).

Vitesse d'animation

Limitation de la vitesse d'animation

rate( frequency )

Interruption des calculs jusqu'à 1.0/fréquence secondes après le précédent appel à rate().

Par exemple, rate(50) stoppera les calculs assez longtemps pour s'assurer qu'au moins 1.0/50.0 seconde se sont écoulées. Si ce temps s'est déjà écoulé, aucune interruption n'est déclenchée. Si vous placez rate(50) à l'intérieur d'une boucle de calculs, la boucle sera exécutée au plus 50 fois par seconde, même si l'ordinateur peut fonctionner plus rapidement que cela. Ceci fera que les animations sembleront identiques sur des ordinateurs de puissances différentes, aussi longtemps que les ordinateurs seront capables de supporter 50 calculs à la seconde.

Rotation d'un objet

Rotation d'un objet

Les objets autres que la courbe, l'objet convexe, les faces et les points peuvent être tournés à partir d'une origine spécifiée (pour tourner ces autres objets, insérez-les dans une structure (frame) et faites pivoter la structure.

object.rotate(angle=pi/4., axis=axis, origin=pos)

La fonction rotate applique une transformation à l'objet spécifié (sphère, boîte, etc.). La transformation est une rotation d’angle (en radians), dans le sens contraire des aiguilles d'une montre autour de la ligne définie par origin et origin+axis. Par défaut, les rotations se font autour des attributs pos et axis propres à l'objet.

Voir aussi la fonction rotation disponible pour les vecteurs.

Attributs supplémentaires

Attributs supplémentaires

Les attributs suivants s'appliquent à tous les objets Vpython :

visible : si faux (0), l'objet n'est pas affiché; exemple : ball.visible = 0
Utilisez ball.visible = 1 pour rendre visible la balle de nouveau ;

frame : place cet objet dans une structure spécifiée, comme dans ball = sphere(frame = f1) ;

display : quand vous démarrez un programme VPython, pour des raisons de commodité, Visual crée une fenêtre d'affichage et la nomme scene. Par défaut, les objets que vous créez vont dans cette fenêtre d'affichage. Vous pouvez choisir de placer un objet dans une fenêtre différente comme ceci :

scene2 = display( title = "Act IV, Scene 2" )
rod = cylinder( display = scene2 )

Executer myscene = display.get_selected() retourne une référence de la fenêtre d'affichage dans laquelle les objets sont actuellement créés. Étant donnée une fenêtre d'affichage spécifique nommée scene2, scene2.select() rend scene2 la "fenêtre d'affichage sélectionnée", si bien que les objets seront dessinés par défaut dans scene2.

Il y a une fonction de rotation pour tous les objets autres que les objets courbe (curve), convexes (convex), faces (faces) et nuages de points (points) (qui peuvent être placés dans une structure (frame) qui subira la rotation).

__class__ : nom de la classe de l'objet. Par exemple, ball.__class__ is sphere est vraie si ball est une sphère. Il y a deux underscores avant et après le mot class. Dans une liste d'objets visibles donnée par scene.objects, si obj est dans cette liste, vous pouvez déterminer la classe de l'objet avec obj.__class__.

__copy__() : fait une copie de l'objet. Il y a deux underscores avant et après le copy. Sans argument, il en résulte la création d'un second objet dans le même état que le premier, ce qui n'est probablement pas ce que vous voulez. La fonction __copy__() prend une liste de paires d'arguments "mots clé=valeur" qui sont appliquées au nouvel objet avant de le rendre visible. Par exemple, pour cloner un objet d'une scène à une autre, vous exécuterez: new_object = old_object.__copy__( display=new_display). Restriction: Si l'objet originel appartient à une structure (frame), et que le nouvel objet est sur une fenêtre d'affichage différente, vous devez fournir une nouvelle fenêtre d'affichage ainsi qu'une nouvelle structure pour le nouvel objet (la nouvelle structure peut valoir None). Ceci est dû à la restriction qu'un objet ne peut pas être localisé dans une structure qui est dans une fenêtre d'affichage séparée.

Voici un exemple qui utilise la fonction __copy__(). La routine suivante copie tous les objets Visual courants existant dans une fenêtre dans une seconde fenêtre précédemment définie, aussi longtemps qu'il n'y a pas de structures imbriquées (structure dans des structures):

def clone_universe( new_display, old_display):
# Crée un dictionnaire de structure dans l'ancienne fenêtre
# pour les structures correspondantes dans la nouvelle fenêtre.
frames = {} # crée un dictionnaire vide
for obj in old_display.objects:
if obj.__class__ == frame:
frames[obj] = obj.__copy__( frame=None,
display=new_display)
# Pour chaque ancienne structure référencée qui était dans une autre structure référencée,
# on place la nouvelle référence dans une structure appropriée dans la nouvelle
# fenêtre. Ici old est un object et new est sa frame dans la nouvelle fenêtre
for old, new in frames.iteritems():
if old.frame:
new.frame = frames[old.frame]
# Copie en parcourant l'univers des objets
for obj in old_display.objects:
if obj.__class__ == frame:
# Cas déjà traité plus haut
pass
elif obj.frame:
# Puis on initialise avec la structure correspondante référencée
# dans la nouvelle fenêtre.
obj.__copy__( display=new_display,
frame=frames[obj.frame])
else:
# Pas de problème de structure;
obj.__copy__( display=new_display)

Voir Contrôler Une ou Plusieurs Fenêtres d'Affichage Visual pour plus d'informations sur la création et la manipulation d'objets d'affichage.

Suppression d'un objet

Suppression d'un objet

Pour supprimer un objet Visual, rendez-le simplement invisible : ball.visible = 0.

Détail technique: si vous voulez réutiliser plus tard le nom ball, par exemple en créant un nouvel objet et en le nommant ball, Python sera libre de libérer la mémoire utilisée par l'objet appelé auparavant ball (en supposant qu'aucun autre nom ne réfère actuellement cet objet).

3/4 = 0 ?

La division flottante

Par défaut, Python opère une troncature sur les divisions d'entiers, si bien que 3/4 vaut 0 et non 0.75. Ceci est gênant pour des calculs scientifiques et peut conduire à des bogues dans le programme difficiles à trouver. Vous pouvez écrire 3./4. qui vaut 0.75 par les règles de divisions par "virgule flottante".

Vous pouvez changer le traitement par défaut si bien que 3/4 est traité comme 0.75. Placez ceci au début de votre programme :

from __future__ import division

Il y a deux undescores ("_" et "_") avant "future" et deux après.

Le module Visual fait pour vous la conversion des entiers en nombres à virgule flottante lorsque vous donnez des valeurs aux attributs d'objets:

object.pos = (1,2,3) est équivalent à object.pos = (1.,2.,3.)

Fenêtres, évènements, fichiers

Contrôler une ou plusieurs fenêtres d'affichage visual

Au début, il y a déjà une fenêtre d'affichage nommée scene. Les objets fenêtre d'affichage ne créent pas de fenêtre à l'écran, à moins qu'ils soient utilisés. Si vous créez votre propre objet fenêtre d'affichage tôt dans votre programme, vous n'aurez pas à vous soucier de l'objet scene. Si vous commencez simplement en créant des objets tels que la sphère, ils iront dans l'objet scene.

display() Crée une scène avec des attributs spécifiés, cette scène devient la scène sélectionnée et est retournée par la fonction. Par exemple, les lignes suivantes créent une autre fenêtre d'affichage Visual 600 par 200, avec son coin haut gauche au coin en haut à gauche de l'écran (y est mesuré à partir du haut de l'écran), avec 'Examples of Tetrahedrons' dans la barre de titre, centrée à la position (5,0,0) et avec un arrière-plan de couleur cyan remplissant la fenêtre.

scene2 = display(title='Examples of Tetrahedrons',
x=0, y=0, width=600, height=200,
center=(5,0,0), background=(0,1,1))

Options d'usage universel

select() : sélectionne la scène spécifiée, ainsi les objets seront dessinés dans cette scène par défaut; par exemple scene.select().

Exécuter myscene = display.get_selected() retourne une référence à la scène dans laquelle les objets sont actuellement créés.

Foreground : définit la couleur utilisée par défaut lors de la création de nouveaux objets tels que la sphère; par défaut c'est le blanc. Exemple: scene.foreground = (1,0,0).

background : définit la couleur utilisée pour remplir la fenêtre d'affichage; par défaut c'est le noir.

Ambient : couleur de la lmuière non directionnelle ("ambiante"). Par défaut, ekke vaut color.gray(0.2), pour une compatibilité avec les versions antérieures de Visual, ceci peut être exprimé comme scene.ambient=0.2. Voir aussi l'attribut suivant lights.

Ligths : liste d'objets lumière créés pour cette scène. Par défaut, une scène a deux lumières lointaines :
distant_light(direction=(0.22, 0.44, 0.88), color=color.gray(0.8)) ;
distant_light(direction=(-0.88, -0.22, -0.44), color=color.gray(0.3)) .
Ceci est équivalent aux lumières par défaut dans Visual à une version antérieure à la 5. Vous pouvez vous débarrasser de ces lumières par défaut avec scene.lights = []. La couleur d’objets lumière et la quantité de scene.ambient doivent être précisées avec attention, parce que si le total de l'intensité lumineuse excède 1 quelque part dans la scène les résultats seront imprévisibles. scene.lights est une liste de toutes les lumières que vous avez créées.

Vous pouvez créer des lumières qui sont locales, à proximité d'autres objets. La déclaration suivante crée une lumière jaune positionnée à (x, y, z), et si vous mettez à jour constamment lamp.pos à jour, la lumière se déplacera. Vous pouvez placer une sphère (sphere) ou une boîte (box) avec material=materials.emissive au même endroit, de sorte que la lampe ressemble à une lampe incandescente.

lamp = local_light(pos=(x,y,z), color=color.yellow)

Une lumière lointaine rouge localisée dans la direction (x, y, z) est créée comme ceci :

distant_light(direction=(x,y,z), color=color.red)

Précédemment à la version 5 de Visual, vous définissiez une lumière en spécifiant un vecteur dans la direction de la lumière depuis l'origine et la norme du vecteur définissait l'intensité. Par exemple, scene.lights = [vecteur (1,0,0)] avec scene.ambient = 0, allumera la scène avec une intensité maximale depuis le côté droit, avec aucune lumière ambiante sur la gauche. Dans la version 5 de Visual et plus tard, cette façon de spécifier les lumières continuera de fonctionner, mais il sera préférable de créer des objets lumière.

Pour obtenir la position de la caméra, voir Interactions Souris.

Objects : une liste de tous les objets visibles à l'écran, les objets non visibles et les lumières ne sont listés (scene.lights est une liste des lumières existantes). Par exemple, la suite rend visibles et rouges toutes les boîtes dans la scène :

for obj in scene2.objects:
if obj.__class__ == box # on peut écrire box ou 'box'
obj.color = color.red

show_rendertime : si vous définissez scene.show_rendertime = 1, dans le coin inférieur gauche de l'écran, vous verrez quelque chose comme "cycle: 27 render: 5", c'est-à-dire 27 millisecondes entre les rendus de la scène, en prenant 5 millisecondes pour l'affichage, auquel cas 22 des 27 millisecondes, ont été consacrées à l'exécution de vos instructions Python.

Stereo : option stéréoscopique; scene.stereo = 'redcyan' permet de générer une vue pour l'œil gauche et une vue pour l'œil droit, à regarder avec des lunettes rouge et cyan, avec des verres rouges pour l'œil gauche ( il y a aussi les options 'redblue' et 'yellowblue'; on notera que les objets qui n'étaient pas blancs initialement seront quelque peu moins lumineux.)

L'option scene.stereo = 'crosseyed' produit des images côte à côte qui, si elles sont suffisamment petites, peuvent être vues en 3D en louchant, mais en faisant la mise au point sur l'écran (cela requiert un peu d'entraînement). L'option scene.stereo = 'passive' produit des images côte à côte qui, si elles sont suffisamment petites, peuvent être vues en 3D en regardant "face à un mur", c'est-à-dire en regardant au loin, mais en faisant la mise au point sur l'écran (cela aussi nécessite un peu d'entraînement).

scene.stereo = 'active' permettra d'alterner des images pour l'œil gauche et pour l'œil droit, à regarder avec des lunettes stéréoscopiques, si le système graphique supporte les pages stéréo quadruples. Si l'équipement stéréo n'est pas disponible, régler l'option n'a pas d'effet et scene.stereo aura la valeur 'nostereo'. Le réglage scene.stereo = 'passive' donnera une vue d'une largeur de deux fenêtres pour l'affichage utilisant deux projecteurs polarisés (pour être regardée avec de simples lunettes passives polarisées pour voir le relief). ( Les pages stéréo quadruple 'actives' sont disponibles seulement sur des systèmes graphiques spécialisés qui ont le matériel nécessaire et un connecteur pour les lunettes stéréoscopiques, comme les PC munis d'affichage CRT et de cartes graphiques nVidia Quadro. Cela génère l'illusion de profondeur en rendant chaque image deux fois depuis des angles légèrement différents correspondant aux yeux gauche et droit. Les lunettes stéréoscopiques sont synchronisées avec les images en alternance de sorte que chaque œil ne voit que l'image qui lui est destinée, et notre cerveau fait le reste. Cela s'appelle 'page vidéo quadruple' parce qu'il y a un tampon OpenGL par œil, et chaque tampon est dédoublé pour une mise à jour plus fluide. L'option stéréo 'Passive' nécessite une carte vidéo qui peut piloter deux moniteurs ou deux projecteurs).

cursor.visible : en définissant scene.cursor.visible = 0, le curseur de la souris deviendra insivible. Ceci est souvent approprié lorsqu'on fait glisser un objet avec la souris. On fait réapparaître le curseur avec scene.cursor.visible = 1. NON ENCORE IMPLANTE DANS VISUAL 5.

Contrôler la fenêtre

Les attributs de fenêtre x, y, width, height, title et fullscreen ne peuvent pas être modifiés pendant que la fenêtre est active; ils sont utilisés pour créer la fenêtre, pas pour la modifier. Si vous souhaitez modifier l'un de ces attributs de fenêtre, d'abord rendez invisible la fenêtre, faites les changements, et ensuite rendez de nouveau la fenêtre visible. Cela crée une nouvelle fenêtre avec les nouveaux attributs, tous les objets existants font toujours partie de la nouvelle fenêtre.

x, y : position de la fenêtre à l'écran (pixel en haut à gauche); scene.y = 200 positionne la fenêtre standard 200 pixels en dessous du haut de l'écran.

width, height : largeur et hauteur de la zone d'affichage en pixels: scene.height = 200 (barre de titre incluse).

title : texte dans la barre de titre de la fenêtre: scene.title = 'Planetary Orbit'.

fullscreen Option de plein écran; scene2.fullscreen = 1 fait passer la scène appelée scene2 en plein écran. Dans ce cas il n'y a pas de croix de fermeture visible; pressez Escape pour quitter. (Il y a un bogue en ce moment dans l'option fullscreen sur Linux, la touche Escape n'a aucun effet. Si vous utilisez l'option fullscreen sur Linux, soyez sûr d'avoir programmé une entrée souris pour quitter le programme.

visible : assure que la scène est visible; scene2.visible = 1 rend la scène nommée scene2 visible. Cette fonction est automatiquement appelée lorsque de nouvelles primitives sont ajoutées à la scène, ou si la souris est référencée. Définir visible à 0 cache la scène.

exit : si scene2.exit = 0, le programme ne quitte pas lorsque la croix de fermeture de la fenêtre scene2 est cliquée. Par défaut, sceneb.exit = 1, dans ce cas cliquer sur la croix de fermeture quittera le programme.

Contrôler la vue

center : position à partir de laquelle la caméra regarde continuellement, même lorsque l'utilisateur tourne la position de la caméra. Si vous changez center, la caméra bouge pour continuer de regarder dans les mêmes directions "limites" à partir du nouveau centre, à moins que vous changiez aussi forward (voir le prochain attribut). Par défaut (0,0,0).

autocenter : scene.center est continuellement mis à jour pour être le centre de la plus petite boîte contenant la scène et alignée sur l'axe. Cela signifie que si votre programme déplace la scène entière, le centre de cette scène continuera d'être centré dans la fenêtre.

forward : vecteur pointant dans la même direction que le regard de la caméra (c'est-à-dire, de la position courante de la caméra donnée par scene.mouse.camera vers scene.center). Les contrôles de rotation de l'utilisateur, lorsqu'ils sont actifs, changeront ce vecteur continuellement. Quand forward est modifié, la position de la caméra change pour continuer de regarder depuis center. Par défaut (0,0,-1).

fov : champ de visualisation de la caméra en radians. Ceci est défini comme le maximum des champs horizontaux et verticaux de la vue. Vous pouvez le penser comme la taille angulaire d'un objet de taille range, ou comme la taille angulaire du plus long axe de la fenêtre vue par l'utilisateur. Par défaut pi/3.0 radians (60 degrés).

range : l'étendue de la région d'intérêt depuis center le long de chaque axe. Cet attribut vaut toujours 1.0/scale, si bien que vous utiliserez soit range soit scale en fonction de ce qui donnera le plus de sens à votre programme. Définir range à 10 est équivalent à le définir à (10,10,10). Définir range à (10,0,0) signifie que scene.center+scene.range sera au bord droit d'une fenêtre carrée. Une sphère de rayon 10 remplira la fenêtre. Une boîte cubique dont la demi-largeur vaut 10 débordera de la fenêtre, parce que l'avant de la boîte en 3D apparaît plus large que le plan xy traversant scene.center, à moins que le champ de vision soit très faible.

scale: un facteur d'échelle qui dimensionne la région d'intérêt dans la sphère avec un rayon unitaire. Ceci vaut toujours 1.0/range, si bien que vous utiliserez soit range soit scale en fonction de ce qui donnera le plus de sens à votre programme. Définir scale à 0.1 est équivalent à le définir à (0.1,0.1,0.1) ou définir range à (10,10,10).

up : un vecteur représentant le haut de l'espace-monde. Ce vecteur est le long de la ligne verticale de l'écran (pensez à la caméra ayant un "plomb à plomb" qui garde le haut de l'écran orienté vers up). La caméra tourne aussi autour de cet axe quand l'utilisateur tourne "horizontalement". Par défaut l'axe y est le vecteur up.

Il y a une interaction entre up et forward, la direction que la caméra pointe. Par défaut, la caméra pointe dans la direction -z (0,0,-1). Dans ce cas, vous pouvez faire que l'axe x ou y (ou n'importe quelle direction comprise entre ces deux axes) soit le vecteur up, mais vous ne pouvez pas faire que l'axe z soit le vecteur up, parce que c'est l'axe autour duquel la caméra tourne lorsque vous définissez l'attribut up. Si vous voulez que l'axe z pointe dans la direction up, définissez d'abord forward à quelque chose d'autre que l'axe -z, par exemple (1,0,0).

autoscale = 0 : pas de redimensionnement automatique (définissez range ou scale explicitement), autoscale = 1 Redimensionnement automatique (scene.autoscale = 1 par défaut). Il est souvent utile de permettre à Visual de faire un affichage initial avec une échelle automatique, puis de couper le redimensionnement automatique pour empêcher plus tard les modifications automatiques.

userzoom = 0 l'utilisateur ne peut pas zoomer ou dézoomer dans la scène.

userzoom = 1 l'utilisateur peut zoomer (par défaut).

userspin = 0 l'utilisateur ne peut pas tourner la scène.

userspin = 1 l'utilisateur peut la tourner (par défaut).

Interactions Souris

Introduction

Les objets souris sont obtenus par l'attribut mouse d'un objet d'affichage tel que scene. Par exemple, pour obtenir l'entrée souris de la fenêtre par défaut créée par Visual, utilisez scene.mouse. Pour des exemples simples de manipulation de la souris, voir Exemple de clic de souris et Exemple de dragage de souris.

Un objet souris possède un groupe d'attributs correspondant à l'état courant de la souris. Il a aussi les fonctions getevent() et getclick(), qui retournent un objet avec des attributs semblables correspondant à l'état de la souris lors du dernier appui de l'utilisateur sur les boutons de la souris. Si l'utilisateur n'a encore rien fait avec les boutons de la souris, getevent() et getclick() arrêteront l'exécution du programme jusqu'à ce que cela arrive.

Différentes sortes de souris

Les routines de l'objet souris peuvent manipuler des souris à trois boutons, avec les boutons "gauche", "droit", et "du milieu". Pour les systèmes avec une souris à deux boutons, le bouton "du milieu" est constitué des boutons gauche et droit pressés en même temps. Pour les systèmes avec une souris à un bouton, le bouton droit est invoqué en maintenant appuyée la touche de Commande et le bouton du milieu est invoqué en maintenant appuyée la touche d'Options.

État courant de la souris

pos : la position courante en 3D du curseur de la souris; scene.mouse.pos. Visual choisit toujours un point dans le plan parallèle à l'écran et passant à travers display.center. (Voir Projection des informations de la souris sur un plan donné pour d'autres options.)

button = None (pas de bouton pressé), 'left', 'right', 'middle', ou 'wheel' (molette appuyée sur certaines souris Windows). Exemple: scene.mouse.button == 'left' est vrai si le bouton gauche de la souris est actuellement appuyé.

pick : le plus proche objet de la scène qui tombe sous le curseur ou None. Actuellement seuls les sphères, boîtes, cylindres et objets convexes peuvent être sélectionnés. L'objet sélectionné est scene.mouse.pick.

pickpos : le point 3D sur la surface de l'objet sélectionné qui tombe sous le curseur, ou None; scene.mouse.pickpos.

camera: la position actuelle en lecture seule de la caméra ainsi positionnée par l'utilisateur, scene.mouse.camera. Par exemple, mag(scene.mouse.camera-scene.center) est la distance du centre de la scène à la position courante de la caméra. Si vous voulez définir la position et la direction de la caméra en le programmant, utilisez scene.forward et scene.center, décrit dans Contrôler la fenêtre.

ray :un vecteur unitaire pointant depuis la caméra dans la direction du curseur de la souris. Les points sous lesquels le curseur sont exactement { camera + t*ray pour t>0}.

Les attributs camera et ray définissent ensemble tous les points 3D sous le curseur de la souris.

project() projette la position sur un plan. Voir Projeter la position de la souris sur un plan donné.

alt = 1 si la touche ALT est pressée, sinon 0.

ctrl = 1 si la touche CTRL est pressée, sinon 0 (pour une souris à un bouton, a un sens uniquement si les boutons de la souris sont non appuyés).

shift = 1 si la touche SHIFT est pressée, sinon 0 (pour une souris à un bouton, a un sens uniquement si les boutons de la souris sont non appuyés).

Obtention des évènements

Il y a cinq sortes d'évènements souris : press (pression), click (clic), drag (dragage), drop (relâchement) et release (relâchement).

- Un évènement press intervient lorsqu'un bouton de la souris est pressé.

- Un évènement click intervient lorsque tous les boutons de la souris sont relâchés avec aucun ou un très léger mouvement de celle-ci.
Notez qu'un évènement click arrive quand le bouton de la souris est relâché. Voir Exemple de clic de souris.

- Un évènement drag intervient lorsque la souris est déplacée légèrement après un évènement press avec les boutons de la souris encore appuyés.
Ceci peut être utilisé pour signaler le début d'un dragage d'un objet. Voir Exemple de dragage.

- Un évènement drop intervient lorsque les boutons de la souris sont relâchés après un évènement drag.

- Un évènement release intervient lorsque les boutons de la souris sont relâchés après un évènement click ou drag.

Entre un évènement drag (début d'un dragage) et un évènement drop (fin du dragage), il n'y a aucun évènement souris, mais vous pouvez examiner continuellement la position mise à jour de la souris indiquée par scene.mouse.pos. Voici comment appeler un évènement qui arrive et obtenir les informations à propos de cet évènement :

events le nombre d'évènements (press, click, drag, ou drop) qui sont dans la file d'attente; c'est-à-dire scene.mouse.events.
scene.mouse.events = 0 peut être utilisé pour abandonner toutes les entrées. Aucune valeur autre que 0 ne peut être assignée ;

getevent() obtient l'évènement souris le plus vieux et le supprime de la file d'attente d'entrées. Si aucun évènement n'attend dans la file d'attente (c'est-à-dire si scene.mouse.events vaut zéro), getevent() attend jusqu'à ce que l'utilisateur entre un évènement souris (press, click, drag, ou drop). getevent() retourne un objet avec des attributs semblables à un objet souris: pos, button, pick, pickpos, camera, ray, project(), alt, ctrl, et shift. Ces attributs correspondent à l'état de la souris quand l'évènement arrive. Par exemple, après avoir exécuté mm = scene.mouse.getevent() vous pouvez visualiser les propriétés changeantes de cet évènement telles que mm.pos, mm.pick, mm.drag (voir ci-dessous), etc.

Si vous êtes intéressé par chaque type d'évènement (press, click, drag, et drop), vous devez utiliser events et getevent(). Si vous n'êtes intéressé que par les évènements de clic gauche (bouton gauche appuyé et relâché sans mouvements significatifs de la souris), vous pouvez utiliser clicked et getclick() :

clicked le nombre de clics gauches qui sont dans la file d'attente; c'est-à-dire scene.mouse.clicked.
Ceci n'inclut pas le nombre d'évènements autres (press, drag, ou drop).

getclick() obtient l'évènement clic gauche de la souris le plus vieux (pression du bouton gauche et relâchement de celui-ci dans presque la même position) et le supprime de la file d'attente d'entrées, se débarrassant de tous les évènements press, drag ou drop. Si aucun clic n'est en attente dans la queue (c'est-à-dire, si scene.mouse.clicked vaut zéro), getclick() attend jusqu'à ce que l'utilisateur clique. Autrement, getclick() est la même chose que getevent().

C'est une technique utile de débogage que d'insérer scene.mouse.getclick() dans votre programme à un endroit où vous souhaitez vous arrêter temporairement pour examiner la scène. Puis cliquez simplement pour continuer.

Informations supplémentaires obtenues avec getevent() ou getclick()

En plus des informations disponibles avec scene.mouse, getevent() et getclick() fournissent ces informations supplémentaires :

press = 'left' pour un évènement press, ou None ('right' ou 'middle' non actuellement implanté) ;

click = 'left' pour un évènement click ou None ('right' ou 'middle' non actuellement implanté), dans ce cas, pos et d'autres attributs correspondent à l'état de la souris au moment du déclenchement de l'évènement press, ainsi impossible de perdre l'information de la position initiale. Voir Exemple de clic.

drag = 'left' pour un évènement drag, ou None ('right' ou 'middle' non actuellement implanté); dans ce cas, pos et d'autres attributs correspondent à l'état de la souris au moment du déclenchement de l'évènement press, ainsi impossible de perdre l'information de la position initiale. Voir Exemple de dragage.

drop = 'left' pour un évènement drop, ou None ('right' ou 'middle' non actuellement implanté).

release = 'left' selon les évènements click et drop, indiquant quel bouton a été relâché, ou None ('right' ou 'middle' non actuellement implantés).

Projection de la position de la souris sur un plan donné

Voici comment obtenir la position de la souris relativement à un plan particulier de l'espace :

temp = scene.mouse.project(normal=(0,1,0), point=(0,3,0))
if temp: # temp vaut None si aucune intersection avec le plan
ball.pos = temp

Ceci projette le curseur de la souris sur un plan qui est perpendiculaire à la normale spécifiée. Si point n'est pas spécifié, le plan passe à travers l'origine. Cela retourne une position 3D, ou None si la projection de la souris manque le plan.

Dans l'exemple montré ci-dessus, l'utilisateur de votre programme sera capable d'utiliser la souris pour placer la balle dans un plan parallèle au plan xy, à une hauteur de 3 au-dessus du plan xy, peu importe que l'utilisateur ait ou non modifé le point de vue.

Vous pouvez spécifier à la place une distance perpendiculaire d de l'origine au plan qui est perpendiculaire à la normale spécifiée. L'exemple au-dessus est équivalent à :

temp = scene.mouse.project(normal=(0,1,0), d=3)

Mouse Click

Exemple de clic

Ce programme affiche une boîte (ce qui crée automatiquement une fenêtre référencée par scene), puis attend l'appui du bouton gauche de la souris, affiche la position de la souris dans le shell de Python, et affiche une sphère de couleur cyan. Un clic de souris est défini par la pression et le relâchement du bouton gauche de la souris sans que celle-ci ne bouge (ou presque), ainsi la sphère apparaît quand vous relâchez le bouton de la souris.

from visual import *
scene.range = 4
box() # display a box for context
while 1:
if scene.mouse.clicked:
m = scene.mouse.getclick()
loc = m.pos
print loc
sphere(pos=loc, radius=0.2, color=color.cyan)

Copiez ce programme dans une fenêtre IDLE et lancez le programme. Cliquez à l'extérieur de la boîte et une sphère de couleur cyan apparaît là où vous cliquez. Si vous cliquez à l'intérieur de la boîte, rien ne semble se passer. Ceci est dû au fait que le clic de a souris se passe dans le plan xy, et la sphère est positionné à l'intérieur de la boîte. Si vous faites pivoter la scène et que vous cliquez ensuite, vous verrez que les sphères iront dans le nouveau plan parallèle à l'écran et passant par scene.center. Si vous souhaitez que toutes les sphères aillent dans le plan xy, perpendiculairement à l'axe z, modifiez la dernière partie du programme comme ceci :

loc = m.project(normal=(0,0,1))
# loc is None if no intersection with plane
if loc:
print loc
sphere(pos=loc, radius=0.2, color=color.cyan)

Retournez ici à la documentation générale sur la souris.

Mouse Drag

Exemple de dragage

Voici une séquence d'évènements souris invoquée en draguant quelque chose :

1) m1.press vaut VRAI si vous pressez le bouton de la souris (celui-ci vaut 'left' si c'est le bouton gauche; n'importe quelle quantité non nulle est considérée comme VRAI en Python) ;

2) m1.drag vaut VRAI si les coordonnées de la souris ont changé depuis le temps de m1.press.

Au moment de l'évènement drag, la position de la souris est rapportée pour être ce qu'elle était à l'instant de l'évènement press, si bien que le dragage peut démarrer au lieu où l'utilisateur à d'abord cliqué. Si la souris est en mouvement au moment de l'évènement press, il est tout à fait possible que la prochaine position vue par l'ordinateur, au moment de l'évènement drag, puisse être non loin de la position du clic. Ceci explique pourquoi la position de l'évènement drag est rapportée comme s’il survenait à la position press ;

3) aucun évènement ne survient pendant le dragage; vous utilisez continuellement scene.mouse.pos pour mettre à jour ce que vous draguez ;

4) m1.drop vaut VRAI si vous relâchez le bouton de la souris.

Vous pouvez programmer le dragage de la souris simplement en lisant continuellement la valeur courante de scene.mouse.pos. Voici une routine complète de dragage d'une sphère avec le bouton gauche appuyé. Copiez ceci dans une fenêtre d'édition et essayez-le !

from visual import *
scene.range = 5 # taille fixée, pas de redimensionnement automatique
ball = sphere(pos=(-3,0,0), color=color.cyan)
cube = box(pos=(+3,0,0), size=(2,2,2), color=color.red)
pick = None # aucun objet de la scène encore sélectionné
while 1:
if scene.mouse.events:
m1 = scene.mouse.getevent() # obtention de l'évènement
if m1.drag and m1.pick == ball: # si ball est touché
drag_pos = m1.pickpos # lieu sur ball
pick = m1.pick # pick vaut True (et non plus None)
elif m1.drop: # relacement à la fin du dragage
pick = None # fin du dragage (None vaut False)
if pick:
# projette sur le plan xy même si la scène a pivoté:
new_pos = scene.mouse.project(normal=(0,0,1))
if new_pos != drag_pos: # si la souris a bougé
# offset d'où la balle a été cliquée:
pick.pos += new_pos - drag_pos
drag_pos = new_pos # mise à jour de la position draguée

Si vous faites de nombreux traitements de chaque mouvement de souris ou que vous laissez une trainée derrière l'objet en mouvement, vous pouvez avoir besoin de vérifier si la "nouvelle" position de la souris est en faite différente de la position précédente avant de traiter le "mouvement", comme c'est le cas dans l'exemple ci-dessus. Par exemple, une trainée dessinée avec l'objet courbe qui contient un nombre très important de points tous à la même position peut ne pas être affichée correctement.

La plupart des objets de VPython peuvent être "sélectionnés" en cliquant dessus. Voici une routine plus générale qui vous permet de draguer soit la hampe soit la pointe d'une flèche. Copiez ceci dans une fenêtre d'édition et essayez-le !

from visual import *
scene.range = 8 # taille fixée, pas de redimensionnement automatique
arr = arrow(pos=(2,0,0),axis=(0,5,0))
by = 0.3 # distance minimale du clic entre la hampe et la pointe
drag = None # n'a pas sélectionné la hampe ou la pointe de la flèche
while 1:
if scene.mouse.events:
m1 = scene.mouse.getevent() # obtention de l'évènement
if m1.press:
if mag(arr.pos-m1.pos) <= by:
drag = 'tail' # proche de la hampe de la flèche
elif mag((arr.pos+arr.axis)-m1.pos) <= by:
drag = 'tip' # proche de la pointe de la flèche
drag_pos = m1.pos # sauvegarde de la position pressée
elif m1.drop: # relâchement à la fin du dragage
drag = None # fin du dragage (None vaut False)
if drag:
new_pos = scene.mouse.pos
if new_pos != drag_pos: # si la souris a bougée
displace = new_pos - drag_pos # longueur du déplacement
drag_pos = new_pos # mise à jour de la position draguée
if drag == 'tail':
arr.pos += displace # déplace la hampe
else:
arr.axis += displace # déplace la pointe

Retournez ici à la documentation générale sur la souris.

Interactions Clavier

Interactions clavier

Si scene.kb.keys est non nul, un ou plusieurs évènements clavier ont été stockés, en attendant d'être traités.

L'exécution de key = scene.kb.getkey() récupère la touche entrée et la supprime de la file d'attente d'entrées. S'il n'y a pas d'évènement dans la file d'attente, getkey() attend jusqu'à ce qu'une touche soit pressée.

Si len(key) == 1, l'entrée est un caractère unique imprimable tel que 'b' ou 'B' ou un retour à la ligne ('\n') ou une tabulation ('\t'). Autrement la clé est une chaîne de caractères telle que 'escape' ou 'backspace' ou 'f3'. Pour de telles entrées, les touches ctrl, alt, et shift sont associées au nom de la clé. Par exemple, si vous maintenez appuyée la touche shift et que vous pressez F3, la clé sera la chaîne de caractères 'shift+f3', que vous pouvez tester explicitement. Si vous maintenez appuyées les trois touches modificatrices, vous obtenez 'ctrl+alt+shift+f3'; l'ordre est toujours ctrl, alt, shift.

Les noms des caractères spéciaux incluent delete, backspace, page up, page down, home, end, left, up, right, down, numlock, scrlock, f1, f2, f3, f4, f5, f6, f7, f8. Windows et Linux a aussi f9, f11, f12, insert.

Voici une routine de test qui vous permet de taper un texte dans un label :

from visual import *
prose = label() # initiallement un texte vide
while 1:
if scene.kb.keys: # y a-t-il un évènement attendant d'être traité ?
s = scene.kb.getkey() # # obtention de l'information clavier
if len(s) == 1:
prose.text += s # ajout du nouveau caractère
elif ((s == 'backspace' or s == 'delete') and
len(prose.text)) > 0:
prose.text = prose.text[:-1] # efface une lettre
elif s == 'shift+delete':
prose.text = '' # efface tout le texte

Notez que les évènements souris fournissent aussi des renseignements sur les touches ctrl, alt et shift, qui peuvent être utilisées pour modifier les actions de la souris.

Contrôles: boutons (button), glissières (slider), interrupteurs à bascule (toggle), et menus déroulants (menu)

Vous pouvez créer des boutons, glissières, interrupteurs à bascule et menus déroulants pour contrôler votre programme. Vous importez ces possibilités avec l'instruction :

from visual.controls import *

L'importation de visual.controls rend disponibles tous les objets Visual ainsi que le module controls. Pour utiliser les caractéristiques des contrôles, créez une fenêtre spéciale pour, les contrôles et ajoutez les contrôles sur cette fenêtre, en spécifiant quelles actions devraient prendre place quand les contrôles sont manipulés. Par exemple, une action associée à un bouton peut être exécutée à partir d'une fonction pour changer la couleur d'un objet Visual. Après avoir créé des contrôles, appelez de nombreuses fois une routine interactive pour vérifier la manipulation de l'utilisateur des contrôles qui déclenchent les actions. Pour un exemple détaillé, regardez le programme de démonstration VPython controlstest.py.

Voici un petit exemple. Ceci change le texte du bouton quand vous cliquez sur celui-ci. La construction Python "lambda:" est nécessaire pour le module controls pour avoir un contexte correct ("espace de nom") pour l'appel de la routine spécifiée.

from visual.controls import *

def change(): # Appelé par controls quand on clique sur le bouton
if b.text == 'Click me':
b.text = 'Try again'
else:
b.text = 'Click me'

c = controls() # Crée une fenêtre pour les contrôles
# Crée un bouton dans la fenêtre des contrôles:
b = button( pos=(0,0), width=60, height=60,
text='Click me', action=lambda: change() )
while 1:
c.interact() # Vérifie les évènements de la souris et déclenche les actions spécifiées.

La fenêtre des contrôles

controls() Crée une fenêtre pour les contrôles avec des attributs spécifiés et la retourne. Par exemple, la suite crée une fenêtre 300 par 300, positionnée à (0,400) en respectant le coin haut gauche de l'écran, avec 'Controlling the Scene' dans la barre de titre et une étendue de 50 (les coordonnées de la fenêtre vont de -50 à +50 en x et y) :

c = controls(title='Controlling the Scene',
x=0, y=400, width=300, height=300, range=50)

Les paramètres de la fenêtre des contrôles :

x, y Position de la fenêtre sur l'écran (pixel en haut à gauche) ;

width, height largeur et hauteur de la zone d'affichage en pixels ;

title texte dans la barre de titre de la fenêtre des contrôles ;

range l'étendue de la région d'intérêt à partir du centre et le long de chaque axe. La valeur par défaut est 100. Le centre de la fenêtre des contrôles est toujours (0,0) ;

display toutes les fenêtres des contrôles ont l'attribut display; sphere(display=c.display) placera une sphère dans la fenêtre des contrôles nommée c.

Les contrôles

Après avoir créé une fenêtre pour les contrôles, vous pouvez créer les contrôles suivants qui apparaîtront dans cette fenêtre :

button un bouton pour cliquer ;

slider réglez une glissière pour entrer graphiquement une valeur numérique ;

toggle cliquez sur le levier pour basculer un interrupteur ;

menu un menu déroulant à options.

Les contrôles ont les attributs suivants :

pos position du contrôle (centre du bouton ou de l'interrupteur, une des extrémités de la glissière, le coin en haut à gauche du titre du menu) ;

color gris par défaut ;

width largeur du bouton, de l'interrupteur ou du menu ;

height hauteur du bouton, de l'interrupteur ou du menu ;

axis axe pour la glissière, pointant de pos à l'autre extrémité (comme pour le cylindre ou la flèche) ;

length longueur de la glissière (dans la direction de l'axe) ;

min, max valeurs minimale et maximale pour une glissière ;

value valeur de l'interrupteur (0 ou 1), de la glissière (dépendant du min et du max spécifiés), ou du menu déroulant (le texte seulement sélectionné dans le menu déroulant). La valeur de l'interrupteur ou de la glissière (mais pas d'un menu déroulant) peut être écrite aussi bien que lue. Si vous définissez la valeur de l'interrupteur ou de la glissière , le contrôle se déplacera à la position qui correspond à cette valeur ;

text texte à afficher sur un bouton ou l'entête en haut d'un menu ;

text0 texte à afficher en dessous d'un interrupteur à bascule (associé à la valeur 0 de l'interrupteur) ;

text1 texte à afficher au-dessus d'un interrupteur à bascule (associé à la valeur 1 de l'interrupteur) ;

action spécifie une commande Python à exécuter lorsqu'un contrôle est manipulé ;

items pour les menus seulement, liste des options à sélectionner. Voici un exemple qui montre comment ajouter une option à un menu nommé m1 :

m1.items.append( ('Red', lambda: cubecolor(color.red)) )

Ceci ajoute au menu déroulant une option 'Red' qui fera passer la valeur color.red à la sous-routine cubecolor(). La construction Python "lambda:" est nécessaire pour le module controls pour avoir un contexte correct ("espace de nom") pour appeler la routine spécifiée.

Lecture et Écriture de fichiers

Le module visual.filedialog contient simplement une boîte de dialogues pour les fichiers.

Voici comment créer une boîte de dialogue de fichiers pour choisir un fichier à lire, et ensuite afficher le contenu. La routine get_file() vous permet de choisir un fichier et retourne un descripteur de fichiers, un pointeur sur le fichier sélectionné (ici, le descripteur de fichiers a été nommé fd). Si vous annulez la boîte de dialogue, get_file() retourne None, ce que vous devriez vérifier (les instructions juste après le "if fd" seront exécutées seulement si fd est différent de None). En utilisant un descripteur de fichiers, vous pouvez lire le fichier en entier comme une unique chaîne de caractères, ou avec readlines(), vous pouvez lire une liste contenant les lignes de textes, chacune finissant avec un caractère de fin de ligne ('\n').

from visual.filedialog import get_file
fd = get_file()
if fd:
data = fd.read() # ou fd.readlines()
fd.close() # ferme le fichier (we're through with it)
print data

Pour choisir un fichier et écrire des données dans le fichier choisi, faites ceci :

from visual.filedialog import save_file
fd = save_file()
if fd:
fd.write("This is a test.\nThis is only a test.")
fd.close() # ferme le fichier (nous en avons terminé avec lui)

Il y a d'autres fonctions pour les descripteurs de fichiers en plus de read(), readlines(), write() et close(); voir la documentation de Python. Par exemple, fd.name() renvoie le nom du fichier associé avec le descripteur du fichier.

Les exemples ci-dessus sont suffisants pour la plupart des tâches, mais vous pouvez personnaliser l'affichage de la boîte de dialogue de fichiers en spécifiant des paramètres pour les fonctions get_file() et save_file(), comme indiqué ici avec leurs valeurs par défaut :

save_file(file_extensions=None, x=100, y=100,
title="Save", mode='w', maxfiles=20)

get_file(file_extensions=None, x=100, y=100,
title="Open", mode='rU', maxfiles=20)

Par exemple, get_file(file_extensions=['.txt.', '.py']) affichera seulement les fichiers se finissant par ces extensions. Le paramètre maxfiles spécifie le nombre maximum de fichiers à montrer sur une page, ce qui détermine la hauteur de l'affichage de la boîte de dialogue de fichiers. Le mode de lecture "universel" de fichiers par défaut est 'rU' qui convertit différentes sortes de marqueurs de fin de lignes pour des fichiers Windows, Mac et Linux au même caractère standard '\n'. Les paramètres x et y spécifient la localisation en pixel du coin en haut à gauche de l'affichage de la boîte de dialogue de fichiers, mesuré depuis le coin en haut à gauche de l'écran de l'ordinateur. Le titre est affiché en haut de la fenêtre.

Calculs vectoriels

Le vecteur (vector)

Le vecteur n'est pas un objet dessinable, mais il est d'une aide puissante pour les calculs 3D. Ses propriétés sont semblables à celles des vecteurs utilisés en science ou en ingénierie. Il peut être utilisé en même temps que les tableaux de Numeric. (Numeric est un module ajouté à Python pour fournir des possibilités de calcul ultrarapide à travers un traitement optimisé des tableaux. Le module Numeric est importé automatiquement par Visual.)

vector(x,y,z)

Retourne un vecteur avec les composantes données qui sont transformées en virgules flottantes (Ainsi, 3 est converti en 3.0).

Les vecteurs peuvent être ajoutés ou soustraits l'un de l'autre, ou multipliés par un nombre ordinaire. Par exemple,

v1 = vector(1,2,3)
v2 = vector(10,20,30)
print v1+v2 # affiche (11 22 33)
print 2*v1 # affiche (2 4 6)

Vous pouvez faire référence à une composante individuelle d'un vecteur :

v2.x vaut 10, v2.y vaut 20, v2.z vaut 30.

Il est permis de créer un vecteur à partir d'un autre: vector(v2) vaut ainsi vector(10,20,30).

La forme vector(10,12) a la même signification que vector(10,12,0).

Un vecteur est une séquence Python, ainsi v2.x est équivalent à v2[0], v2.y est équivalent à v2[1], et v2.z est équivalent à v2[2].

mag( vector ) # calcule la norme du vecteur
mag(vector(1,1,1)) # est égal à racine(3)
mag2(vector(1,1,1)) # est égal à 3, la norme au carré

Vous pouvez aussi obtenir la norme du vecteur avec la forme v2.mag, et le carré de la norme du vecteur avec v2.mag2.

Il est possible de redéfinir la norme ou la norme au carré d'un vecteur :

v2.mag = 5 # définit la norme de v2 à 5
v2.mag2 = 2.7 # définit le carré de la norme de v2 à 2.7

Vous pouvez redéfinir la norme à 1 avec norm() :

norm( vector ) # normalisé; norme de 1
norm(vector(1,1,1)) # vaut vector(1,1,1)/sqrt(3)

Vous pouvez aussi écrire v1.norm(). Pour plus de commodité, norm(vector(0,0,0)) est calculé pour valoir vector(0,0,0).

Pour calculer l'angle entre deux vecteurs (la "différence" des angles des deux vecteurs).

v1.diff_angle(v2)

Vous pouvez aussi écrire v1.diff_angle(v1,v2). Par commodité, si l'un des vecteurs a une norme de 0, la différence des angles est calculée de manière à être égale à zéro.

Il y a une fonction pour le produit vectoriel de deux vecteurs, qui est un vecteur perpendiculaire au plan défini par vector1 et vector2, dans une direction définie par la règle de la main droite: si les doigts de la main droite tournent de vector1 vers vector2, le pouce pointe dans la direction du produit vectoriel. La norme de ce vecteur est égale au produit des normes de vector1 et vector2, multiplié par le sinus des angles entre les deux vecteurs.

cross( vector1, vector2 )

Il y a une fonction pour le calcul du produit scalaire de deux vecteurs qui est un nombre ordinaire égal au produit des normes des vector1 et vector2, multiplié par le cosinus de l'angle entre les deux vecteurs. Si les deux vecteurs sont normés, le produit scalaire retourne le cosinus de l'angle entre les vecteurs, qui est souvent utile.

dot( vector1, vector2 )

Vous pouvez aussi écrire vector1.cross(vector2) ou vector1.dot(vector2)).

Rotation d'un vecteur

Il y a une fonction pour la rotation d'un vecteur :

v2 = rotate(v1, angle=theta, axis=(1,1,1))

L'axe par défaut est (0,0,1), pour une rotation dans le plan xy autour de l'axe z. Il n'y a pas d'origine pour une rotation de vecteur. Vous pouvez aussi écrire v2 = v1.rotate(angle=theta, axis=(1,1,1)). Il y a aussi une possibilité de rotation pour les objets.

Conversion pratique

Par commodité, Visual convertit automatiquement (a,b,c) en vector(a,b,c), avec des valeurs à virgule flottante, lors de la création d'objets Visual: sphere.pos=(1,2,3) est équivalent à sphere.pos=vector(1.,2.,3.). Cependant, utiliser la forme (a,b,c) directement dans des calculs vectoriels entraînera des erreurs, parce (a,b,c) n'est pas un vecteur; écrivez vector(a,b,c) à la place.

Vous pouvez convertir un vecteur vec1 en un tuple Python (a,b,c) avec tuple(vec1) ou avec une option beaucoup plus rapide vec1.as_tuple().

Tracer des graphes, des fonctions ou des données

Tracer des graphes

Dans cette section nous décrivons les caractéristiques pour tracer des graphes avec des marqueurs et étiquettes. Voici un exemple simple qui montre comment tracer un graphe (arange créée un tableau numeric allant de 0 à 8, s'arrêtant avant 8.1) :

from visual.graph import * # importation des fonctions de tracés
funct1 = gcurve(color=color.cyan) # une graphique courbe
for x in arange(0., 8.1, 0.1): # x va de 0 à 8
funct1.plot(pos=(x,5.*cos(2.*x)*exp(-0.2*x))) # plot

Importer visual.graph rend disponibles tous les objets Visual ainsi que le module pour tracer des graphes. Les graphes sont automatiquement redimensionnés pour afficher toutes les données dans la fenêtre.

Une courbe connexe (gcurve) n'est qu'un des nombreux tracés de graphes disponibles. Il y a d'autres options comme des points discontinus (gdots), des barres verticales (gvbars), des barres horizontales (ghbars), et des données rangées dans des casiers affichés comme des barres verticales (ghistogram; voir plus loin dans la discussion). Lors de la création d'un de ces objets, vous pouvez spécifier un attribut de couleur. Pour gvbars et ghbars, vous pouvez spécifier un attribut delta, qui spécifie la largeur de la barre (la valeur par défaut est delta=1.). Pour gdots, vous pouvez spécifier un attribut shape "round" ou "square" (par défault shape="round") et un attribut size, qui spécifie la largeur des points en pixels (par défaut size=5).

Vous pouvez tracer plus d'une chose sur le même graphe :

funct1 = gcurve(color=color.cyan)
funct2 = gvbars(delta=0.05, color=color.blue)
for x in arange(0., 8.1, 0.1):
funct1.plot(pos=(x,5.*cos(2.*x)*exp(-0.2*x))) # courbe
funct2.plot(pos=(x,4.*cos(0.5*x)*exp(-0.1*x))) # vbars

Dans l'opération de traçage, vous pouvez spécifier une couleur différente pour outrepasser le réglage original :

mydots.plot(pos=(x1,y1), color=color.green)

Quand vous créez un objet gcurve, gdots, gvbars, ou ghbars, vous pouvez fournir une liste de points à tracer, comme c'est le cas avec l'objet ordinaire curve :

values = [(1,2), (3,4), (-5,2), (-5,-3)]
data = gdots(pos=values, color=color.blue)

Cette option de liste est disponible seulement lors de la création de l'objet gdots.

Options générales de gdisplay

Vous pouvez établir un gdisplay pour définir la taille, position et le titre de la barre de titre de la fenêtre graphique, spécifier les noms des axes x et y, et spécifier les valeurs maximales pour chaque axe, avant la création d'un objet gcurve ou d'un autre objet de tracés de graphes :

graph1 = gdisplay(x=0, y=0, width=600, height=150,
title='N vs. t', xtitle='t', ytitle='N',
xmax=50., xmin=-20., ymax=5E3, ymin=-2E3,
foreground=color.black, background=color.white)

Dans cet exemple, la fenêtre graphique sera localisée à la position (0,0), avec une taille de 600 pixels par 150 pixels et il y aura 'N vs. t' dans la barre de titre. L'axe horizontal aura le titre 't' et l'axe vertical le titre 'N'. Au lieu d'un redimensionnement automatique du graphe pour afficher toutes les données, le graphe aura des limites fixées. L'axe horizontal s'étendra de -20 à +50, et l'axe vertical s'étendra de -200. à +5000. (xmin et ymin devront être négatifs; xmax et ymax devront être positifs.) La couleur du premier plan (le blanc par défaut) est le noir et la couleur d'arrière-plan (noir par défaut) est le blanc. Si vous exécutez simplement gdisplay(), les valeurs par défaut sont x=0, y=0, width=800, height=400, aucun titre, redimensionnées automatiquement.

Chaque gdisplay possède l'attribut display, si bien que vous pouvez manipuler les aspects basiques d'affichage d'une fenêtre graphique. Les seuls objets que vous pouvez placer dans la fenêtre graphique sont des étiquettes (labels), des courbes (curves), des faces (faces) et des nuages de points (points).

graph1 = gdisplay()
label(display=graph1.display, pos=(3,2), text="P")
graph1.display.visible = 0 # rend l'affichage invisible

Vous pouvez avoir plus d'une fenêtre graphique: créez simplement un autre gdisplay. Par défaut, chaque objet graphique créé selon un gdisplay appartient à cette fenêtre, où vous pouvez spécifier à quelle fenêtre appartient le nouvel objet :

energy = gdots(gdisplay=graph2, color=color.blue)

Histogrammes (données triées rangées dans des casiers)

Le but de ghistogram est de trier des données dans des casiers et d'afficher la distribution. On suppose que vous avez une liste d'âges d'un groupe de personnes, tel que [5, 37, 12, 21, 8, 63, 52, 75, 7]. Vous voulez trier ces données dans des tranches de 20 ans et afficher les nombres de chaque tranche sous la forme de barres verticales. La première tranche (0 à 20) contiendra quatre personnes [5, 12, 8, 7], la deuxième tranche (20 à 40) contiendra deux personnes [21, 37], la troisième tranche (40 à 60) contiendra une personne [52], et la quatrième tranche (60 à 80) contiendra deux personnes [63, 75]. Voici comment vous pourriez faire cet affichage :

from visual.graph import *
.....
agelist1 = [5, 37, 12, 21, 8, 63, 52, 75, 7]
ages = ghistogram(bins=arange(0, 80, 20), color=color.red)
ages.plot(data=agelist1) # affiche la distribution des ages
.....
ages.plot(data=agelist2) # affiche une distribution différente

Vous spécifiez une liste (casiers) dans laquelle les données vont être triées. Dans l'exemple donné ici, les casiers vont de 0 à 80 par tranche de 20. Par défaut, si vous exécutez plus tard

ages.plot(data=agelist2)

la nouvelle distribution remplace l'ancienne. D'un autre côté, si vous exécutez

ages.plot(data=agelist2, accumulate=1)

les nouvelles données seront ajoutées aux anciennes.

Si vous exécutez la suite,

ghistogram(bins=arange(0,50,0.1), accumulate=1, average=1)

chaque opération accumulera les données et calculera la moyenne des données accumulées. Par défaut, il n'y a aucune accumulation et aucun calcul de la moyenne.

gdisplay contre display

Une fenêtre gdisplay est étroitement liée à une fenêtre display. La principale différence est qu'un gdisplay est essentiellement bidimensionnel et a des facteurs d'échelle en x et y non uniformes. Lorsque vous créez un gdisplay (explicitement ou implicitement avec l'objet gcurve ou un autre objet graphique), l'affichage courant est sauvé et restauré, si bien que la création plus loin d'un objet ordinaire Visual tel que la sphère ou la boîte sera correctement associée avec le précédent affichage, et non plus avec le récent gdisplay.

Les fonctions factorielle (factorial) et combinaison (combin)

Les fonctions factorielle (factorial) et combinaison (combin)

from visual import *
from visual.factorial import * # import after visual
print factorial(4) # gives 24
print combin(10,2) # gives 45

Remarque: Pour éviter de confondre avec le module nommé "factorial" et la fonction appelée "factorial", importez le module factorial après avoir importé le module visual module lui-même.

La fonction factorielle factorial(N) vaut N!; 4! vaut (4)(3)(2)(1) = 24, et 0! vaut 1.
La fonction combinaison est combin(a,b) = a!/(b!*(a-b)!).

Une utilisation courante de ces fonctions est le calcul du nombre de façons d'arranger un groupe d'objets. Par exemple, s'il y a 5 boules numérotées dans un sac, il y a factorial(5) = 5! = 5*4*3*2*1 = 120 façons de les sortir séquentiellement du sac (5 possibilités pour la première boule, 4 pour la suivante et ainsi de suite).

Si par contre les cinq boules ne sont pas numérotées, mais deux sont vertes et trois rouges, de 120 façons de choisir les boules, on passe à 2! façons indiscernables d'arranger les boules vertes et 3! façons d'arranger les boules rouges, ainsi le nombre d'arrangements différents de boules est égal à combin(5,2) = 5!/(3!*2!) = 10.

Logiquement, la fonction combin (combinaison) est simplement une combinaison de fonctions factorial (factorielles). Cependant, la simplification dans le numérateur et le dénominateur rend possible d'évaluer la fonction combin pour des valeurs avec lesquelles on obtiendrait un dépassement de capacité pour la fonction factorial à cause de la taille limitée des nombres flottants. Par exemple, combin(5,2) = 5!/(3!*2!) = (5*4)/2 = 10, et nous n'avons pas à calculer 5! du tout.

Licence

The Visual library is Copyright (c) 2000 by David Scherer.

All Rights Reserved

Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of David Scherer not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission.

DAVID SCHERER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DAVID SCHERER BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

The following notice applies to the CXX library, which is linked into cvisual.dll:

*** Legal Notice for all LLNL-contributed files ***

Copyright (c) 1996. The Regents of the University of California. All rights reserved.

Permission to use, copy, modify, and distribute this software for any purpose without fee is hereby granted, provided that this entire notice is included in all copies of any software which is or includes a copy or modification of this software and in all copies of the supporting documentation for such software.

This work was produced at the University of California, Lawrence Livermore National Laboratory under contract no. W-7405-ENG-48 between the U.S. Department of Energy and The Regents of the University of California for the operation of UC LLNL.

DISCLAIMER
This software was prepared as an account of work sponsored by an agency of the United States Government. Neither the United States Government nor the University of California nor any of their employees, makes any warranty, express or implied, or assumes any liability or responsibility for the accuracy, completeness, or usefulness of any information, apparatus, product, or process disclosed, or represents that its use would not infringe privately-owned rights. Reference herein to any specific commercial products, process, or service by trade name, trademark, manufacturer, or otherwise, does not necessarily constitute or imply its endorsement, recommendation, or favoring by the United States Government or the University of California. The views and opinions of authors expressed herein do not necessarily state or reflect those of the United States Government or the University of California, and shall not be used for advertising or product endorsement purposes.