\section{Méthodes graphiques élémentaires} Toutes les méthodes graphiques 2D s'appliquent. À cela s'ajoute la possibilité de dessiner dans l'espace des lignes polygonales, des segments, droites, courbes, chemins, points, labels, plans, solides. Avec les solides vient également la notion de facettes que l'on ne trouvait pas en 2D. Les méthodes graphiques 3D vont calculer automatiquement la projection sur le plan de l'écran, après avoir appliquer aux objets la matrice de transformation 3D associée au graphique (qui est l'identité par défaut), ce sont ensuite les méthodes graphiques 2D qui prendront le relai. La méthode qui applique la matrice 3D et fait la projection sur l'écran (plan passant par l'origine et normal au vecteur unitaire dirigé vers l'observateur et défini par les angles de vue), est : \cmd{g:Proj3d(L)} où \argu{L} est soit un point 3D, soit une liste de points 3D, soit une liste de listes de points 3D. Cette fonction renvoie des complexes (affixes des projetés sur l'écran). \textbf{Attention} : lorsque la matrice 3D du graphe est une transformation affine non linéaire, le projeté sur l'écran d'un vecteur $u$ de l'espace n'est pas \code{g:Proj3d(u)}, mais \code{g:Proj3d(A+u)-g:Proj3d(A)} où $A$ désigne un point quelconque de l'espace. Pour éviter ces calculs, la méthode \cmd{g:Proj3dV()} a été introduite, elle fait la projection des \textbf{vecteurs} sur l'écran, et renvoie des complexes (affixes des projetés sur l'écran). \subsection{Dessin aux traits} \subsubsection{Ligne polygonale : Dpolyline3d} La méthode \cmd{g:Dpolyline3d(L \fac{, close, draw\_options, clip})} (où \emph{g} désigne le graphique en cours de création), \argu{L} est une ligne polygonale 3D (liste de listes de points 3D), \argu{close} un argument facultatif qui vaut \true ou \false, indiquant si la ligne doit être refermée ou non (\false par défaut), et \argu{draw\_options} est une chaîne de caractères qui sera passée directement à l'instruction \drawcmd dans l'export. L'argument \argu{clip} vaut \false par défaut, il indique si la ligne \argu{L} doit être clippée avec la fenêtre 3D courante. \subsubsection{Angle droit : Dangle3d} La méthode \cmd{g:Dangle3d(B, A, C \fac{, r, draw\_options, clip})} dessine l'angle \(BAC\) avec un parallélogramme (deux côtés seulement sont dessinés), l'argument facultatif \argu{r} précise la longueur d'un côté ($0.25$ par défaut). Le parallélogramme est dans le plan défini par les points \argu{A}, \argu{B} et \argu{C}, ceux-ci ne doivent donc pas être alignés. L'argument \argu{draw\_options} est une chaîne (vide par défaut) qui sera passée telle quelle à l'instruction \drawcmd . L'argument \argu{clip} vaut \false par défaut, il indique si le tracé doit être clippé avec la fenêtre 3D courante. \subsubsection{Segment : Dseg3d} La méthode \cmd{g:Dseg3d(seg \fac{, scale, draw\_options, clip})} dessine le segment défini par l'argument \argu{seg} qui doit être une liste de deux points 3D. L'argument facultatif \argu{scale} ($1$ par défaut) est un nombre qui permet d'augmenter ou réduire la longueur du segment (la longueur naturelle est multipliée par \argu{scale}). L'argument \argu{draw\_options} est une chaîne (vide par défaut) qui sera passée telle quelle à l'instruction \drawcmd . L'argument \argu{clip} vaut \false par défaut, il indique si le tracé doit être clippé avec la fenêtre 3D courante. \subsubsection{Droite : Dline3d} La méthode \cmd{g:Dline3d(d \fac{, draw\_options, clip})} trace la droite \argu{d}, celle-ci est une liste du type \argu{d}=$\{A,u\}$ où $A$ représente un point de la droite (point 3D) et $u$ un vecteur directeur (un point 3D non nul). Variante : la méthode \cmd{g:Dline3d(A, B \fac{, draw\_options, clip})} trace la droite passant par les points \argu{A} et \argu{B} (deux points 3D). L'argument \argu{draw\_options} est une chaîne (vide par défaut) qui sera passée telle quelle à l'instruction \drawcmd . L'argument \argu{clip} vaut \false par défaut, il indique si le tracé doit être clippé avec la fenêtre 3D courante. La méthode \cmd{g:Line3d2seg(d \fac{, scale})} renvoie une table constituée de deux points 3D représentant un segment, ce segment est la partie de la droite \argu{d} à l'intérieur la fenêtre 3D courante. L'argument \argu{scale} ($1$ par défaut) permet de faire varier la taille de ce segment. Lorsque la fenêtre est trop petite l'intersection peut être vide. \subsubsection{Arc de cercle : Darc3d} \begin{itemize} \item La méthode \cmd{g:Darc3d(B, A, C, r, sens \fac{, normal, draw\_options, clip})} dessine un arc de cercle de centre \argu{A} (point 3D), de rayon \argu{r}, allant de \argu{B} (point 3D) vers \argu{C} (point 3D) dans le sens direct si l'argument \argu{sens} vaut $1$, le sens inverse sinon. Cet arc est tracé dans le plan contenant les trois points \argu{A}, \argu{B} et \argu{C}, lorsque ces trois points sont alignés il faut préciser l'argument \argu{normal} (point 3D non nul) qui représente un vecteur normal au plan. Ce plan est orienté par le produit vectoriel $\vec{AB}\wedge\vec{AC}$ ou bien par le vecteur \argu{normal} si celui-ci est précisé. L'argument \argu{draw\_options} est une chaîne (vide par défaut) qui sera passée telle quelle à l'instruction \drawcmd . L'argument \argu{clip} vaut \false par défaut, il indique si le tracé doit être clippé avec la fenêtre 3D courante. \item La fonction \cmd{ld.arc3d(B, A, C, r, sens \fac{, normal})} renvoie la liste des points de cet arc (ligne polygonale 3D). \item La fonction \cmd{ld.arc3db(B, A, C, r, sens \fac{, normal})} renvoie cet arc sous forme d'un chemin 3D (voir \emph{Dpath3d} page \pageref{Dpath3d}) utilisant des courbes de Bézier. \end{itemize} \subsubsection{Cercle : Dcircle3d} \begin{itemize} \item La méthode \cmd{g:Dcircle3d(I, R, normal \fac{, draw\_options, clip})} trace le cercle de centre \argu{I} (point 3D) et de rayon \argu{R}, dans le plan contenant \argu{I} et normal au vecteur défini par l'argument \argu{normal} (point 3D non nul). L'argument \argu{draw\_options} est une chaîne (vide par défaut) qui sera passée telle quelle à l'instruction \drawcmd . L'argument \argu{clip} vaut \false par défaut, il indique si le tracé doit être clippé avec la fenêtre 3D courante. Autre syntaxe possible : \cmd{g:Dcircle3d(C \fac{, draw\_options, clip})} où \argu{C}=\{\argu{I},\argu{R},\argu{normal}\}. \item La fonction \cmd{ld.circle3d(I, R, normal)} renvoie la liste des points de ce cercle (ligne polygonale 3D). \item La fonction \cmd{ld.circle3db(I, R, normal)} renvoie ce cercle sous forme d'un chemin 3D (voir \emph{Dpath3d} page \pageref{Dpath3d}) utilisant des courbes de Bézier. \end{itemize} \subsubsection{Chemin 3D : Dpath3d}\label{Dpath3d} La méthode \cmd{g:Dpath3d(chemin \fac{, draw\_options, clip})} fait le dessin du \argu{chemin}. L'argument \argu{draw\_options} est une chaîne (vide par défaut) qui sera passée telle quelle à l'instruction \drawcmd . L'argument \argu{clip} vaut \false par défaut, il indique si le tracé doit être clippé avec la fenêtre 3D courante. L'argument \argu{chemin} est une liste de points 3D suivis d'instructions (chaînes) fonctionnant \textbf{sur le même principe qu'en 2D}. Instructions disponibles et leur syntaxe, le mot \emph{last} représente le dernier point du morceau précédent: \begin{itemize} \item \code{p1,"m"} (moveto), permet de commencer une nouvelle composante du chemin au point 3D $p_1$. \item \code{p1,...,pn,"l"} (lineto), dessine la ligne polygonale 3D \code{\{last,p1,...,pn\}}. \item \code{c1,c2,p2,"b"} (bézier) dessine la courbe de Bézier \code{\{last,c1,c2,p2\}}, où $c_1$ et $c_2$ sont les deux points 3D de contrôle. \item \code{p1,n,"c"} (cercle), dessine le cercle de centre $p_1$ et passant par le point \emph{last}, et normal au vecteur 3D $n$. \item \code{p1,p2,r,sens,n,"ca"} (arc de cercle), dessine un arc de cercle de centre $p_1$, de rayon $r$, allant de \emph{last} vers $p_2$, dans le sens direct lorsque \emph{sens}=$1$ (et donc dans le sens inverse si \emph{sens}=$-1$). Le vecteur 3D $n$ est optionnel, il indique un vecteur normal au plan du cercle lorsque les points \emph{last}, $p_1$ et $p_2$ sont alignés (et dans ce cas, le vecteur $n$ est obligatoire). \item \code{"cl"} (closepath), cette instruction s'utilise seule, elle permet de refermer la composante courante en traçant un segment reliant le dernier point au premier point (de la composante courante). \end{itemize} Voici par exemple le code de la figure \ref{viewdir}. \begin{Luacode} \begin{luadraw}{name=viewdir} local ld = luadraw local pt3d = ld.pt3d local Origin, vecI, vecJ, vecK = pt3d.Origin, pt3d.vecI, pt3d.vecJ, pt3d.vecK local g = ld.graph3d:new{ size={8,8} } local i, M = ld.cpx.I, ld.pt3d.M local O, A = Origin, M(4,4,4) local B, C, D, E = ld.pxy(A), ld.px(A), ld.py(A), ld.pz(A) --projeté de A sur le plan xOy et sur les axes g:Dpolyline3d( {{O,A},{-5*vecI,5*vecI},{-5*vecJ,5*vecJ},{-5*vecK,5*vecK}}, "->") -- axes g:Dpolyline3d( {{E,A,B,O}, {C,B,D}}, "dashed") g:Dpath3d( {C,O,B,2.5,1,"ca",O,"l","cl"}, "draw=none,fill=cyan,fill opacity=0.8") --secteur angulaire g:Darc3d(C,O,B,2.5,1,"->") -- arc de cercle pour theta g:Dpath3d( {E,O,A,2.5,1,"ca",O,"l","cl"}, "draw=none,fill=cyan,fill opacity=0.8") --secteur angulaire g:Darc3d(E,O,A,2.5,1,"->") -- arc de cercle pour phi g:Dballdots3d(O) -- le point origine sous forme d'une petite sphère g:Labelsize("footnotesize") g:Dlabel3d( "$x$", 5.25*vecI,{}, "$y$", 5.25*vecJ,{}, "$z$", 5.25*vecK,{}, "vers observateur", A, {pos="E"}, "$O$", O, {pos="NW"}, "$\\theta$", (B+C)/2, {pos="N", dist=0.15}, "$\\varphi$", (A+E)/2, {pos="S",dist=0.25}) g:Dlabel("viewdir=\\{"ortho",$\\theta,\\varphi$\\} (en degrés)",-5*i,{pos="N"}) -- label 2D g:Show() \end{luadraw} \end{Luacode} \textbf{Conversion} : la fonction \cmd{ld.polyline2path3d(L)} renvoie \argu{L} qui est une liste de points 3D ou une liste de listes de points 3D, sous la forme d'un chemin. \subsubsection{Plan : Dplane} \begin{itemize} \item La méthode \cmd{g:Dplane(P, V, L1, L2 \fac{, mode, draw\_options})} permet de dessiner les bords du plan \argu{P}=$\{A,u\}$ où $A$ est un point du plan et $u$ un vecteur normal au plan (\argu{P} est donc une table de deux points 3D). L'argument \argu{V} doit être un vecteur non nul du plan \argu{P}, Les arguments \argu{L1} et \argu{L2} sont deux longueurs. La méthode construit un parallélogramme centré sur $A$, dont un côté est $L_1\frac{V}{\|V\|}$ et l'autre $L_2\frac{W}{\|W\|}$ où $W = u\wedge V$. L'argument \argu{mode} est un entier naturel qui indique les bords à tracer. Pour calculer cet entier on utilise les variables prédéfinies : \varglob{ld.top} (=8), \varglob{ld.right} (=4), \varglob{ld.bottom} (=2), \varglob{ld.left} (=1) et \varglob{ld.all} (=15), que l'on peut ajouter entre elles, par exemple : \begin{itemize} \item \code{mode=ld.bottom+ld.left} : pour les côtés bas et gauche \item \code{mode=ld.top+ld.right+ld.bottom} : pour les côtés haut, droit et bas \item etc. \end{itemize} Par défaut le mode vaut \varglob{ld.all} ce qui correspond à \code{mode=ld.top+ld.right+ld.bottom+ld.left}. \item La fonction \cmd{ld.plane2rectangle(P \fac{, V, L1, L2})} calcule et renvoie le rectangle (liste de points 3D) dessiné par la méthode \cmd{g:Dplane()}. Le vecteur \argu{V} est facultatif, il permet d'imposer un bord du rectangle (il doit appartenir au plan), s'il est omis la fonction choisira elle-même un vecteur $V$. Les longueurs \argu{L1} et \argu{L2} sont facultatives et valent $5$ par défaut. Lorsque l'argument \argu{L2} et omis, il a implicitement la même valeur que \argu{L1}. Le résultat peut être dessiné avec la méthode \cmd{g:Dpolyline3d()}, ou bien dessiné en tant que facette. \end{itemize} \begin{demo}{Dplane, exemple avec mode = left+bottom} \begin{luadraw}{name=Dplane} local ld = luadraw local cpx, pt3d = ld.cpx, ld.pt3d local Origin, vecI, vecJ, vecK, M = pt3d.Origin, pt3d.vecI, pt3d.vecJ, pt3d.vecK, pt3d.M local g = ld.graph3d:new{size={8,8},window={-5.25,3,-2.5,2.5},margin={0,0,0,0},border=true} local i = cpx.I g:Labelsize("footnotesize") local A = Origin local P = {A, vecK} g:Dplane(P, vecJ, 6, 6, ld.left + ld.bottom) g:Dcrossdots3d({A,vecK},nil,0.75) g:Dseg3d({A,A+2*vecK},"->") g:Dangle3d(-vecJ,A,vecK,0.25) g:Dpolyline3d({{M(3.5,-3,0),M(3.5,3,0)},{M(3,-3.5,0), M(-3,-3.5,0)}}, "->,line width=0.8pt") g:Dlabel3d("$A$",A,{pos="E"}, "$u$",2*vecK,{}, "$P$", M(3,-3,0),{pos="NE", dir={vecJ,-vecI}}, "$L_1\\frac{V}{\\|V\\|}$ (bottom)", M(3.5,0,0), {pos="S"}, "$L_2\\frac{W}{\\|W\\|}$ (left)", M(0,-3.5,0), {pos="N",dir={-vecI,-vecJ}} ) g:Show() \end{luadraw} \end{demo} \paragraph{Attention} : les notions de haut, droite, bas et gauche sont relatives ! Elles dépendent du sens des vecteurs $u$ (vecteur normal au plan) et $V$ (vecteur donné dans le plan). Le troisième vecteur $W$ est le produit vectoriel $u\wedge V$. \subsubsection{Courbe paramétrique : Dparametric3d} \begin{itemize} \item La fonction \cmd{ld.parametric3d(p, t1, t2 \fac{, nbdots, discont, nbdiv})} fait le calcul des points de la courbe et renvoie une ligne polygonale 3D (pas de dessin). \begin{itemize} \item L'argument \argu{p} est le paramétrage, ce doit être une fonction d'une variable réelle $t$ et à valeurs dans $\mathbf R^3$ (les images sont des points 3D), par exemple : \code{local p=function(t) return Mc(3,t,t/3) end}. \item Les arguments \argu{t1} et \argu{t2} sont obligatoires avec \(t_1 < t_2\), ils forment les bornes de l'intervalle pour le paramètre. \item L'argument \argu{nbdots} est facultatif, c'est le nombre de points (minimal) à calculer, il vaut $40$ par défaut. \item L'argument \argu{discont} est un booléen facultatif qui indique s'il y a des discontinuités ou non, c'est \false par défaut. \item L'argument \argu{nbdiv} est un entier positif qui vaut $5$ par défaut et indique le nombre de fois que l'intervalle entre deux valeurs consécutives du paramètre peut être coupé en deux (par dichotomie) lorsque les points correspondants sont trop éloignés. \end{itemize} \item La méthode \cmd{g:Dparametric3d(p, options)} fait le calcul des points et le dessin de la courbe paramétrée par \argu{p}. L'argument \argu{options} est une table dont les champs sont les options possibles. Celles-ci sont, avec leur valeur par défaut: \begin{itemize} \item \opt{t=\{g:Xinf(),g:Xsup()\}}, \item \opt{nbdots=40}, \item \opt{discont=false}, \item \opt{nbdiv=5}, \item \opt{clip=false}, il indique si la courbe doit être clippée avec la fenêtre 3D courante. \item \opt{draw\_options=""}, chaîne qui sera transmise telle quelle à l'instruction \drawcmd . \end{itemize} \end{itemize} \begin{demo}{Une courbe et ses projections sur trois plans} \begin{luadraw}{name=Dparametric3d} local ld = luadraw local pt3d = ld.pt3d local vecI, vecJ, vecK, M, Mc = pt3d.vecI, pt3d.vecJ, pt3d.vecK, pt3d.M, pt3d.Mc local g = ld.graph3d:new{window3d={-4,4,-4,4,-3,3}, window={-7.5,6.5,-7,6}, size={8,8}} local pi = math.pi g:Labelsize("footnotesize") local p = function(t) return Mc(3,t,t/3) end local L = ld.parametric3d(p,-2*pi,2*pi,25,false,2) g:Dboxaxes3d({grid=true,gridcolor="gray",fillcolor="LightGray"}) g:Lineoptions("dashed","red",2) -- projection sur le plan y=-4 g:Dpolyline3d(ld.proj3d(L,{M(0,-4,0),vecJ})) -- projection sur le plan x=-4 g:Dpolyline3d(ld.proj3d(L,{M(-4,0,0),vecI})) -- projection sur le plan z=-3 g:Dpolyline3d(ld.proj3d(L,{M(0,0,-3),vecK})) -- dessin de la courbe g:Lineoptions("solid","Navy",8) g:Dparametric3d(p,{t={-2*pi,2*pi}}) g:Show() \end{luadraw} \end{demo} \subsubsection{Paramétrisation d'une ligne polygonale: \emph{curvilinear\_param3d}} Soit $L$ une liste de points 3D représentant une ligne continue, il est possible d'obtenir une paramétrisation de cette ligne en fonction d'un paramètre $t$ entre $0$ et $1$ ($t$ est l'abscisse curviligne divisée par la longueur totale de $L$). La fonction \cmd{ld.curvilinear\_param3d(L \fac{, close})} renvoie une fonction d'une variable $t\in[0;1]$ et à valeurs sur la ligne \argu{L} (points 3D), la valeur en $t=0$ est le premier point de \argu{L}, et la valeur en $t=1$ est le dernier point; cette fonction est suivie d'un nombre qui représente la longueur total de \argu{L}. L'argument optionnel \argu{close} indique si la ligne doit être refermée (\false par défaut). \subsubsection{Le repère : Dboxaxes3d} La méthode \cmd{g:Dboxaxes3d(options)} permet de dessiner les trois axes, avec un certain nombre d'options définies dans la table \argu{options}. Ces options sont : %\def\opt#1{\textcolor{blue}{\texttt{#1}}}% \begin{itemize} \item \opt{xaxe=true}, \opt{yaxe=true} et \opt{zaxe=true} : indique si les axes correspondant doivent être dessinés ou non. \item \opt{drawbox=false} : indique si une boite doit être dessinée avec les axes. \item \opt{grid=false} : indique si une grille doit être dessinée (une pour $x$, une pour $y$ et une pour $z$). Lorsque cette option vaut \true, on peut utiliser aussi les options suivantes : \begin{itemize} \item \opt{gridwidth=1}: indique l'épaisseur de trait de la grille en dixième de point, \item \opt{gridcolor="black"}: indique la couleur de la grille, \item \opt{fillcolor=""}: couleur pour peindre le fond des grilles. \end{itemize} \item \opt{xlimits=\{x1,x2\}}, \opt{ylimits=\{y1,y2\}}, \opt{zlimits=\{z1,z2\}} : permet de définir les trois intervalles utilisés pour les axes. Par défaut ce sont les valeurs fournies à l'argument \opt{window3d} à la création du graphe. \item \opt{xgradlimits=\{x1,x2\}}, \opt{ygradlimits=\{y1,y2\}}, \opt{zgradlimits=\{z1,z2\}} : permet de définir les trois intervalles de graduation sur les axes. Par défaut ces options ont la valeur \val{"auto"}, ce qui veut dire qu'elles prennent les mêmes valeurs que \opt{xlimits}, \opt{ylimits} et \opt{zlimits}. \item \opt{xyzstep=1} : indique le pas des graduations sur les trois axes. \item \opt{xstep=xyzstep}, \opt{ystep=xyzstep}, \opt{zstep=xyzstep} : indique le pas des graduations sur chaque axe (valeur de \opt{xyzstep} par défaut). \item \opt{xyzticks=0.2} : indique la longueur des graduations. \item \opt{labels=true} : indique si la valeur des graduations doit être affichée ou non. \item \opt{xlabelsep=0.25}, \opt{ylabelsep=0.25}, \opt{zlabelsep=0.25} : indique la distance entre les labels et les graduations. \item \opt{xlabelstyle=