Exploration module Python ti_graphics TI-83 Premium CE 5.5
Posted: 04 May 2020, 10:58
Dans sa prochaine mise à jour 5.5 gratuite prévue pour Mai 2020, Texas Instruments va rajouter de formidables possibilités à ta TI-83 Premium CE :
Cette dernière application apporte de nouveaux modules importables pour tes scripts Python :
- mise à jour en 5.5 de l'application SciTools
- mise à jour en 5.5 de l'application Periodic
- mise à jour en 5.5 de l'application Python (TI-83 Premium CE Édition Python uniquement)
Cette dernière application apporte de nouveaux modules importables pour tes scripts Python :
- time, certes déjà présent mais maintenant listé au menu et donc officiel; il ne risque plus de disparaitre
- ti_system, avec diverses possibilités :
- détection des simples pressions de touches clavier (sans validation donc) par l'utilisateur, avec même l'éventuel modificateur actif (
2nde
oualpha
), et ça marche aussi avec un clavier USB ! - affichage dans la console à la ligne que tu veux
- exportation de listes de nombres (entiers, flottants ou complexes) existant dans le contexte Python vers l'environnement de la calculatrice, pour traitement à l'aide d'autres applications
- importation depuis le contexte Python de listes ou équation de régression existant dans l'environnement de la calculatrice
- et donc plus généralement un début d'intégration du Python à l'environnement mathématique de la calculatrice, enfin l'application Python va pouvoir servir non plus seulement à coder un truc déconnecté dans un coin, mais à traiter des problèmes et tâches complexes dans leur globalité !
- détection des simples pressions de touches clavier (sans validation donc) par l'utilisateur, avec même l'éventuel modificateur actif (
- ti_plotlib, une bibliothèque graphique pour tracer dans un repère, conformément aux programmes de Physique-Chimie, SNT et NSI, tout en permettant également nombre d'applications en Mathématiques !
- ti_hub, pour les projets d'objects connectés à l'aide de l'interface TI-Innovator Hub
- ti_rover, pour les projets de robotique à l'aide du TI-Innovator Rover
- ainsi qu'un mystérieux ti_graphics pour sa part non listé au menu, mais justement utilisé par ti_plotlib
Sommaire :
1) exploration ti_graphics
Go to topti_graphics n'étant pas listée et étant donc non documentée, commençons donc par en explorer le contenu secret à l'aide du script suivant :
Pas mal de choses a première vue, nous découvrons déjà 30 éléments accessibles rien qu'au premier niveau, et jusqu'à 45 en comptant les sous-éléments.
Une première lecture des noms de différentes fonctions, comme getPixel() et setPixel() nous permet de deviner de quoi il s'agit.
ti_graphics est un module Python permettant de dessiner sur l'écran de ta TI-83 Premium CE Edition Python, non pas en donnant des coordonnées approximatives dans un repère mais en accédant directement les pixels de l'écran !
Pour te donner un point de repère, nous pouvons donc a priori le rapprocher des modules casioplot sur Casio Graph 90/35+E II ou kandinsky sur NumWorks.
Nous allons bien évidemment te tester et documenter tout ça sans tarder, mais en attendant cela nous permet déjà de mettre à jour notre petit classement des Pythonettes :
Classement en terme d'éventail de modules :
Classement en terme de richesse des modules :
Classement en terme d'éventail de modules :
Classement en terme de richesse des modules :
- Code: Select all
def getplatform():
id=-1
try:
import sys
try:
if sys.platform=='nspire':id=0
if sys.platform.startswith('TI-Python') or sys.platform=='Atmel SAMD21':id=4
except:id=3
except:
try:
import kandinsky
id=1
except:
try:
if chr(256)==chr(0):id=5+(not ("HP" in version()))
except:
id=2
return id
platform=getplatform()
#lines shown on screen
#plines=[29,12, 7, 9,11,0,0]
plines=[29,16, 7, 9,11,0,0]
#max chars per line
#(error or CR if exceeded)
pcols =[53,99,509,32,32,0,0]
nlines=plines[platform]
ncols=pcols[platform]
curline=0
def mprint(*ls):
global curline
st=""
for s in ls:
if not(isinstance(s,str)):
s=str(s)
st=st+s
stlines=1+int(len(st)/ncols)
if curline+stlines>=nlines:
input("Input to continue:")
curline=0
print(st)
curline+=stlines
def sstr(obj):
try:
s=obj.__name__
except:
s=str(obj)
a=s.find("'")
b=s.rfind("'")
if a>=0 and b!=a:
s=s[a+1:b]
return s
def isExplorable(obj):
s=str(obj)
return s.startswith("<") and s.find(" ")>=0 and not s.startswith("<module")
def explmod(pitm,pitmsl=[],reset=True):
global curline
if(reset):
curline=0
pitmsl=[sstr(pitm)]
hd="."*(len(pitmsl)-1)
spath=".".join(pitmsl)
c,c2=0,0
spitm=str(pitm)
for itms in sorted(dir(pitm)):
c,c2=c+1,c2+1
try:
itm=eval(spath+"."+itms)
mprint(hd+itms+"="+str(itm))
if isExplorable(itm) and itm!=pitm:
pitmsl2=pitmsl.copy()
pitmsl2.append(itms)
c2=c2+explmod(itm,pitmsl2,False)[1]
except:
mprint(hd+itms)
if c>0 and reset:
mprint(hd+"Total: "+str(c)+" 1st level item(s)")
if c2>0 and c2!=c:
mprint(hd+" "+str(c2)+" item(s)")
return [c,c2]
Pas mal de choses a première vue, nous découvrons déjà 30 éléments accessibles rien qu'au premier niveau, et jusqu'à 45 en comptant les sous-éléments.
Une première lecture des noms de différentes fonctions, comme getPixel() et setPixel() nous permet de deviner de quoi il s'agit.
ti_graphics est un module Python permettant de dessiner sur l'écran de ta TI-83 Premium CE Edition Python, non pas en donnant des coordonnées approximatives dans un repère mais en accédant directement les pixels de l'écran !
Pour te donner un point de repère, nous pouvons donc a priori le rapprocher des modules casioplot sur Casio Graph 90/35+E II ou kandinsky sur NumWorks.
Nous allons bien évidemment te tester et documenter tout ça sans tarder, mais en attendant cela nous permet déjà de mettre à jour notre petit classement des Pythonettes :
Casio Graph 35+E II 90+E | NumWorks | TI-83PCE Ed. Python | ||
builtins array collections cmath gc math matplotlib matplotlib.pyplot micropython os random sys time turtle uerrno | 84-175 . . . . 25 . . . . 8 . . . . | 97-440 3-13 . 13-17 9-13 42-46 . . 10-14 . . 17-63 . . 25-29 | 88-188 . . 12 . 41 3 11 6 . 9 . 3 38 . | 92-189 2-4 2 . 7 28 . . . . 8 15-42 4 . . |
spécifique | casioplot:6 | prime:3-7 | ion:48 kandinsky:6 | ti_graphics:30-45 ti_hub:? ti_plotlib:49-56 ti_system:12 ti_rover:? |
Modules | 4 | 9 | 11 | 13 |
Eléments | 123-214 | 219-642 | 265-365 | 249-397 |
Classement en terme d'éventail de modules :
- 13 modules : TI-83 Premium CE Edition Python
- 11 modules : NumWorks
- 9 modules : HP Prime (version alpha)
- 4 modules : Casio Graph 90+E / 35+E II
Classement en terme de richesse des modules :
- 219-642 éléments : HP Prime (version alpha)
- 249-397 éléments : TI-83 Premium CE Edition Python
- 265-365 éléments : NumWorks
- 123-214 éléments : Casio Graph 90+E / 35+E II
Casio Graph 35+E II 90+E | CasioPython Casio Graph 35+E II 35+E/USB 75/85/95 | MicroPython TI-Nspire | TI-Python | ||
builtins array collections cmath gc math matplotlib matplotlib.pyplot micropython os random sys time turtle uerrno | 84-175 . . . . 25 . . . . 8 . . 69 . | 91-204 2-4 . 12 7 41 . . 6 . 8 12 . . 24 | 93-218 2-4 . 12 7 41 . . 3 . . 15-45 . . . | 92-189 2-4 2 . 7 28 . . . . 8 15-42 4 . . | 93-191 2-4 2 12 7 41 . . 6 15 8 15-45 8-10 . . |
spécifique | casioplot:6 matplotl:25 | nsp:3-10 | board:22 storage:7-21 | ||
Modules | 6 | 9 | 8 | 9 | 13 |
Eléments | 217-308 | 203-318 | 176-340 | 158-284 | 238-384 |
Classement en terme d'éventail de modules :
- 13 modules : TI-83 Premium CE + TI-Python (firmware tiers)
TI-83 Premium CE Edition Python - 11 modules : NumWorks
- 9 modules : HP Prime (version alpha) + Casio Graph 75/85/95 / 35+E/USB / 35+E II / fx-9750GII/GIII / fx-9860G/GII/GIII (appli CasioPython)
- 8 modules : TI-Nspire (appli MicroPython) + TI-83 Premium CE + TI-Python
- 6 modules : Casio Graph 90+E / 35+E II / fx-CG50 / fx-9750/9860GIII
Classement en terme de richesse des modules :
- 219-642 éléments : HP Prime (version alpha)
- 249-397 éléments : TI-83 Premium CE Edition Python
- 265-365 éléments : NumWorks
- 238-384 éléments : TI-83 Premium CE + TI-Python (firmware tiers)
- 217-308 éléments : Casio Graph 90+E / 35+E II / fx-CG50 / fx-9750/9860GIII
- 203-318 éléments : Casio Graph 75/85/95 / 35+E/USB / 35+E II / fx-9750GII/GIII / fx-9860G/GII/GIII (appli CasioPython)
- 176-340 éléments : TI-Nspire (appli MicroPython)
- 158-284 éléments : TI-83 Premium CE + TI-Python
2) zone graphique contrôlable
Go to topExplorons maintenant notre environnement graphique. Pour cela nous allons utiliser quelques premières fonctions élémentaires, commençons déjà par en préciser les spécifications :
Petite astuce pour la détecter automatiquement sans intervention humaine, on peut remarquer que getPixel() renvoie (0,0,0) lorsque l'on interroge un pixel hors écran.
Un simple boucle de tests suffit alors, avec un éventuel changement de couleur préalable pour les quelques pixels de l'écran qui seraient déjà noirs.
Mettons à jours notre classe de compatibilité écrans polyscr en ce sens :
Appelons ensuite le code suivant pour obtenir la réponse :
Mais c'est fantastique, nous bénéficierions donc apparemment un contrôle plein écran 320×240 pixels !
Sauf que... non, fausse joie.
On se rend vite compte que même si Texas Instruments nous autorise contrairement à la concurrence à lire tous les pixels de l'écran, ceux utilisés pour l'affichage de la barre d'état en haut d'écran ne peuvent apparemment pas être réécrits :
Complétons donc l'initialisation de notre classe polyscr avec une boucle de tests supplémentaire pour gérer ce cas particulier :
Appelons enfin le code suivant pour obtenir toutes les informations écran :
Voilà, nous bénéficions en réalité d'un accès total à seulement 320×210 pixels, les écritures sur les 30 premières lignes de l'écran étant ignorées.
A noter que l'origine restant tout en haut à gauche de l'écran, les valeurs de paramètres y à utiliser pour tes scripts adressant les pixels démarreront obligatoirement à 30.
Puisque notre classe polyscr cible la compatibilité, profitons-en pour comparer avec les modèles concurrents :
Dans la version alpha qui a fuité pour HP Prime avec l'application Python, il y a bien une fonction
Mais à la différence, rien pour tester l'état d'un pixel.
Procédons donc autrement en tentant de tracer un rectangle aussi grand que possible à l'aide du code suivant :
L'appel
D'où le classement en terme de zones graphiques dédiées au Python :
getPixel(x, y)
setPixel(x, y, c)
Petite astuce pour la détecter automatiquement sans intervention humaine, on peut remarquer que getPixel() renvoie (0,0,0) lorsque l'on interroge un pixel hors écran.
Un simple boucle de tests suffit alors, avec un éventuel changement de couleur préalable pour les quelques pixels de l'écran qui seraient déjà noirs.
Mettons à jours notre classe de compatibilité écrans polyscr en ce sens :
- Code: Select all
class polyscr:
w, h = 0, 0
# get_pixel(x, y)
# set_pixel(x, y, color(r8, g8, b8))
show_screen = lambda self: None
need_show_screen = False
# color mode :
# 0: (R8, G8, B8)
# 1: int RGB-565
color_mode = 0
def color(self, r, g=0, b=0):
if isinstance(r, tuple) or isinstance(r,list):
r, g, b = r[0], r[1], r[2]
return self.color_mode == 0 and (r,g,b) or r<<11 | g<<5 | b
def __init__(self):
try: # TI-Nspire Ndless
from nsp import Texture as myscr
self.w, self.h = 320, 240
myscr = myscr(self.w, self.h, None)
self.get_pixel = myscr.getPx
self.set_pixel = myscr.setPx
self.show_screen = myscr.display
self.need_show_screen = True
self.color_mode = 1
except:
try: # TI-83/84 CE
import ti_graphics as myscr
self.get_pixel = myscr.getPixel
self.set_pixel = myscr.setPixel
except ImportError:
try: # Casio USB Power Graphic 3
import casioplot as myscr
self.show_screen = myscr.show_screen
self.need_show_screen = True
except ImportError: # NumWorks
import kandinsky as myscr
self.get_pixel = myscr.get_pixel
self.set_pixel = myscr.set_pixel
# detect readable pixel array
if self.w <= 0:
def _can_get_pixel(x, y):
c = self.get_pixel(x, y)
if c == self.color(0, 0, 0):
self.set_pixel(x, y, self.color(255,0,0))
c = self.get_pixel(x, y)
return c is not None and c != self.color(0, 0, 0)
self.w, self.h, dw, dh = 0, 0, 1, 1
while dw or dh:
if not _can_get_pixel(self.w - (dw == 0),self.h - (dh == 0)):
if _can_get_pixel(self.w,self.h-1): dh = 0
elif _can_get_pixel(self.w-1,self.h): dw = 0
else: dw, dh = 0, 0
self.w += dw; self.h += dh
Appelons ensuite le code suivant pour obtenir la réponse :
- Code: Select all
scr = polyscr()
print('can get {}x{} pixels at (0,0)'.format(scr.w, scr.h))
Mais c'est fantastique, nous bénéficierions donc apparemment un contrôle plein écran 320×240 pixels !
Sauf que... non, fausse joie.
On se rend vite compte que même si Texas Instruments nous autorise contrairement à la concurrence à lire tous les pixels de l'écran, ceux utilisés pour l'affichage de la barre d'état en haut d'écran ne peuvent apparemment pas être réécrits :
- Code: Select all
from ti_system import *
import ti_graphics as scr
for k in range(240):
sct.setPixel(k, k, (0, 0, 0))
disp_wait()
Complétons donc l'initialisation de notre classe polyscr avec une boucle de tests supplémentaire pour gérer ce cas particulier :
- Code: Select all
class polyscr:
w, h, w0, h0, x0, y0 = 0, 0, 0, 0, 0, 0
# get_pixel(x, y)
# set_pixel(x, y, color(r8, g8, b8))
show_screen = lambda self: None
need_show_screen = False
# color mode :
# 0: (R8, G8, B8)
# 1: int RGB-565
color_mode = 0
def color(self, r, g=0, b=0):
if isinstance(r, tuple) or isinstance(r,list):
r, g, b = r[0], r[1], r[2]
return self.color_mode == 0 and (r,g,b) or r<<11 | g<<5 | b
def __init__(self):
try: # TI-Nspire Ndless
from nsp import Texture as myscr
self.w, self.h = 320, 240
myscr = myscr(self.w, self.h, None)
self.get_pixel = myscr.getPx
self.set_pixel = myscr.setPx
self.show_screen = myscr.display
self.need_show_screen = True
self.color_mode = 1
except:
try: # TI-83/84 CE
import ti_graphics as myscr
self.get_pixel = myscr.getPixel
self.set_pixel = myscr.setPixel
except ImportError:
try: # Casio USB Power Graphic 3
import casioplot as myscr
self.show_screen = myscr.show_screen
self.need_show_screen = True
except ImportError: # NumWorks
import kandinsky as myscr
self.get_pixel = myscr.get_pixel
self.set_pixel = myscr.set_pixel
# detect readable pixel array
if self.w <= 0:
def _can_get_pixel(x, y):
c = self.get_pixel(x, y)
if c == self.color(0, 0, 0):
self.set_pixel(x, y, self.color(255,0,0))
c = self.get_pixel(x, y)
return c is not None and c != self.color(0, 0, 0)
self.w, self.h, dw, dh = 0, 0, 1, 1
while dw or dh:
if not _can_get_pixel(self.w - (dw == 0),self.h - (dh == 0)):
if _can_get_pixel(self.w,self.h-1): dh = 0
elif _can_get_pixel(self.w-1,self.h): dw = 0
else: dw, dh = 0, 0
self.w += dw; self.h += dh
# detect writable pixel array
# remove top status bar
def _can_set_pixel(x, y):
def _invert_color(r, g=0, b=0):
if isinstance(r, tuple) or isinstance(r,list):
r, g, b = r[0], r[1], r[2]
return self.color(~r & 0xFF, ~g & 0xFF, ~b & 0xFF)
c = self.get_pixel(x, y)
self.set_pixel(x, y, _invert_color(c))
return c != self.get_pixel(x, y)
self.w0, self.h0 = self.w, self.h
while not _can_set_pixel(0, self.y0):
self.y0 += 1; self.h0 -= 1
Appelons enfin le code suivant pour obtenir toutes les informations écran :
- Code: Select all
scr = polyscr()
print('can get {}x{} pixels at (0,0)'.format(scr.w, scr.h))
print('can set {}x{} pixels at ({},{})'.format(scr.w0, scr.h0, scr.x0, scr.y0))
Voilà, nous bénéficions en réalité d'un accès total à seulement 320×210 pixels, les écritures sur les 30 premières lignes de l'écran étant ignorées.
A noter que l'origine restant tout en haut à gauche de l'écran, les valeurs de paramètres y à utiliser pour tes scripts adressant les pixels démarreront obligatoirement à 30.
Puisque notre classe polyscr cible la compatibilité, profitons-en pour comparer avec les modèles concurrents :
Dans la version alpha qui a fuité pour HP Prime avec l'application Python, il y a bien une fonction
prime.pixon(x, y, c)
pour allumer les pixels.Mais à la différence, rien pour tester l'état d'un pixel.
Procédons donc autrement en tentant de tracer un rectangle aussi grand que possible à l'aide du code suivant :
- Code: Select all
import prime as scr
def rect(x, y, w, h, c=(0,0,0)):
for k in range(w):
scr.pixon(x+k, y, c)
scr.pixon(x+k, y+h-1, c)
for k in range(h):
scr.pixon(x, y+k, c)
scr.pixon(x+w-1, y+k, c)
L'appel
rect(0, 0, 320, 240, 255<<16)
nous affiche bien un rectangle au complet et nous confirme donc que nous contrôlons ici la totalité des 320×240 pixels de l'écran.D'où le classement en terme de zones graphiques dédiées au Python :
- 320×240 = 76800 pixels : HP Prime (version alpha)
- 384×192 = 73728 pixels : Casio Graph 90+E
- 320×222 = 71040 pixels : NumWorks
- 320×210 = 67200 pixels : TI-83 Premium CE Edition Python
- 128×64 = 8192 pixels : Casio Graph 35+E II
- 320×240 = 76800 pixels : HP Prime (version alpha) + TI-Nspire (appli MicroPython)
- 384×192 = 73728 pixels : Casio Graph 90+E / fx-CG50
- 320×222 = 71040 pixels : NumWorks
- 320×210 = 67200 pixels : TI-83 Premium CE Edition Python
- 128×64 = 8192 pixels : Casio Graph 35+E II / fx-9750/9860GIII
3) profondeur de couleurs
Go to topComme vu plus haut avec les fonctions getPixel() et setPixel() et comme l'on peut encore le remarquer à quelques couleurs remarquables définies dans ti_graphics, les couleurs sont spécifiées en coordonnées RGB-888 (Rouge, Green/Vert, Bleu, avec 8 bits par canal autorisant donc des entiers de 0 à 28-1=255).
Mais couleurs spécifiées et affichées sont deux choses différentes. Pour mieux t'illustrer les possibilités Python de ton écran graphique en terme de couleurs, nous allons t'afficher un dégradé avec toutes les couleurs et tous les éclairages.
Pour cela nous travaillerons en coordonnées HSV/TSV (Hue/teinte, Saturation, Valeur), bien plus naturelles et donc intuitives pour l'oeil humain que les coordonnées RGB :
Bricolons-nous donc quelques petites fonctions pour ça :
L'appel suivant nous produit alors l'affichage ci-contre :
Fantastique, non ? Quand tu penses que dans le langage TI-Basic historique tu n'avais droit qu'à 15 couleurs, mais comment as-tu pu survivre avec ça ?
Déjà pour information, on peut mesurer précisément le temps d'affichage à l'aide du script suivant. L'appel
Or, remarquons un petit truc fort intéressant, une exclusivité à ce jour par rapport à la concurrence. Le module ti_graphics fournit d'origine une fonction de conversion de coordonnées HSV en coordonnées RGB, hsv_to_rgb(h, s, v).
Ce qui veut dire que tu n'as pas à t'embêter à la coder et peux donc ainsi économiser de la mémoire, et qu'elle est peut-être déjà optimisée.
Empressons-nous de tester. Modifions déjà notre bibliothèque de compatibilité pour permettre l'accès à ce genre de fonction spécifique :
Modifions maintenant le script de tracer du dégradé :
Ce n'est pas la révolution mais c'est quand même significatif, l'appel
Bon, revenons-en enfin à cet affichage de dégradé. Si tu regardes bien, tu remarqueras que les lignes tirant sur le vert donnent 2 fois plus de teintes intermédiaires et donc un dégradé bien plus continu, bien moins saccadé.
C'est-à-dire que même si les coordonnées sont spécifiées en RGB-888, le matériel utilise pour sa part du RGB-565 :
Passons maintenant à la HP Prime. La version alpha avec Python publiée par erreur n'étant pas très stable, nous utiliserons un code dédié mais équivalent :
On pourrait croire à la capture d'écran ci-contre présentant des saccades régulières dans l'ensemble des teintes que l'on aurait affaire à du RGB-666, ce qui n'est pas très logique.
En réalité, c'est le protocole utilisé pour les captures d'écran qui fait perdre des informations couleur, et il faut donc se référer à la photo ci-contre.
Sur la photo donc aucune saccade mais un dégradé des plus lisses, c'est ici du RGB-888 :
Ici encore, il serait bien de pouvoir détecter cela automatiquement sans intervention humaine.
Et bien c'est possible si on se rend compte que les valeurs effectivement réglées pour les pixels diffèrent parfois de celles spécifiées.
Modifions encore une fois notre classe polyscr avec un test de ces différences :
Appelons enfin le code suivant pour obtenir l'intégralité des informations écran, et les comparer aux solutions concurrentes :
Voilà, nous obtenons bien comme prévu du RGB565 pour le format utilisé en interne pour les pixels
Testons également la concurrence en lançant le même code :
Au classement selon les meilleurs rendus de couleurs, nous avons donc :
Mais couleurs spécifiées et affichées sont deux choses différentes. Pour mieux t'illustrer les possibilités Python de ton écran graphique en terme de couleurs, nous allons t'afficher un dégradé avec toutes les couleurs et tous les éclairages.
Pour cela nous travaillerons en coordonnées HSV/TSV (Hue/teinte, Saturation, Valeur), bien plus naturelles et donc intuitives pour l'oeil humain que les coordonnées RGB :
- teinte qui sera ici codée par un nombre flottant de 0 à 2 est en gros ce que tu appelles naturellement couleur.
- saturation, un flottant de 0 à 1 indique de façon inverse la quantité de blanc.
- valeur, ici encore un flottant de 0 à 1 indique de façon inverse la quantité de noir.
Bricolons-nous donc quelques petites fonctions pour ça :
- Code: Select all
from polyscr import *
scr = polyscr()
def hsv2c(h,s,v):
c=v*s
x,m,k=c*(1-abs((h%(2/3))*3-1)),v-c,(h*3)//1
return (round(255*(m+x*(k%3==1)+c*(k%5==0))),round(255*(m+c*(k==1 or k==2)+x*(k%3==0))),round(255*(m+x*(k%3==2)+c*(k==3 or k==4))))
def grad(x,y,w,h):
for i in range(w):
for j in range(h):
c=hsv2c(2*j/(h-1),i>=w//2 and 1 or i/(w//2-1),i<w//2 and 1 or (w-1-i)/((w-w//2)-1))
scr.set_pixel(x+i,y+j,c)
L'appel suivant nous produit alors l'affichage ci-contre :
- Code: Select all
grad(scr.x0, scr.y0, scr.w0, scr.h0)
Fantastique, non ? Quand tu penses que dans le langage TI-Basic historique tu n'avais droit qu'à 15 couleurs, mais comment as-tu pu survivre avec ça ?
Déjà pour information, on peut mesurer précisément le temps d'affichage à l'aide du script suivant. L'appel
timer(grad, scr.x0, scr.y0, scr.w0, scr.h0)
nous renvoie alors 25min 24,283s.- Code: Select all
from time import monotonic
def timer(f, *par):
start=monotonic()
f(*par)
return monotonic()-start
Or, remarquons un petit truc fort intéressant, une exclusivité à ce jour par rapport à la concurrence. Le module ti_graphics fournit d'origine une fonction de conversion de coordonnées HSV en coordonnées RGB, hsv_to_rgb(h, s, v).
Ce qui veut dire que tu n'as pas à t'embêter à la coder et peux donc ainsi économiser de la mémoire, et qu'elle est peut-être déjà optimisée.
Empressons-nous de tester. Modifions déjà notre bibliothèque de compatibilité pour permettre l'accès à ce genre de fonction spécifique :
- Code: Select all
class polyscr:
w, h, w0, h0, x0, y0 = 0, 0, 0, 0, 0, 0
myscr = None
# get_pixel(x, y)
# set_pixel(x, y, color(r8, g8, b8))
show_screen = lambda self: None
need_show_screen = False
# color mode :
# 0: (R8, G8, B8)
# 1: int RGB-565
color_mode = 0
def color(self, r, g=0, b=0):
if isinstance(r, tuple) or isinstance(r,list):
r, g, b = r[0], r[1], r[2]
return self.color_mode == 0 and (r,g,b) or r<<11 | g<<5 | b
def __init__(self):
try: # TI-Nspire Ndless
from nsp import Texture as myscr
self.w, self.h = 320, 240
myscr = myscr(self.w, self.h, None)
self.get_pixel = myscr.getPx
self.set_pixel = myscr.setPx
self.show_screen = myscr.display
self.need_show_screen = True
self.color_mode = 1
except:
try: # TI-83/84 CE
import ti_graphics as myscr
self.get_pixel = myscr.getPixel
self.set_pixel = myscr.setPixel
except ImportError:
try: # Casio USB Power Graphic 3
import casioplot as myscr
self.show_screen = myscr.show_screen
self.need_show_screen = True
except ImportError: # NumWorks
import kandinsky as myscr
self.get_pixel = myscr.get_pixel
self.set_pixel = myscr.set_pixel
self.myscr = myscr
# detect readable pixel array
if self.w <= 0:
def _can_get_pixel(x, y):
c = self.get_pixel(x, y)
if c == self.color(0, 0, 0):
self.set_pixel(x, y, self.color(255,0,0))
c = self.get_pixel(x, y)
return c is not None and c != self.color(0, 0, 0)
self.w, self.h, dw, dh = 0, 0, 1, 1
while dw or dh:
if not _can_get_pixel(self.w - (dw == 0),self.h - (dh == 0)):
if _can_get_pixel(self.w,self.h-1): dh = 0
elif _can_get_pixel(self.w-1,self.h): dw = 0
else: dw, dh = 0, 0
self.w += dw; self.h += dh
# detect writable pixel array
# remove top status bar
def _can_set_pixel(x, y):
def _invert_color(r, g=0, b=0):
if isinstance(r, tuple) or isinstance(r,list):
r, g, b = r[0], r[1], r[2]
return self.color(~r & 0xFF, ~g & 0xFF, ~b & 0xFF)
c = self.get_pixel(x, y)
self.set_pixel(x, y, _invert_color(c))
return c != self.get_pixel(x, y)
self.w0, self.h0 = self.w, self.h
while not _can_set_pixel(0, self.y0):
self.y0 += 1; self.h0 -= 1
Modifions maintenant le script de tracer du dégradé :
- Code: Select all
from polyscr import *
scr = polyscr()
def grad(x,y,w,h):
for i in range(w):
for j in range(h):
c=scr.myscr.hsv_to_rgb(360*j/(h-1),i>=w//2 and 1 or i/(w//2-1),i<w//2 and 1 or (w-1-i)/((w-w//2)-1))
scr.set_pixel(x+i,y+j,c)
Ce n'est pas la révolution mais c'est quand même significatif, l'appel
timer(grad, scr.x0, scr.y0, scr.w0, scr.h0)
ne mesure plus que 24min 33,282s. On gagne 1 minute, soit environ 4%. Bon, revenons-en enfin à cet affichage de dégradé. Si tu regardes bien, tu remarqueras que les lignes tirant sur le vert donnent 2 fois plus de teintes intermédiaires et donc un dégradé bien plus continu, bien moins saccadé.
C'est-à-dire que même si les coordonnées sont spécifiées en RGB-888, le matériel utilise pour sa part du RGB-565 :
- 25=32 teintes de rouge
- 26=64 teintes de vert
- 25=32 teintes de bleu
Passons maintenant à la HP Prime. La version alpha avec Python publiée par erreur n'étant pas très stable, nous utiliserons un code dédié mais équivalent :
- Code: Select all
import prime as scr
def grad(x,y,w,h):
for i in range(w):
for j in range(h):
_h = 2*j/(h-1)
_s = i>=w//2 and 1 or i/(w//2-1)
_v = i<w//2 and 1 or (w-1-i)/((w-w//2)-1)
_c=_v*_s
_x,_m,_k=_c*(1-abs((_h%(2/3))*3-1)),_v-_c,(_h*3)//1
scr.pixon(x+i,y+j,round(255*(_m+_x*(_k%3==1)+_c*(_k%5==0)))*2**16 + round(255*(_m+_c*(_k==1 or _k==2)+_x*(_k%3==0)))*2**8 + round(255*(_m+_x*(_k%3==2)+_c*(_k==3 or _k==4))))
On pourrait croire à la capture d'écran ci-contre présentant des saccades régulières dans l'ensemble des teintes que l'on aurait affaire à du RGB-666, ce qui n'est pas très logique.
En réalité, c'est le protocole utilisé pour les captures d'écran qui fait perdre des informations couleur, et il faut donc se référer à la photo ci-contre.
Sur la photo donc aucune saccade mais un dégradé des plus lisses, c'est ici du RGB-888 :
- 28=256 teintes de rouge
- 28=256 teintes de vert
- 28=256 teintes de bleu
Ici encore, il serait bien de pouvoir détecter cela automatiquement sans intervention humaine.
Et bien c'est possible si on se rend compte que les valeurs effectivement réglées pour les pixels diffèrent parfois de celles spécifiées.
Modifions encore une fois notre classe polyscr avec un test de ces différences :
- Code: Select all
class polyscr:
w, h, w0, h0, x0, y0 = 0, 0, 0, 0, 0, 0
col_bits = [8, 8, 8]
myscr = None
# get_pixel(x, y)
# set_pixel(x, y, color(r8, g8, b8))
show_screen = lambda self: None
need_show_screen = False
# color mode :
# 0: (R8, G8, B8)
# 1: int RGB-565
color_mode = 0
has_color = True
def color(self, r, g=0, b=0):
if isinstance(r, tuple) or isinstance(r,list):
r, g, b = r[0], r[1], r[2]
return self.color_mode == 0 and (r,g,b) or r<<(self.col_bits[0]+self.col_bits[1]) | g<<self.col_bits[0] | b
def __init__(self):
try: # TI-Nspire Ndless
from nsp import Texture as myscr
self.w, self.h = 320, 240
myscr = myscr(self.w, self.h, None)
self.get_pixel = myscr.getPx
self.set_pixel = myscr.setPx
self.show_screen = myscr.display
self.need_show_screen = True
self.color_mode = 1
self.col_bits = (5, 6, 5)
except:
try: # TI-83/84 CE
import ti_graphics as myscr
self.get_pixel = myscr.getPixel
self.set_pixel = myscr.setPixel
except ImportError:
try: # Casio USB Power Graphic 3
import casioplot as myscr
self.show_screen = myscr.show_screen
self.need_show_screen = True
except ImportError: # NumWorks
import kandinsky as myscr
self.get_pixel = myscr.get_pixel
self.set_pixel = myscr.set_pixel
self.myscr = myscr
# detect readable pixel array
if self.w <= 0:
def _can_get_pixel(x, y):
c = self.get_pixel(x, y)
if c == self.color(0, 0, 0):
self.set_pixel(x, y, self.color(255,0,0))
c = self.get_pixel(x, y)
return c is not None and c != self.color(0, 0, 0)
self.w, self.h, dw, dh = 0, 0, 1, 1
while dw or dh:
if not _can_get_pixel(self.w - (dw == 0),self.h - (dh == 0)):
if _can_get_pixel(self.w,self.h-1): dh = 0
elif _can_get_pixel(self.w-1,self.h): dw = 0
else: dw, dh = 0, 0
self.w += dw; self.h += dh
# detect writable pixel array
# remove top status bar
def _can_set_pixel(x, y):
def _invert_color(r, g=0, b=0):
if isinstance(r, tuple) or isinstance(r,list):
r, g, b = r[0], r[1], r[2]
return self.color(~r & 0xFF, ~g & 0xFF, ~b & 0xFF)
c = self.get_pixel(x, y)
self.set_pixel(x, y, _invert_color(c))
return c != self.get_pixel(x, y)
self.w0, self.h0 = self.w, self.h
while not _can_set_pixel(0, self.y0):
self.y0 += 1; self.h0 -= 1
if not self.color_mode:
# test color screen
self.set_pixel(self.x0, self.y0, (0, 127, 255))
col = self.get_pixel(self.x0, self.y0)
self.has_color = col[0] != col[1] or col[1] != col[2]
# detect color channel bits
self.set_pixel(self.x0, self.y0, (255, 255, 255))
col = list(self.get_pixel(self.x0, self.y0))
for k in range(3):
while col[k]<255:
col[k] += 2 ** (8 - self.col_bits[k])
self.col_bits[k] -= 1
Appelons enfin le code suivant pour obtenir l'intégralité des informations écran, et les comparer aux solutions concurrentes :
- Code: Select all
scr = polyscr()
print('can get {}x{} pixels at (0,0)'.format(scr.w, scr.h))
print('can set {}x{} pixels at ({},{})'.format(scr.w0, scr.h0, scr.x0, scr.y0))
print(scr.has_color and 'color' or 'monochrome')
if scr.has_color: print('internal : RGB{}{}{}'.format(scr.col_bits[0], scr.col_bits[1], scr.col_bits[2]))
Voilà, nous obtenons bien comme prévu du RGB565 pour le format utilisé en interne pour les pixels
Testons également la concurrence en lançant le même code :
Au classement selon les meilleurs rendus de couleurs, nous avons donc :
- 24 bits / 16777216 couleurs: HP Prime (version alpha)
- 16 bits / 65536 couleurs: TI-83 Premium CE Edition Python + Casio Graph 90+E + NumWorks
- 1 bit / 2 couleurs: Casio Graph 35+E II
- 24 bits / 16777216 couleurs: HP Prime (version alpha)
- 16 bits / 65536 couleurs: TI-83 Premium CE Edition Python + Casio Graph 90+E / fx-CG50 + NumWorks + TI-Nspire CX
- 1 bit / 2 couleurs: Casio Graph 35+E II / fx-9750/9860GIII + TI-Nspire
4) allumage de pixels et performances
Go to topTentons maintenant de déterminer les performances graphiques, soit la vitesse d'allumage des pixels.
Reprenons déjà le script permettant de chronométrer l'exécution d'une fonction :
Faisons maintenant un script allumant un par un tous les pixels de l'écran, et afin de mieux pouvoir mesurer et comparer les performances graphiques nous minimiserons les calculs en ne faisant pas appel à notre classe de compatibilité, mais en appelant directement les fonctions graphiques :
L'appel
Voici maintenant la version NumWorks :
L'appel
Passons maintenant sur Casio. Ici hélas pas de module timer, donc il va falloir chronométrer à la main, bien évidemment avec une montre Casio. Autre différence, les affichages sont à la différence effectués ici sur un calque invisible et ne passent à l'écran que lorsqu'on le demande. Afin donc de tester dans des conditions aussi équivalentes que possibles, nous demanderons un affichage écran après chaque traitement de pixel.
La montre Casio nous retourne :
De façon similaire pour TI-Nspire Ndless :
Nous n'avons malheureusement pas de montre Texas Instruments, espérons donc que la montre Casio ne trichera pas trop.
Enfin sur HP Prime G1 :
La machine nous remplit tout l'écran en seulement 0.49s !
Bien évidemment, tous ces écrans ont des définitions différentes. Pour le classement ramenons cela en terme de vitesse d'affichage :
En terme de boucle d'allumages individuels de pixels, la TI-83 Premium CE Edition Python ne serait donc apparemment pas très performante.
Mais attends un petit peu avant de partir, nous sommes très loin d'avoir dit notre dernier mot, nous allons approfondir cela de suite dans les deux prochaines parties.
Reprenons déjà le script permettant de chronométrer l'exécution d'une fonction :
- Code: Select all
from time import monotonic
def timer(f, *par):
start=monotonic()
f(*par)
return monotonic()-start
Faisons maintenant un script allumant un par un tous les pixels de l'écran, et afin de mieux pouvoir mesurer et comparer les performances graphiques nous minimiserons les calculs en ne faisant pas appel à notre classe de compatibilité, mais en appelant directement les fonctions graphiques :
- Code: Select all
from ti_graphics import *
def rectf(x, y, w, h, c=(0, 0, 0)):
for i in range(h):
for k in range(w):
setPixel(x+j, y+i, c)
L'appel
timer(rectf, 0, 30, 320, 210, (255, 0, 0)))
nous retourne 1390.487s soit 23min10.487s pour l'allumage donc de 320×210 pixels.Voici maintenant la version NumWorks :
- Code: Select all
from kandinsky import *
def rectf(x, y, w, h, c=(0, 0, 0)):
for i in range(h):
for k in range(w):
set_pixel(x+j, y+i, c)
L'appel
timer(rectf, 0, 30, 320, 222, (255, 0, 0)))
pour chronométrer l'allumage de 320×222 pixels nous donne :- 1.541s sur NumWorks N0110 munie du firmware officiel Epsilon
- 1.145s sur NumWorks N0110 munie du firmware tiers Omega
- 1.605s sur NumWorks N0100 munie du firmware officiel Epsilon
- 1.623s sur NumWorks N0100 munie du firmware tiers Omega
Passons maintenant sur Casio. Ici hélas pas de module timer, donc il va falloir chronométrer à la main, bien évidemment avec une montre Casio. Autre différence, les affichages sont à la différence effectués ici sur un calque invisible et ne passent à l'écran que lorsqu'on le demande. Afin donc de tester dans des conditions aussi équivalentes que possibles, nous demanderons un affichage écran après chaque traitement de pixel.
- Code: Select all
from casioplot import *
def rectf(x, y, w, h, c=(0, 0, 0)):
for i in range(h):
for k in range(w):
set_pixel(x+j, y+i, c)
show_screen()
La montre Casio nous retourne :
- 1.64s pour l'appel
rectf(0, 0, 128, 64, (0, 0, 0)
sur Graph 35+E II - 9.93s pour l'appel
rectf(0, 0, 384, 192, (255, 0, 0)
sur Graph 90+E
De façon similaire pour TI-Nspire Ndless :
- Code: Select all
import nsp.Texture as scr
scr = scr(320, 240, None)
def rectf(x, y, w, h, c=0):
for i in range(h):
for k in range(w):
scr.setPx(x+j, y+i, c)
scr.display()
Nous n'avons malheureusement pas de montre Texas Instruments, espérons donc que la montre Casio ne trichera pas trop.
- 10min36.74s pour l'appel
rectf(0, 0, 320, 240, 31)
sur TI-Nspire CX CR4+ - 21min15.42s pour l'appel
rectf(0, 0, 320, 240, 31)
sur TI-Nspire CX CR3- - 4min49.5s pour l'appel
rectf(0, 0, 320, 240, 0)
sur TI-Nspire
Enfin sur HP Prime G1 :
- Code: Select all
from prime import *
def rectf(x, y, w, h, c=0):
for i in range(h):
for k in range(w):
pixon(x+j, y+i, c)
La machine nous remplit tout l'écran en seulement 0.49s !
Bien évidemment, tous ces écrans ont des définitions différentes. Pour le classement ramenons cela en terme de vitesse d'affichage :
- 156735 pixels/s: HP Prime G1 (version alpha)
- 62044 pixels/s: NumWorks N0110 (firmware Omega)
- 46100 pixels/s: NumWorks N0110
- 44262 pixels/s: NumWorks N0100
- 43771 pixels/s: NumWorks N0100 (firmware Omega)
- 7425 pixels/s : Casio Graph 90+E
- 4995 pixels/s : Casio Graph 35+E II
- 48 pixels/s : TI-83 Premium CE Edition Python
- 156735 pixels/s: HP Prime G1 (version alpha)
- 62044 pixels/s: NumWorks N0110 (firmware Omega)
- 46100 pixels/s: NumWorks N0110
- 44262 pixels/s: NumWorks N0100
- 43771 pixels/s: NumWorks N0100 (firmware Omega)
- 7425 pixels/s : Casio Graph 90+E / fx-CG50
- 4995 pixels/s : Casio Graph 35+E II / fx-9750/9860GIII
- 265 pixels/s: TI-Nspire
- 121 pixels/s: TI-Nspire CX CR4+
- 60 pixels/s: TI-Nspire CX CR3-
- 48 pixels/s : TI-83 Premium CE Edition Python
En terme de boucle d'allumages individuels de pixels, la TI-83 Premium CE Edition Python ne serait donc apparemment pas très performante.
Mais attends un petit peu avant de partir, nous sommes très loin d'avoir dit notre dernier mot, nous allons approfondir cela de suite dans les deux prochaines parties.
5) écriture texte et performances
Go to topNous avions été assez déçus des instructions d'affichage de texte présentes dans les modules ti_plotlib et ti_system :
- impossibilité de positionner le texte comme on voulait verticalement, nous ne pouvions que choisir une des 11 à 12 bandes horizontales de 17 pixels de hauteur, numérotées de haut en bas, même dans le contexte de ti_plotlib pourtant censé travailler dans un repère
- impossibilité de positionner le texte comme on voulait horizontalement, nous ne pouvion que choisir entre l'aligner à gauche, au centre ou à droite
- et en prime effet de bord sur l'affichage avec effacement de la partie droite non utilisée de la bande ou même de toute la bande
ti_graphics dispose lui aussi d'une instruction d'affichage similaire
drawString('texte', x, y)
.Mais ici rien à voir avec les précédentes, (x, y) sont les coordonnées comptées cette fois-ci au pixel près à partir du coin en haut à gauche, et le tout ne produit aucun effet de bord !
Si si, tu pourras bien afficher tes textes en toute liberté !
C'est le cas de le dire, merci TI !
Si si, tu pourras bien afficher tes textes en toute liberté !
- Code: Select all
from ti_system import *
import ti_graphics as scr
tw = 10
s = 'Thank you TI'
xmin, xmax, ymin, ymax = 0, 319, 30, 239
x, y, dx, dy = xmin, ymin, 1, 9
scr.cls()
while x <= xmax - tw*len(s):
scr.drawString(s, x, y)
y += dy
x += dx
dx += 1
disp_wait()
C'est le cas de le dire, merci TI !
Et puis, ce n'est pas tout. Le test de la partie précédente nous a donc donné une vitesse de traitement calamiteuse de moins d'une 50aine de pixels à la seconde.
Et pourtant, aucun problème ici avec la fonction drawString(), l'affichage pourtant conséquent en nombre de pixels prenant moins d'une paire de secondes !
Que se passe-t-il donc ? Sans doute que c'est ici qu'il faut tenir comtpe de l'architecture matérielle très spéciale de la TI-83 Premium CE, avec :
- un cœur secondaire Atmel SAMD21E18A-U intégrant un ARM Cortex-M0+ cadencé à 48 MHz, coprocesseur 32-bits dédié à l'exécution des scripts Python
- un cœur principal eZ80 qui à la différence dispose d'un accès direct à l'ensemble des autres composantes matérielles (Flash, contrôleur écran, cœur secondaire...)
Alors qu'ici chaque appel à drawString() allume d'un coup plein de pixels que l'on peut supposer à la différence partager un seul et unique événément de mise à jour.
Un comparatif s'appuyant sur une boucle d'allumage de pixels n'est donc pas représentatif des performances graphiques moyennes de la TI-83 Premium CE Edition Python puisque c'est pour elle le pire des cas, et donc non pertinent. Mais en même temps, quand les modules graphiques de la concurrence sont à la différence très minimalistes, nous ne voyons pas d'autre fonction commune et identique à utiliser pour construire un test de performances...
6) fonctions de tracé de formes géométriques
Go to topAbordons maintenant les autres fonctions de tracer de ti_graphics.
Les modules équivalents chez la concurrence sont assez minimalistes, te fournissant juste de quoi choisir la couleur, allumer/éteindre des pixels, et afficher du texte. Tu devais te fabriquer tes autres fonctions graphiques (lignes, rectangles, cercles, etc...).
Et bien ici tu es gâté, ti_graphics est très riche.
Commençons déjà par de la configuration. Déjà, on eut effacer l'écran à l'aide de la fonction cls(). Son comportement semble identique à celui des fonctions ti_plotlib.cls() et ti_system.disp_clr().
La fonction
A la différence ici que les effets des valeurs sont inversés :
On peut maintenant choisir la couleur du stylo avec
D'ailleurs si l'on importe les deux modules ti_graphics et ti_plotlib, on peut appeler n'importe laquel de ces deux fonctions pour obtenir le même effet, et ce simultanément dans les deux contextes graphiques. Sans doute que ces deux fonctions partagent le même code.
On peut également régler la plume du stylo, avec
A la différence près que setPen() n'accepte pas d'arguments sous forme de chaînes de caractères, uniquement des entiers. On peut donc supposer que ti_plotlib.pen() est définie pour faire appel à setPen() de la façon suivante :
Mais ici, pas d'erreur avec des paramètres supérieurs à 2...
Nous allons voir de suite ce que ça donne. Commençons par la fonction
Ci-contre l'affichage obtenu, ainsi que pour comparaison celui du test similaire dans le contexte de la fonction ti_plotlib.pen().
Ce qui nous permet de terminer la documentation de pen() :
Testons maintenant de façon similaire les fonctions
La fonction drawPolyLine() permet donc de tracer une ligne brisée. Elle serait donc équivalente au code suivant :
La fonction fillPolygon() permet quant à elle de colorier le polygone obtenu en fermant cette ligne brisée.
Et comme tu vois c'est remarquable, elle marche même avec des polygones croisés !
Passons maintenant à
Voici maintenant du lourd avec
La fonction
Et La fonction fillArc() permet quant à elle de colorier le secteur d'ellipse obtenu par balayage de l'arc en question.
Petite curiosité, nous avons une fonction
Ce qui est curieux ? Et bien qu'il n'y ait apparemment pas de fonction similaire
Les modules équivalents chez la concurrence sont assez minimalistes, te fournissant juste de quoi choisir la couleur, allumer/éteindre des pixels, et afficher du texte. Tu devais te fabriquer tes autres fonctions graphiques (lignes, rectangles, cercles, etc...).
Et bien ici tu es gâté, ti_graphics est très riche.
Mais c'est aussi surtout un moyen de répondre au problème découvert plus haut, à savoir que la TI-83 Premium CE Edition Python est très lente pour les boucles appelant des setPixel(). Coder toi-même ces mêmes fonctions en utilisant setPixel() faute de mieux eut été désastreux.
Commençons déjà par de la configuration. Déjà, on eut effacer l'écran à l'aide de la fonction cls(). Son comportement semble identique à celui des fonctions ti_plotlib.cls() et ti_system.disp_clr().
La fonction
cursor(c=1)
permet d'activer ou désactiver l'affichage du curseur de texte, comme le permettait déjà la fonction ti_system.cursor(c)
.A la différence ici que les effets des valeurs sont inversés :
- 0: curseur affiché
- 1: curseur masqué
On peut maintenant choisir la couleur du stylo avec
setColor(r, g, b)
, appel équivalent à ti_plotlib.color(r, g, b)
.D'ailleurs si l'on importe les deux modules ti_graphics et ti_plotlib, on peut appeler n'importe laquel de ces deux fonctions pour obtenir le même effet, et ce simultanément dans les deux contextes graphiques. Sans doute que ces deux fonctions partagent le même code.
On peut également régler la plume du stylo, avec
setPen(taille, type)
, un appel donc similaire à ti_plotlib.pen('taille', 'type')
.A la différence près que setPen() n'accepte pas d'arguments sous forme de chaînes de caractères, uniquement des entiers. On peut donc supposer que ti_plotlib.pen() est définie pour faire appel à setPen() de la façon suivante :
- Code: Select all
def setPen(taille, type):
_strtest(taille)
_strtest(type)
if taille == 'thin': taille = 0
elif taille == 'medium': taille = 1
elif taille == 'thick': taille = 2
else: _excpt('Invalid pen size.')
if type == 'solid': type = 0
elif type == 'dot': type = 1
elif type == 'dash': type = 2
else: _excpt('Invalid pen style.')
gr.pen(taille, type)
Mais ici, pas d'erreur avec des paramètres supérieurs à 2...
Nous allons voir de suite ce que ça donne. Commençons par la fonction
drawLine(x1, y1, x2, y2)
:- Code: Select all
from ti_system import *
import ti_graphics as scr
tw, th = 8, 15
xmin, xmax, ymin, ymax = tw, 319, 30+th, 239
nta, nty = 4, 4
lx = [xmin + k*(xmax-xmin)/(2*nta+1) for k in range(1, 2*nta+1)]
ly = [ymin + k*(ymax-ymin)/(2*nty+1) for k in range(1, 2*nty+1)]
l = (xmax-xmin+1) / (2*nta+1)
scr.cls()
for i in range(nty):
scr.drawString(str(i), xmin-tw, ly[i*2])
for j in range(nta):
scr.drawString(str(j), lx[j*2], ymin-th)
scr.setPen(j, i)
scr.drawLine(lx[j*2], ly[i*2], lx[j*2 + 1], ly[i*2])
disp_wait()
Ci-contre l'affichage obtenu, ainsi que pour comparaison celui du test similaire dans le contexte de la fonction ti_plotlib.pen().
Ce qui nous permet de terminer la documentation de pen() :
setPen(0, 0)
=ti_plotlib.pen('thin', 'solid')
setPen(1, 1)
=ti_plotlib.pen('medium', 'dot')
setPen(2, 2)
=ti_plotlib.pen('thick', 'dash')
setPen(3, 3)
, il permet donc d'accéder à deux réglages secrets non offerts via ti_plotlib : - une taille de stylo encore plus grande que 'thick'
- un tracé en pointillés qui enchaîne non pas des tirets mais des petits points
Testons maintenant de façon similaire les fonctions
drawPolyLine([(x1,y1), (x2,y2), ..., (xn,yn)])
et fillPolyLine([(x1,y1), (x2,y2), ..., (xn,yn)])
:- Code: Select all
from ti_system import *
import ti_graphics as scr
tw, th = 8, 15
xmin, xmax, ymin, ymax = tw, 319, 30+th, 239
nta, nty = 4, 4
lx = [xmin + k*(xmax-xmin)/(2*nta+1) for k in range(1, 2*nta+1)]
ly = [ymin + k*(ymax-ymin)/(2*nty+1) for k in range(1, 2*nty+1)]
l = (xmax-xmin+1) / (2*nta+1)
scr.cls()
for i in range(nty):
scr.drawString(str(i), xmin-tw, ly[i*2])
for j in range(nta):
scr.drawString(str(j), lx[j*2], ymin-th)
scr.setPen(j, i)
scr.setColor((255,0,0))
scr.fillPolygon([(lx[j*2], ly[i*2]), (lx[j*2 + 1], ly[i*2]), (lx[j*2], ly[i*2+1]), (lx[j*2 + 1], ly[i*2+1])])
scr.setColor((0,0,0))
scr.drawPolyLine([(lx[j*2], ly[i*2]), (lx[j*2 + 1], ly[i*2]), (lx[j*2], ly[i*2+1]), (lx[j*2 + 1], ly[i*2+1])])
disp_wait()
La fonction drawPolyLine() permet donc de tracer une ligne brisée. Elle serait donc équivalente au code suivant :
- Code: Select all
def drawPolyLine(l):
for k in range(len(l) - 1):
drawLine(l[k][0], l[k][1], l[k+1][0], l[k+1][1])
La fonction fillPolygon() permet quant à elle de colorier le polygone obtenu en fermant cette ligne brisée.
Et comme tu vois c'est remarquable, elle marche même avec des polygones croisés !
Passons maintenant à
drawRect(x, y, w, h)
et fillRect(x, y, w, h)
:- Code: Select all
from ti_system import *
import ti_graphics as scr
tw, th = 8, 15
xmin, xmax, ymin, ymax = tw, 319, 30+th, 239
nta, nty = 4, 4
lx = [xmin + k*(xmax-xmin)/(2*nta+1) for k in range(1, 2*nta+1)]
ly = [ymin + k*(ymax-ymin)/(2*nty+1) for k in range(1, 2*nty+1)]
l = (xmax-xmin+1) / (2*nta+1)
scr.cls()
for i in range(nty):
scr.drawString(str(i), xmin-tw, ly[i*2])
for j in range(nta):
scr.drawString(str(j), lx[j*2], ymin-th)
scr.setPen(j, i)
scr.setColor((255,0,0))
scr.fillRect(lx[j*2], ly[i*2], lx[j*2+1]-lx[j*2], ly[i*2+1]-ly[i*2])
scr.setColor((0,0,0))
scr.drawRect(lx[j*2], ly[i*2], lx[j*2+1]-lx[j*2], ly[i*2+1]-ly[i*2])
disp_wait()
drawRect(x, y, w, h)
permet donc de tracer un rectangle :- de dimensions w et h données en pixels
- aux côtés parallèles aux bors de l'écran
- et en utilisant le point de coordonnées (x, y) comme sommet supérieur gauche
Voici maintenant du lourd avec
drawArc(x, y, w, h, t1, t2)
et fillArc(x, y, w, h, t1, t2)
:- Code: Select all
from ti_system import *
import ti_graphics as scr
tw, th = 8, 15
xmin, xmax, ymin, ymax = tw, 319, 30+th, 239
nta, nty = 4, 4
lx = [xmin + k*(xmax-xmin)/(2*nta+1) for k in range(1, 2*nta+1)]
ly = [ymin + k*(ymax-ymin)/(2*nty+1) for k in range(1, 2*nty+1)]
l = (xmax-xmin+1) / (2*nta+1)
scr.cls()
for i in range(nty):
scr.drawString(str(i), xmin-tw, ly[i*2])
for j in range(nta):
scr.drawString(str(j), lx[j*2], ymin-th)
scr.setPen(j, i)
scr.setColor((255,0,0))
scr.fillArc(lx[j*2], ly[i*2], lx[j*2+1]-lx[j*2], ly[i*2+1]-ly[i*2], 0, 3150)
scr.setColor((0,0,0))
scr.drawArc(lx[j*2], ly[i*2], lx[j*2+1]-lx[j*2], ly[i*2+1]-ly[i*2], 0, 3150)
disp_wait()
La fonction
drawArc(x, y, dx, dy, t1, t2)
permet donc de tracer un arc d'une ellipse elle-même inscrite dans un rectangle :- de dimensions w et h données en pixels
- aux côtés parallèles aux bors de l'écran
- et en utilisant le point de coordonnées (x, y) comme sommet supérieur gauche
Et La fonction fillArc() permet quant à elle de colorier le secteur d'ellipse obtenu par balayage de l'arc en question.
Petite curiosité, nous avons une fonction
fillCircle(x, y, r)
permettant de préciser des éléments caractéristiques différents plus naturels dans le cas particulier d'un disque. La fonction serait donc équivalente au code suivant :- Code: Select all
def fillCircle(x, y, r):
fillArc(x-r, y-r, 2*r, 2*r, 0, 3600)
Ce qui est curieux ? Et bien qu'il n'y ait apparemment pas de fonction similaire
drawCircle(x, y, r)
pour le tracé d'un cercle, obligeant dans ce cas à utiliser une logique complètement différente.- Code: Select all
from ti_system import *
import ti_graphics as scr
tw, th = 8, 15
xmin, xmax, ymin, ymax = tw, 319, 30+th, 239
nta, nty = 4, 4
lx = [xmin + k*(xmax-xmin)/(2*nta+1) for k in range(1, 2*nta+1)]
ly = [ymin + k*(ymax-ymin)/(2*nty+1) for k in range(1, 2*nty+1)]
l = (xmax-xmin+1) / (2*nta+1)
scr.cls()
for i in range(nty):
scr.drawString(str(i), xmin-tw, ly[i*2])
for j in range(nta):
scr.drawString(str(j), lx[j*2], ymin-th)
scr.setPen(j, i)
scr.setColor((255,0,0))
scr.fillCircle(lx[j*2]+(ly[i*2+1]-ly[i*2])/2, (ly[i*2]+ly[i*2+1])/2, (ly[i*2+1]-ly[i*2])/2)
scr.setColor((0,0,0))
scr.drawArc(lx[j*2], ly[i*2], ly[i*2+1]-ly[i*2], ly[i*2+1]-ly[i*2], 0, 3600)
disp_wait()
7) fonctions dédiées aux images
Go to topEnorme surprise, ti_graphics dispose apparemment de pas moins de 3 fonctions dédiées à l'affichage d'images, et donc entre autres de sprites pour tes interfaces de menus et jeux !
C'est sans doute un moyen une fois encore de répondre au problème de performances des boucles d'allumage de pixels que tu aurais utilisées par défaut
Mais ces fonctions dédiées n'en restent pas moins un formidable avantage sur la concurrence, ces boucles d'allumage n'étant sur la plupart des modèles pas assez rapides pour permettre d'animer ou déplacer un sprite de façon fluide dans le contexte par exemple d'un jeu.
Mais ces fonctions dédiées n'en restent pas moins un formidable avantage sur la concurrence, ces boucles d'allumage n'étant sur la plupart des modèles pas assez rapides pour permettre d'animer ou déplacer un sprite de façon fluide dans le contexte par exemple d'un jeu.
Comme ces fonctions ne sont pas au menu il nous faut donc arriver à deviner ce qu'elles attendent comme arguments.
L'appel
pushImage(x, y, w, h)
semble définir une image de dimensions w×h qui pourra être affichée avec comme coin supérieur gauche le pixel de coordonnées (x,y).La fonction popImage() quant à elle en déclenche ensuite l'affichage, effectivement très rapide même si par défaut cela nous affiche ici n'importe quoi.
Par exemple ci-contre, le résultat du code suivant :
- Code: Select all
from ti_system import *
import ti_graphics as scr
scr.pushImage(50, 50, 269, 170)
scr.popImage()
disp_wait()
drawImage(?, ?, ?)
doit pour sa part servir à dessiner l'image en question avant affichage, mais nous n'avons pas réussi à en comprendre le fonctionnement.Si l'on se réfère à notre test précédent ayant mis en évidence que nous disposions de près de 17.5K de mémoire de tas (heap) il semble impensable que cette fonction puisse accepter des données d'image brutes, que ce soit sous forme de liste ou de chaîne de caractères. 320×240 pixels codés sur 16 bits nécessiteraient en effet pas moins de 153.6 Ko, qui déclencheront ici une erreur de mémoire.
Nous avons deux hypothèses :
- Soit la fonction attend une liste ou une chaîne de données compressées par exemple en RLE, et peut-être que TI a prévu un outil générant automatiquement à partir d'une image fournie la liste ou chaîne compressée à coller dans ton script. Mais en tous cas cet outil ne nous as pas été passé.
- Soit la fonction attend le nom d'une ressource image à aller chercher en externe dans les variables du système de la calculatrice. En fouillant l'application Python à l'éditeur hexadécimal nous avons effectivement trouvé un indice en ce sens, avec un 'imgname' qui est bien présent en clair dans le code même nous n'avons trouvé pour le moment aucun menu l'affichant.
En tous cas, faire appel aux variables images préchargées dans le calculatrice avec par exemple
scr.drawImage('Image1', 50, 50)
semble ne rien donner.On pouvait quand même s'en douter, vu que ces images ont une taille fixe prévue pour un affichage en plein écran :
- 265×165 pixels pour les images 16 couleurs Pic0 à Pic9
- 133×83 pixels pour les images d'arrière plan Image0 à Image9 (agrandies d'un facteur 2 pour l'affichage)
Peut-être donc plutôt que drawImage() va chercher des AppVars (variables d'applications) qui contiendraient des images dédiées au Python et qu'un futur TI-Connect CE 5.5 effectuera la conversion à la volée lorsque l'on lui fournira des images. Ce serait l'hypothèse la plus plausible, mais en tous cas on ne nous l'a pas passé.
8) ti_graphics et autres fonctions
Go to topti_graphics comporte également quelques autres fonctions privées ou issues d'autres modules.
Déjà, il inclut le module sys que tu n'auras donc pas à importer simultanément.
Il inclut également une fonction sleep() équivalente à time.sleep(), autre économie de mémoire pour tes importations.
La fonction privée
Sauf qu'ici elle est accompagnée d'une fonction
Egalement quelques autres mystères à découvrir et qui peut-être nous permettront des choses bien pratiques :
Déjà, il inclut le module sys que tu n'auras donc pas à importer simultanément.
Il inclut également une fonction sleep() équivalente à time.sleep(), autre économie de mémoire pour tes importations.
La fonction privée
_write('')
semble être équivalente avec ti_plotlib._write('')
.Sauf qu'ici elle est accompagnée d'une fonction
_read(n)
. Attention, si on lui demande de lire plus de données qu'il y en a, on ne sait où en passant, la calculatrice rentre dans une boucle d'attente infinie qu'il est apparemment impossible d'interrompre autrement que par un reset.Egalement quelques autres mystères à découvrir et qui peut-être nous permettront des choses bien pratiques :
_grcmd('')
, _grcif('')
et _handshake(?)
.Conclusion
Go to topTexas Instruments nous signe donc ici un module ti_graphics de dessin sur écran extrêmement complet, face à une concurrence à ce jour très minimaliste sur ce sujet.
Il y a clairement eu un travail très conséquent là-dessus, c'est un module conçu à partir de zéro et taillé sur-mesure pour te donner le meilleur avec le matériel choisi pour ta TI-83 Premium CE Edition Python.
Pixels, textes, formes géométriques diverses et images, chaque fonction te permet ici d'exploiter l'intégralité des capacités matérielles. ti_graphics te permet de réaliser avec de bien meilleurs performances tout ce que tu pouvais déjà faire avec le langage historique TI-Basic et même davantage, notamment au niveau des ellipses, couleurs et images !
De quoi initier de formidables créations (interfaces de menus, jeux, ...) pour tes projets, aussi bien scolaires (SNT, NSI, ...) que non scolaires !
Merci TI !
Il y a clairement eu un travail très conséquent là-dessus, c'est un module conçu à partir de zéro et taillé sur-mesure pour te donner le meilleur avec le matériel choisi pour ta TI-83 Premium CE Edition Python.
Pixels, textes, formes géométriques diverses et images, chaque fonction te permet ici d'exploiter l'intégralité des capacités matérielles. ti_graphics te permet de réaliser avec de bien meilleurs performances tout ce que tu pouvais déjà faire avec le langage historique TI-Basic et même davantage, notamment au niveau des ellipses, couleurs et images !
De quoi initier de formidables créations (interfaces de menus, jeux, ...) pour tes projets, aussi bien scolaires (SNT, NSI, ...) que non scolaires !
Merci TI !