« Programmation objet et géométrie/Les lignes droites de canvas » : différence entre les versions

Un livre de Wikilivres.
Contenu supprimé Contenu ajouté
Ligne 200 : Ligne 200 :
L'utilisation de boucles JavaScript permet de construire des polygones très complexes, comme par exemple le [[w:Flocon de von Koch|flocon de Von Koch]]. Ici on va plutôt dessiner l'[[w:Arbre de Stern-Brocot|arbre de Stern-Brocot]]. Le dessin d'un arbre se fait par récurrence: Le principe est de dessiner la branche gauche et la branche droite (des segments) puis de rajouter à leur extrémité un (sous-)arbre. Pour calculer les coordonnées des extrémités des segments, on utilise le développement en fraction continue d'une fraction:
L'utilisation de boucles JavaScript permet de construire des polygones très complexes, comme par exemple le [[w:Flocon de von Koch|flocon de Von Koch]]. Ici on va plutôt dessiner l'[[w:Arbre de Stern-Brocot|arbre de Stern-Brocot]]. Le dessin d'un arbre se fait par récurrence: Le principe est de dessiner la branche gauche et la branche droite (des segments) puis de rajouter à leur extrémité un (sous-)arbre. Pour calculer les coordonnées des extrémités des segments, on utilise le développement en fraction continue d'une fraction:


Si le développement en fraction continue est ''[a1,a2,a3,...,an]'' alors
Si le développement en [[w:Fraction continue|fraction continue]] est ''[a1,a2,a3,...,an]'' alors
# l'une des branches partant de cette fraction va vers la fraction ''[a1,a2,a3,...,an+1]''; on appellera ''fils'' de la fraction cette nouvelle fraction;
# l'une des branches partant de cette fraction va vers la fraction ''[a1,a2,a3,...,an+1]''; on appellera ''fils'' de la fraction cette nouvelle fraction;
# l'autre branche va vers la fraction ''fille'', de développement ''[a1,a2,a3,...,an-1,2]''
# l'autre branche va vers la fraction ''fille'', de développement ''[a1,a2,a3,...,an-1,2]''.

L'algorithme de tracé de l'arbre peut donc s'écrire

# On part d'une fraction, représentée par le point d'abscisse sa valeur et d'ordonnée l'inverse de son dénominateur (par convention)
# On tire un segment vers son fils;
# On tire un autre segment vers sa fille;
# On trace l'arbre du fils;
# On trace l'arbre de la fille.

La condition pour finir la récurrence est la taille du dénominateur: S'il est trop grand (en pratique, supérieur ou égal à 400) la fraction est proche de la [[w:Canopée|canopée]] de l'[[w:Arbre binaire|arbre]] (l'axe des abscisses) et on s'arrête.

Version du 11 janvier 2012 à 18:56

Pour tracer un segment, il suffit de fournir les coordonnées de son extrémité (donc 2 nombres), du moment que c'est après beginPath() et avant stroke(). Les segments sont donc plus faciles à tracer que les courbes de Bézier, et plus rapides à tracer aussi. En plus, en utilisant moveTo() on peut tracer des segments discontinus (ou des graduations). La principale question est où est l'origine du segment?. En fait elle est mémorisée comme la position actuelle du pinceau, définie par le dernier moveTo() ou le dernier lineTo() appliqué. Ceci permet de tracer des polygones ou de représenter graphiquement des fonctions.

Exemples de base

Segment

Segment en traits pleins

L'algorithme est le suivant:

  1. déclarer le début d'un trait de pinceau (tremper le pinceau dans la peinture), avec beginPath();
  2. poser le pinceau au début du trait, avec moveTo();
  3. tirer le trait jusqu'au point d'arrivée, avec lineTo();
  4. lever le pinceau, avec stroke().

Voici un exemple:

<html>
<style type="text/css">
      canvas { border: 4px solid brown; background: #FFFFFF }
</style>
<body>
<canvas id="cadre" width="400" height="200">
<script>
var chevalet=document.getElementById('cadre');
var pinceau=chevalet.getContext('2d');
pinceau.beginPath();
pinceau.moveTo(50,100);
pinceau.lineTo(350,100);
pinceau.stroke();
</script>
</canvas>
<br/>
</body>
</html>

Segment en pointillés

Avec une boucle

On peut faire un segment en pointillés avec une boucle, en alternant les traits tracés (avec lineTo()) et les traits non tracés (avec moveTo()):

<html>
<style type="text/css">
      canvas { border: 4px solid brown; background: #FFFFFF }
</style>
<body>
<canvas id="cadre" width="400" height="200">
<script>
var chevalet=document.getElementById('cadre');
var pinceau=chevalet.getContext('2d');
pinceau.beginPath();
pinceau.moveTo(50,100);
for(n=1;n<=30;n+=2){
	pinceau.lineTo(50+n*10,100);
	pinceau.moveTo(60+n*10,100);
}
pinceau.stroke();
</script>
</canvas>
<br/>
</body>
</html>

Une variante permet d'ajouter des graduations (en faisant des pointillés perpendiculaires au segment).

Avec un dégradé

<html>
<style type="text/css">
      canvas { border: 4px solid brown; background: #FFFFFF }
</style>
<body>
<canvas id="cadre" width="400" height="200">
<script>
var chevalet=document.getElementById('cadre');
var pinceau=chevalet.getContext('2d');
var pointille=pinceau.createLinearGradient(50,100,350,100);
for(n=0;n<=15;n++){
	pointille.addColorStop(n/16,"Black");
	pointille.addColorStop((n+0.499)/16,"Black");
	pointille.addColorStop((n+0.501)/16,"White");
	pointille.addColorStop((n+0.999)/16,"White");
}
pinceau.strokeStyle=pointille;
pinceau.beginPath();
pinceau.moveTo(50,100);
pinceau.lineTo(350,100);
pinceau.stroke();
</script>
</canvas>
<br/>
</body>
</html>

Cette variante, qui nécessite aussi une boucle (pour fabriquer le dégradé), présente l'avantage de s'appliquer aussi à des courbes.

Triangle

Pour tracer un polygone, il faut faire un lineTo() pour chaque côté (en n'oubliant pas de revenir au point de départ):

<html>
<style type="text/css">
      canvas { border: 4px solid brown; background: #FFFFFF }
</style>
<body>
<canvas id="cadre" width="400" height="200">
<script>
var chevalet=document.getElementById('cadre');
var pinceau=chevalet.getContext('2d');
pinceau.beginPath();
pinceau.moveTo(50,150);
pinceau.lineTo(350,150);
pinceau.lineTo(200,50);
pinceau.lineTo(50,150);//pour refermer le triangle
pinceau.stroke();
</script>
</canvas>
<br/>
</body>
</html>

Une variante consiste à remplir le triangle au lieu de seulement dessiner ses côtés, et dans ce cas le dernier côté n'est pas nécessaire:

<html>
<style type="text/css">
      canvas { border: 4px solid brown; background: #FFFFFF }
</style>
<body>
<canvas id="cadre" width="400" height="200">
<script>
var chevalet=document.getElementById('cadre');
var pinceau=chevalet.getContext('2d');
pinceau.moveTo(50,150);
pinceau.lineTo(350,150);
pinceau.lineTo(200,50);
pinceau.fill();
</script>
</canvas>
<br/>
</body>
</html>

Fonction

Pour représenter graphiquement une fonction, il suffit de dessiner un polygone ayant beaucoup de côtés assez petits pour donner l'illusion d'une courbe. Par exemple, pour dessiner une parabole on peut faire comme ceci:

<html>
<style type="text/css">
      canvas { border: 4px solid brown; background: #FFFFFF }
</style>
<body>
<canvas id="cadre" width="400" height="400">
<script>
var chevalet=document.getElementById('cadre');
var pinceau=chevalet.getContext('2d');
pinceau.strokeStyle="Red";
pinceau.beginPath();
pinceau.moveTo(0,0);
for(x=0;x<=400;x++){
	pinceau.lineTo(x,400-Math.pow(x-200,2)/100);
}
pinceau.stroke();
</script>
</canvas>
<br/>
</body>
</html>

On peut ajouter des axes gradués avec d'autres boucles:

pinceau.strokeStyle="Blue";
pinceau.beginPath();
pinceau.moveTo(0,400);
pinceau.lineTo(400,400);
for(x=0;x<=400;x+=20){
	pinceau.moveTo(x,400);
	pinceau.lineTo(x,395);
}
pinceau.stroke();

Et quelque chose d'analogue pour l'axe des ordonnées (attention à ne pas oublier qu'il est à l'envers).

Arbre de Stern-Brocot

L'utilisation de boucles JavaScript permet de construire des polygones très complexes, comme par exemple le flocon de Von Koch. Ici on va plutôt dessiner l'arbre de Stern-Brocot. Le dessin d'un arbre se fait par récurrence: Le principe est de dessiner la branche gauche et la branche droite (des segments) puis de rajouter à leur extrémité un (sous-)arbre. Pour calculer les coordonnées des extrémités des segments, on utilise le développement en fraction continue d'une fraction:

Si le développement en fraction continue est [a1,a2,a3,...,an] alors

  1. l'une des branches partant de cette fraction va vers la fraction [a1,a2,a3,...,an+1]; on appellera fils de la fraction cette nouvelle fraction;
  2. l'autre branche va vers la fraction fille, de développement [a1,a2,a3,...,an-1,2].

L'algorithme de tracé de l'arbre peut donc s'écrire

  1. On part d'une fraction, représentée par le point d'abscisse sa valeur et d'ordonnée l'inverse de son dénominateur (par convention)
  2. On tire un segment vers son fils;
  3. On tire un autre segment vers sa fille;
  4. On trace l'arbre du fils;
  5. On trace l'arbre de la fille.

La condition pour finir la récurrence est la taille du dénominateur: S'il est trop grand (en pratique, supérieur ou égal à 400) la fraction est proche de la canopée de l'arbre (l'axe des abscisses) et on s'arrête.