\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}

\subsubsection{Fonctions sur les chemins 3D}

\begin{itemize}
    \item La fonction \cmd{ld.path3d(chemin \fac{, nbdots})} renvoie une ligne polygonale 3D contenant les points constituant le \argu{chemin}. L'argument facultatif, \argu{nbdots} est le nombre minimal de points calculés pour chaque courbe de Bézier contenue dans le chemin, sa valeur par défaut est la variable globale \varglob{ld.bezier\_nbdots} qui est initialisée à $12$.
    
    \item À l'inverse, la fonction \cmd{ld.polyline2path3d(L \fac{, close})} où \argu{L} est une ligne polygonale 3D (liste de points 3D ou une liste de listes de points 3D), renvoie \argu{L} sous la forme d'un chemin. L'argument optionnel \argu{close} permet de refermer ou non chaque composante du chemin (\false par défaut).
    
    \item La méthode \cmd{g:Convpath3d(chemin)} convertit le \argu{chemin} en un autre chemin n'utilisant que les instructions "m", "l" et "b" (toutes les autres instructions sont transformées en courbes de Bézier). La fonction renvoie le nouveau chemin, l'intérêt de ce nouveau chemin est qu'on peut lui appliquer une matrice de transformation 3D (fonction \cmd{ld.mtransform3d()}).
    
    \item La méthode \cmd{g:Path3d2path2d(chemin)} convertit le chemin 3D \argu{chemin} en un chemin 2D (qui est la projection sur l'écran) et renvoie le résultat.
\end{itemize}


\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{xlabels=\{x1,\ldots,xn\}}, \opt{ylabels=\{y1,\ldots,yn\}}, \opt{zlabels=\{z1,\ldots,zn\}} : ces options permettent d'imposer les labels sur les axes. Par défaut ces options ont la valeur \nil, dans ce cas ce sont les labels par défaut (un par graduation) qui sont affichés.
    
    \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=<style courant>}, \opt{ylabelstyle=<style courant>}, \opt{zlabelstyle=<style courant>} : indique le style des labels, c'est à dire la position par rapport au point d'ancrage. Par défaut c'est le style en cours qui s'applique.

    \item \opt{xlegend="\$x\$"}, \opt{ylegend="\$y\$"}, \opt{zlegend="\$z\$"} : permet de définir une légende pour les axes.
    
    \item \opt{xlegendsep=0.5}, \opt{ylegendsep=0.5}, \opt{zlegendsep=0.5} : indique la distance entre les legendes et les graduations.     
\end{itemize}

\subsubsection{Dessiner sur un plan}

Il est possible d'utiliser les méthodes de dessin 2D sur un plan $P$ de l'espace. Il faut pour cela choisir tout d'abord un repère cartésien $(A,u,v)$ du plan $P$.
\begin{itemize}
    \item La méthode \cmd{g:BeginOnPlane(coordsystem \fac{, options})} permet de passer en mode "dessin sur un plan". L'argument \argu{coordsystem} est une table de la forme \{A,u,v\} représentant un repère cartésien du plan choisi, donc $A$ est un point 3D appartenant au plan, $u$ et $v$ sont deux vecteurs 3D formant une base de la direction du plan. L'argument \argu{options} est une table définissant les options, qui sont (avec leur valeur par défaut):
        \begin{itemize}
            \item \opt{labeldir=\nil}, cette option définit le sens de l'écriture, avec la valeur \nil c'est le sens courant, avec la valeur \val{"auto"} le sens de l'écriture est donnée par les vecteurs $u$ et $v$. On peut également imposer un autre sens de l'écriture ainsi: \opt{labeldir=\val{\{dir1, dir2\}}}, où \emph{dir1} et \emph{dir2} sont deux vecteurs 3D indépendants.
            Cette option ne donne pas toujours de bons résultats en projection centrale, car celle-ci n'est pas une transformation affine.
            
            \item \opt{view=\nil}, avec la valeur \nil la fenêtre sera la même que la fenêtre 2D du graphique. Avec une valeur de la forme \opt{view=\val{\{x1,x2,y1,y2\}}}, le dessin sera clippé par la fenêtre $[x_1;x_2]\times[y1;y_2]$ \textbf{dans le repère $(A,u,v)$}.
            
            \item \opt{out=\nil}, si l'utilisateur donne à cette option une variable de type table (\opt{out=<var>}), alors il pourra récupérer dans cette variable une matrice 2D qui redéfinit les axes pour correspondre à ceux du plan choisi. Cette matrice est utile notamment pour pouvoir utiliser la méthode \cmd{g:Dimage()} sur ce plan.
        \end{itemize}
    Une fois cette méthode exécutée, tout nombre complexe $z=Z(a,b)$ correspondra en réalité au point 3D $A+a\cdot u+b\cdot v$.
    
    \item La méthode \cmd{g:EndOnPlane()}, met fin au mode "dessin sur un plan".
\end{itemize}

\begin{demo}{Dessiner sur un plan}
\begin{luadraw}{name=draw_on_plane}
local ld = luadraw
local cpx, pt3d = ld.cpx, ld.pt3d
local Z, M = cpx.Z, pt3d.M
local Origin, vecI, vecJ, vecK = pt3d.Origin, pt3d.vecI, pt3d.vecJ, pt3d.vecK

local g = ld.graph3d:new{ window={-8,8,-9,8}, size={10,10}}
g:Labelsize("footnotesize")
local function f(x) return 2*math.sin(x) end
-- gauche
g:BeginOnPlane( {M(0,-5,0), vecI, vecK}, {labeldir="auto", view={-5,5,-5,5}})
    g:Daxes(nil, {limits={{-5,5},{-5,5}}})
    g:Dcartesian(f, {x={-5,5}, draw_options="red,thick"})
    g:Dcircle(0,3, "ForestGreen, fill=green!30,opacity=0.3")
    g:Dlabel("$\\mathcal{C}_{f}$", Z(2,2),{pos="N",node_options="red"})
g:EndOnPlane()
-- cube
g:Dpoly( g:Box3d(), {color="LightBlue!50!white", opacity=0.6})
-- dessus
g:BeginOnPlane( {M(0,0,5), vecJ, -vecI}, {labeldir="auto", view={-5,5,-5,5}})
    g:Daxes(nil, {limits={{-5,5},{-5,5}}, grid=true})
    g:Dcartesian(f, {x={-5,5}, draw_options="red,thick"})
    g:Dcircle(0,3, "ForestGreen, fill=green!30,opacity=0.3")
    g:Dlabel("$\\mathcal{C}_{f}$", Z(2,2),{pos="N",node_options="red"})
g:EndOnPlane() 
-- devant
g:BeginOnPlane( {M(5,0,0), vecK, -vecJ}, {labeldir={vecJ,vecK}, view={-5,5,-5,5}})
    g:Daxes(nil, {limits={{-5,5},{-5,5}}, labelstyle={"E","S"}, arrows="-stealth",
        legend={"$x$","$y$"}, legendpos={0.9,0.98}})
    g:Dcartesian(f, {x={-5,5}, draw_options="red,thick"})
    g:Dcircle(0,3, "ForestGreen, fill=green!30,opacity=0.3")
    g:Dlabel("$\\mathcal{C}_{f}$", Z(2,2),{pos="W",node_options="red"})
g:EndOnPlane()
-- droite
g:BeginOnPlane( {M(0,5,10), -vecK, -vecI}, {labeldir="auto", view={5,15,-5,5}})
    g:Daxes({10,1,1}, {grid=true, arrows="-stealth", labelshift={0,0}})
    g:Dcartesian(f, {x={5,15}, draw_options="red,thick"})
    g:Dlabel("$\\mathcal{C}_{f}$", Z(14,2),{pos="NW",node_options="red"})
g:EndOnPlane()
g:Show()
\end{luadraw}
\end{demo}

\subsection{Points et labels}

\subsubsection{Points 3D : Ddots3d, Dballdots3d, Dcrossdots3d}

Il y a trois possibilités de dessiner des points 3D. Pour les deux premières, l'argument \argu{L} peut être soit un seul point 3D, soit une liste (une table) de points 3D, soit une liste de listes de points 3D :

\begin{itemize}
    \item La méthode \cmd{g:Ddots3d(L \fac{, mark\_options, clip})}. Le principe est le même que dans la version 2D, les points sont dessinés dans la couleur courante du tracé de lignes avec le style courant. L'argument \argu{mark\_options} est une chaîne de caractères facultative qui sera passée telle quelle à l'instruction \drawcmd (modifications locales). 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 méthode \cmd{g:Dballdots3d(L \fac{, color, scale, clip})} dessine les points de \argu{L} sous forme d'une sphère. L'argument facultatif \argu{color} précise la couleur de la sphère (\val{"black"} par défaut), et l'argument facultatif \argu{scale} permet de jouer sur la taille de la sphère ($1$ par défaut).
    
    \item La méthode \cmd{g:Dcrossdots3d(L \fac{, color, scale, clip})} dessine les points de \argu{L} sous forme d'une croix plane. L'argument \argu{L} est une liste de la forme \{point 3D, vecteur normal\} ou \{ \{point3d, vecteur normal\}, \{point3d, vecteur normal\}, ...\}. Pour chaque point 3D, le vecteur normal associé permet de déterminer le plan contenant la croix. L'argument facultatif \argu{color} précise la couleur de la croix (\val{"black"} par défaut), et l'argument facultatif \argu{scale} permet de jouer sur la taille de la croix ($1$ par défaut).
\end{itemize}

\begin{demo}{Un tétraèdre et les centres de gravité de chaque face}
\begin{luadraw}{name=Ddots3d}
local ld = luadraw
local pt3d = ld.pt3d
local vecI, vecJ, vecK, M = pt3d.vecI, pt3d.vecJ, pt3d.vecK, pt3d.M

local g = ld.graph3d:new{viewdir={15,60},bbox=false,size={8,8}}
local A, B, C, D = 4*M(1,0,-0.5), 4*M(-1/2,math.sqrt(3)/2,-0.5), 4*M(-1/2,-math.sqrt(3)/2,-0.5), 4*M(0,0,1)
local u, v, w = B-A, C-A, D-A
-- centres de gravité faces cachées
for _, F in ipairs({{A,B,C},{B,C,D}}) do
local G, u = pt3d.isobar3d(F), pt3d.prod(F[2]-F[1],F[3]-F[1])
g:Dcrossdots3d({G,u}, "blue",0.75)
g:Dpolyline3d({{F[1],G,F[2]},{G,F[3]}},"dotted")
end
-- dessin du tétraèdre construit sur A, B, C et D
g:Dpoly( ld.tetra(A,u,v,w),{mode=ld.mShaded,opacity=0.7,color="Crimson"})
-- centres de gravité faces visibles
for _, F in ipairs({{A,B,D},{A,C,D}}) do
    local G, u = pt3d.isobar3d(F), pt3d.prod(F[2]-F[1],F[3]-F[1])
    g:Dcrossdots3d({G,u}, "blue",0.75)
    g:Dpolyline3d({{F[1],G,F[2]},{G,F[3]}},"dotted")
end
g:Dballdots3d({A,B,C,D}, "orange") --sommets
g:Show()
\end{luadraw}
\end{demo}

\subsubsection{Labels 3D : Dlabel3d}

La méthode pour placer un label dans l'espace est :

cmdln{g:Dlabel3d(text1, anchor1, options1, text2, anchor2, options2, \ldots).}

    \begin{itemize}
    \item  Les arguments \argu{text1}, \argu{text2}, \ldots, sont des chaînes de caractères, ce sont les labels.
    \item  Les arguments \argu{anchor1}, \argu{anchor2}, \ldots, sont des points 3D représentant les points d'ancrage des labels.
    \item  Les arguments \argu{options1}, \argu{options2}, \ldots,  permettent de définir localement les options des labels, ces options sont (avec leur valeur par défaut) :

        \begin{itemize}
            \item \opt{pos="center"} : indique la position du label dans le plan de l'écran par rapport au point d'ancrage, il peut valoir \val{"N"} pour nord, \val{"NE"} pour nord-est, \val{"NW"} pour nord-ouest, ou encore \val{"S"}, \val{"SE"}, \val{"SW"}. Par défaut, il vaut \val{"center"}, et dans ce cas le label est centré sur le point  d'ancrage.
            
            \item \opt{dist=0} : c'est la distance (en cm) entre le label et son point d'ancrage lorsque \opt{pos} n'est pas égal a \val{"center"}.
            
            \item \opt{dir=\{\}} : indique la direction de l'écriture dans l'espace, la liste vide indique le sens par défaut. Plus généralement, \code{dir=\{dirX,dirY,dep\}}, les 3 valeurs \emph{dirX}, \emph{dirY} et \emph{dep} sont trois points 3D représentant 3 vecteurs, les deux premiers indiquent le sens de l'écriture, le troisième un déplacement (translation) du label par rapport au point d'ancrage.
            
            \item \opt{node\_options=""} : chaîne destinée à recevoir des options qui seront directement passées à TikZ dans l'instruction \emph{\textbackslash node[]}.
            
            \item Les labels sont dessinés dans la couleur courante du texte du document, mais on peut changer de couleur avec l'option \opt{node\_options} en mettant par exemple : \opt{node\_options="color=blue"}.
            
            \textbf{Attention} : les options choisies pour un label s'appliquent aussi aux labels suivants si elles sont inchangées.
        \end{itemize}
  \end{itemize}

\subsection{Solides de base (sans facette)}

Les quatre méthodes décrites ci-dessous sont sensibles à la variable globale \varglob{ld.Hiddenlines} qui vaut \false par défaut.

\subsubsection{Cylindre : Dcylinder}

Dessiner un cylindre à base circulaire (droit ou penché). Plusieurs syntaxes possibles :
\begin{itemize}
    \item Ancienne syntaxe : \cmd{g:Dcylinder(A, V, r \fac{, options})} dessine un cylindre droit, où \argu{A} est un point 3D représentant le centre d'une des faces circulaires, \argu{V} est un point 3D, c'est un vecteur représentant l'axe du cylindre, le centre de la face circulaire opposée est le point $A+V$ (cette face est orthogonale à \argu{V}), et \argu{r} est le rayon de la base circulaire.
    
    \item La syntaxe : \cmd{g:Dcylinder(A, r, B \fac{, optons})} dessine un cylindre droit, où \argu{A} est un point 3D représentant le centre d'une des faces circulaires, \argu{B} est le centre de la face opposée, et \argu{r} est le rayon. Le cylindre est droit, c'est à dire que les faces circulaires sont orthogonales à l'axe $(AB)$.
    
    \item Pour un cylindre penché :  \cmd{g:Dcylinder(A, r, V, B \fac{, options})}, où \argu{A} est un point 3D représentant le centre d'une des faces circulaires, \argu{B} est le centre de la face circulaire opposée, \argu{r} est le rayon, et \argu{V} est un vecteur 3D non nul orthogonal au plan des faces circulaires.
\end{itemize}

Pour les trois syntaxes, \argu{options} est une table dont les champs définissent les options. Ces options sont (avec leur valeur par défaut) :
\begin{itemize}
    \item \opt{mode=ld.mWireframe} : deux valeurs possibles \val{ld.mWireframe} ou \val{ld.mGrid}. En mode \val{ld.mWireframe} c'est un dessin en fil de fer, en mode \val{ld.mGrid} c'est un dessin en grille (comme s'il y avait des facettes).
    
    \item \opt{hiddenstyle=ld.Hiddenlinestyle} : définit le style de ligne pour les parties cachées (mettre \val{"noline"} pour ne pas les afficher). Par défaut cette option a la valeur de la variable globale \varglob{ld.Hiddenlinestyle} qui est elle même initialisée avec la valeur \val{"dotted"}.
    
    \item \opt{hiddencolor=edgecolor}: définit la couleur des lignes cachées, par défaut c'est la même valeur que l'option \opt{edgecolor}.
    
    \item \opt{edgecolor=<couleur courante>}, définit la couleur des lignes.
    
    \item \opt{edgestyle=<style courant>}, définit le style de ligne pour les arêtes visibles.

    \item \opt{edgewidth=<épaisseur courante>}, définit l'épaisseur des des arêtes visible en dixième de point.    
    
    \item \opt{color=""}, lorsque cette option est une chaîne vide (valeur par défaut) il n'y a pas de remplissage,  lorsque c'est une couleur (sous forme de chaîne) il y a un remplissage avec un gradient linéaire.
    
    \item \opt{opacity=1}, définit la transparence du dessin.
    
    \item Paramètres pour le gradient : lorsqu'il y a un remplissage avec la couleur, un gradient linéaire est utilisé pour le côté du cylindre et un autre pour la section, dans les deux cas le gradient est défini comme suit:\par
    \codeln{left color=<color>!<l>, right color=<color>!<r>, middlecolor=<color>!<m>}
    où \emph{<color>} désigne la couleur utlisée, et \emph{<l>}, \emph{<m>}, \emph{<r>} sont trois nombres entre $0$ et $100$, ce sont ces trois nombres qui constituent les paramètres du gradient sous forme d'une table \emph{\{<l>,<m>,<r>\}}:
        \begin{itemize}
            \item Pour le côté du cylindre, c'est l'option \opt{gradside}, par défaut : \opt{gradside=\{50,10,100\}}.
            \item Pour la section du cylindre, c'est l'option \opt{gradsection}, par défaut : \opt{gradsection=\{25,18,50\}}.
        \end{itemize}
\end{itemize}

\subsubsection{Cône : Dcone}

Dessiner un cône à base circulaire (droit ou penché). Plusieurs syntaxes possibles :
\begin{itemize}
    \item Ancienne syntaxe : \cmd{g:Dcone(A, V, r \fac{, options})} dessine un cône droit, où \argu{A} est un point 3D représentant le sommet du cône, \argu{V} est un point 3D, c'est un vecteur représentant l'axe du cône, le centre de la face circulaire est le point $A+V$ (cette face est orthogonale à \argu{V}), et \argu{r} est le rayon de la base circulaire.
    
    \item La syntaxe : \cmd{g:Dcone(C, r, A \fac{, options})} dessine un cône droit, où \argu{A} est un point 3D représentant le sommet du cône, \argu{C} est le centre de la face circulaire, et \argu{r} est le rayon. Le cône est droit, c'est à dire que la face circulaire est orthogonale à l'axe $(AC)$.
    
    \item Pour un cône penché : \cmd{g:Dcone(C, r, V, A \fac{, options})}, où \argu{A} est un point 3D représentant le sommet du cône, \argu{C} est le centre de la face circulaire, \argu{r} est le rayon, et \argu{V} est un vecteur 3D non nul orthogonal au plan de la face circulaire.
\end{itemize}

Pour les trois syntaxes, \argu{options} est une table dont les champs définissent les options. Ces options sont (avec leur valeur par défaut) :
\begin{itemize}
    \item \opt{mode=ld.mWireframe} : deux valeurs possibles \val{ld.mWireframe} ou \val{ld.mGrid}. En mode \val{ld.mWireframe} c'est un dessin en fil de fer, en mode \val{ld.mGrid} c'est un dessin en grille (comme s'il y avait des facettes).
    
    \item \opt{hiddenstyle=ld.Hiddenlinestyle} : définit le style de ligne pour les parties cachées (mettre \val{"noline"} pour ne pas les afficher). Par défaut cette option a la valeur de la variable globale \varglob{ld.Hiddenlinestyle} qui est elle même initialisée avec la valeur \val{"dotted"}.
    
    \item \opt{hiddencolor=edgecolor}: définit la couleur des lignes cachées, par défaut c'est la même valeur que l'option \opt{edgecolor}.
    
    \item \opt{edgecolor=<couleur courante>}, définit la couleur des lignes.
    
    \item \opt{edgestyle=<style courant>}, définit le style de ligne pour les arêtes visibles.

    \item \opt{edgewidth=<épaisseur courante>}, définit l'épaisseur des des arêtes visible en dixième de point.    
    
    \item \opt{color=""}, lorsque cette option est une chaîne vide (valeur par défaut) il n'y a pas de remplissage,  lorsque c'est une couleur (sous forme de chaîne) il y a un remplissage avec un gradient linéaire.
    
    \item \opt{opacity=1}, définit la transparence du dessin.
    
    \item Paramètres pour le gradient : lorsqu'il y a un remplissage avec la couleur, un gradient linéaire est utilisé pour le côté du cône et un autre pour la section, dans les deux cas le gradient est défini comme suit:\par
    \codeln{left color=<color>!<l>, right color=<color>!<r>, middlecolor=<color>!<m>}
    où \emph{<color>} désigne la couleur utlisée, et \emph{<l>}, \emph{<m>}, \emph{<r>} sont trois nombres entre $0$ et $100$, ce sont ces trois nombres qui constituent les paramètres du gradient sous forme d'une table \emph{\{<l>,<m>,<r>\}}:
        \begin{itemize}
            \item Pour le côté du cône, c'est l'option \opt{gradside}, par défaut : \opt{gradside=\{50,10,100\}}.
            \item Pour la section du cône, c'est l'option \opt{gradsection}, par défaut : \opt{gradsection=\{25,18,50\}}.
        \end{itemize}
\end{itemize}

\subsubsection{Tronc de cône : Dfrustum}

Dessiner un tronc de cône à base circulaire (droit ou penché). Deux syntaxes possibles :

\begin{itemize}
    \item La syntaxe : \cmd{g:Dfrustum(A, R, r, B \fac{, options})} pour un tronc de cône droit, \argu{A} est un point 3D représentant le centre de la face de rayon \argu{R}, \argu{B} est le centre de la deuxième face circulaire, et son rayon est \argu{r}, les faces sont orthogonales au vecteur $\vec{AB}$. Lorsque $R=r$ on a simplement un cylindre.
    
    \item La syntaxe : \cmd{g:Dfrustum(A, R, r, V, B \fac{, options})} pour un tronc de cône penché, \argu{A} est un point 3D représentant le centre de la face de rayon \argu{R}, \argu{V} est un vecteur 3D représentant un vecteur normal aux faces circulaires, le centre de la deuxième face circulaire est le point \argu{B}, et son rayon est \argu{r}. Lorsque $R=r$ on a un cylindre penché.
\end{itemize}

Dans les deux cas, \argu{options} est une table dont les champs définissent les options. Ces options sont (avec leur valeur par défaut) :
\begin{itemize}
    \item \opt{mode=ld.mWireframe} : deux valeurs possibles \val{ld.mWireframe} ou \val{ld.mGrid}. En mode \val{ld.mWireframe} c'est un dessin en fil de fer, en mode \val{ld.mGrid} c'est un dessin en grille (comme s'il y avait des facettes).
    
    \item \opt{hiddenstyle=ld.Hiddenlinestyle} : définit le style de ligne pour les parties cachées (mettre \val{"noline"} pour ne pas les afficher). Par défaut cette option a la valeur de la variable globale \varglob{ld.Hiddenlinestyle} qui est elle même initialisée avec la valeur \val{"dotted"}.
    
    \item \opt{hiddencolor=edgecolor}: définit la couleur des lignes cachées, par défaut c'est la même valeur que l'option \opt{edgecolor}.
    
    \item \opt{edgecolor=<couleur courante>}, définit la couleur des lignes.
    
    \item \opt{edgestyle=<style courant>}, définit le style de ligne pour les arêtes visibles.

    \item \opt{edgewidth=<épaisseur courante>}, définit l'épaisseur des des arêtes visible en dixième de point.
    
    \item \opt{color=""}, lorsque cette option est une chaîne vide (valeur par défaut) il n'y a pas de remplissage,  lorsque c'est une couleur (sous forme de chaîne) il y a un remplissage avec un gradient linéaire.
    
    \item \opt{opacity=1}, définit la transparence du dessin.
    
    \item Paramètres pour le gradient : lorsqu'il y a un remplissage avec la couleur, un gradient linéaire est utilisé pour le côté du cône et un autre pour la section, dans les deux cas le gradient est défini comme suit:\par
    \codeln{left color=<color>!<l>, right color=<color>!<r>, middlecolor=<color>!<m>}
    où \emph{<color>} désigne la couleur utlisée, et \emph{<l>}, \emph{<m>}, \emph{<r>} sont trois nombres entre $0$ et $100$, ce sont ces trois nombres qui constituent les paramètres du gradient sous forme d'une table \emph{\{<l>,<m>,<r>\}}:
        \begin{itemize}
            \item Pour le côté du cône, c'est l'option \opt{gradside}, par défaut : \opt{gradside=\{50,10,100\}}.
            \item Pour la section du cône, c'est l'option \opt{gradsection}, par défaut : \opt{gradsection=\{25,18,50\}}.
        \end{itemize}
        
    \item \opt{old=\false} : avec la valeur \true, on peut utiliser l'ancienne syntaxe  \cmd{g:Dfrustum(A, R, r, V \fac{, options})}, dans ce cas le centre de la seconde face circulaire est $A+V$.
\end{itemize}

\subsubsection{Sphère : Dsphere}

La méthode \cmd{g:Dsphere(A, r \fac{, options})} dessine une sphère.

\begin{itemize}
    \item \argu{A} est un point 3D représentant le centre de la sphère.
    \item \argu{r} est le rayon de la pshère
    \item \argu{options} est une table dont les champs définissent les options. Ces options sont (avec leur valeur par défaut) :
        \begin{itemize}
            \item \opt{mode=ld.mWireframe} : trois valeurs possibles \val{ld.mWireframe} ou \val{ld.mGrid} ou \val{ld.mBorder}. En mode \val{ld.mWireframe} on dessine le contour (cercle) et l'équateur, en mode \val{ld.mGrid} c'est le contour avec méridiens et fuseaux (grille), et en mode \val{ld.mBorder} c'est le contour uniquement.
            
            \item \opt{hiddenstyle=ld.Hiddenlinestyle} : définit le style de ligne pour les parties cachées (mettre \val{"noline"} pour ne pas les afficher). Par défaut cette option a la valeur de la variable globale \varglob{ld.Hiddenlinestyle} qui est elle même initialisée avec la valeur \val{"dotted"}.
            
            \item \opt{hiddencolor=edgecolor}: définit la couleur des lignes cachées, par défaut c'est la même valeur que l'option \opt{edgecolor}.
            
            \item \opt{edgecolor=<couleur courante>}, définit la couleur des lignes.

            \item \opt{edgestyle=<style courant>}, définit le style de ligne pour les arêtes visibles.

            \item \opt{edgewidth=<épaisseur courante>}, définit l'épaisseur des des arêtes visible en dixième de point.            
    
            \item \opt{color=""}: lorsque cette option est une chaîne vide (valeur par défaut) il n'y a pas de remplissage, lorsque c'est une couleur (sous forme de chaîne) il y a un remplissage avec "ball color".
            
            \item \opt{opacity=1}, définit la transparence du dessin.
        \end{itemize}
\end{itemize}

\begin{demo}{Cylindres, cônes et sphères}
\begin{luadraw}{name=cylindre_cone_sphere}
local ld = luadraw
local pt3d = ld.pt3d
local vecI, vecJ, vecK, M = pt3d.vecI, pt3d.vecJ, pt3d.vecK, pt3d.M

local g = ld.graph3d:new{ size={10,10} }
local dessin = function(args)
    g:Dsphere(M(-1,-2.5,1),2.5, args)
    g:Dcone(M(-1,2.5,5),-5*vecK,2, args)
    g:Dcylinder(M(3,-2,0),6*vecJ,1.5, args)
end
-- en haut à gauche, options par défaut
g:Saveattr(); g:Viewport(-5,0,0,5); g:Coordsystem(-5,5,-5,5,true); dessin(); g:Restoreattr()
g:Saveattr(); g:Viewport(0,5,0,5); g:Coordsystem(-5,5,-5,5,true) -- en haut à droite
dessin({mode=ld.mGrid, hiddenstyle="solid", hiddencolor="LightGray"}); g:Restoreattr()
g:Saveattr(); g:Viewport(-5,0,-5,0); g:Coordsystem(-5,5,-5,5,true) -- en bas à gauche
dessin({mode=ld.mBorder, color="orange"}); g:Restoreattr()
g:Saveattr(); g:Viewport(0,5,-5,0); g:Coordsystem(-5,5,-5,5,true) -- en bas à droite
dessin({mode=ld.mGrid,opacity=0.8,hiddenstyle="noline",color="LightBlue"}); g:Restoreattr()
g:Show()
\end{luadraw}
\end{demo}

\subsubsection{Cone\_outline, Cylinder\_outline, Frustum\_outline, Sphere\_outline}

Les méthodes suivantes calculent et renvoient une table contenant les éléments caractéristiques relatifs au cône, au cylindre, au cône tronqué ou à la sphère. Ces méthodes prennent en compte le mode de projection ainsi que la matrice de transformation 3D du graphe. Les trois premières fonctions renvoient une table donc les champs sont:
    \begin{itemize}
        \item \opt{side} : chemin 3D représentant le contour de la partie latérale du solide.
        \item \opt{section} : liste de chemins 3D, chacun de ces chemins représente le contour d'une des bases visibles du solide.
        \item \opt{visible} : chemin 3D représentant le contour visible du solide.
        \item \opt{hidden} : chemin 3D représentant le contour caché du solide.
        \item \opt{tangency} : liste de points 3D représentant les points de tangence du solide, ce sont des points pour lesquels le plan tangent au solide contient la direction de l'observateur (vecteur \cmd{g.Normal}), ils sont sur les bases circulaires.
        \item \opt{angle} : angle en degré que fait l'axe du solide par rapport à l'horizontal.
    \end{itemize}

\paragraph{Description des quatre méthodes}

\begin{itemize}
    \item La méthode \cmd{g:Cone\_outline(C, r, \fac{V,} A)} calcule et renvoie les éléments caractéristiques du cône de sommet \argu{A},  et dont la base circulaire a pour centre \argu{C} et rayon \argu{r}. Le cône est droit si \argu{V} est omis, sinon la base est orthogonale au vecteur \argu{V} (cône penché).

    \item La méthode \cmd{g:Cylinder\_outline(C, r, \fac{V,} A)} calcule et renvoie les éléments caractéristiques du cylindre de rayon \argu{r}, et dont les bases circulaires ont pour centre \argu{C} et \argu{A}. Le cylindre est droit si \argu{V} est omis, sinon les bases circulaires sont orthogonales au vecteur \argu{V} (cylindre penché).
    
    \item La méthode \cmd{g:Frustum\_outline(C, R, r, \fac{V,} A)} calcule et les éléments caractéristiques du cône tronqué dont les bases circulaires ont pour centre \argu{C} et \argu{A}, et pour rayon \argu{R} (pour la première) et \argu{r}. Le cône tronqué est droit si \argu{V} est omis, sinon les bases circulaires sont orthogonales au vecteur \argu{V} (cône tronqué penché).
    
    \item La méthode \cmd{g:Sphere\_outline(C, R)} calcule et les éléments caractéristiques de la sphère, sous la forme d'une table dont les champs sont:
    \begin{itemize}
        \item \opt{visible} : chemin 3D représentant le contour apparent de la sphère.
        \item \opt{data} : liste de la forme $\{O,r,n\}$ où $O$ est le centre du cercle apparent, $r$ son rayon et $n$ un vecteur normal au plan du cercle apparent.
    \end{itemize}
\end{itemize}


\subsubsection{Cone\_tangency, Cylinder\_tangency, Frustum\_tangency, Sphere\_tangency}

Les méthodes suivantes calculent et renvoient sous forme d'une liste, les points de tangence, lorsqu'ils existent, au cône, au cylindre, au cône tronqué ou à la sphère.

\begin{itemize}
    \item La méthode \cmd{g:Cone\_tangency(C, r, \fac{V,} A)} calcule et renvoie les deux points de tangence au cône de sommet \argu{A},  et dont la base circulaire a pour centre \argu{C} et rayon \argu{r}. Le cône est droit si \argu{V} est omis, sinon la base est orthogonale au vecteur \argu{V} (cône penché). Les deux points de tangence sont sur la base circulaire, ce sont des points pour lesquels le plan tangent au cône contient la direction de l'observateur (vecteur \cmd{g.Normal}).
    
    \item La méthode \cmd{g:Cylinder\_tangency(C, r, \fac{V,} A)} calcule et renvoie les quatre points de tangence au cylindre de rayon \argu{r}, et dont les bases circulaires ont pour centre \argu{C} et \argu{A}. Le cylindre est droit si \argu{V} est omis, sinon les bases circulaires sont orthogonales au vecteur \argu{V} (cylindre penché). Les deux premiers points de tangence sont sur la base circulaire de centre \argu{C}, et les deux suivants sur l'autre base circulaire.
    
    \item La méthode \cmd{g:Frustum\_tangency(C, R, r, \fac{V,} A)} calcule et renvoie les quatre points de tangence au cône tronqué dont les bases circulaires ont pour centre \argu{C} et \argu{A}, et pour rayon \argu{R} (pour la première) et \argu{r}. Le cône tronqué est droit si \argu{V} est omis, sinon les bases circulaires sont orthogonales au vecteur \argu{V} (cône tronqué penché). Les deux premiers points de tangence sont sur la base circulaire de centre \argu{C}, et les deux suivants sur l'autre base circulaire.
    
    \item La méthode \cmd{g:Sphere\_tangency(C, R, P)} calcule et renvoie les deux points de tangence à la sphère de centre \argu{C} et de rayon \argu{R}, et au cercle correspondant à l'intersection de cette sphère avec le plan \argu{P} (qui est une liste de la forme $\{A,n\}$ où $A$ est un point du plan, et $n$ un vecteur normal au plan).
    
    \item La méthode \cmd{g:Sphere\_outline(C, R)} calcule et renvoie le cercle représentant le contour de la sphère, sous la forme d'une séquence : $O, r, n$ où $O$ est le centre du cercle, $r$ le rayon et $n$ un vecteur normal au plan du cercle. La méthode tient compte du mode de projection.
\end{itemize}

\begin{demo}{Points de tangence}
\begin{luadraw}{name=tangency}
local ld = luadraw
local pt3d, cpx = ld.pt3d, ld.cpx
local M, Z = pt3d.M, cpx.Z
local O, I, J, K = M(0,0,0), M(1,0,0), M(0,1,0), M(0,0,1)
local g = ld.graph3d:new{ size={10,10}, window={-5,5,-5,6} }
g:Shift( Z(-2.5,3.5) ) -- cylinder
local A, B, C, D = table.unpack( g:Cylinder_tangency(-3*K, 1.5, 2*K) )
g:Dcylinder(-3*K, 1.5, 2*K, {color="blue"})
g:Ddots3d({A,B,C,D})
g:Shift( Z(5,0) ) -- cone
local A, B = table.unpack( g:Cone_tangency(-3*K, 1.5, 2*K) )
g:Dcone(-3*K, 1.5, 2*K, {color="red"})
g:Ddots3d({A,B})
g:Shift( Z(0,-5) ) -- frustum
local A, B, C, D = table.unpack( g:Frustum_tangency(-3*K, 1.5,0.5, K) )
g:Dfrustum(-3*K, 1.5, 0.5, K, {color="green"})
g:Ddots3d({A,B,C,D})
g:Shift(Z(-5,-1.5)) -- sphere
local R, P = 2, {K, K}
local I, r, n = ld.interPS(P, {O,R})
local A, B = table.unpack( g:Sphere_tangency(O, R, P) )
g:Dsphere(O, R, {color="orange", mode=ld.mBorder})
g:Ddots3d({A,B})
g:Darc3d(A,I,B,r,1,n); g:Darc3d(A,I,B,r,-1,n,"dotted")
g:Show()
\end{luadraw}
\end{demo}
