Page 1 of 1

Cercle chromatique paramétrable et plus rapide pour NumWorks

Unread postPosted: 20 May 2019, 21:41
by Admin
Petit retour ce soir sur la possibilité de mettre le cercle chromatique dans ta NumWorks.

A la rentrée 2019 en Seconde, le programme de Physique-Chimie fait en effet appel aux scripts Python afin d'illustrer graphiquement divers phénomènes physiques. La NumWorks est à ce jour la seule calculatrice dont le Python offre des possibilités graphiques, et donc la seule calculatrice entièrement conforme au nouveau programme. :bj:

Nous avions donc vu un premier script en ce sens dans un article précédent. Script qui avait la particularité très artistique de colorier le cercle de façon concentrique en partant du centre.

Un inconvénient de cette méthode est qu'elle est peu précise pour allumer une grille de pixels.

Les approximations poussent à jouer la sécurité afin de ne pas laisser de trous, quitte à traiter certains pixels plusieurs fois, ce qui ralentit le tracé.

Aussi, les cercles concentriques étant de plus en plus grands, cela donne visuellement l'impression peu agréable que le tracé ralentit de plus en plus.

11257Voici donc ce soir un autre script Python dédié au cercle chromatique, qui cette fois-ci colorie le disque ligne par ligne de haut en bas.

Une méthode sans doute moins esthétique en cours de tracer, mais qui permet ici de viser précisément chaque pixel et qui est donc beaucoup plus rapide ! :bj:
Aussi, la fonction de ce nouveau script a l'avantage d'offrir le contrôle de nombre de paramètres, afin de se s'adapter au mieux à tes besoins ou ceux de tes propres scripts.

Tu pourras préciser notamment cette fois-ci la position du centre ainsi que le rayon, et même décider d'inverser l'ordre des couleurs.

En interne, le script travaille sur des couleurs en coordonnées non pas RVB (Rouge-Vert-Bleu) mais TSV (Teinte-Saturation-Valeur), possiblement plus connues chez les graphistes et anglophones en tant que HSV (Hue-Saturation-Value) ou HSB (Hue-Saturation-Brightness). Ce système de coordonnées a l'avantage d'être basé sur une approche de la perception des couleurs, ce qui simplifie énormément nombre d'effets optiques. ;)

Tu pourras par exemple demander à la fonction d'augmenter ou de diminuer progressivement la saturation ou la valeur du centre à la périphérique pour des effets que tu peux constater sur la démo ci-contre, de quoi illustrer aussi bien la synthèse additive que soustractive par exemple. :D

11252Avertissement pour les codeurs NumWorks dont les scripts manipulent des couleurs.

La version bêta 11.0.0 actuellement en phase de tests change le comportement de la fonction kandinsky.color(r,g,b), qui ne renvoie plus un nombre mais un tuple.

L'avantage est de permettre la récupération facile des différentes composantes RVB au codeur débutant, exactement comme avec une liste. Un changement une fois de plus à l'heure et en parfaite adéquation avec l'évolution des programmes scolaires du lycée à la rentrée 2019 ! :bj:

Toutefois, selon comment les scripts déjà existants récupéraient et utilisaient la valeur retour de cette fonction, certains pourront ne plus fonctionner correctement lors d'une prochaine mise à jour NumWorks. Notamment ceux qui en récupéraient les composantes RVB pour y appliquer des transformations, et qui devront donc être corrigés.

Le script de cet article n'est pas concerné par le problème. Il a en effet été écrit de sorte à fonctionner aussi bien avec le nouveau comportement que l'ancien. :bj:


Téléchargement : archives_voir.php?id=2107931

Re: Cercle chromatique paramétrable et plus rapide pour NumW

Unread postPosted: 21 May 2019, 08:32
by parisse
Une adaptation pour Xcas en ligne:
session XcasIl y a un des disques qui ne donne pas le meme rendu, je ne sais pas trop pourquoi. J'ai du modifier des appels a % qui dans Xcas attend des entiers, en utilisant fmod a la place, et j'ai du remplacer la fonction modsv, l'utilisation du or pour renvoyer un flottant et pas un booleen est un comportement specifique a Python.
Je vais voir ce que ca donne sur la graph 90.
[Edit] script mis a jour.

Re: Cercle chromatique paramétrable et plus rapide pour NumW

Unread postPosted: 21 May 2019, 15:29
by UnCurieux
Félicitation, c'est impressionnant :bj:

Re: Cercle chromatique paramétrable et plus rapide pour NumW

Unread postPosted: 21 May 2019, 15:39
by critor
Merci. J'ai travaillé sur l'optimisation dont tu m'avais parlée rapidement sur le chat.

Ton script est également impressionnant dans son style. Formidable que tu ne laisses aucun pixel blanc avec la méthode de parcours du disque que tu as choisie, chapeau ! :bj:

N'hésite pas à reprendre des idées ou du code, si cela peut t'aider. :)

Re: Cercle chromatique paramétrable et plus rapide pour NumW

Unread postPosted: 22 May 2019, 13:03
by parisse
Sur la graph 90, c'est tres lent: https://www-fourier.ujf-grenoble.fr/~parisse/casio/sessions/chroma.xw. J'ai reussi a optimiser legerement en exploitant les quelques symetries du probleme, mais il faut encore presque 50 secondes pour faire un seul disque et 6 minutes pour les 8 disques (contre environ 5 secondes et 35 secondes sur la Numworks, qui plus est avec un rayon de disque legerement superieur car elle a un ecran avec une taille verticale un peu plus grande). Voici le script que j'ai utilise, qui est essentiellement compatible Python natif (il faut remplacer les ifte et enlever evalf), il y a surement moyen d'en tirer des idees pour accelerer un peu sur la Numworks:
Code: Select all
def hsv2color(h,s=1,v=1): # s est en fait s*v
  x,k=s*(1.0-abs((fmod(h/3.1415926535,0.66666666666))*3.0-1.0)),int(h*0.954929658551) % 6
  h,k=x*(k%3==1)+s*(k%5==0),x*(k%3==0)+s*(k==1 || k==2)
  return rgb(v+h-s,v+k-s,v+x-h-k)

def chromac(xc=160,yc=110,rmax=110,ds=0,dv=0,tred=0,rev=False):
  xc,yc=round(xc),round(yc)+24 # 24 decalage ligne d'etat Casio
  rev=1-2*rev
  # y==0
  for x in range(rmax+1):
    r=x/rmax
    v=ifte(dv,fmod(r*dv,1.0),1)
    s=ifte(ds,fmod(r*ds,1.0),1)*v
    set_pixel(xc+x,yc,hsv2color((-tred)*rev,s,v))   
    set_pixel(xc-x,yc,hsv2color((pi-tred)*rev,s,v))
  for y in range(1,rmax+1):
    if y%5==0:
      set_pixel() # synchro ecran de temps en temps
    xmin=floor(sqrt(rmax**2-y**2))
    z=complex(0,evalf(y))
    for x in range(0,xmin+1):
      a,r=arg(z),abs(z)/rmax
      v=ifte(dv,fmod(r*dv,1.0),1)
      s=ifte(ds,fmod(r*ds,1.0),1)*v
      set_pixel(xc+x,yc+y,hsv2color((a-tred)*rev,s,v))
      set_pixel(xc+x,yc-y,hsv2color((-a-tred)*rev,s,v))
      if x:
        a=3.1415926535-a
        set_pixel(xc-x,yc+y,hsv2color((a-tred)*rev,s,v))
        set_pixel(xc-x,yc-y,hsv2color((-a-tred)*rev,s,v))
      z+=1.0;
  set_pixel()

def demo():
  sw,sh=320,192
  r=40
  lx3=[r,(sw-1)/2,sw-1-r]
  ly2=[r,sh-1-r]
  lx2=[(lx3[0]+lx3[1])/2,(lx3[1]+lx3[2])/2]
  for x in range(2):
    chromac(lx2[x],sh/2,r,-1,not(x)*-1,x*3.1415926535/4,x%2)
  for y in range(2):
    for x in range(3):
      chromac(lx3[x],ly2[y],r,not(y),x-1,(2+3*y+x)*3.1415926535/4,(x+y)%2)

Re: Cercle chromatique paramétrable et plus rapide pour NumW

Unread postPosted: 22 May 2019, 13:08
by critor
Merci.

C'est pour KhiCAS, donc ?

Re: Cercle chromatique paramétrable et plus rapide pour NumW

Unread postPosted: 23 May 2019, 06:02
by parisse
Pour KhiCAS et Xcas oui.
Comme c'est tres lent sur la Casio, j'ai fait une version plus rapide mais moins precise (un calcul pour 4 pixel). C'est un compromis que je pense plus acceptable (qui utilise des instructions KhiCAS specifiques comme draw_circle pour gommer des imperfections au bord du disque)
Code: Select all
def hsv2color(h,s=1,v=1): # s est en fait s*v
  x,k=s*(1.0-abs((fmod(h/3.1415926535,0.66666666666))*3.0-1.0)),int(h*0.954929658551) % 6
  h,k=x*(k%3==1)+s*(k%5==0),x*(k%3==0)+s*(k==1 || k==2)
  return rgb(v+h-s,v+k-s,v+x-h-k)

def chromac(xc=160,yc=110,rmax=110,ds=0,dv=0,tred=0,rev=False):
  xc,yc=round(xc),round(yc)+12
  rev=1-2*rev
  # y==0
  for x in range(rmax+1):
    r=x/rmax
    v=ifte(dv,fmod(r*dv,1.0),1)
    s=ifte(ds,fmod(r*ds,1.0),1)*v
    fill_rect(2*xc+2*x,2*yc,2,2,hsv2color((-tred)*rev,s,v))   
    fill_rect(2*(xc-x),2*yc,2,2,hsv2color((pi-tred)*rev,s,v))
  for y in range(1,rmax+1):
    if y%3==0:
      set_pixel()
    xmin=floor(sqrt(rmax**2-y**2))
    z=complex(0,evalf(y))
    for x in range(0,xmin+1):
      a,r=arg(z),abs(z)/rmax
      v=ifte(dv,fmod(r*dv,1.0),1)
      s=ifte(ds,fmod(r*ds,1.0),1)*v
      fill_rect(2*(xc+x),2*(yc+y),2,2,hsv2color((a-tred)*rev,s,v))
      fill_rect(2*(xc+x),2*(yc-y),2,2,hsv2color((-a-tred)*rev,s,v))
      if x:
        a=3.1415926535-a
        fill_rect(2*(xc-x),2*(yc+y),2,2,hsv2color((a-tred)*rev,s,v))
        fill_rect(2*(xc-x),2*(yc-y),2,2,hsv2color((-a-tred)*rev,s,v))
      z+=1.0;
  draw_circle( 2*xc,2*yc,2*rmax,white)
  draw_circle( 2*xc,2*yc,2*rmax+1,white)
  set_pixel()

def demo():
  sw,sh=160,96
  r=20
  lx3=[r,(sw-1)/2,sw-1-r]
  ly2=[r,sh-1-r]
  lx2=[(lx3[0]+lx3[1])/2,(lx3[1]+lx3[2])/2]
  for x in range(2):
    chromac(lx2[x],sh/2,r,-1,not(x)*-1,x*3.1415926535/4,x%2)
  for y in range(2):
    for x in range(3):
      chromac(lx3[x],ly2[y],r,not(y),x-1,(2+3*y+x)*3.1415926535/4,(x+y)%2)