Créer un motif en utilisant le modulo

a marqué ce sujet comme résolu.

Bonjour,

Aujourd'hui, j'avais un peu de temps libre au boulot, du coup j'ai créé un petit programme marrant, basé sur des mathématiques de collège (voire de lycée avec le modulo). Pour ceux d'entre vous qui savent bien programmer (ce qui n'est pas mon cas) ou qui font des maths à un niveau supérieur, ca ne va pas être marrant. Pour les autres, on peut passer une demie-heure ensemble :)

Je ne sais pas trop si j'aurais du poster sur le forum science ou programmation. Déplacez le sujet au besoin.

J'en vois certains venir, je vais présenter tout ca de manière très informelle. Je ne pense pas qu'il soit nécessaire de dire qu'on travaille dans R2, etc.

Le principe

Le principe sera de créer une image. Cette image sera constituée d'un cercle, et de segments dans ce cercle. Ces segments, reliants deux points du cercle, s'appellent des cordes. Ces cordes seront choisies à partir de deux paramètres : le nombre de points sur le cercle et un facteur multiplicatif. Vous verez que bien souvent, vous pourrez obtenir de "jolies" images.

Le nombre de points sur le cercle

Il va vous falloir les coordonnées de tous ces points. Le plus simple, c'est d'utiliser un cercle unité. Les points devront être équidistants. Ici, il faudra utiliser un peu de trigonométrie.

Le facteur multiplicatif

C'est ce facteur qui va définir les cordes à tracer. Si on numérote les points de 1 à N, et que l'on considère un point $i$, avec le facteur multiplicatif $f$, il faudra tracer une corde allant du point $i$ au point $i*f$

Une autre information ici. Si l'indice du point final est plus grand que N, c'est à dire qu'il n'y a aucun point avec cet indice, alors il vous faudra retrancher N jusqu'à obtenir un indice existant. Par exemple, si vous avez dix points sur le cercle, et que vous avez un indice multiplicatif qui vaut 3, il vous faudra tracer les cordes allant du point 1 au point 3, du point 2 au point 6, du point 3 au point 9.

La suivante devrait aller du point 4 au point 12, mais il n'y a pas de point 12. Du coup, on va aller au point 12-10=2. Suivant le même principe, il devrait y avoir une corde du point 7 au point 21, mais ce point n'existe pas. Il faudra donc retrancher 10. Mais le point 11 n'existe pas non plus. Du coup, il faut soustraire 10 une fois de plus, et tracer une corde aller du point 7 au point 1.

Cette opération s'appelle "prendre le modulo". On dira que 21 modulo 10 vaut 1. Quand vous allez programmer le code, écrire cette fonction pourrait être un bon exercice, mais elle sera très probablement déjà existante dans le langage que vous choisirez.

Le programme

Je ne suis absolument pas un expert en programmation, et ce que je propose est seulement une suggestion.

  1. Il faut lire les deux paramètres donnés en entrée
  2. Ensuite, il faut créer une liste/un tableau/peu importe où vous allez mettre les coordonnées de tous les points, après les avoir calculées
  3. Il vous faudra aussi créer une autre liste/un autre tableau ou vous allez mettre toutes les cordes à tracer.
  4. La dernière étape sera de tracer ces cordes
  5. Si vous le voulez, vous pouvez ajouter le cercle, pour rendre le tout plus joli.

Quelques exemples

100 points avec un facteur 2

100 points avec un facteur 2

100 points avec un facteur 10

100 points avec un facteur 10

Et un bonus pour la Saint Valentin, 200 points avec un facteur 68

200 points avec un facteur 68

Le faire avec des arcs de cercle ?

ρττ a eu l'ídée, quelques posts plus bas, de remplacer les cordes par des arcs de cercle. Il s'est imposé une condition, c'est que ces arcs de cercles devaient être perpendiculaires au cercle extérieur. Et les résultats sont aussi très jolis.

Pour y arriver, je vais vous l'expliquer pas à pas.

On va commencer par représenter le problème, sur un (beau) dessin.

Arcsdecercle

Que voit-on ici ? Tout d'abord, les deux angles correspondant aux points de départ (d) et d'arrivée (a). Ensuite, un angle, correspondant à l'angle de la bissectrice (m). Les angles t sont les angles (égaux) entre la bissectrice et les angles de départ et d'arrivée.

Ensuite, il y a trois points : C, le centre de l'arc de cercle que l'on veut tracer, et P1 et P2, les points entre lesquels il faut tracer l'arc de cercle.

Il va falloir utiliser la trigonométrie pour calculer :

  • La distance entre C et le centre du cercle initial
  • Le rayon de l'arc de cercle

En plus de ça, il vous faudra faire quelques opérations sur les angles pour déterminer entre quels angles tracer l'arc de cercle. Un dernier point sur lequel il faudra faire attention est de définir la bissectrice pour un angle saillant, et tracer l'arc de cercle pour un angle saillant aussi.

Et voici ce que ça peu donner (image prise d'un poste de ρττ un peu plus bas)

circles

Conclusion

Si vous avez des questions, n'hésitez pas, et n'hésitez pas non plus à poster vos résultats !

Pour ceux d'entre vous qui savent bien programmer (ce qui n'est pas mon cas) ou qui font des maths à un niveau supérieur, ca ne va pas être marrant. Pour les autres, on peut passer une demie-heure ensemble :)

[Rockaround] (http://zestedesavoir.com/forums/sujet/5334/creer-un-motif-en-utilisant-le-modulo/?page=1#p97927)

Ne pars pas dans cet optique. Ton atelier est rigolo, il m'a l'air très sympa à faire et tout le monde peut apprécier la diversité des formes ainsi obtenues, et s'amuser à bricoler ça. Il ne faut pas s'autocensurer et considérer que ce qu'on fait est indigne d'un doctorant en maths/info théorique. Il faut juste s'amuser et bricoler ce qui nous intéresse.

Je n'avais pas vu cette vidéo, mais c'est en effet exactement la même chose. Disons que c'est plus axé pratique ici.

Ca peut donner des idées d'amélioration pour les plus courageux. Au lieu de donner une valeur, en donnant un intervale et un pas, on peut facilement retomber sur ce qu'il y a dans la vidéo.

Quelqu'un saurait si il est possible de généraliser en 3D ?

On pourrait se demander comment généraliser ce genre de figures. Par exemple je suis bien curieux de savoir ce que ça donnerait sur un disque hyperbolique. J'ai pas trop le temps de faire ça, mais si quelqu'un peut proposer des images ça serait sympa :-).

Banni

@Holosmos : Je ne sais pas si c'est ce dont tu parles mais voici en javascript.

Le machin avec des cercles.

circles

Avec des lignes droites.

lines

Si vous voulez tester, le code est ci-dessous. Mettre les deux fichiers dans le même dossier, nommer le js "thejs.js" et ouvrir le html avec un navigateur. Pour modifier les paramètres, ça se passe dans les deux dernières lignes du fichier js. La fonction foo pour des cercles, la fonction bar pour des lignes droites.

Le javascript.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
size = Math.min(canvas.width, canvas.height);

function mod(a, b)
{
  return ((a%b)+b)%b;
}

pi = Math.PI;
tau = 2*pi;

cos = Math.cos;
sin = Math.sin;
tan = Math.tan;

function t(x)
{
  return (x+1)*(size/2);
}

function arc(x, y, r, start, end)
{
  ctx.beginPath();
  ctx.arc(t(x), t(y), r*(size/2), mod(start,tau), mod(end,tau));
  ctx.stroke();
}

function line(x1, y1, x2, y2)
{
  ctx.beginPath();
  ctx.moveTo(t(x1), t(y1));
  ctx.lineTo(t(x2), t(y2));
  ctx.stroke();
}

arc(0, 0, 1, 0, tau);

function circle_between_angles(start, end)
{
  m = (start + end)/2;
  theta = (end - start)/2;
  
  theta = mod(theta, tau);
  
  if (theta > pi)
  {
    theta = tau-theta;
  }
  
  if (theta > pi/2)
  {
    theta = pi - theta;
    m = m + pi;
  }
  
  d = 1/cos(theta);
  x = d*cos(m);
  y = d*sin(m);
  r = tan(theta);
  
  arc(x, y, r, m+pi - (pi/2-theta), m+pi + (pi/2-theta));
}

function line_between_angles(start, end)
{
  line(cos(start), sin(start), cos(end), sin(end));
}

ctx.strokeStyle = "rgba(0,0,0,0.05)";

for (var i = 0; i < 1000; i += 0.2)
{
  circle_between_angles(i, 2*i);
}

Le html.

1
2
3
4
5
6
<HTML>
<BODY>
  <canvas id="canvas" width="600px" height="600px"></canvas>
  <script type="text/javascript" src="thejs.js"></script>
</BODY>
</HTML>

+0 -0

Excusez-moi pour le message totalement raté au-dessus.

Voilà ce que j'obtiens :

Image générée avec Python et simpleSVG

Est-ce que quelqu'un saurait pourquoi mes images sont inclinées de 90° ? Voici le gist.

Merci, génial ce TP. Je pense me pencher sur une interface graphique maintenant ! :-°

@Holosmos : Je ne sais pas si c'est ce dont tu parles mais voici en javascript.

Le machin avec des cercles.

circles

Avec des lignes droites.

lines

Si vous voulez tester, le code est ci-dessous. Mettre les deux fichiers dans le même dossier, nommer le js "thejs.js" et ouvrir le html avec un navigateur. Pour modifier les paramètres, ça se passe dans les deux dernières lignes du fichier js. La fonction foo pour des cercles, la fonction bar pour des lignes droites.

Le javascript.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
size = Math.min(canvas.width, canvas.height);

function t(x)
{
  return (x+1)*(size/2);
}

function arc(x, y, r, start, end)
{
  ctx.beginPath();
  ctx.arc(t(x), t(y), r*(size/2), start, end);
  ctx.stroke();
}

function line(x1, y1, x2, y2)
{
  ctx.beginPath();
  ctx.moveTo(t(x1), t(y1));
  ctx.lineTo(t(x2), t(y2));
  ctx.stroke();
}

pi = Math.PI;
tau = 2*pi;

arc(0, 0, 1, 0, tau);

cos = Math.cos;
sin = Math.sin;
tan = Math.tan;

function foo(start, end)
{
  start = start % tau;
  end = end % tau;
  
  theta = Math.abs(end-start);
  
  if (theta > pi)
  {
    end += tau;
    theta = tau - theta;
  }
  
  m = (start+end)/2;
  
  d = 1/cos(theta/2);
  x = d*cos(m);
  y = d*sin(m);
  r = tan(theta/2);
  
  arc(x, y, r, m+pi-(pi-theta)/2, m+pi+(pi-theta)/2);
}

function bar(start, end)
{
  line(cos(start), sin(start), cos(end), sin(end));
}

ctx.strokeStyle = "rgba(0,0,0,0.08)";

for (var i = 0; i < 70; i += 0.03)
  foo(i, 5*i);

Le html.

1
2
3
4
5
6
<HTML>
<BODY>
  <canvas id="canvas" width="600px" height="600px"></canvas>
  <script type="text/javascript" src="thejs.js"></script>
</BODY>
</HTML>

ρττ

Je comprends pas bien ce que tu as fait. Tu peux expliciter ?

Banni

J'ai commencé par dessiner un grand cercle. Ensuite, on fait tourner un point A sur ce cercle, et un autre point B à une vitesse double (ou autre). À intervalle régulier, on trace un cercle perpendiculaire au grand cercle, passant par A et B. Voici les premiers cercles tracés pour une vitesse double et un pas de 0.2 radian.

début

Si à la place de tracer des cercles perpendiculaires on trace des droites, ça revient à faire le truc initial qui donne la cardioïde pour une vitesse double.

Je ne suis pas certain que c'est ce que tu aies voulu dire cependant.

+0 -0

Bon bah l'interface graphique commence à ressembler à quelque chose ! La preview est en direct, donc en restant cliqué sur les SpinButtons on peut voir la figure s'animer !

Trekke, un logiciel pour visualiser en direct les figures !

@ρττ J'aimerais ajouter la possibilité de faire avec les cercles, puis-je m'inspirer de ton algorithme ? Merci !

Un autre truc qui pourrait rendre bien (peut-être, je n'ai pas essayé), c'est d'avoir des cercles concentriques avec des modulos et facteurs indépendants. Et pour les cercles exterieurs, le trait serait tronqué en en pénétrant un autre.

Je vois deux manières de le faire. La première, c'est en commencant par les couches externes, et en dessinnant celles internes "par dessus", dans ton cas, en mettant un grand disque noir qui cacherait les portions de trait non voulues.

L'autre, plus intéressante mathématiquement, c'est en calculant les points d'intersection d'une droite et d'un cercle.

Bravo pour ton avancement !

Banni

@ρττ J'aimerais ajouter la possibilité de faire avec les cercles, puis-je m'inspirer de ton algorithme ? Merci !

Oui, bien sûr. J'ai nettoyé le code un peu. L'idée est de transformer la description des deux points sur le cercle entre lesquels tracer. On nous donne une description sous la forme de deux angles (start, end), et on transforme cette description en une autre, sous la forme (m,θ) avec {m-θ, m+θ} = {start, end}. L'angle m est un milieu de start et end, et l'angle θ est la distance à parcourir des deux côtés de ce milieu. On joue ensuite avec les symétries (par exemple (m,θ) est équivalent à (m,-θ)) pour trouver une représentation avec θ positif et le plus petit possible, afin de tracer l'arc de cercle dans le bon sens (on le trace uniquement à l'intérieur du disque).

PS :

Cette image sera constituée d'un cercle, et de segments dans ce cercle.

Juste comme ça, un mot désignant ces segments est « corde ».

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

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