Les courbes de Lissajous

Les courbes de Lissajous

Présentation

J'avoue que là je me suis honteusement inspiré d'un gif trouvé sur internet mais je le trouvais tellement beau que je me suis dit qu'il fallait absolument que je le refasse. (Attention, ce gif va consommer tout votre data)



Je ne connaissais pas ces éléments mais il s'agit apparemment de courbes de Lissajous. Une construction mathématique se basant sur la trajectoire d'un point dont les composantes rectangulaires ont un mouvement sinusoïdal.

Le code

Comme je suis sympa (et que j'ai enfin trouvé comment intégrer du code dans le blog) je vais vous partager ma création/copie, réalisée en R. C'est finalement assez simple puisque chacune des trajectoires ne dépend que du mouvement indiqué par la position des points sur les cercles extérieurs. Il suffit alors de coder la trajectoire de manière générique pour ne pas avoir à faire 49 morceaux de codes différents. On commence par deux petites fonctions, la première qui permet de créer un dégradé dans les couleurs (en bricolant le rgb) et la seconde qui permet de calculer les coordonnées d'un point en fonction d'un angle.
meancol=function(col1,col2){
  col1=gsub("#","",col1)
  col2=gsub("#","",col2)
  res=c()
  for(i in seq(1,nchar(col1)-1,by=2)){
    c1=substring(col1,i,i+1)
    c2=substring(col2,i,i+1)
    s = round( (strtoi(sprintf("0x%s",tolower(c1))) + strtoi(sprintf("0x%s",tolower(c2))))/2)
    res=c(res,toupper(as.hexmode(s)))
  }
  res[nchar(res)==1]=sprintf("%s0",res[nchar(res)==1])
  return(sprintf("#%s",paste(res,sep="",collapse="")))
}

coord=function(x,y,s,k=1,r=.4){  return(c(x+r*cos(s/k),y+r*sin(s/k))) }

Et on enchaine avec le code de la fonction principale, la première étape consiste à initialiser les objets qui nous seront utiles par la suite. On crée les points à parcourir (de 0 à 14 pi par pas de pi/8). C'est cet angle qui décidera de la position de chaque point et donc de l'apparence de chaque image. Ensuite, on crée les 7 vitesses de parcours de cercles (Par défaut de 1 à 7 mais c'est paramétrable). Dans notre cas, quand le point dans le premier cercle fait un tour complet, le point du deuxième cercle en fait deux, celui du troisième cercle en fait trois, etc...

S=seq(0,14*pi,by=pi/8)
X=Y=7/(1:7)
COL=colorRampPalette(c("lightblue","orange"))(length(X));
XX=YY=array(0,dim=c(length(X),length(Y),length(S)));  


Et le gros du code, une boucle qui va remplir les 8 x 8 éléments de notre dessin. Si on est sur la première colonne ou la première ligne, on fait juste un cercle et on place un point en fonction de la valeur de l'angle de l’itération en cours.
Pour les autres éléments (qui ne sont pas forcement des cercles) on trace le parcours du point (que l'on stocke à chaque itération dans les arrays à 3 dimensions XX et YY pour pouvoir l'afficher à l’étape suivante)

for(s in S){
  k=match(s,S)
  # Plot
  par(mar=c(0,0,0,0), bg="grey40");
  plot(0, type="n", xlim=c(-.5,length(X)+.5), ylim=c(-.5,length(Y)+.5))
 
  # Iterations
  for(i in 0:length(X)){
    for(j in 0:length(Y)){
      if(i*j==0){
        # Cercle
        if(i+j>0){
          points(x=i,y=length(Y)-j, cex=14, col=COL[i+j], lwd=4)
          if(i>0) cc=coord(i,length(Y)-j,s,X[i]) else cc=coord(i,length(Y)-j,s,Y[j])
          points(x=cc[1],y=cc[2],  col="white", pch=16, cex=2)
        }
    
      }else{        
        # On calcule la position du point i j pour l'iteration s et on stocke
          yy = coord(i,length(Y)-j,s,Y[j])[2]
          xx = coord(i,length(Y)-j,s,X[i])[1]
          XX[i,j,k]=xx
          YY[i,j,k]=yy
        # On affiche les points deja traces
          lines(XX[i,j,1:k],YY[i,j,1:k], col= meancol(COL[i],COL[j]), lwd=4)
         # On plot les elts
          points(x=XX[i,j,k],y=YY[i,j,k],col="white", pch=16, cex=2)
      }
       
    }
  # On fait les abline
 for(n in 1:length(X)){
  abline(v=XX[n,1,k], lty=2 ,col="grey60")
  abline(h=YY[1,n,k], lty=2 ,col="grey60")
 }
  }
  # Sys.sleep(2)
}

J'avoue par contre que le code n'est pas nickel, un des souci est le tracé du cercle dans la première ligne et la première colonne. J'ai utilisé la fonction points avec pch=16 mais ce n'est pas la bonne méthode car la taille du cercle n'est pas définie de manière dynamique (normalement on souhaite qu'il fasse un rayon de 1)
Cette fonction va donc créer un graphique pour chaque itération, libre à vous ensuite de stocker ces résultats (dans un gif par exemple). Dans l'idéal il faut avancer par pas assez petit (pi/8 c'est le minimum, on constate d'ailleurs que le cercle en bas à droite n'est d'ailleurs pas très circulaire). Il semble aussi nécessaire d'avoir un parcours allant de 0 à 14 pi pour pouvoir observer les différents parcours dans leur intégralité. On a donc au moins 104 graphiques à réaliser.

Aucun commentaire:

Enregistrer un commentaire