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

\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 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).
\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=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{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 cône, 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, V \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{V} est un vecteur 3D représentant l'axe du tronc de cône, le centre de la deuxième face circulaire est le point $A+V$, et son rayon est \argu{r},  (les faces sont orthogonales à \argu{V}). 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}
\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}
