%%%
% Fonction
%%%
\setKVdefault[ClesFonction]{Nom=f,Variable=x,Calcul=x,Tableau=false,Largeur=5mm,Ecriture=false,Definition=false,Points=false,Tangentes=false,PasX=1,PasY=1,UniteX=1,UniteY=1,Prolonge=false,Trace=false,Catmull=false,Epaisseur=1,Couleur=black,CouleurTrace=black,PointsCourbe=true,Codes=false,Origine={(0,0)},Vide=false}
\defKV[ClesFonction]{Traces=\setKV[ClesFonction]{Codes}}%

\newtoks\toklistePtsFn%pour la discipline

\def\UpdatePtsFn#1/#2/#3/#4\nil{\addtotok\toklistePtsFn{#1,(#2,#3),#4,}}%
\def\UpdatePtsFN#1/#2/#3/#4\nil{\addtotok\toklistePtsFn{(#2,#3),}}%

\NewDocumentCommand\Fonction{o m}{%
  \useKVdefault[ClesFonction]%
  \setKV[ClesFonction]{#1}%
  \ifboolKV[ClesFonction]{Trace}{%
    \useKVdefault[TraceG]%
    \setKV[TraceG]{#1}%
    \MPTraceFonction[#1]{\useKV[ClesFonction]{Calcul}}%
  }{%
    \ifboolKV[ClesFonction]{Points}{%
      \toklistePtsFn{}%
      \setsepchar[*]{§*/}%\ignoreemptyitems%
      \readlist*\ListePoints{#2}%
      \ifboolKV[ClesFonction]{Catmull}{%
        \xdef\PfCFooListePoints{(\ListePoints[1,2],\ListePoints[1,3]),}%
        \foreachitem\compteur\in\ListePoints{%
          \xdef\PfCFooListePoints{\PfCFooListePoints (\ListePoints[\compteurcnt,2],\ListePoints[\compteurcnt,3]),}%
        }%
        \xdef\PfCFooListePoints{\PfCFooListePoints (\ListePoints[\ListePointslen,2],\ListePoints[\ListePointslen,3]),}%
        \MPCatmull{\PfCFooListePoints}{\useKV[ClesFonction]{PasX}}{\useKV[ClesFonction]{PasY}}{\useKV[ClesFonction]{UniteX}}{\useKV[ClesFonction]{UniteY}}%
      }{%
        \xdef\PfCFooListePoints{}
        \ifboolKV[ClesFonction]{Tangentes}{%
          \foreachitem\compteur\in\ListePoints{%
            % \expandafter\UpdatePtsFn\compteur\nil%
            \xdef\PfCFooListePoints{\PfCFooListePoints \ListePoints[\compteurcnt,1],(\ListePoints[\compteurcnt,2],\ListePoints[\compteurcnt,3]),\ListePoints[\compteurcnt,4],}%
          }%
        }{%
          \foreachitem\compteur\in\ListePoints{%
            % \expandafter\UpdatePtsFN\compteur\nil%
            \xdef\PfCFooListePoints{\PfCFooListePoints (\ListePoints[\compteurcnt,2],\ListePoints[\compteurcnt,3]),}%
          }%
        }%
        \MPCourbeNew{\PfCFooListePoints}%\the\toklistePtsFn}%
      }%
    }{%
      \setsepchar{,}\ignoreemptyitems%
      \readlist*\ListeFonction{#2}%
      \StrSubstitute{\useKV[ClesFonction]{Calcul}}{\useKV[ClesFonction]{Variable}}{\i}[\temp]%
      \StrSubstitute{\useKV[ClesFonction]{Calcul}}{**}{^}[\tempa]%
      \StrSubstitute{\tempa}{*}{}[\tempab]%
      \ifboolKV[ClesFonction]{Ecriture}{%
        \ensuremath{\useKV[ClesFonction]{Nom}(\useKV[ClesFonction]{Variable})=\tempab}%
      }{}%
      \ifboolKV[ClesFonction]{Definition}{%
        \ensuremath{\useKV[ClesFonction]{Nom}:\useKV[ClesFonction]{Variable}\mapsto\tempab}%
      }{}%
      \ifboolKV[ClesFonction]{Tableau}{%
        \buildtabfonction%
      }{}%
      \reademptyitems%
    }%
  }%
}%

\def\MPCourbeNew#1{%#2#3#4#5#6{%
  \ifluatex
  \mplibforcehmode
  \begin{mplibcode}
    x.u:=\useKV[ClesFonction]{PasX};
    y.u:=\useKV[ClesFonction]{PasY};
    X.u:=\useKV[ClesFonction]{UniteX};
    Y.u:=\useKV[ClesFonction]{UniteY};
    Epaisseur:=\useKV[ClesFonction]{Epaisseur};
    
    boolean Prolonge,Tangentes,PointsCourbe,Codes;
    Prolonge=\useKV[ClesFonction]{Prolonge};
    Tangentes=\useKV[ClesFonction]{Tangentes};
    PointsCourbe=\useKV[ClesFonction]{PointsCourbe};
    Codes=\useKV[ClesFonction]{Codes};

    color CouleurTrace;
    CouleurTrace=\useKV[ClesFonction]{CouleurTrace};

    def enplace=
    xscaled X.u yscaled Y.u
    enddef;

    vardef placepoint(expr q,r)=
    (q,r)*cm enplace
    enddef;
    
    numeric dirav[],dirap[];
    pair Fn[],Gn[];
    n=0;
    if Tangentes:
    for p_=#1:
    if (n mod 3)=0:
    dirav[n div 3]=p_;
    fi;
    if (n mod 3)=1:
    Gn[n div 3]=p_;
    Fn[n div 3]=cm*(X.u*xpart(p_),Y.u*ypart(p_));
    fi;
    if (n mod 3)=2:
    dirap[n div 3]=p_;
    fi;
    n:=n+1;
    endfor;
    N:=(n-1) div 3;
    else:
    for p_=#1:
    Gn[n]=p_;
    Fn[n]=cm*(X.u*xpart(p_),Y.u*ypart(p_));
    n:=n+1;
    endfor;
    N:=(n-1);
    fi;
    MinX=999;
    MaxX=-999;
    MinY=999;
    MaxY=-999;
    for k=0 upto N:
    if xpart(Gn[k])<MinX:
    MinX:=xpart(Gn[k]);
    fi;
    if xpart(Gn[k])>MaxX:
    MaxX:=xpart(Gn[k]);
    fi;
    if ypart(Gn[k])<MinY:
    MinY:=ypart(Gn[k]);
    fi;
    if ypart(Gn[k])>MaxY:
    MaxY:=ypart(Gn[k]);
    fi;
    endfor;
    if MinY<0:
    if MinY<>ceiling(MinY):
    MinY:=ceiling(MinY)-1;
    fi;
    fi;
    if MinX<0:
    if MinX<>ceiling(MinX):
    MinX:=ceiling(MinX)-1;
    fi;
    fi;
    if MaxY<>ceiling(MaxY):
    MaxY:=ceiling(MaxY);
    fi;
    if MaxX<>ceiling(MaxX):
    MaxX:=ceiling(MaxX);
    fi;
    if MaxX<1:
    MaxX:=1;
    fi;
    if MaxY<1:
    MaxY:=1;
    fi;
    if Prolonge:
    for k=MinY-1 step y.u until MaxY+1:
    draw cm*((MinX)*X.u,k*Y.u)--cm*((MaxX)*X.u,k*Y.u) withcolor 0.75white;
    endfor;
    for k=MinX step x.u until MaxX:
    draw cm*(k*X.u,(MinY-1)*Y.u)--cm*(k*X.u,(MaxY+1)*Y.u) withcolor 0.75white;
    endfor;
    else:
    for k=MinY-1 step y.u until MaxY+1:
    draw cm*((MinX-1)*X.u,k*Y.u)--cm*((MaxX+1)*X.u,k*Y.u) withcolor 0.75white;
    endfor;
    for k=MinX-1 step x.u until MaxX+1:
    draw cm*(k*X.u,(MinY-1)*Y.u)--cm*(k*X.u,(MaxY+1)*Y.u) withcolor 0.75white;
    endfor;
    fi;
    if Prolonge:    
    drawarrow (0,(MinY-1)*Y.u*cm)--(0,(MaxY+1)*Y.u*cm);
    drawarrow ((MinX)*X.u*cm,0)--((MaxX)*X.u*cm,0);
    else:
    drawarrow (0,(MinY-1)*Y.u*cm)--(0*cm,(MaxY+1)*Y.u*cm);
    drawarrow ((MinX-1)*X.u*cm,0*cm)--((MaxX+1)*X.u*cm,0*cm);
    fi;
    label.llft(btex O etex,(0,0));
    dotlabel.bot(btex 1 etex,cm*X.u*(1,0));
    dotlabel.lft(btex 1 etex,cm*Y.u*(0,1));
    draw if Tangentes:
    Fn[0]{dir dirap[0]}
    for k=1 upto (N-1):
    ..{dir dirav[k]}Fn[k]{dir dirap[k]}
    endfor
    ..{dir dirav[N]}Fn[N]
    else:
    Fn[0]
    for k=1 upto N:
    ..Fn[k]
    endfor fi withpen pencircle scaled Epaisseur withcolor CouleurTrace;
    if PointsCourbe:
    if Prolonge:
    for k=1 upto N-1:
    fill cercles(Fn[k],0.5mm);
    endfor;
    else:
    for k=0 upto N:
    fill cercles(Fn[k],0.5mm);
    endfor;
    fi;
    fi;
    if Codes:
    \useKV[ClesFonction]{Traces};
    fi;
  \end{mplibcode}
  \else
  \begin{mpost}[mpsettings={%
      x.u:=\useKV[ClesFonction]{PasX};y.u:=\useKV[ClesFonction]{PasY};
      X.u:=\useKV[ClesFonction]{UniteX};Y.u:=\useKV[ClesFonction]{UniteY};
      Epaisseur:=\useKV[ClesFonction]{Epaisseur};
      boolean Prolonge,Tangentes,PointsCourbe,Codes;
      Prolonge=\useKV[ClesFonction]{Prolonge};
      Tangentes=\useKV[ClesFonction]{Tangentes};
      PointsCourbe=\useKV[ClesFonction]{PointsCourbe};
      Codes=\useKV[ClesFonction]{Codes};
      color CouleurTrace;
      CouleurTrace=\useKV[ClesFonction]{CouleurTrace};
      }]
      def enplace=
      xscaled X.u yscaled Y.u
      enddef;
      vardef placepoint(expr q,r)=
      (q,r)*cm enplace
      enddef;
    numeric dirav[],dirap[];
    pair Fn[],Gn[];
    n=0;
    if Tangentes:
    for p_=#1:
    if (n mod 3)=0:
    dirav[n div 3]=p_;
    fi;
    if (n mod 3)=1:
    Gn[n div 3]=p_;
    Fn[n div 3]=cm*(X.u*xpart(p_),Y.u*ypart(p_));
    fi;
    if (n mod 3)=2:
    dirap[n div 3]=p_;
    fi;
    n:=n+1;
    endfor;
    N:=(n-1) div 3;
    else:
    for p_=#1:
    Gn[n]=p_;
    Fn[n]=cm*(X.u*xpart(p_),Y.u*ypart(p_));
    n:=n+1;
    endfor;
    N:=(n-1);
    fi;
    MinX=999;
    MaxX=-999;
    MinY=999;
    MaxY=-999;
    for k=0 upto N:
    if xpart(Gn[k])<MinX:
    MinX:=xpart(Gn[k]);
    fi;
    if xpart(Gn[k])>MaxX:
    MaxX:=xpart(Gn[k]);
    fi;
    if ypart(Gn[k])<MinY:
    MinY:=ypart(Gn[k]);
    fi;
    if ypart(Gn[k])>MaxY:
    MaxY:=ypart(Gn[k]);
    fi;
    endfor;
    if MinY<0:
    if MinY<>ceiling(MinY):
    MinY:=ceiling(MinY)-1;
    fi;
    fi;
    if MinX<0:
    if MinX<>ceiling(MinX):
    MinX:=ceiling(MinX)-1;
    fi;
    fi;
    if MaxY<>ceiling(MaxY):
    MaxY:=ceiling(MaxY);
    fi;
    if MaxX<>ceiling(MaxX):
    MaxX:=ceiling(MaxX);
    fi;
    if MaxX<1:
    MaxX:=1;
    fi;
    if MaxY<1:
    MaxY:=1;
    fi;
    if Prolonge:
    for k=MinY-1 step y.u until MaxY+1:
    draw cm*((MinX)*X.u,k*Y.u)--cm*((MaxX)*X.u,k*Y.u) withcolor 0.75white;
    endfor;
    for k=MinX step x.u until MaxX:
    draw cm*(k*X.u,(MinY-1)*Y.u)--cm*(k*X.u,(MaxY+1)*Y.u) withcolor 0.75white;
    endfor;
    else:
    for k=MinY-1 step y.u until MaxY+1:
    draw cm*((MinX-1)*X.u,k*Y.u)--cm*((MaxX+1)*X.u,k*Y.u) withcolor 0.75white;
    endfor;
    for k=MinX-1 step x.u until MaxX+1:
    draw cm*(k*X.u,(MinY-1)*Y.u)--cm*(k*X.u,(MaxY+1)*Y.u) withcolor 0.75white;
    endfor;
    fi;
    if Prolonge:    
    drawarrow (0,(MinY-1)*Y.u*cm)--(0,(MaxY+1)*Y.u*cm);
    drawarrow ((MinX)*X.u*cm,0)--((MaxX)*X.u*cm,0);
    else:
    drawarrow (0,(MinY-1)*Y.u*cm)--(0*cm,(MaxY+1)*Y.u*cm);
    drawarrow ((MinX-1)*X.u*cm,0*cm)--((MaxX+1)*X.u*cm,0*cm);
    fi;
    label.llft(btex O etex,(0,0));
    dotlabel.bot(btex 1 etex,cm*X.u*(1,0));
    dotlabel.lft(btex 1 etex,cm*Y.u*(0,1));
    draw if Tangentes:
    Fn[0]{dir dirap[0]}
    for k=1 upto (N-1):
    ..{dir dirav[k]}Fn[k]{dir dirap[k]}
    endfor
    ..{dir dirav[N]}Fn[N]
    else:
    Fn[0]
    for k=1 upto N:
    ..Fn[k]
    endfor fi withpen pencircle scaled Epaisseur withcolor CouleurTrace;
    if PointsCourbe:
    if Prolonge:
    for k=1 upto N-1:
    fill cercles(Fn[k],0.5mm);
    endfor;
    else:
    for k=0 upto N:
    fill cercles(Fn[k],0.5mm);
    endfor;
    fi;
    fi;
  \end{mpost}
  \fi
}

\def\MPCatmull#1#2#3#4#5{%
  % #1 la liste des points
  % #2: pas en x
  % #3: pas en y
  % #4: unit\'e en x
  % #5: unit\'e en y
  \ifluatex
  \mplibforcehmode
  \begin{mplibcode}
    boolean PointsCourbe;
    PointsCourbe=\useKV[ClesFonction]{PointsCourbe};

    boolean Code;
    Code=\useKV[ClesFonction]{Codes};
        
    x.u:=#2;
    y.u:=#3;
    X.u:=#4;
    Y.u:=#5;

    def enplace=
    xscaled X.u yscaled Y.u
    enddef;

    vardef placepoint(expr q,r)=
    (q,r)*cm enplace
    enddef;
    
    pair Fn[],Gn[];
    n=0;
    for p_=#1:
    Gn[n]=p_;
    Fn[n]=cm*(X.u*xpart(p_),Y.u*ypart(p_));
    n:=n+1;
    endfor;
    N:=(n-1);
    MinX=999;
    MaxX=-999;
    MinY=999;
    MaxY=-999;
    debutbalai=0;
    finbalai=N;
    if \useKV[ClesFonction]{Prolonge}:
    debutbalai:=2;
    finbalai:=N-2;
    fi;
    for k=debutbalai upto finbalai:
    if xpart(Gn[k])<MinX:
    MinX:=xpart(Gn[k]);
    fi;
    if xpart(Gn[k])>MaxX:
    MaxX:=xpart(Gn[k]);
    fi;
    if ypart(Gn[k])<MinY:
    MinY:=ypart(Gn[k]);
    fi;
    if ypart(Gn[k])>MaxY:
    MaxY:=ypart(Gn[k]);
    fi;
    endfor;
    if MaxY<1:
    MaxY:=2;
    fi;
    if MinY>-1:
    MinY:=-2;
    fi;
    if MinY<0:
    if MinY<>ceiling(MinY):
    MinY:=ceiling(MinY)-1;
    fi;
    fi;
    if MinX<0:
    if MinX<>ceiling(MinX):
    MinX:=ceiling(MinX)-1;
    fi;
    fi;
    if MaxY<>ceiling(MaxY):
    MaxY:=ceiling(MaxY);
    fi;
    if MaxX<>ceiling(MaxX):
    MaxX:=ceiling(MaxX);
    fi;
    if MaxX<1:
    MaxX:=1;
    fi;
    if MaxY<1:
    MaxY:=1;
    fi;
    %
    path cadreexterieur;
    cadreexterieur=(((MinX-1)*X.u*cm,(MinY-1)*Y.u*cm)--((MaxX+1)*X.u*cm,(MinY-1)*Y.u*cm)--((MaxX+1)*X.u*cm,(MaxY+1)*Y.u*cm)--((MinX-1)*X.u*cm,(MaxY+1)*Y.u*cm)--cycle);
    draw Fn[1]
    for k=2 upto N-1:
    ..{dir angle(Fn[k+1]-Fn[k-1])}Fn[k]{dir angle(Fn[k+1]-Fn[k-1])}
    endfor withpen pencircle scaled \useKV[ClesFonction]{Epaisseur} withcolor \useKV[ClesFonction]{Couleur};
    clip currentpicture to cadreexterieur;
    picture RetiensCourbe;
    RetiensCourbe=currentpicture;
    currentpicture:=nullpicture;
    for k=MinY-1 step y.u until MaxY+1:
    draw cm*((MinX-1)*X.u,k*Y.u)--cm*((MaxX+1)*X.u,k*Y.u) withcolor 0.75white;
    endfor;
    for k=MinX-1 step x.u until MaxX+1:
    draw cm*(k*X.u,(MinY-1)*Y.u)--cm*(k*X.u,(MaxY+1)*Y.u) withcolor 0.75white;
    endfor;
    if PointsCourbe:
    for k=debutbalai upto finbalai:
    fill cercles(Fn[k],0.5mm);
    endfor;
    fi;
    drawarrow (0,(MinY-1)*Y.u*cm)--(0,(MaxY+1)*Y.u*cm);
    drawarrow ((MinX-1)*X.u*cm,0)--((MaxX+1)*X.u*cm,0);
    %
    draw RetiensCourbe;
    label.llft(btex O etex,(0,0));
    dotlabel.bot(btex 1 etex,cm*X.u*(1,0));
    dotlabel.lft(btex 1 etex,cm*Y.u*(0,1));
    if Code:
    \useKV[ClesFonction]{Traces};
    fi;
  \end{mplibcode}
  \else
  \begin{mpost}[mpsettings={numeric Epaisseur; Epaisseur=\useKV[ClesFonction]{Epaisseur}; color CouleurCourbe; CouleurCourbe=\useKV[ClesFonction]{Couleur};boolean PointsCourbe;PointsCourbe=\useKV[ClesFonction]{PointsCourbe};}]
        x.u:=#2;
    y.u:=#3;
    X.u:=#4;
    Y.u:=#5;

    pair Fn[],Gn[];
    n=0;
    for p_=#1:
    Gn[n]=p_;
    Fn[n]=cm*(X.u*xpart(p_),Y.u*ypart(p_));
    n:=n+1;
    endfor;
    N:=(n-1);
    MinX=999;
    MaxX=-999;
    MinY=999;
    MaxY=-999;
    debutbalai=0;
    finbalai=N;
    if \useKV[ClesFonction]{Prolonge}:
    debutbalai:=2;
    finbalai:=N-2;
    fi;
    for k=debutbalai upto finbalai:
    if xpart(Gn[k])<MinX:
    MinX:=xpart(Gn[k]);
    fi;
    if xpart(Gn[k])>MaxX:
    MaxX:=xpart(Gn[k]);
    fi;
    if ypart(Gn[k])<MinY:
    MinY:=ypart(Gn[k]);
    fi;
    if ypart(Gn[k])>MaxY:
    MaxY:=ypart(Gn[k]);
    fi;
    endfor;
    if MaxY<1:
    MaxY:=2;
    fi;
    if MinY>-1:
    MinY:=-2;
    fi;
    if MinY<0:
    if MinY<>ceiling(MinY):
    MinY:=ceiling(MinY)-1;
    fi;
    fi;
    if MinX<0:
    if MinX<>ceiling(MinX):
    MinX:=ceiling(MinX)-1;
    fi;
    fi;
    if MaxY<>ceiling(MaxY):
    MaxY:=ceiling(MaxY);
    fi;
    if MaxX<>ceiling(MaxX):
    MaxX:=ceiling(MaxX);
    fi;
    if MaxX<1:
    MaxX:=1;
    fi;
    if MaxY<1:
    MaxY:=1;
    fi;
    %
    path cadreexterieur;
    cadreexterieur=(((MinX-1)*X.u*cm,(MinY-1)*Y.u*cm)--((MaxX+1)*X.u*cm,(MinY-1)*Y.u*cm)--((MaxX+1)*X.u*cm,(MaxY+1)*Y.u*cm)--((MinX-1)*X.u*cm,(MaxY+1)*Y.u*cm)--cycle);
    draw Fn[1]
    for k=2 upto N-1:
    ..{dir angle(Fn[k+1]-Fn[k-1])}Fn[k]{dir angle(Fn[k+1]-Fn[k-1])}
    endfor withpen pencircle scaled \useKV[ClesFonction]{Epaisseur} withcolor \useKV[ClesFonction]{Couleur};
    clip currentpicture to cadreexterieur;
    picture RetiensCourbe;
    RetiensCourbe=currentpicture;
    currentpicture:=nullpicture;
    for k=MinY-1 step y.u until MaxY+1:
    draw cm*((MinX-1)*X.u,k*Y.u)--cm*((MaxX+1)*X.u,k*Y.u) withcolor 0.75white;
    endfor;
    for k=MinX-1 step x.u until MaxX+1:
    draw cm*(k*X.u,(MinY-1)*Y.u)--cm*(k*X.u,(MaxY+1)*Y.u) withcolor 0.75white;
    endfor;
    if PointsCourbe:
    for k=debutbalai upto finbalai:
    fill cercles(Fn[k],0.5mm);
    endfor;
    fi;
    drawarrow (0,(MinY-1)*Y.u*cm)--(0,(MaxY+1)*Y.u*cm);
    drawarrow ((MinX-1)*X.u*cm,0)--((MaxX+1)*X.u*cm,0);
    %
    draw RetiensCourbe;
    label.llft(btex O etex,(0,0));
    dotlabel.bot(btex 1 etex,cm*X.u*(1,0));
    dotlabel.lft(btex 1 etex,cm*Y.u*(0,1));
  \end{mpost}
  \fi
}%

\def\buildtabfonction{%
  \[%
    \begin{array}{|>{\columncolor{gray!15}}c|*{\number\numexpr\ListeFonctionlen}{>{\centering\arraybackslash}p{\useKV[ClesFonction]{Largeur}}|}}%
      \hline%
      \useKV[ClesFonction]{Variable}\xintFor* ##1 in {\xintSeq {1}{\ListeFonctionlen}}\do{&\num{\ListeFonction[##1]}}\\
      \hline%
      \useKV[ClesFonction]{Nom}(\useKV[ClesFonction]{Variable})\xintFor* ##1 in {\xintSeq {1}{\ListeFonctionlen}}\do{&\ifboolKV[ClesFonction]{Vide}{}{\StrSubstitute{\useKV[ClesFonction]{Calcul}}{\useKV[ClesFonction]{Variable}}{(\ListeFonction[##1])}[\tempab]\num{\fpeval{\tempab}}}}%
      \\\hline
    \end{array}%
  \]%
}%