Asymptote : Démarrage « rapide »

Christophe GROSPELLIER

Asymptote est un langage de description de graphismes vectoriels, particulièrement adapté pour le dessin technique.
Entre autres avantages, Asymptote, possède une syntaxe proche de celle de C++, interagit naturellement avec , et gère les nombres flottants.

Cette documentation est avant tout destinée à ceux qui voudraient débuter avec Asymptote. Commentez

- Titre : Asymptote : Démarrage « rapide »

- Auteur : Christophe GROSPELLIER

- Parution : 2 décembre 2014

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2014 Christophe GROSPELLIER. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Installation

- II. Les différentes compilations

- II-A. Options de compilation

- II-B. Compilation à l'intérieur d'un fichier .tex

- III. Quelques généralités

- III-A. Unités, dimensions de la figure

- III-B. Quelques commandes de dessin

- IV. Transformations

- V. Quelques figures basiques

- VI. Quelques modules

- VI-A. markers

- VI-B. geometry

- VI-B-1. De nouveaux types d'objets sont définis

- VI-B-2. De nouvelles transformations sont définies

- VI-B-3. geometry introduit aussi des fonctions de marquage

- VI-C. trembling

- VI-D. graph

- VI-D-1. Axes et repères

- VI-D-2. Représentations de fonctions

- VI-D-3. Extension graph_pi

- VI-E. animation

- VI-E-1. Création d'animations autonomes

- VI-E-2. Inclure une animation externe dans un fichier .tex

- VI-E-3. Inclure le code dans un fichier .tex

- VII. Remerciements developpez

I - Installation

Tout d'abord, une distribution minimale doit être installée. Asymptote fait partie des principales distributions .

Pour savoir si Asymptote est installé, taper asy dans un terminal, vous verrez apparaître le numéro de version si c'est le cas. Taper quit pour sortir du mode interactif.

Sinon, il faut l'installer.

Ensuite, je ne traiterai pas l'installation sur Microsoft Windows ou MacOS X, ne connaissant pas (ou plus) ces systèmes. Vous trouverez tous les renseignements dans la documentation officielle, ou sur asymptote.sourceforge.net.

Sur Unix, il existe un paquet Asymptote sur la plupart des distributions, à installer par votre gestionnaire de paquets, mais cette version est parfois loin d'être à jour…

Pour avoir une version récente du logiciel, une compilation des sources pour installer la version svn est un bon choix.

Voici comment faire sur (X)Ubuntu 14.04.

Attention, il faut désinstaller toute version préalablement installée.

Si Asymptote a été installé en même temps que TeX Live, par le script install-tl par exemple, il faut le supprimer à l'aide de tlmgr :

sudo tlmgr remove --force asymptote

1. Les paquets nécessaires

sudo apt-get install build-essential subversion flex texinfo autoconf
zlib1g-dev bison freeglut3-dev cdbs libfftw3-dev libreadline6-dev
libncurses5-dev libgsl0-dev libsigsegv-dev imagemagick libosmesa6-dev

2. Récupérer les sources

mkdir asymptote_svn
cd asymptote_svn
svn co http://svn.code.sf.net/p/asymptote/code/trunk/asymptote

3. Compiler

cd asymptote
./autogen.sh
wget http://hboehm.info/gc/gc_source/gc-7.4.0.tar.gz
wget http://hboehm.info/gc/gc_source/libatomic_ops-7.4.0.tar.gz
./configure
make all
sudo make install

4. Pour les mises à jour, c'est

cd asymptote_svn/asymptote
svn update
sudo make install

Remarques :

Si vous êtes sous Gnome, vous avez l'éditeur de texte Gedit déjà installé. Vous trouverez tout ce qu'il faut pour l'utiliser avec Asymptote à cette adresse : cgmaths.fr/Atelier/Asymptote/OutilsGedit.html.

Un équivalent sur Windows est Notepad++, pour son utilisation, vous pouvez vous rendre dans la rubrique « Installation d'Asymptote » sur le forum asy.gmaths.net/forum.

II - Les différentes compilations

II-A - Options de compilation

Les options de compilation sont très nombreuses (voir la documentation officielle). Nous ne nous intéresserons ici qu'à quelques-unes.

Créez un fichier texte,nommez-le exemple.asy et collez-y un des codes d'exemple ci-après (pas le premier !). Enregistrez le document.

La compilation de ce code se fait en ligne de commande, avec les options par défaut, par

asy exemple.asy

Quelques options intéressantes :

-V : utile notamment pour les figures 3D, la figure s'ouvre dans une fenêtre de rendu OpenGL. La figure est alors manipulable, et un double-clique droit permet d'accéder à différents paramètres ;

-noV : pour que le PDF (ou eps, ou autre) soit créé directement. ;

-f : pour préciser le format de sortie (PDF…). Équivalent à settings.outformat='pdf'; (ou autre) dans le code de la figure ;

-prc : pour les figures 3D : format prc d'Adobe dans le PDF. Le PDF ne sera visualisable qu'avec une version suffisamment récente d'Acrobat Reader. La figure sera manipulable et on aura accès à un menu 3D ;

-noprc : pas de format prc. La figure peut être visualisée dans n'importe quel lecteur PDF. Équivalent à settings.prc=false; dans le code de la figure ;

-render n : rendu des figures 3D (n pixels/bp). Équivalent à settings.render=n; dans le code de la figure.

Exemple de compilation

asy -noV -noprc -f pdf exemple.asy

La figure produite peut être incluse dans un document .tex par un \includegraphics.

II-B - Compilation à l'intérieur d'un fichier .tex

Il sera vu le minimum ici. Pour davantage d'explications, voir la documentation officielle.

- Méthode « classique »
Il faut ajouter au début du document la ligne : \usepackage{asymptote}
Le code de la figure doit être compris entre les balises \begin{asy} et \end{asy}.

\begin{asy}[width=\the\linewidth,inline=true]
…
\end{asy}

- Ci-dessus sont précisées en options la largeur et inline=true qui permet d'utiliser des symboles définis en dehors de l'environnement asy.
La compilation se fait en trois temps :

1. Une compilation latex (ou pdflatex). Un fichier .asy par figure est créé ;Une compilation asy.

2. Pour compiler toutes les figures, si le fichier tex s'appelle exemple.tex :

asy exemple-*.asy

Les figures sont créées au format eps pour une compilation , ou au format PDF pour une compilation pdflatex ;

3. Une nouvelle compilation latex (ou pdflatex).

- Latexmk
Toutefois, il est dorénavant possible de tout compiler en une fois grâce à une version suffisamment récente du script latexmk. Ce script est peut-être déjà installé sur votre distribution ou alors il est téléchargeable sur le CTAN : www.ctan.org/tex-archive/support/latexmk/.
Une fois installé, il faut créer un fichier nommé latexmkrc contenant :

sub asy {return system("asy '$_[0]'");}
add_cus_dep("asy","eps",0,"asy");
add_cus_dep("asy","pdf",0,"asy");
add_cus_dep("asy","tex",0,"asy");

Ce fichier peut être placé dans le même répertoire que le fichier tex.Note : sur linux, placer ce fichier une fois pour toutes dans le répertoire personnel en le nommant « latexmkrc ».

Attention, perl doit être installé sur l'ordinateur.

Ensuite une seule compilation suffit :

latexmk -pdf exemple.tex

créera un PDF (seules les figures ayant été modifiées depuis la dernière compilation seront compilées).

Remarque :Pour que les figures soient créées dans un sous-dossier figures, il faut ajouter dans le préambule du document tex :

\def\asydir{figures}

et remplacer la première ligne du fichier latexmkrc par : sub asy {return system("asy -o figures/ '$_[0]'");}

- Package asypictureB
Nouveau package, très bon substitut à latexmk, mais ne fonctionne pas (encore) pour la 3D. Il suffit de l'importer dans le préambule à la place du package asymptote. Une seule compilation suffit : www.ctan.org/pkg/asypictureb.

III - Quelques généralités

Une bonne partie de la documentation officielle sera reprise ici. Les exemples de cette partie pourront être compilés simplement par : asy mafigure.asy (pour de l'eps) ou asy -f pdf mafigure.asy (pour du PDF).

III-A - Unités, dimensions de la figure

Contrairement à des logiciels comme GeoGebra, on ne peut pas placer de points « au hasard », tout se passe dans un repère : les points sont placés par leurs coordonnées. Ces coordonnées, appelées pairs sont en « big points » PostScript (1 bp = 1/72 inch).

Ainsi, avec le code 1, on ne verra rien ! la figure étant beaucoup trop petite…

Les codes 2 et 3 produiront la même figure, à savoir un segment de longueur

Code 1

pair A=(0,0), B=(2,2);
draw(A--B);

Code 2

pair A=(0,0), B=(2cm,2cm);
draw(A--B);

Code 3

unitsize(1cm);
pair A=(0,0), B=(2,2);
draw(A--B);

Remarques :

- L'« unité » peut être différente pour les abscisses et les ordonnées : unitsize(1cm,1.5cm);

- On peut aussi spécifier la taille finale de la figure produite :
Pour une figure de 3 cm de largeur, on précisera : size(3cm,0); (0 pour ne pas avoir à spécifier la hauteur, la mise à l'échelle étant automatique.)La taille peut être spécifiée en bp, pt, cm, mm ou inches.

- -- est un connecteur qui joint les points par un segment. Les autres connecteurs sont .. , :: et --- (voir la documentation officielle).

Code 4

size(0,1cm);
draw((0,0)--(1,.5)--(2,0)--(3,.5),blue);

Code 5

size(0,1cm);
draw((0,0)..(1,.5)..(2,0)..(3,.5),blue);

III-B - Quelques commandes de dessin

1. draw

void draw(picture pic=currentpicture, Label L="", path g,
align align=NoAlign, pen p=currentpen,
arrowbar arrow=None, arrowbar bar=None, margin margin=NoMargin,
Label legend="", marker marker=nomarker)

Voyons en détail quelques options (pour les autres, voir la documentation officielle) :

- picture pic=currentpicture : dessine dans l'image pic, par défaut currentpicture ;

- Label L="" : permet de placer un texte ;

- path g : le chemin à dessiner ;

- pen p=currentpen : le stylo à utiliser ;

- arrowbar arrow=None : les flèches. Les valeurs possibles sont : None, Blank, BeginArrow, MidArrow, Arrow, et Arrows (flèches aux deux extrémités). On peut de plus préciser le type de tête (DefaultHead, SimpleHead, HookHead, TeXHead), la taille, l'angle de la tête, le type de remplissage (FillDraw, Fill, NoFill, UnFill, Draw) et la position relative.
Il y a aussi certaines versions modifiées (taille et angle) : BeginArcArrow, MidArcArrow, ArcArrow, et ArcArrows ;

- arrowbar bar=None : les barres aux extrémités. Les valeurs possibles sont : None, BeginBar, Bar et Bars. On peut préciser la taille.

Code 6

size(5cm,0);
path chemin=(0,0)..(1,.5)..(2,0)..(3,.5);
draw("Chemin",chemin,blue,Arrow);
draw(shift(0,-.6)*chemin,green,BeginArrow(5mm,Draw),Bar);
draw(shift(0,-1.2)*chemin,.8*red,Arrows(TeXHead));
draw(shift(0,-1.8)*chemin,bp+magenta,MidArrow(HookHead,Fill(blue)),Bars(2mm));

- fill

void fill(picture pic=currentpicture, path g, pen p=currentpen)
void filldraw(picture pic=currentpicture, path g,
pen fillpen=currentpen,pen drawpen=currentpen)

Ces deux fonctions servent à remplir les chemins cycliques :

Code 7

size(5cm,0);
path rec=(0,0)--(1,0)--(1,.5)--(0,.5)--cycle;
fill(rec,lightyellow);

Code 8

size(5cm,0);path r=(0,0)--(1,0)--(1,.5)--(0,.5)--cycle;
filldraw(r,fillpen=lightyellow,
drawpen=2bp+.8green);

- label

void label(picture pic=currentpicture, Label L, pair position,
align align=NoAlign, pen p=nullpen, filltype filltype=NoFill)

Cette fonction permet de placer un texte au point de coordonnées position. Le texte peut être une simple chaîne de caractères (respectant la syntaxe ) ou une structure plus complexe obtenue par une fonction du type (il y en a d'autres, voir la documentation officielle) :

Label Label(string s="", pair position, align align=NoAlign,
pen p=nullpen, embed embed=Rotate, filltype filltype=NoFill)

align peut prendre n'importe quel pair comme valeurs. Certaines sont prédéfinies : N, S, E, W, NE, NW, SE, SW, LeftSide, RightSide, Center.

Voir les exemples qui suivent pour les différents paramètres.

Code 9

size(5cm,0);
pair A=(0,0);
dot(A);
label("$N$",A,5*N);
label("$S$",A,5*S);
label("$E$",A,5*E);
label("$W$",A,5*W);

Code 10

size(5cm);
pair A=(0,0), B=(2,1);
path seg=A--B;
label("$A$",A,W);
label("$B$",B,E);
draw("$\sqrt{5}$",seg,
linewidth(bp));

Code 11

size(5cm);
pair A=(0,0), B=(2,1);
path seg=A--B;
label("$A$",A,dir(A-B));
label("$B$",B,dir(B-A));
draw(Label("$\sqrt{5}$",
align=LeftSide),
seg,bp+deepgreen+dashed);

Code 12

size(5cm);
pair A=(0,0), B=(2,1);
path seg=A--B;
label("$A$",A,dir(A-B));
label("$B$",B,dir(B-A));
draw(Label("$\sqrt{5}$",
Rotate(dir(seg)),
align=LeftSide),
seg,blue);

Code 13

size(5cm);
pair A=(0,0), B=(2,1);
path seg=A--B;
label("$A$",A,dir(A-B));
label("$B$",B,dir(B-A));
draw(Label("$\sqrt{5}$",
Rotate(dir(seg)),
align=S),
seg,longdashdotted);

Code 14

size(5cm);
pair A=(0,0), B=(2,1);
path seg=A--B;
label("$A$",A,dir(A-B));
label("$B$",B,dir(B-A));
draw(Label("$\sqrt{5}$",
Rotate(dir(seg)),
align=LeftSide,
position=Relative(.75)),
seg,bp+brown+dotted);

Code 15

size(5cm);
pair A=(0,0), B=(1,0);
path seg=A--B;
label("$x'$",A,N);
label("$x$",B,N);
draw(Label("abscisses",
filltype=Fill(orange)),
seg,bp+deepcyan);

Code 16

unitsize(1cm);
pair A=(0,0), B=(4,0);
path seg=A--B;
label("$A$",A,W);
label("$B$",B,E);
draw(Label("$4$~cm",
align=Center,
filltype=UnFill),
seg,bp+fuchsia,
Arrows(SimpleHead),Bars);

Code 17

size(5cm,0);
import fontsize;
defaultpen(fontsize(10pt));
pair A=(0,0), B=(1,0);
draw(A--B,linewidth(bp));
label("$A$",A,W,.8blue);
pen f20=fontsize(20pt);
label("$B$",B,E,f20+brown);

Remarque

Dans les exemples, B-A peut être interprété comme le vecteur AB.

On peut réaliser différentes opérations sur les pairs. Par exemple pair I=(A+B)/2; donnera le milieu I de [AB] (équivalent à pair I=midpoint(A—B);).

IV - Transformations

Présentation rapide des transformations d'Asymptote. Pour la première, pas besoin de figure : transform identity();

Ensuite :

transform shift(pair z);
transform shift(real x,real y);

Code 18

size(7cm);
pair A=(0,0), B=(3,1);
path c=unitcircle;
path c1=shift(3,1)*c;
draw("$\mathcal{C}$",c);
draw("$\mathcal{C'}$",c1,bp+purple);
draw("$\overrightarrow{AB}$",
A--B,blue,Arrow);
dot("$A$",A,SW);
dot("$B$",B,SE);

Code 19

size(4cm);
pair A=(0,0);
path c=unitcircle;
path c1=xscale(.5)*c;
path c2=yscale(.5)*c;
draw("$\mathcal{C}$",c);
draw("$\mathcal{C'}$",c1,E,bp+purple);
draw("$\mathcal{C''}$",c2,E,bp+royalblue);
dot("$A$",A,SW);

transform xscale(real x);

transform yscale(real y);

Code 20

size(4cm);
pair A=(0,0);
path c=unitcircle;
path c1=scale(.5)*c;
draw(scale(2)*"$\mathcal{C}$",c);
draw("$\mathcal{C'}$",c1,bp+purple);
dot("$A$",A,SW);

Code 21

size(7cm);
pair A=(0,0);
path c=unitcircle;
path c1=scale(2,.5)*c;
draw("$\mathcal{C}$",c);
draw("$\mathcal{C'}$",c1,bp+purple);
dot("$A$",A,SW);

transform slant(real s);

envoie le pair (x,y) sur (x+s*y,y)

transform rotate(real angle,pair z=(0,0));

Code 22

size(7cm);
pair A=(0,0);
path c=unitcircle;
path c1=slant(1.5)*c;
draw("$\mathcal{C}$",c,NW);
draw("$\mathcal{C'}$",c1,SE,bp+purple);
dot("$A$",A,SW);

Code 23

import markers; // pour utiliser markangle
size(7cm);
pair A=(0,0), B=(-1.5,-1);
transform rot=rotate(108,B);
path c=unitcircle;
pair A1=rot*A;
path c1=rot*c;
draw("$\mathcal{C}$",c,NW);
draw("$\mathcal{C'}$",c1,S,bp+purple);
draw(A--B--A1,dashed);
markangle("$\frac{3\pi}{5}$",A,B,A1,
radius=6mm,Arrow);
dot("$A$",A,SE);dot("$A'$",A1,SW);
dot("$B$",B,SE);

transform reflect(pair a, pair b);

Code 24

size(6cm);

pair A=(0,0), B=(.7,-1.3), C=(.7,1.3);

path c=unitcircle;
path c1=reflect(B,C)*c;
pair A1=reflect(B,C)*A;

draw("$\mathcal{C}$",c,NW);
draw("$\mathcal{C'}$",c1,NE,bp+purple);
draw(Label("$\mathcal{D}$",EndPoint),B--C,SW,.8red);
dot("$A$",A,SW);dot("$A'$",A1,SE,purple);

V - Quelques figures basiques

Voici quelques figures permettant de parcourir une partie des outils de base d'Asymptote.

Code 25

size(5cm,0);

pair A=(0,0);
path c=circle(A,1.5);
pair B=relpoint(c,0), C=relpoint(c,.15),
D=relpoint(c,.65);
path a=subpath(c,reltime(c,.15),reltime(c,.65));
path b=subpath(c,3,4);

draw(c);
draw(a,bp+red);
draw(b,bp+green);
dot(c,linewidth(bp),UnFill);
dot("$A$",A,SW);dot("$B$",B,E,blue);
dot("$C$",C,NE,blue);dot("$D$",D,SW,blue);

Code 26

size(7cm,0);

pair A=(0,0), B=(-1.5,1), C=(1.5,1.5),
D=(2.5,.5), pE=(2.5,-.5);
path seg1=A--C, seg2=B--D;
pair inter=intersectionpoint(seg1,seg2);
pair ext=extension(B,C,D,pE);
dot("intersectionpoint",inter,1.5*S,5bp+red);
dot("extension",ext,SE,5bp+blue);

draw(seg1,linewidth(bp));
draw(seg2,linewidth(bp));
draw(B--interp(B,C,2),dashed);
draw(pE--interp(pE,D,2.5),dashed);
dot("$A$",A,SW);dot("$B$",B,NW);
dot("$C$",C,N);dot("$D$",D,NE);
dot("$E$",pE,E);

Code 27

size(7cm,0);

pair A=(0,0), B=(-2.5,-1), C=(3,.5);
path c=circle(A,1.5);
path d=interp(B,C,-.2)--interp(B,C,1.2);

draw(c,bp+heavyred);draw(d,bp+heavymagenta);
// tableau de pairs
pair[] inter=intersectionpoints(c,d);
for(int i=0; i<inter.length; ++i) {
dot("inter"+string(i),inter[i],S,5bp+blue);
}
dot("$A$",A,NW);dot("$B$",B,NW);dot("$C$",C,N);

Code 28

import patterns; // hachures
size(6cm,0);

pair A=(0,0), B=(3,0), C=(1,2);
path tri=A--B--C--cycle;
path c=circle(B,1.5);
pair[] P=intersectionpoints(tri,c);
path intersec=B--P[0]--arc(B,P[0],P[1],CW)--cycle;
// CW : ClockWise, CCW : Counter-ClockWise (défaut)
draw(tri);
draw(c);
// Définition des hachures :
add("hachure",hatch(3mm,NE,1.5mm+royalblue));
filldraw(intersec,pattern("hachure"));
dot("$P[0]$",P[0],SW);dot("$P[1]$",P[1],N);
dot("$A$",A,dir(C--A,B--A)); //direction de la bissectrice
dot("$B$",B,dir(C--B,A--B));dot("$C$",C,N);

Code 29

size(6cm);
pair A=(0,0), B=(1,0), C=(1,.5), D=(1,-.5),
pE=(3,.5), F=(3,-.5), G=(3,0), H=(4,0);
draw(A--B--C--pE--G--H);
draw(A—B--D--F--G--H);

draw("$R_1$",box,(2,.5),xmargin=3mm,ymargin=0,UnFill);
draw("$R_1$",box,(2,.5),xmargin=3mm,ymargin=0);

draw("$R_2$",box,(2,-.5),xmargin=3mm,ymargin=0,UnFill);
draw("$R_2$",box,(2,-.5),xmargin=3mm,ymargin=0);

Code 30

unitsize(1cm);

defaultpen(fontsize(10pt));
usepackage("amsmath");
usepackage("amsfonts");
usepackage("amssymb");

pair z0=(-1.75,0), z1=(1.75,0), z2=(0,1), z3=(0,-1);

object boite1=draw("$x \geqslant -3$",box,z2,invisible);
object boite2=draw("$\times (-2)$",ellipse,z0);
object boite3=draw("$\times (-2)$",ellipse,z1);
object boite4=draw("$\quad\dots\quad$",box,z3,invisible);
add(new void(picture pic, transform t) {
draw(pic,point(boite1,W,t){W}..{S}point(boite2,N,t));
draw(pic,point(boite2,S,t){S}..{E}point(boite4,NW,t),Arrow);
draw(pic,point(boite1,E,t){E}..{S}point(boite3,N,t));
draw(pic,point(boite3,S,t){S}..{W}point(boite4,NE,t),Arrow);
});

Code 31

size(4cm);
transform r=reflect((0,0),(0,1));
// Fonction pour tracer les boules
void boule(Label L="", pair a, pen p=currentpen, pen fillpen=nullpen) {
filldraw(shift(a)*unitcircle,fillpen,p);
label(scale(1.5)*L,a);
}
// Urne
pair A=(3.1,0), B=(3.1,4), C=(2.1,5), D=(1.1,6), pE=(1.1,7), F=(2.1,8), G=(3.1,8);
pair H=r*A;
path demi=G--F{dir(180)}..{dir(270)}pE--D{dir(270)}..{dir(0)}C{dir(0)}..{dir(-90)}B--A;
path demi2=r*demi;
draw(demi^^demi2,linewidth(3bp));draw(A--H,linewidth(3bp));
// Boules
boule("$5$",(0,1.1),linewidth(bp),gray+opacity(.7));
boule("$1$",(-2,1.1),linewidth(bp));
boule("$4$",(2,1.1),linewidth(bp));
boule("$3$",(-1,2.85),linewidth(bp),gray+opacity(.7));
boule("$1$",(1,2.85),linewidth(bp));

Code 32

import markers;
size(4cm);
real ang=50;
pair A=(0,0), B=(3,0);
transform r=rotate(ang,A);
pair C=r*B;
path seg1=A--B;
path seg2=r*seg1;
draw(seg1^^seg2,linewidth(bp));
// fonction format, voir ci-contre
markangle(format("$%f^\circ$",ang),
B,A,C,radius=6mm);
label("$A$",A,SW);
label("$B$",B,SE);
label("$C$",C,NE);

Code 33

import labelpath;
size(0,3.5cm);
path p=(0,0)..(2,-1)..(2.5,-.5)..(3,-.75);
labelpath("\Large Fin de la pr\'esentation des outils de base",p,purple);
draw(p,heavygreen);

VI - Quelques modules

Je ne présenterai ici que les modules que j'utilise et donc, que je connais un peu…

Pour les autres (graph3, grid3, interpolate, etc.), voir la documentation officielle, et les galeries d'exemples (asymptote.sourceforge.net).

VI-A - markers

Le module markers fournit tout ce qu'il faut pour marquer segments et angles.

Les marqueurs pour les segments sont :

marker StickIntervalMarker(int i=2, int n=1, real size=0, real space=0,
real angle=0, pair offset=0, bool rotated=true,
pen p=currentpen, frame uniform=newframe,
bool above=true)

Code 34

import markers;
size(7cm,0);
pair A=(0,0), B=(3,0);
draw(A—B,StickIntervalMarker(3,2,
angle=25,dotframe(purple)));
label("$A$",A,W);label("$B$",B,E);

Code 35

import markers;
size(7cm,0);
pair A=(0,0), B=(3,0);
draw(A--B,StickIntervalMarker(4,1,size=5mm,
angle=-45,bp+.8green,dotframe(purple)));
label("$A$",A,W);label("$B$",B,E);

marker CrossIntervalMarker(int i=2, int n=3, real size=0, real space=0,
real angle=0, pair offset=0, bool rotated=true,
pen p=currentpen, frame uniform=newframe,
bool above=true)

Code 36

import markers;
size(7cm,0);
pair A=(0,0), B=(3,0);
draw(A--B,CrossIntervalMarker(2,4,angle=0,
bp+red,dotframe(purple)));
label("$A$",A,W);label("$B$",B,E);

Code 37

import markers;
size(7cm,0);
pair A=(0,0), B=(3,0);
draw(A--B,CrossIntervalMarker(3,6,size=2mm,
angle=45,bp+blue,dotframe(purple)));
label("$A$",A,W);label("$B$",B,E);

marker CircleBarIntervalMarker(int i=2, int n=1, real barsize=0, real radius=0,
real angle=0, pair offset=0, bool rotated=true,
pen p=currentpen, filltype filltype=NoFill,
bool circleabove=false, frame uniform=newframe,
bool above=true)

Code 38

import markers;
size(7cm,0);
pair A=(0,0), B=(3,0);
draw(A--B,CircleBarIntervalMarker(3,2,
barsize=5mm,radius=1.5mm,
angle=-45,darkgreen,
filltype=NoFill,dotframe(purple)));
label("$A$",A,W);label("$B$",B,E);

Code 39

import markers;
size(7cm,0);
pair A=(0,0), B=(3,0);
draw(A--B,CircleBarIntervalMarker(4,1,
barsize=5mm,radius=1.5mm,bp+blue,
filltype=Fill(brown),
circleabove=true,
dotframe(purple),above=false));
label("$A$",A,W);label("$B$",B,E);

Code 40

import markers;
size(7cm,0);
pair A=(0,0), B=(3,0);
draw(A--B,CircleBarIntervalMarker(4,1,
barsize=5mm,radius=1.5mm,
bp+blue,filltype=Fill(brown),
dotframe(purple)));
label("$A$",A,W);label("$B$",B,E);

Code 41

import markers;
size(7cm,0);
pair A=(0,0), B=(3,0);
draw(A--B,CircleBarIntervalMarker(3,0,
radius=1.2mm,bp+fuchsia,
filltype=NoFill,dotframe(purple)));
label("$A$",A,W);label("$B$",B,E);

marker TildeIntervalMarker(int i=2, int n=1, real size=0, real space=0,
real angle=0, pair offset=0, bool rotated=true,
pen p=currentpen, frame uniform=newframe,
bool above=true)

Code 42

import markers;
size(7cm,0);
pair A=(0,0), B=(3,0);
draw(A--B,TildeIntervalMarker(3,2,size=1mm,
space=4mm,bp+orange,
dotframe(purple),above=false));
label("$A$",A,W);label("$B$",B,E);

Code 43

import markers;
size(7cm,0);
pair A=(0,0), B=(3,0);
draw(A--B,TildeIntervalMarker(4,1,size=1mm,
angle=-40,offset=(0,2),bp+darkcyan,
dotframe(purple),above=true));
label("$A$",A,W);label("$B$",B,E);

Il est bien sûr possible de définir ses propres « markers » :

Code 44

import markers;
size(7cm,0);
pair A=(0,0), B=(3,0);
frame cg;
filldraw(cg,scale(5)*polygon(7),Yellow,bp+Magenta);
marker markcg = marker(crossframe(n=4,size=1.5mm,bp+purple),
markinterval(2,cg,true));
draw(A--B,markcg);
label("$A$",A,W);label("$B$",B,E);

Les marques prédéfinies sont :

frame stickframe(int n=1, real size=0, pair space=0, real angle=0,
pair offset=0, pen p=currentpen)

frame circlebarframe(int n=1, real barsize=0,
real radius=0,real angle=0,
pair offset=0, pen p=currentpen,
filltype filltype=NoFill, bool above=false) above=false)

frame crossframe(int n=3, real size=0, pair space=0,
real angle=0, pair offset=0, pen p=currentpen)

frame tildeframe(int n=1, real size=0, pair space=0,
real angle=0, pair offset=0, pen p=currentpen)

Pour marquer l'angle AOB (dans le sens direct), on dispose de :

void markangle(picture pic=currentpicture, Label L="",
int n=1, real radius=0, real space=0,
pair A, pair O, pair B, arrowbar arrow=None,
pen p=currentpen, filltype filltype=NoFill,
margin margin=NoMargin, marker marker=nomarker)

Code 45

import markers;
size(5cm,0);
pair O=(0,0), A=(2,0), B=(1,1.5);
draw(A--O--B);
markangle(scale(1.5)*"$\alpha$",radius=40,
A,O,B,ArcArrow,bp+red);
markangle(scale(1.5)*"$\beta$",radius=30,
B,O,A,BeginArcArrow(HookHead,2mm),
bp+deepgreen);
label("$O$",O,SW);
label("$A$",A,SE);label("$B$",B,N);

Code 46

import markers;
size(5cm,0);
pair O=(0,0), A=(2,0), B=(1,1.5),
C=A+dir(A—O,A--B);

markangle(n=2,radius=20,
A,O,B,p=2bp+deepcyan,
filltype=Fill(magenta));
markangle(n=1,radius=20,
O,B,A,p=2bp+deepcyan,
marker(markinterval(stickframe(n=2,
4mm,bp+red),true)));
markangle(n=2,radius=20,
B,A,O,p=bp+heavyblue,
marker(markinterval(2,stickframe(n=1,
2mm,bp+purple),true)));

draw(A--interp(A,C,2),bp+dashed);
draw(A--O--B--cycle,linewidth(bp));
label("$O$",O,SW);
label("$A$",A,SE);label("$B$",B,N);

VI-B - geometry

Ce module apporte un grand nombre d'outils permettant de faciliter la construction de figures géométriques dans le plan.

Une fois n'est pas coutume, il y a une vraie documentation en français, faite par l'auteur du module : Philippe Ivaldi. On la trouve ici : www.piprime.fr/files/res/geometry_fr.pdf

Elle est extrêmement complète. Il existe de plus un index à cette adresse : www.piprime.fr/files/asymptote/geometry/modules/geometry.asy.index.type.html

Ce qui suit n'est ni plus ni moins qu'un copié-collé d'une toute petite partie de cette documentation dont la lecture est essentielle.

VI-B-1 - De nouveaux types d'objets sont définis

- coordsys: permet d'utiliser n'importe quel repère cartésien.

- point : équivalent au type pair dans le repère par défaut.

- vector : aussi équivalent au type pair dans le repère par défaut.

- mass : pour les barycentres.

- line : quelques objets de type line :

- line line(point A, bool extendA=true, point B, bool extendB=true)
Pour les droites, demi-droites (extendA=false ou extendB=false) et segments de droites (extendA=false et extendB=false).
line line(coordsys R=currentcoordsys, real a, real b, real c)
Renvoie la droite d'équation dans le repère R.
line line(coordsys R=currentcoordsys, real slope, real origin)
Renvoie la droite de pente slope et d'ordonnée à l'origine origin données relativement au repère R.
line parallel(point M, line l)
Renvoie la droite parallèle à l passant par M.
line parallel(point M, explicit vector dir)
Renvoie la droite de vecteur directeur dir et passant par M.
line parallel(point M, explicit pair dir)
Renvoie la droite de vecteur directeur dir donné dans le repère courant currentcoordsys et passant par M.
line line(real a, point A=point(currentcoordsys,(0,0)))
Renvoie la droite passant par A et faisant un angle de a degrés avec l'axe des abscisses du repère dans lequel est défini A.
line bisector(line l1, line l2, real angle=0, bool sharp=true)
Renvoie l'image de la bissectrice de l'angle formé par les droites orientées l1 et l2 par la rotation de centre « l'intersection de l1 et l2 » et d'angle angle. Si le paramètre sharp vaut true, renvoie la bissectrice de l'angle aigu.
line sector(int n=2, int p=1, line l1, line l2, real angle=0, bool sharp=true)
Renvoie l'image de la p-ième droite qui partage l'angle formé par les droites orientées l_1 et l_2 en n parties égales par la rotation de centre « l'intersection de l_1 et l_2 » et d'angle angle. Si le paramètre sharp vaut true, considère l'angle aigu.
line perpendicular(point M, line l)
Renvoie la droite perpendiculaire à l passant par M.
line perpendicular(point M, explicit vector normal)
Renvoie la droite passant par M et de vecteur normal normal.
line perpendicular(point M, explicit pair normal)
Renvoie la droite passant par M et de vecteur normal normal donné dans le repère courant currentcoordsys.
line reverse(line l)
Renvoie la droite représentée par l avec une orientation contraire à celle de l.
line extend(line l)
Renvoie la droite portée par l qui peut être une demi-droite ou un segment de droite.
line complementary(explicit line l)
Renvoie la demi-droite complémentaire de l. Ne fonctionne que si l représente effectivement une demi-droite.

- Segment :
segment segment(point A, point B)
On notera notamment la routine :
line bisector(segment s, real angle=0)
qui renvoie l'image de la médiatrice de s par la rotation de centre « le milieu de s » et d'angle angle.
Ainsi que :
line[] complementary(explicit segment s)
qui renvoie sous forme de tableau les deux demi-droites de support s et d'extrémités respectives s.A et s.B.

- conic : pour une conique quelconque non dégénérée. Les types dérivés sont : circle, ellipse, parabola et hyperbola.
De nombreuses routines permettent de définir un cercle. Entre autres :
circle circle(explicit point C, real r)
Renvoie le cercle de centre C et de rayon r.
circle circle(point A, point B)
Renvoie le cercle de diamètre AB.
circle circle(point A, point B, point C)
Renvoie le cercle passant par les points distincts A, B et C.
Etc. (Voir la documentation.)

- arc : pour les arcs orientés d'ellipses.
arc arc(ellipse el, real angle1, real angle2,polarconicroutine polarconicroutine=polarconicroutine(el), bool direction=CCW)

- abscissa : pour instancier une abscisse sur un objet de type line, segment, conic et arc.

- triangle : structure assez complexe bénéficiant de nombreuses routines. Encore une fois, le minimum sera vu. Ici, la lecture de la documentation est essentielle.

struct triangle {
restricted point A, B, C; // points marquant les sommets du triangle
struct vertex { // sommet de triangle
int n;
triangle t;
}
restricted vertex VA, VB, VC; // les sommets du triangle
struct side { // côté de triangle
int n;
triangle t;
}
side AB, BC, CA, BA, AC, CB; // les côtés du triangle
}

void label(picture pic=currentpicture, Label LA="$A$",
Label LB="$B$", Label LC="$C$",
triangle t,
real alignAngle=0,
real alignFactor=1,
pen p=nullpen, filltype filltype=NoFill)

- Place les labels LA, LB et LC aux sommets du triangle t, alignés suivant la première bissectrice du sommet correspondant.
Les paramètres alignAngle et alignFactor permettent de modifier la direction et la longueur de l'alignement.

void show(picture pic=currentpicture,
Label LA="$A$", Label LB="$B$", Label LC="$C$",
Label La="$a$", Label Lb="$b$", Label Lc="$c$",
triangle t, pen p=currentpen, filltype filltype=NoFill)

- Trace le triangle t et affiche les labels aux sommets du triangle ainsi que les longueurs de ses côtés. Cette routine est surtout utile pour localiser les sommets t.A, t.B et t.C en cours de codage.

void draw(picture pic=currentpicture, triangle t,
pen p=currentpen, marker marker=nomarker)

- Trace le triangle t ; les côtés sont tracés comme des segments.
void drawline(picture pic=currentpicture, triangle t, pen p=currentpen)
Trace le triangle t ; les côtés sont tracés comme des droites.
triangle triangle(point A, point B, point C)
Renvoie le triangle dont les sommets sont A, B et C.
triangle triangleabc(real a, real b, real c, real angle=0, point A=(0,0))
Retourne le triangle ABC tel que BC=a, AC=b, AB=c et
triangle triangleAbc(real alpha, real b, real c, real angle=0, point A=(0,0))
Retourne le triangle ABC tel que , AC=b, AB=c et
triangle triangle(line l1, line l2, line l3)
Renvoie le triangle dont les côtés sont l1, l2 et l3.
Et de nombreuses autres routines permettant de tracer l'orthocentre, les hauteurs, le centre de gravité, les médianes, etc.

- trilinear : instancie des coordonnées trilinéaires relatives à un triangle (sic).

- inversion : permet d'instancier l'inversion de pôle C et de puissance k.

struct inversion
{
point C;
real k;
}

VI-B-2 - De nouvelles transformations sont définies

transform scale(real k, point M)

Homothétie de centre M et de rapport k.

transform scale(real k, line l1, line l2, bool safe=false)

Renvoie l'affinité de rapport k, d'axe l1 et de direction l2.

Si safe vaut true et l1 parallèle à l2, la routine renvoie l'identité.

transform projection(point A, point B)

Projection orthogonale sur la droite (AB).

transform projection(line l)

Renvoie la projection orthogonale sur l.

transform projection(point A, point B, point C, point D, bool safe=false)

Projection sur la droite (AB) parallèlement à (CD).

Si safe vaut true et (AB) est parallèle à (CD), l'identité est renvoyée.

Si safe vaut false et (AB) est parallèle à (CD), l'homothétie de centre O et de rapport infini est renvoyée.

transform projection(line l1, line l2, bool safe=false)

Renvoie la projection sur l1 parallèlement à l2.

Si safe vaut true et l1 parallèle à l2, la routine renvoie l'identité.

transform vprojection(line l, bool safe=false)

Renvoie la projection sur l parallèlement à la verticale.

Si safe vaut true et l est une droite verticale, la routine renvoie l'identité.

transform hprojection(line l, bool safe=false)

Renvoie la projection sur l parallèlement à l'horizontale.

Si safe vaut true et l est une droite horizontale, la routine renvoie l'identité.

transform scale(real k, point A, point B, point C, point D, bool safe=false)

Affinité de rapport k, d'axe (AB) et de direction (CD). Si safe vaut true et (AB) est parallèle à (CD), l'identité est renvoyée.

Si safe vaut false et (AB) est parallèle à (CD), l'homothétie de centre O et de rapport infini est renvoyée.

transform xscale(real k, point M)

Affinité de rapport k, d'axe « l'axe passant par M et parallèle à (Oy) » et de direction (Ox).

transform yscale(real k, point M)

Affinité de rapport k, d'axe « l'axe passant par M et parallèle à (Ox) » et de direction (Oy).

transform scaleO(real x)

Homothétie de rapport x et de centre « l'origine du repère courant ». Cette transformation est identique à scale(x, origin()).

transform xscaleO(real x)

Identique à xscale(x, origin()).

transform yscaleO(real x)

Identique à yscale(x, origin()).

transform rotateO(real angle)

Identique à rotate(angle, origin()).

transform reflect(line l)

Renvoie la réflexion par rapport à l.

VI-B-3 - geometry introduit aussi des fonctions de marquage

void distance(picture pic=currentpicture, Label L="", point A, point B,
bool rotated=true, real offset=3mm,
pen p=currentpen, pen joinpen=invisible,
arrowbar arrow=Arrows(NoFill))

void markrightangle(picture pic=currentpicture, point A, point O,
point B, real size=0, pen p=currentpen,
margin margin=NoMargin,
filltype filltype=NoFill)

void perpendicularmark(picture pic=currentpicture, point z,
explicit pair align,
explicit pair dir=E, real size=0,
pen p=currentpen,
margin margin=NoMargin,
filltype filltype=NoFill)

void perpendicularmark(picture pic=currentpicture, point z,
vector align,
vector dir=E, real size=0,
pen p=currentpen,
margin margin=NoMargin,
filltype filltype=NoFill)

void perpendicularmark(picture pic=currentpicture, point z, explicit pair align, path g,
real size=0, pen p=currentpen,
margin margin=NoMargin,
filltype filltype=NoFill)

void perpendicularmark(picture pic=currentpicture, point z, vector align, path g,
real size=0, pen p=currentpen,
margin margin=NoMargin,
filltype filltype=NoFill)

path compassmark(pair O, pair A, real position, real angle=10)

À noter aussi la routine :

void addMargins(picture pic=currentpicture,
real lmargin=0, real bmargin=0,
real rmargin=lmargin, real tmargin=bmargin,
bool rigid=true, bool allObject=true)

Pour le tracé des droites, ajoute des marges à l'image (remplace avantageusement interp).

Si rigid vaut false, les marges sont ajoutées si et seulement si une courbe infinie se prolonge jusqu'à la marge.

Si allObject vaut false, les objets de taille fixe (comme les labels et pointes de flèches) seront ignorés.

Quelques exemples :

Code 47

import geometry;
size(7cm);

real ac=3, am=2, coef=am/ac;
triangle t=triangleAbc(40,ac,4);
drawline(t); label("$A$",t.A,NW);
label("$B$",t.B,NE); label("$C$",t.C,2N);
point M=relpoint(line(t.AC),-coef);
line par=parallel(M,t.BC);
draw(par);
point pN=intersectionpoint(par,t.AB);
label("$M$",M,2*S);
label("$N$",pN,N+.5*E);

addMargins(1cm,.5cm);

Code 48

import geometry;
size(6cm);

triangle t=triangleabc(4,5,6);
label(t); draw(t,linewidth(bp));

point pE=midpoint(t.AB),
pF=t.A+(1/3)*(t.C-t.A),
pG=t.B+(1/3)*(t.C-t.B);
dot("$E$",pE,-dir(t.VC));
dot("$F$",pF,-dir(t.VB));
dot("$G$",pG,-dir(t.VA));

draw(segment(t.AB),
StickIntervalMarker(2,2,angle=-35));
draw(t.C--pE^^t.B--pF^^t.A--pG);

line CE=line(t.C,pE);
line AG=line(t.A,pG);
dot(intersectionpoint(CE,AG));

Code 49

import geometry;
size(6cm);

triangle t=triangleabc(4,5,6);
label(t); draw(t,linewidth(bp));

point pE=midpoint(t.AB),
pF=t.A+(1/3)*(t.C-t.A),
pG=t.B+(1/3)*(t.C-t.B);
dot("$E$",pE,-dir(t.VC));
dot("$F$",pF,-dir(t.VB));
dot("$G$",pG,-dir(t.VA));

draw(segment(t.AB),
StickIntervalMarker(2,2,angle=-35));
draw(t.C--pE^^t.B--pF^^t.A--pG);

line CE=line(t.C,pE);
line AG=line(t.A,pG);
dot(intersectionpoint(CE,AG));

Code 50

import geometry;
size(6cm);

triangle t=triangleabc(4,5,6);
label(t); draw(t,linewidth(bp));

point pE=midpoint(t.AB),
pF=t.A+(1/3)*(t.C-t.A),
pG=t.B+(1/3)*(t.C-t.B);
dot("$E$",pE,-dir(t.VC));
dot("$F$",pF,-dir(t.VB));
dot("$G$",pG,-dir(t.VA));

draw(segment(t.AB),
StickIntervalMarker(2,2,angle=-35));
draw(t.C--pE^^t.B--pF^^t.A--pG);

line CE=line(t.C,pE);
line AG=line(t.A,pG);
dot(intersectionpoint(CE,AG));

Code 51

size(8cm);
import geometry;
usepackage("fourier");

void filldrawtri(triangle t,
pen fpen=currentpen,
pen dpen=currentpen)
{
filldraw(t.A--t.B--t.C--cycle,fpen,dpen);
}
point A=(0,0),B=(3,0),C=(1,2.5),pI=(A.x,C.y);
point D=(4,0),pE=(7,0),G=(8.5,2.5),F=(G.x,0);
point H=projection(A,B)*C;
triangle t1=triangle(A,B,C);
triangle t2=triangle(D,pE,G);

filldrawtri(t1,lightgreen,linewidth(bp));
filldrawtri(t2,lightred,linewidth(bp));

draw(C--H^^pE--F^^G--F,dashed);
markrightangle(C,H,A,3mm);
markrightangle(G,F,D,3mm);
distance("$\frac{1}{3}$",A,H,4mm,
Arrows(1mm,NoFill));
distance("$\frac{1}{2}$",H,B,4mm);
distance("$\frac{3}{5}$",A,pI,
rotated=false,-2mm);
distance("$\frac{3}{4}$",D,pE,4mm);
distance("$\frac{2}{3}$",F,G,rotated=false);

Code 52

import geometry;
usepackage("fourier","upright");
usepackage("mathrsfs");
size(6cm);

triangle t=triangleAbc(75,7,8.5,225);
point H=foot(t.VA);
circle c=circle(t.A,H);
point[] ct=intersectionpoints(t,c);

draw(t,heavyblue);
draw(t.A--H);
draw(c,red);
draw(ct[0]--ct[3],deepgreen);

label(t,heavyblue);dot("$O$",c.C,W);
label("$\mathscr{C}$",angpoint(c,50),NE,red);
label("$H$",H,NW);
label("$D$",ct[0],NW,deepgreen);
label("$E$",ct[3],E,deepgreen);
markrightangle(t.A,H,t.C);
markangle(scale(.8)*"$45^\circ$",5mm,
t.B,t.A,H);
markangle(scale(.8)*"$30^\circ$",n=2,6mm,
H,t.A,t.C);

import geometry;
usepackage("fourier","upright"); usepackage("mathrsfs");
size(10cm);
pen mediane=brown, bissec=heavymagenta, mediat=deepcyan, ortho=deepgreen;
// ----------------------------------------------------------------------
triangle t=triangleabc(5,4,6); drawline(t); label(t);
// ----------------------------------------------------------------------
line med=median(t.VA); point A1=midpoint(t.BC); point G=centroid(t);
draw(med,mediane); dot("$A'$",A1,N+.5*E,mediane); dot("$G$",G,S,mediane);
// ----------------------------------------------------------------------
line biss=bisector(t.VC); point Bi=bisectorpoint(t.AB);
point Ci=incenter(t); circle ci=incircle(t);
draw(biss,bissec); draw(ci,bissec);
dot("$C_1$",Bi,SE,bissec); dot("$I$",Ci,N+.5*E,bissec);
// ----------------------------------------------------------------------
line mediatrice=bisector(t.AC); point B1=midpoint(t.AC);
point Cc=circumcenter(t); circle cc=circle(t);
draw(mediatrice,mediat); draw(cc,mediat);
dot("$B'$",B1,N,mediat); dot("$O$",Cc,E+.5*N,mediat);
// ----------------------------------------------------------------------
line haut=altitude(t.VC); point C2=foot(t.VC);
point orth=orthocentercenter(t);
draw(haut,ortho); dot("$C_2$",C2,SW,ortho); dot("$H$",orth,SW,ortho);
// ----------------------------------------------------------------------
draw(line(orth,Cc),dashdotted);
label(Label("droite d'Euler",Rotate(dir(orth--Cc)),align=RightSide),
relpoint(line(orth,Cc),1.7));
// ----------------------------------------------------------------------
addMargins(.5cm,.5cm);

VI-C - trembling

Ce module permet de faire des figures « à main levée ». Plusieurs paramètres permettent de modifier l'effet :

real magneticRadius=1;
real trembleFuzz(){return min(1e-3,magneticRadius/10);}
real trembleAngle=4, trembleFrequency=0.5, trembleRandom=2;

Pour saisir leur rôle, le plus simple est de faire des essais. Des explications sont données directement dans le fichier trembling.asy.

Il faut utiliser la structure tremble, ainsi que la méthode deform :

tremble tremble(real angle=trembleAngle, real frequency=trembleFrequency,
real random=trembleRandom, real fuzz=trembleFuzz())

path deform(path g...pair[] magneticPoints)

Il faudra donc impérativement un type path …

Code 54

import trembling;
import geometry;
size(5cm,0);
pair A=(0,0), B=(3,0), C=(0,2),
O=midpoint(B--C);
path t=B--A--C--cycle;
// paramètres par défaut
tremble tr=tremble(angle=4,
frequency=.5,
random=2);
draw(tr.deform(t),blue);
path c=circle(O,sqrt(13)/2);
draw(c);
markrightangle(B,A,C,bp+darkmagenta,
filltype=Fill(Yellow));

Code 55

import trembling;
import geometry;
size(5cm,0);
pair A=(0,0), B=(3,0), C=(0,2),
O=midpoint(B--C);
path t=B--A--C--cycle;
tremble tr=tremble(angle=10,
frequency=.5, random=2);
draw(tr.deform(t),blue);
path c=circle(O,sqrt(13)/2);
draw(c);
markrightangle(B,A,C,bp+darkmagenta,
filltype=Fill(Yellow));

Cod 56

import trembling;
import geometry;
tremble tr=tremble(angle=6,
frequency=1,
random=5);
size(5cm,0);
pair A=(0,0), B=(3,0), C=(0,2),
O=midpoint(B--C);
path t=B--A--C--cycle;
path c=circle(O,sqrt(13)/2);
draw(tr.deform(t),blue);
dot(A^^B^^C);
draw(tr.deform(c));
markrightangle(B,A,C,bp+darkmagenta,
filltype=Fill(Yellow));

Code 57

import trembling;
import geometry;
tremble tr=tremble(angle=6,
frequency=1,
random=5);
size(5cm,0);
pair A=(0,0), B=(3,0), C=(0,2),
O=midpoint(B--C);
path t=B--A--C--cycle;
path c=circle(O,sqrt(13)/2);
draw(tr.deform(t),blue);
dot(A^^B^^C);
// A, B et C "magnétisés" :
draw(tr.deform(c,A,B,C));
markrightangle(B,A,C,bp+darkmagenta,
filltype=Fill(Yellow));
label(scale(.7)*"magneticPoints",
C,9E,.8red);

VI-D - graph

La documentation officielle est très complète sur ce module. Ce qui suit est un résumé de ce qui sera le plus utile dans un premier temps.

VI-D-1 - Axes et repères

graph fournit les routines suivantes :

void xaxis(picture pic=currentpicture, Label L="", axis axis=YZero,
real xmin=-infinity, real xmax=infinity, pen p=currentpen,
ticks ticks=NoTicks, arrowbar arrow=None, bool above=false);

Dessine l'axe des abscisses. Certains paramètres méritent de s'y attarder :

- axis : détermine la position de l'axe. Les différents types sont :

- YZero(bool extend=true) : l'axe a pour équation y = 0 (ou y =.1 pour une échelle logarithmique),
extend=true (valeur par défaut) pour que l'axe soit aux dimensions complètes de la figure,

- YEquals(real Y, bool extend=true) : l'axe a pour équation y = Y. (Voir plutôt yequals.),

- Bottom(bool extend=false) : l'axe est au bas de la figure,

- Top(bool extend=false) : l'axe est en haut,

- BottomTop(bool extend=false) : axes en bas et en haut ;

- xmin et xmax : automatiquement déterminés par les dimensions de la figure si non spécifiés ;

- ticks : les traits de graduation. Les valeurs sont NoTicks (par défaut, aucune graduation), LeftTicks (graduations uniquement à gauche de l'axe), RightTicks (graduations uniquement à droite de l'axe) et Ticks (graduations des deux côtés de l'axe). Ces trois dernières routines prennent elles-mêmes de nombreux arguments en option :

ticks Ticks(Label format="", ticklabel ticklabel=null,
bool beginlabel=true, bool endlabel=true,
int N=0, int n=0, real Step=0, real step=0,
bool begin=true, bool end=true, tickmodifier modify=None,
real Size=0, real size=0, bool extend=false,
pen pTick=nullpen, pen ptick=nullpen);

- format : format des nombres sur les axes (par défaut "$%.4g$"). Pour n'avoir que les traits, sans les labels, la valeur est "%" ;

- ticklabel : fonction string(real x) qui retourne le label (par défaut format(format.s,x)) de chaque graduation principale d'abscisse x. Voir par exemple labelfrac page 41 et le code 73.
Le ticklabel OmitFormat(string s=defaultformat ... real[] x) permet d'enlever certains labels, mais pas la graduation correspondante.
NoZeroFormat est une abréviation pour OmitFormat(0) ;

- beginlabel et endlabel : inclut le premier et le dernier label ;

- N : quand la mise à l'échelle est activée (par défaut), l'axe est divisé en N intervalles séparés par les graduations principales ;

- n : chaque intervalle principal est divisé en n intervalles secondaires séparés par les graduations secondaires ;

- Step : la valeur entre chaque trait de graduation principale (si N=0) ;

- step : la valeur entre chaque trait de graduation secondaire (si n=0) ;

- begin et end : inclut le premier et le dernier trait de graduation principale ;

- tickmodifier modify : fonction permettant de modifier des graduations « manuellement ».
Certains tickmodifier sont prédéfinis :
OmitTick(... real[] x), OmitTickInterval(real a, real b) et OmitTickIntervals(real[] a, real[] b) peuvent servir à enlever des graduations, ainsi que leurs labels.
NoZero est une abréviation pour OmitTick(0) ;

- Size et size : taille des graduations principales et secondaires ;

- extend : étend les graduations. Permet de tracer des grilles ;

- pen pTick et ptick : stylos pour le tracé des traits de graduation.

Code 58

import graph;
unitsize(1cm);
xaxis(L="$x$", axis=YZero,
xmin=-3, xmax=3, p=bp+blue,
ticks=LeftTicks(ticklabel=OmitFormat(1),
endlabel=false,Step=1,step=.5,
end=false,modify=OmitTick(-2),
pTick=bp+red,ptick=bp+.8green),
arrow=Arrow);

Code 59

import graph;
unitsize(1cm);
real[] tabT={-2,0,1}, tabt={-1.5,-.5,.5};
xaxis(L="$x$", axis=YZero(extend=true),
xmin=-3, xmax=3, p=bp+blue,
ticks=Ticks(Ticks=tabT, ticks=tabt,
pTick=bp+red,ptick=bp+.8green),
arrow=Arrow, above=false);

Il est aussi possible de spécifier l'emplacement des graduations à l'aide d'un tableau de réels à l'aide de la routine (voir le code 59, valable aussi pour LeftTicks et RightTicks) :

ticks Ticks(Label format="", ticklabel ticklabel=null,
bool beginlabel=true, bool endlabel=true,
real[] Ticks, real[] ticks=new real[],
real Size=0, real size=0, bool extend=false,
pen pTick=nullpen, pen ptick=nullpen)

De la même façon que xaxis est défini :

void yaxis(picture pic=currentpicture, Label L="", axis axis=XZero,
real ymin=-infinity, real ymax=infinity, pen p=currentpen,
ticks ticks=NoTicks, arrowbar arrow=None, bool above=false,
bool autorotate=true);

Les paramètres sont similaires à ceux de xaxis. On notera pour le type axis les valeurs Left, Right et LeftRight.

Il est possible de fixer les valeurs xmin, xmax, ymin et ymax par la routine :

xlimits(picture pic=currentpicture, real min=-infinity,
real max=infinity, bool crop=NoCrop);

et la routine ylimits.

Le booléen crop=Crop sert à couper les parties de la figure qui dépassent les limites.

Code 60

import graph;
unitsize(1cm);
xaxis(L="$x$", axis=YZero,
xmin=-3, xmax=3, p=bp+blue,
ticks=Ticks(endlabel=false,
beginlabel=false,
Step=1,step=.5,
end=false,pTick=bp+red,
ptick=bp+.8green),
arrow=Arrow);

yaxis(L="$y$", axis=LeftRight,
ymin=-1, ymax=3, p=bp+purple,
ticks=Ticks(beginlabel=false,
Step=1,step=.25,
pTick=bp+red,
ptick=bp+.8green),
arrow=Arrow);

Code 61

import graph;
unitsize(1cm);
xlimits(-3, 3);
ylimits(-1, 3);
xaxis(L="$x$",axis=BottomTop,p=bp+blue,
ticks=Ticks(Step=1,step=.5,extend=true,
pTick=bp+red,
ptick=bp+dotted+.8green),
arrow=Arrow);

yaxis(L="$y$",axis=LeftRight,p=bp+purple,
ticks=Ticks(Step=1,step=.5,extend=true,
pTick=bp+red,
ptick=bp+dotted+.8green),
arrow=Arrow);

Pour des axes déportés, on peut utiliser les routines suivantes :

void xequals(picture pic=currentpicture, Label L="", real x,
bool extend=false, real ymin=-infinity, real ymax=infinity,
pen p=currentpen, ticks ticks=NoTicks, bool above=true,
arrowbar arrow=None);

void yequals(picture pic=currentpicture, Label L="", real y,
bool extend=false, real xmin=-infinity, real xmax=infinity,
pen p=currentpen, ticks ticks=NoTicks, bool above=true,
arrowbar arrow=None);

void axes(picture pic=currentpicture, Label xlabel="", Label ylabel="",
pair min=(-infinity,-infinity), pair max=(infinity,infinity),
pen p=currentpen, arrowbar arrow=None, bool above=false);

Voir le code 65. Dans cet exemple, les axes sont tracés dans une image séparée, qui est ajoutée à currentpicture à la fin.

Code 62

import graph;
unitsize(1cm);
xlimits(17,23); ylimits(52,55);
xequals(pic=currentpicture,L="$y$",x=17,
ticks=Ticks(Step=1,step=.5,end=false),
arrow=Arrow(HookHead));

yequals(pic=currentpicture,L="$x$",y=52,
ticks=Ticks(Step=1,step=.5,end=false),
arrow=Arrow(HookHead));

Code 63

import graph;
unitsize(x=1cm, y=.5cm);
xlimits(-1, 5); ylimits(-2, 2);
xaxis(BottomTop, Ticks("%",extend=true,
pTick=linewidth(.5pt),ptick=dotted));
yaxis(LeftRight, Ticks("%",extend=true,
pTick=linewidth(.5pt),     ptick=dotted));
xequals(Label("$y$",align=2NW), 0,
p=linewidth(bp), Arrow(2mm));
yequals(Label("$x$",align=2SE), 0,
p=linewidth(bp), Arrow(2mm));
labelx(Label("$1$",UnFill), 1);
labely(Label("$1$",UnFill), 1);
dot("$O$",(0,0),2SW);

Code 64

import graph;
unitsize(1cm);
xlimits(-1,6); ylimits(-1,3);
xaxis(L="$x$", p=bp+blue,
ticks=Ticks(NoZero,endlabel=false,
beginlabel=false,Step=1,step=.5,
begin=false,end=false),
arrow=Arrow(TeXHead));
yaxis(L="$y$", p=bp+blue,
ticks=Ticks(NoZero,beginlabel=false,
Step=1,step=.5,
begin=false,end=false),
arrow=Arrow(TeXHead));
labelx("$O$",0,2*SW,blue);
xequals(pic=currentpicture,L="$Y$",x=3,
p=brown+dashed,ticks=NoTicks,
arrow=Arrow(HookHead));
yequals(pic=currentpicture,L="$X$",y=1,
p=brown+dashed,ticks=NoTicks,
arrow=Arrow(HookHead));
labelx("$A$",(3,1),2*SW,brown);
xtick("$1$",(4,1),size=1mm,brown);
xtick(dir=S,(4,1),size=1mm,brown);
ytick("$1$",(3,2),size=1mm,brown);
ytick(dir=W,(3,2),size=1mm,brown);

Code 65

import graph;
unitsize(1cm);
xlimits(-1,6); ylimits(-1,3);
xaxis(L="$x$", p=bp+purple,
ticks=Ticks(NoZero,endlabel=false,
beginlabel=false,Step=1,step=.5,
begin=false,end=false),
arrow=Arrow(TeXHead));
yaxis(L="$y$", p=bp+purple,
ticks=Ticks(NoZero,beginlabel=false,
Step=1,step=.5,
begin=false,end=false),
arrow=Arrow(TeXHead));
labelx("$O$",0,2*SW,purple);
picture pic;
unitsize(pic,1cm);
axes(pic, xlabel="$X$", ylabel="$Y$",
min=(-4,-2), max=(3,2),p=dashed+red,
arrow=Arrow(HookHead));
labelx(pic,"$A$",(0,0),2*SW,red);
xtick(pic,"$1$",1,size=1mm,red);
xtick(pic,dir=S,1,size=1mm,red);
ytick(pic,"$1$",1,size=1mm,red);
ytick(pic,dir=W,1,size=1mm,red);
add(pic.fit(),(3,1));

Les routines suivantes permettent de placer manuellement des graduations :

void xtick(picture pic=currentpicture, Label L="", explicit pair z,
pair dir=N, string format="",
real size=Ticksize, pen p=currentpen);
void xtick(picture pic=currentpicture, Label L="", real x,
pair dir=N, string format="",
real size=Ticksize, pen p=currentpen);

De la même façon que xtick est défini ytick.

void tick(picture pic=currentpicture, pair z,
pair dir, real size=Ticksize, pen p=currentpen);
void labelx(picture pic=currentpicture, Label L="", explicit pair z,
align align=S, string format="", pen p=nullpen);
void labelx(picture pic=currentpicture, Label L="", real x,
align align=S, string format="", pen p=nullpen);
void labelx(picture pic=currentpicture, Label L,
string format="", explicit pen p=currentpen);

De la même façon que labelx est défini labely.

VI-D-2 - Représentations de fonctions

Plusieurs routines permettent de définir un graphe. Seules les plus utiles pour débuter seront vues (voir la documentation officielle pour les autres).

guide graph(picture pic=currentpicture, real f(real), real a, real b,
int n=ngraph, real T(real)=identity,
interpolate join=operator --);

Retourne le graphe de la fonction f sur l'intervalle , basé sur n points (100 par défaut) régulièrement espacés dans .

Code 66

import graph;
unitsize(1cm);
xaxis("$x$", Ticks(scale(.7)*Label(), NoZero),Arrow(2mm));
yaxis("$y$", Ticks(scale(.7)*Label(), NoZero, beginlabel=false, endlabel=false,
begin=false, end=false), Arrow(2mm));
labelx(scale(.7)*"$O$",0,SW);
real f(real x) {return 4*x/(x^2+1);}
draw(graph(f,-5.5,5.5),bp+purple);
label("$y=\frac{4x}{x^2+1}$",(4,f(4)),1.5N,purple);
label("anguin\'ea",(-3.5,1.5),purple);
label(scale(.8)*"(ou cubique serpentine)",(-3.5,1),purple);

guide graph(picture pic=currentpicture, real x(real), real y(real),
real a, real b, int n=ngraph, real T(real)=identity,
interpolate join=operator --);

Retourne la courbe paramétrée .

Code 67

import graph;
unitsize(1cm);
usepackage("inputenc","utf8"); usepackage("icomma");
xaxis("$x$", Ticks(scale(.7)*Label(), NoZero),Arrow(2mm));
yaxis("$y$", Ticks(scale(.7)*Label(), NoZero, beginlabel=false, endlabel=false,
begin=false, end=false), Arrow(2mm));
labelx(scale(.7)*"$O$",0,SW);
real x(real t) {return 2*cos(t)+1.5*cos(2*t);}
real y(real t) {return 2*sin(t)-1.5*sin(2*t);}
pen pg=royalblue;
draw(graph(x,y,0,2*pi),bp+pg);
label(scale(.6)*"$x(t)=2\cos(t)+1,5\cos(2t)$",(1.8,-2),1.5N,pg);
label(scale(.6)*"$y(t)=2\sin(t)-1,5\sin(2t)$",(1.8,-2),pg);

guide polargraph(picture pic=currentpicture, real f(real), real a,
real b, int n=ngraph, interpolate join=operator --);

Retourne le graphe de la fonction en coordonnées polaires sur l'intervalle

Code 68

import graph;
size(6cm);
usepackage("inputenc","utf8");
xaxis(Ticks("%", NoZero, Step=1, step=.5), Arrow(2mm));
yaxis(Ticks("%", NoZero, Step=1, step=.5), Arrow(2mm));
labelx(scale(.7)*"$O$",0,SW);
real r(real t) {return 1+2*sin(t/2);}
pen pg=deepmagenta;
draw(polargraph(r,0,4*pi,n=400),bp+pg);
label(scale(.8)*"$r=1+2\sin\left(\theta/2\right)$",(-1.5,-1),pg);
label("néphroïde de Freeth",(-.5,1.3),pg);

Remarque : Fonctions non définies en certaines valeurs

Deux possibilités ici :

1. « enlever » les valeurs interdites : pour l'exemple, considérons la fonction
Cette fonction est définie surLa courbe sera découpée en trois graphes, qui éviteront soigneusement les valeurs 1 et 3.

Code 69

import graph;
usepackage("mathrsfs");
unitsize(x=1cm,y=1cm);

transform ec=scale(.8);
xaxis(ec*"$x$", Ticks(ec*Label(), NoZero), Arrow(2mm));
yaxis(ec*"$y$", Ticks(ec*Label(), NoZero), Arrow(2mm));
labelx(ec*"$O$",0,SW);

real f(real x) {return -1/(x^2-4*x+3);}
path c1=graph(f,-2.8,.9); // on évite les valeurs
path c2=graph(f,1.1,2.9); // interdites
path c3=graph(f,3.1,6.8); //
draw(c1^^c2^^c3,bp+heavyred);
ylimits(-2.9,2.9,Crop); // on coupe ce qui dépasse
label("$\mathscr{C}_f$",(3,1.5),heavyred);

2. utiliser le module contour et tracer la courbe comme une ligne de niveau.
On utilise la routine suivante :

guide[][] contour(real f(real, real), pair a, pair b,
real[] c, int nx=ngraph, int ny=nx,
interpolate join=operator--, int subsample=1)

- f : fonction de deux variables réelles.

- a et b : les sommets de la diagonale du domaine rectangulaire.

- c : tableau contenant les valeurs des lignes de niveau.

- nx et ny : nombre de subdivisions dans les directions x et y (détermine la précision).

- join : l'opérateur d'interpolation (-- ou ..).

- subsample : nombre de points intérieurs à inclure dans chaque carré de la grille (en plus des points sur le bord).

Pour notre exemple, la courbe a pour équation
D'où l'on tire :
On considérera donc la fonction et on tracera la ligne de niveau -1.

Code 70

import graph;
import contour;
usepackage("mathrsfs");
unitsize(x=1cm,y=1cm);
transform ec=scale(.8);

xaxis(ec*"$x$", Ticks(ec*Label(), NoZero), Arrow(2mm));
yaxis(ec*"$y$", Ticks(ec*Label(), NoZero), Arrow(2mm));
labelx(ec*"$O$",0,SW);

real F(real x, real y) {return y*(x^2-4*x+3);}
draw(contour(F,(-2.8,-2.9),(6.8,2.9),new real[] {-1}),bp+deepcyan);
label("$\mathscr{C}_f$",(3,1.5),deepcyan);

Voir aussi le code 71

VI-D-3 - Extension graph_pi

Cette extension de Philippe Ivaldi apporte bon nombre d'outils intéressants.

Elle peut être téléchargée à cette adresse : git.piprime.fr/?p=asymptote/pi-packages.git;a=tree, lien snapshot, et placée dans le dossier $HOME/.asy.

Pour une utilisation avec git, voir : forum.mathematex.net/asymptote-f34/version-2-10-et-graph-pi-t13226.html#p127606.

Les modules graph, markers et base_pi (voir à l'adresse ci-dessus) sont chargés par graph_pi, ainsi que le package mathrsfs.

Axes et repères :

void graphicrules(picture pic=currentpicture, real unit=1cm,
real xunit=unit != 0 ? unit : 0,
real yunit=unit != 0 ? unit : 0,
real xmin=-infinity, real xmax=infinity,
real ymin=-infinity, real ymax=infinity,
bool crop=NoCrop, bool xcrop=crop, bool ycrop=crop)

Passe les dimensions du graphique à cartesianaxis, grid, et millimeterpaper (voir ci-après).

void cartesianaxis(picture pic=currentpicture,
Label Lx=Label("$x$",align=2S),
Label Ly=Label("$y$",align=2W),
real xmin=-infinity, real xmax=infinity,
real ymin=-infinity, real ymax=infinity,
real extrawidth=1, real extraheight=extrawidth,
pen p=currentpen,
ticks xticks=Ticks("%",pTick=nullpen, ptick=grey),
ticks yticks=Ticks("%",pTick=nullpen, ptick=grey),
bool viewxaxis=true,
bool viewyaxis=true,
bool above=true,
arrowbar arrow=Arrow)

Trace l'axe des abscisses, des ordonnées ou les deux (viewxaxis et viewyaxis qui prennent les valeurs true ou false). extrawidth est la longueur ajoutée à l'axe des abscisses par rapport à xmin et xmax. On a la même chose avec extraheight pour l'axe des ordonnées.

Code 71

import graph_pi;
import contour;
graphicrules(xunit=.5cm, yunit=2cm, xmin=-14.8, xmax=14.8, ymin=-1.9, ymax=1.9);
cartesianaxis(extrawidth=0,xticks=Ticks(NoZero), yticks=Ticks(NoZero), Arrow(2mm));
labelx("$O$",0,SW);
real F(real x, real y) {return x*y-cos(x);}
draw(contour(F,(-14.8,-1.9),(14.8,1.9),new real[] {0}),bp+darkgreen);
label("$y=\displaystyle\frac{\cos x}{x}$",(3,1),darkgreen);

void labeloij(picture pic=currentpicture,
Label Lo=Label("$O$",NoFill),
Label Li=Label("$\overrightarrow{\imath}$",NoFill),
Label Lj=Label("$\overrightarrow{\jmath}$",NoFill),
pen p=scale(2)*currentpen,
pair diro=SW, pair diri=labelijmargin*S, pair dirj=labelijmargin*1.5*W,
filltype filltype=NoFill, arrowbar arrow=Arrow(2mm),
marker marker=dot)

Trace le repère

void labeloIJ(picture pic=currentpicture,
Label Lo=Label("$O$",NoFill),
Label LI=Label("$I$",NoFill),
Label LJ=Label("$J$",NoFill),
pair diro=SW, pair dirI=labelIJmargin*S, pair dirJ=labelIJmargin*W,
pen p=currentpen,
filltype filltype=NoFill,
marker marker=dot)

Trace le repère

void grid(picture pic=currentpicture,
real xmin=pic.userMin.x, real xmax=pic.userMax.x,
real ymin=pic.userMin.y, real ymax=pic.userMax.y,
real xStep=1, real xstep=.5,
real yStep=1, real ystep=.5,
pen pTick=currentpen, pen ptick=grey, bool above=false)

Trace une grille.

Code 72

import graph_pi;
graphicrules(xunit=1cm, yunit=2cm, xmin=-5, xmax=5, ymin=0, ymax=1.5);
grid(pTick=currentpen,ptick=dotted);
cartesianaxis(xticks=Ticks("%"), yticks=Ticks(NoZero,Step=1,step=.5), Arrow(2mm));
labeloij();
real f(real x) {return 1/(1+x^2);}
draw(graph(f), bp+fuchsia);
label("$y=\displaystyle\frac{1}{1+x^2}$",(1,f(1)),NE,fuchsia);
label("Cubique d'Agnesi",(-3,1.2),fuchsia);

picture millimeterpaper(picture pic=currentpicture, pair O=(0,0),
real xmin=infinity, real xmax=infinity,
real ymin=infinity, real ymax=infinity,
pen p=.5bp+orange)

Grille sous forme de papier millimétré.

ticklabel labelfrac(real ep=1/10^5, real factor=1,
string symbol="",
bool signin=false, bool symbolin=true,
bool displaystyle=false,
bool zero=true)

Ce ticklabel permet d'écrire les graduations sous forme de fractions. Attention, base_pi doit être dans le dossier $HOME/.asy.

import graph_pi;
marker croix=marker(scale(4)*rotate(45)*cross(4),linewidth(bp));
pen bpd=bp+brown+linetype("4 4");
graphicrules(xunit=1cm, yunit=3cm, xmin=-6.5, xmax=6.5, ymin=-1.17, ymax=1.17);
add(millimeterpaper(p=1bp+orange),(0,0));
labeloij(Lj=Label(""));
cartesianaxis(Lx=Label("$x$",align=2N),extrawidth=0,
xticks=Ticks(Label(Fill(white)),
labelfrac(factor=pi,symbol="\pi",symbolin=true,
zero=false),Step=pi/2, step=pi/4),
yticks=Ticks(Label(Fill(white)),
labelfrac(zero=false),Step=.5));
// Définition des fonctions
real f(real x) {return cos(x);}
real g(real x) {return sin(x);}
// Tracé de courbe
draw(graph(f),bp+blue);
draw(graph(g),bpd);
// Points sur les courbes
real l=-2pi;
for(int i=0; i<17; ++i) {
draw((l,f(l)),croix);
draw((l,g(l)),croix);
l=l+pi/4;
}
label("$\mathscr{C}_f : y=\cos(x)$",(2.5,f(2.5)),W,blue);
label("$\mathscr{C}_g : y=\sin(x)$",(2.5,g(2.5)),NE,brown);

Représentations graphiques de suites :

recursiveroutime recursiveoption(Label L="u",
bool labelbegin=true,
bool labelend=true,
bool labelinner=true,
bool labelalternate=false,
string format="",
int labelplace=onX,
pen px=nullpen,
pen py=nullpen,
bool startonyaxis=false,
arrowbar circuitarrow=None,
marker automarker=marker(cross(4)),
marker xaxismarker=nomarker,
marker yaxismarker=nomarker,
marker xmarker=nomarker,
marker fmarker=nomarker)

Les options du graphique :

- L : le nom de la suite (à taper sans $) ;

- labelbegin : si la valeur est true, le premier terme est placé ;

- labelend : même chose pour le dernier terme ;

- abelinner : si la valeur est true, les termes compris entre le premier et le dernier sont placés ;

- labelalternate : si la valeur est true, les termes sont alternés par rapport à l'axe ;

- format : le format d'affichage de la valeur. Par exemple « %.2f » (deux chiffres après la virgule) ;

- labelplace : emplacement des termes : onX, onY, ou onXY ;

- px et py : stylos pour les tracés des traits de lecture ;

- startonyaxis : comme son nom l'indique… ;

- circuitarrow : flèches sur le « circuit » ;

- Pour tous les marker, voir le code 75.

recursivegraph recursivegraph(real F(real), real u0, int n0=0, int n)

« Graphe » de la suite : est le premier terme, est l'indice du premier terme et pour spécifier le nombre de termes placés sur le graphique (le dernier terme placé est celui d'indice).

void draw(picture pic=currentpicture, Label L="", recursivegraph g,
recursiveroutime lr=DefaultRecursiveOption, align align=NoAlign,
pen p=currentpen, arrowbar arrow=None, arrowbar bar=None,
margin margin=NoMargin, Label legend="", marker marker=nomarker)

Code 74

import graph_pi;
usepackage("amsmath");
graphicrules(xunit=1cm, yunit=1cm, xmin=-.4, xmax=8.9, ymin=-.4, ymax=7.9);
cartesianaxis(extrawidth=0,xticks=Ticks("%"),yticks=Ticks("%"));
label("$0$",(0,0),2*SW);labely("$1$",1,1.5W);
real f(real x){return 2*sqrt(x)+1;}
draw(graph(f,0,8.9,n=400),bp+purple);
draw(graph(new real(real x){return x;},0,7.9),bp+red);
draw(recursivegraph(f,u0=1,n0=1,n=6),
recursiveoption(L="v", labelplace=onXY),
bp+heavymagenta);
label("$y=2\sqrt{x}+1$",(7.5,f(7.5)),3S,purple);
label("$y=x$",(7,7),2W,red);
label("$\left\{\begin{aligned}&v_1=1\\&v_{n+1}=2\sqrt{v_n}+1
\end{aligned}\right.$",(2.5,7));

Code 75

import graph_pi;
usepackage("amsmath");usepackage("icomma");
graphicrules(xunit=2cm, yunit=2cm, xmin=-.4, xmax=4.4, ymin=-.4, ymax=3.4);
cartesianaxis(extrawidth=0,xticks=Ticks(NoZero),yticks=Ticks(NoZero));
label("$0$",(0,0),2*SW);
real f(real x){return x/2+1/x;}
draw(graph(f,.1,4.4),bp+deepblue);
draw(graph(new real(real x){return x;}),bp+red);
ylimits(-.4,3.4,Crop);
draw(recursivegraph(f,3.5,n=4),
recursiveoption(L=scale(.7)*"u",
labelbegin=true, labelend=true,
labelinner=true, labelalternate=true,
format="\approx %.1f", labelplace=onX,
px=dashed, py=nullpen,
startonyaxis=false, circuitarrow=MidArrow(3mm),
automarker=marker(scale(5)*cross(4),blue),
xaxismarker=dot(orange), yaxismarker=nomarker,
xmarker=dot(green), fmarker=dot(magenta)),
bp+heavycyan);
label("$y=\frac{x}{2}+\frac{1}{x}$",(.5,f(.5)),E,deepblue);
label("$y=x$",(3,3),SE,red);
label(scale(.9)*"$\left\{\begin{aligned}&u_0=3,5\\
&u_{n+1}=\frac{u_n}{2}+\frac{1}{u_n}
\end{aligned}\right.$",(.75,3),E);

void graphpoint(picture pic=currentpicture,
Label L="",
real f(real), real xCoordinate,
real xmin=0, real ymin=0,
int draw=onXY,
pen px=nullpen, pen py=px,
arrowbar arrow=None, arrowbar bar=None,
margin marginy=NoMargin, margin marginx=NoMargin,
bool extend=false, bool extendx=extend, bool extendy=extend,
Label legendx="", Label legendy="",
marker markerx=nomarker, marker markery=nomarker)

path tangent(path g, real x, pathb=box(userMin(currentpicture),userMax(currentpicture)))

void addtangent(picture pic=currentpicture,
path g,//Point on the path g
pair pt,// real x (x-Coordinate) est aussi défini
real size=infinity,//ABSOLUTE size of the tangent line
bool drawright=true,//Draw the tangent at the right
bool drawleft=true,//... left
pair v=(infinity,infinity),//A finite value forces the value of the derivative
pair vr=v,//A finite value forces the value of the derivative at right
pair vl=v,//A finite value forces the value of the derivative at left
arrowbar arrow=null,//null=automatic determination
margin margin=NoMargin,//Useful with size=infinity
Label legend="",
pen p=currentpen,
real dt=2,
bool differentiable=true)

Code 76

import graph_pi;
graphicrules(xunit=1cm, yunit=1cm, xmin=-4, xmax=3, ymin=-.5, ymax=5);
cartesianaxis(xticks=RightTicks(NoZero), yticks=LeftTicks(NoZero,Step=1));
grid(pTick=paleblue,ptick=paleblue);
labeloij();

real f(real x){return exp(x);}
path Cf=graph(f,n=200);
draw(Cf, bp+darkbrown);

addtangent(Cf,x=0,size=1cm,heavymagenta);
addtangent(Cf,x=1,size=1cm,heavymagenta);
graphpoint(f,1,px=dashed+blue);

dot((1,f(1))); dot((0,f(0)));
labely("e",f(1),blue);
ylimits(-1,5.5,Crop);
label("$\mathscr{C}_\mathrm{exp}$",(1.5,f(1.5)),E,darkbrown);

VI-E - animation

Ce module permet de faire des animations aux formats gif et mpeg en utilisant convert d'ImageMagick (qui doit donc être installé sur l'ordinateur), ainsi qu'au format PDF (animations visibles avec Acrobat Reader).

Pour obtenir un gif par exemple, il suffit de compiler avec l'option -f gif :

asy -f gif

ou d'ajouter dans le fichier asy

settings.outformat="gif";

En pratique, le module animate.asy importe le module animation.asy et le package animate.sty. Pour plus d'éclaircissements, il faudra donc se référer au fichier animation.asy, ainsi qu'à la documentation du package animate.sty (qui est donc requis).

VI-E-1 - Création d'animations autonomes

Les principales routines utilisées ici sont :

void erase(picture pic=currentpicture);

qui efface l'image,

void save()

qui sauvegarde l'image à l'endroit où elle est utilisée,

void restore()

qui restaure (c'est facile l'anglais !) l'image au point où elle a été sauvegardée par save(), et enfin

void add(picture pic=currentpicture, enclosure enclosure=NoBox)

qui ajoute l'image à l'animation.

Un exemple : construction de la médiatrice d'un segment. (Pour voir l'animation, il faut utiliser Acrobat Reader.)

Code 77

import geometry;
import animate;
settings.tex="pdflatex";
settings.outformat="pdf";
settings.twice=true;
size(15cm,0);
point A=(0,0), B=(3,-2), lab=(6,1);
circle cA=circle(A,2.5), cB=circle(B,2.5);
point[] int=intersectionpoints(cA,cB);
segment seg=segment(A,B);
line med=line(int[0],int[1]);
animation Anim;
// --------------------------------------------
// Étape 0
draw(seg,bp+heavygreen);
dot("$A$",A,unit(A-B)); dot("$B$",B,unit(B-A));
Anim.add();
// Étape 1
draw(cA,bp+blue);
draw(cB,bp+blue);
Anim.add();
// Étape 2
save(); // tout ce qu'il y a avant sera conservé dans la suite
label("\begin{minipage}{4cm}
On trace deux cercles\\
de m\^eme rayon.\end{minipage}",lab,E);
draw(lab..controls (4,2) and (3,2)..angpoint(cA,45),Arrow());
draw(lab..controls (5.5,1) and (4.5,1)..angpoint(cB,60),Arrow());
Anim.add();
restore();
// Etape 3
save();
label("\begin{minipage}{4cm}
Deux points\\
\'equidistants\\
de $A$ et $B$.\end{minipage}",lab,E);
draw(lab..controls (3,.5) and (2,-.5)..int[0],Arrow());
draw(lab..controls (5,1) and (4.5,1)..int[1],Arrow());
dot(int[0],heavyred); dot(int[1],heavyred);
Anim.add();
restore();
// Étape 4
save();
draw(med,bp+heavyred);
label("\begin{minipage}{4cm}
M\'ediatrice de $\left[AB\right]$\end{minipage}",lab,E,heavyred);
draw(lab..controls (5,1.5) and (4,1.6)..relpoint(med,1.4),Arrow());
dot(int[0],heavyred); dot(int[1],heavyred);
Anim.add();
restore();
// --------------------------------------------
erase(); // permet d'éviter les effets de "décalage"
label(Anim.pdf("controls,step"));

Quelques sorties

label(Anim.pdf("<options>",keep=true,multipage=false));

pour obtenir un PDF par image.

label(Anim.pdf("<options>",keep=true,multipage=true));

pour obtenir l'animation et le PDF multipage (PDF contenant une page par image).

label(Anim.pdf("<options>"));

pour l'animation uniquement.

Anim.movie();

pour obtenir un PDF multipage.

Anim.glmovie();

pour une sortie dans la fenêtre OpenGL, à compiler avec asy -V

Pour les options entre guillemets, ce sont les options du package animate.sty (il faut consulter sa documentation pour davantage de précisions). On trouve entre autres :

- autoplay : démarre l'animation automatiquement ;

- loop : l'animation recommence en boucle ;

- controls : pour les boutons de contrôle (sinon, il faut cliquer sur l'animation pour la lancer) ;

- buttonsize=<size>, buttonbg=<colour>, buttonfg=<colour> : mise en forme des boutons ;

- palindrome : l'animation s'exécute d'avant en arrière ;

- step : pas à pas ;

- width=..., height=..., depth=... : redimensionne l'animation ;

- scale=... : mise à l'échelle de l'animation.

Il est aussi possible de préciser le temps (en millisecondes) entre chaque image, par exemple :

label(Anim.pdf("controls",delay=50));

pour une image toutes les 50 millisecondes.

movie() peut aussi prendre des arguments, utile par exemple pour la création d'un gif (puisqu'il n'y aura pas de boutons de contrôle…). L'exemple ci-contre peut être compilé directement par : asy mongif.asy.

Code 78

import animation;
settings.outformat="gif";
size(100,100);
path c1=circle((0,0),1);
path c2=circle((0,.6),.4);
draw(c1,bp+purple);
animation Anim;
// -------------------------------
for(int i=0; i < 360; i+=10)
{
save();
draw(rotate(i)*c2,bp+heavymagenta);
Anim.add();
restore();
}
// -------------------------------
Anim.movie(loops=3,delay=50);

VI-E-2 - Inclure une animation externe dans un fichier .tex

L'animation doit être créée avec la sortie Anim.movie() (PDF multipage). Le package animate.sty va se charger de reconstituer l'animation à l'aide de la commande : \animategraphics[<options>]{<frame rate>}{<file basename>}{<first>}{<last>}

<file basename> est le nom de l'animation sans extension et <frame rate> est le nombre d'images par seconde. <first> et <last>, la première et dernière image.

Exemple :

\documentclass{article}
\usepackage{animate}
\begin{document}
\animategraphics[width=\linewidth,controls]{10}{animcos}{}{}
\end{document}

Code 79

// Animation réalisée avec l'aide de Gaétan Marris et Olivier Guibé
import graph_pi;
import animate;
settings.tex="pdflatex";
settings.outformat="pdf";
usepackage("fourier","upright");
real f(real x) {return cos(x);}
path Cf1=graph(f,0,pi,n=20,Hermite);
path Cf2=graph(f,-pi,pi,n=20,Hermite);
path Cf3=graph(f,pi,3pi,n=20,Hermite);
transform sc=scale(.8);
pen pinit=1.2bp+magenta, pf=1.2bp+.8blue, pvec=bp+deepgreen;

animation A;
// ------------------------------------------------------------------------------
void trace(path f, pen p,
Label L="", real r=0, real per=2pi, pair NS=(0,0),
pen pv=nullpen, arrowbar arrow=Arrow(HookHead,2mm)){
draw(f,p);
if (NS!=(0,0))
draw(Label(sc*L,Fill(white),align=NS),(r,f(r))--(r+per,f(r+per)),pv,arrow);
}
graphicrules(xunit=1cm, yunit=1cm, xmin=-3pi, xmax=3pi, ymin=-1.5, ymax=1.5);
add(millimeterpaper(p=1bp+orange),(0,0));
labeloij(Lo=sc*"$O$",Li=sc*"$\overrightarrow{\imath}$",Lj=sc*"$\overrightarrow{\jmath}$");
cartesianaxis(xticks=Ticks(sc*Label(Fill(white)),
labelfrac(factor=pi,symbol="\pi",symbolin=true,
zero=false),
Step=pi/2,
ptick=black),
yticks=Ticks(sc*Label(Fill(white)),
labelfrac(zero=false),Step=1,step=.5));
A.add();
// ------------------------------------------------------------------------------
for (real p=-1; p<=1; p+=.1) {
save();
trace(Cf1,pinit);
draw(xscale(-p)*Cf1,pinit);
A.add();
restore();
}
for (real t=0; t<=2pi; t+=pi/25) {
save();
trace(Cf2,pinit,"$2\pi \vec{\imath}$",.75,N,pvec);
draw(shift(t,0)*Cf2,pf);
A.add();
restore();
}
for (real t=0; t<=2pi+pi/25; t+=pi/25) {
save();
trace(Cf2,pinit,"$2\pi \vec{\imath}$",.75,N,pvec);
trace(Cf3,pf,"$-2\pi \vec{\imath}$",-pi,-2pi,S,pvec);
draw(shift(-t,0)*Cf2,pf);
A.add();
restore();
}
erase();
A.movie();
add(millimeterpaper(p=1bp+orange),(0,0));
labeloij(Lo=sc*"$O$",Li=sc*"$\overrightarrow{\imath}$",Lj=sc*"$\overrightarrow{\jmath}$");
cartesianaxis(xticks=Ticks(sc*Label(Fill(white)),
labelfrac(factor=pi,symbol="\pi",symbolin=true,
zero=false),Step=pi/2, ptick=black),
yticks=Ticks(sc*Label(Fill(white)),
labelfrac(zero=false),Step=1,step=.5));
A.add();
// ------------------------------------------------------------------------------
for (real p=-1; p<=1; p+=.1) {
save();
trace(Cf1,pinit);
draw(xscale(-p)*Cf1,pinit);
A.add();
restore();
}
for (real t=0; t<=2pi; t+=pi/25) {
save();
trace(Cf2,pinit,"$2\pi \vec{\imath}$",.75,N,pvec);
draw(shift(t,0)*Cf2,pf);
A.add();
restore();
}
for (real t=0; t<=2pi+pi/25; t+=pi/25) {
save();
trace(Cf2,pinit,"$2\pi \vec{\imath}$",.75,N,pvec);
trace(Cf3,pf,"$-2\pi \vec{\imath}$",-pi,-2pi,S,pvec);
draw(shift(-t,0)*Cf2,pf);
A.add();
restore();
}
erase();
A.movie();

Pour voir l'animation, il faut utiliser Acrobat Reader.

VI-E-3 - Inclure le code dans un fichier .tex

On se contentera ici de copier le code du fichier inlinemovie.tex de la galerie d'exemples du site officiel : asymptote.sourceforge.net/gallery/animations

\documentclass{article}
\usepackage[inline]{asymptote}
%\usepackage{asymptote}
\usepackage{animate}
\begin{document}
Here is an inline PDF movie, generated with the commands
\begin{verbatim}
pdflatex inlinemovie
asy inlinemovie-*.asy
pdflatex inlinemovie
\end{verbatim}
or equivalently,
\begin{verbatim}
latexmk -pdf inlinemovie
\end{verbatim}
\begin{center}
\begin{asy}
import animate;
animation A=animation("movie1");
real h=2pi/10;
picture pic;
unitsize(pic,2cm);
for(int i=0; i < 10; ++i) {
draw(pic,expi(i*h)--expi((i+1)*h));
A.add(pic);
}
label(A.pdf("controls",delay=50,keep=!settings.inlinetex));
\end{asy}
%Uncomment the following line when not using the [inline] package option:
%\ASYanimategraphics[controls]{50}{movie1}{}{}
\end{center}
And here is anasymptote one, clickable but without the control panel:
\begin{center}
\begin{asy}
import animate;
animation A=animation("movie2");
real h=2pi/10;
picture pic;
unitsize(pic,2cm);
for(int i=0; i < 10; ++i) {
draw(pic,expi(-i*h)--expi(-(i+1)*h),red);
A.add(pic);
}
label(A.pdf(keep=!settings.inlinetex));
\end{asy}
%Uncomment the following line when not using the [inline] package option:
%\ASYanimategraphics[controls]{10}{movie2}{}{}
\end{center}
\end{document}

VII - Remerciements developpez

Nous remercions l'auteur Christophe GROSPELLIER de nous avoir permis de publier cet article, nous remercions aussi les membres de l'équipe : Claude LELOUP pour la correction orthographique, Winjerome pour la relecture technique et -nikopol- pour la gabarisation.