% tkz-grapheur-macros.tex
% Copyright 2026 Cédric Pierquet
% Released under the LaTeX Project Public License v1.3c or later, see http://www.latex-project.org/lppl.txt
% macros [int] de tkz-grapheur-fr

%====PATCH SIMPLEKV
% synchronisation booléen FR↔EN (défaut false côté FR)
\newcommand\tkzgrphSetKVboolFalse[3][]{%
  % #1=famille  #2=clé EN  #3=clé FR
  \ifboolKV[#1]{#2}{\setKV[#1]{#3=true}}{}%
}

% synchronisation booléen FR↔EN (défaut true côté FR)
\newcommand\tkzgrphSetKVboolTrue[3][]{%
  % #1=famille  #2=clé EN  #3=clé FR
  \ifboolKV[#1]{#2}{}{\setKV[#1]{#3=false}}%
}

%====CONSTANTE PI pour xint, à voir si incompatibilité...
\xintdefvar pi:=3.141592653589793238462643;
\xintdeffloatvar pi:=3.141592653589793238462643;

%====fonction ln, en langage xint
\xintdeffunc ln(x) := log(x);
\xintdeffloatfunc ln(x) := log(x);

%====fonction minmax, en langage xint
\xintdeffloatfunc tkzgminmax(a,x,b) = (x>b)?{b}{(x<a)?{a}{x}};
\xintdeffunc tkzgminmax(a,x,b) = (x>b)?{b}{(x<a)?{a}{x}};

%====DENSITÉ KHIDEUX
\xintdeffloatfunc pflrecigamma(x) := x+0.577215664901*x^2-0.65587807152056*x^3-0.042002635033944*x^4+0.16653861138228*x^5-0.042197734555571*x^6;
\xintdeffloatfunc pflgamma(x) := (x==1)?{1}{(abs(x)<=0.5)?{1/pflrecigamma(x)}{(x-1)*pflgamma(x-1)}};
\xintdeffloatfunc pflkhideux(x,k) := (x<0)?{0}{(1/(2^(k/2)*pflgamma(k/2)))*x^(k/2-1)*exp(-x/2)};

%====PGFPLOTS MACROS (EN/FR)
\NewDocumentCommand\findintersectionspgf{ O{ITSC} m m D<>{\myt} }{%
  %1 = name of node name
  %2 = 1st object
  %3 = 2d object
  %4 = macro storing number of intersections
  \path[name intersections={of=#2 and #3,name=#1,total=\t}] \pgfextra{\xdef#4{\t}} ;
}

\NewDocumentCommand\gextractxnodepgf{ m O{\myxcoord} }{%
  \path \pgfextra{\pgfplotspointgetcoordinates{#1}\pgfkeysgetvalue{/data point/x}{\tmpxgetvalue}\xdef#2{\tmpxgetvalue}} ;
}

\NewDocumentCommand\gextractynodepgf{ m O{\myycoord} }{%
  \path \pgfextra{\pgfplotspointgetcoordinates{#1}\pgfkeysgetvalue{/data point/y}{\tmpygetvalue}\xdef#2{\tmpygetvalue}} ;
}

\NewDocumentCommand\gextractxynodepgf{  m O{\myxcoord} O{\myycoord} }{%
  \path \pgfextra{\pgfplotspointgetcoordinates{#1}\pgfkeysgetvalue{/data point/x}{\tmpxgetvalue}\xdef#2{\tmpxgetvalue}\pgfkeysgetvalue{/data point/y}{\tmpygetvalue}\xdef#3{\tmpygetvalue}} ;
}

\NewDocumentCommand\fillbetweencurvespgf{ O{gray,fill opacity=0.25} m m D<>{} }{%
  \addplot[#1] fill between [of=#2 and #3,soft clip={#4}];
}

\NewDocumentCommand\gensplinecubicpgf{ s m m O{\monspline} }{%
  %1=liste
  \setsepchar[.]{§./}%
  \readlist*\SPLlistepoints{#2}%
  %les données
  \def\tmpsplinenumdeb{1}
  \def\tmpsplinenumfin{\SPLlistepointslen}%
  \pflextractcoeff{#3}{\tmpsplinenumdeb}%
  %nb de calculs
  \def\SPLnbsplines{\inteval{\tmpsplinenumfin-1}}%
  %extraction des coordonnées
  \itemtomacro\SPLlistepoints[\tmpsplinenumdeb,1]\xa%
  \itemtomacro\SPLlistepoints[\tmpsplinenumdeb,2]\ya%
  \itemtomacro\SPLlistepoints[\tmpsplinenumdeb,3]\fprimea%
  \itemtomacro\SPLlistepoints[\tmpsplinenumdeb,1]\xb%
  \itemtomacro\SPLlistepoints[\tmpsplinenumdeb,2]\yb%
  \itemtomacro\SPLlistepoints[\tmpsplinenumdeb,3]\fprimeb%
  \IfBooleanTF{#1}%
    {%
      \xdef\tmpcontrolsxa{\xintfloateval{(\xa)+((\xb)-(\xa))/\COEFFA}}%
      \xdef\tmpcontrolsya{\xintfloateval{(\ya)+(\fprimea)*((\xb)-(\xa))/\COEFFA}}%
      \xdef\tmpcontrolsxb{\xintfloateval{(\xb)-((\xb)-(\xa))/\COEFFA}}%
      \xdef\tmpcontrolsyb{\xintfloateval{(\yb)-(\fprimeb)*((\xb)-(\xa))/\COEFFA}}%
    }%
    {%
      \xdef\tmpcontrolsxa{\xintfloateval{(\xa)+cos(atand(\fprimea))*(\xb-(\xa))/\COEFFA}}%
      \xdef\tmpcontrolsya{\xintfloateval{(\ya)+sin(atand(\fprimea))*(\xb-(\xa))/\COEFFA}}%
      \xdef\tmpcontrolsxb{\xintfloateval{(\xb)-cos(atand(\fprimeb))*(\xb-(\xa))/\COEFFA}}%
      \xdef\tmpcontrolsyb{\xintfloateval{(\yb)-sin(atand(\fprimeb))*(\xb-(\xa))/\COEFFA}}%
    }%
  \xdef#4{(\xa,\ya) ..controls (\tmpcontrolsxa,\tmpcontrolsya) and (\tmpcontrolsxb,\tmpcontrolsyb).. (\xb,\yb)}%
  \foreach \i in {\tmpsplinenumdeb,...,\SPLnbsplines}{%
    %extraction des coeffs de compensation
    \pflextractcoeff{#3}{\i}%
    \def\j{\inteval{\i+1}}%
    \itemtomacro\SPLlistepoints[\i,1]\xa%
    \itemtomacro\SPLlistepoints[\i,2]\ya%
    \itemtomacro\SPLlistepoints[\i,3]\fprimea%
    \itemtomacro\SPLlistepoints[\j,1]\xb%
    \itemtomacro\SPLlistepoints[\j,2]\yb%
    \itemtomacro\SPLlistepoints[\j,3]\fprimeb%
    \IfBooleanTF{#1}%
      {%
        \xdef\tmpcontrolsxa{\xintfloateval{(\xa)+(\xb-(\xa))/\COEFFA}}%
        \xdef\tmpcontrolsya{\xintfloateval{(\ya)+(\fprimea)*(\xb-(\xa))/\COEFFA}}%
        \xdef\tmpcontrolsxb{\xintfloateval{(\xb)-(\xb-(\xa))/\COEFFA}}%
        \xdef\tmpcontrolsyb{\xintfloateval{(\yb)-(\fprimeb)*(\xb-(\xa))/\COEFFA}}%
      }%
      {%
        \xdef\tmpcontrolsxa{\xintfloateval{(\xa)+cos(atand(\fprimea))*(\xb-(\xa))/\COEFFA}}%
        \xdef\tmpcontrolsya{\xintfloateval{(\ya)+sin(atand(\fprimea))*(\xb-(\xa))/\COEFFA}}%
        \xdef\tmpcontrolsxb{\xintfloateval{(\xb)-cos(atand(\fprimeb))*(\xb-(\xa))/\COEFFA}}%
        \xdef\tmpcontrolsyb{\xintfloateval{(\yb)-sin(atand(\fprimeb))*(\xb-(\xa))/\COEFFA}}%
      }%
    \xdef#4{#4 ..controls (\tmpcontrolsxa,\tmpcontrolsya) and (\tmpcontrolsxb,\tmpcontrolsyb).. (\xb,\yb)}%
  }%
}

\NewDocumentCommand\addplotspline{ s O{} D<>{3} m O{\monspline} }{%
  \IfBooleanTF{#1}%
    {%
      \gensplinecubicpgf*{#4}{#3}[#5]%
    }%
    {%
      \gensplinecubicpgf{#4}{#3}[#5]%
    }%
  \draw[#2] #5 ;
}

%====MACRO INTERNE : transformation d'une liste interpo (x1,y1)(x2,y2)... liste reconstruite est stockée dans \TRFlistedecaleeinterpo
\NewDocumentCommand\tkzg@transfo@interpo{ m m m }{%
  %#1=liste interpo originale, #2=a, #3=b
  %retrait de la première '(' et de la dernière ')'
  \StrGobbleLeft{#1}{1}[\TRFtmpinterpo]%
  \StrGobbleRight{\TRFtmpinterpo}{1}[\TRFtmpinterpo]%
  \setsepchar{)(}%
  \readlist*\TRFlisteinterpo{\TRFtmpinterpo}%
  \gdef\TRFlistedecaleeinterpo{}%
  \foreach \i in {1,...,\TRFlisteinterpolen}{%
    \StrCut{\TRFlisteinterpo[\i]}{,}{\TRFxi}{\TRFyi}%
    \xdef\TRFxip{\xintfloateval{(\TRFxi)+(#2)}}%
    \xdef\TRFyip{\xintfloateval{(\TRFyi)+(#3)}}%
    \xdef\TRFlistedecaleeinterpo{\TRFlistedecaleeinterpo(\TRFxip,\TRFyip)}%
  }%
}

%====MACRO INTERNE : transformation d'une liste spline x/y/d § x/y/d §... liste reconstruite est stockée dans \TRFlistedecaleespline
%   NB : pas de § final (cohérent avec le format attendu par \GenererSpline)
\NewDocumentCommand\tkzg@transfo@spline{ m m m }{%
  %#1=liste spline originale, #2=a, #3=b
  \setsepchar[.]{§./}%
  \readlist*\TRFlistepoints{#1}%
  \gdef\TRFlistedecaleespline{}%
  \foreach \i in {1,...,\TRFlistepointslen}{%
    \itemtomacro\TRFlistepoints[\i,1]\TRFxi%
    \itemtomacro\TRFlistepoints[\i,2]\TRFyi%
    \itemtomacro\TRFlistepoints[\i,3]\TRFdi%
    % x' = xi+a,  y' = yi+b,  d' = di (pente inchangée par translation)
    \xdef\TRFxip{\xintfloateval{(\TRFxi)+(#2)}}%
    \xdef\TRFyip{\xintfloateval{(\TRFyi)+(#3)}}%
    % § entre les points, mais pas après le dernier
    \ifnum\i=\TRFlistepointslen%
    \xdef\TRFlistedecaleespline{\TRFlistedecaleespline\TRFxip/\TRFyip/\TRFdi}%
    \else%
    \xdef\TRFlistedecaleespline{\TRFlistedecaleespline\TRFxip/\TRFyip/\TRFdi §}%
    \fi%
  }%
}

%====MACRO INTERNE : réflexion d'une liste interpo (x1,y1)(x2,y2)...
%   stocke le résultat dans \RFXlistedecaleeinterpo
\NewDocumentCommand\tkzg@reflexion@interpo{ m m }{%
  %#1=liste interpo originale, #2=axe (x/y/yx)
  \StrGobbleLeft{#1}{1}[\RFXtmpinterpo]%
  \StrGobbleRight{\RFXtmpinterpo}{1}[\RFXtmpinterpo]%
  \setsepchar{)(}%
  \readlist*\RFXlisteinterpo{\RFXtmpinterpo}%
  \gdef\RFXlistedecaleeinterpo{}%
  \foreach \i in {1,...,\RFXlisteinterpolen}{%
    \StrCut{\RFXlisteinterpo[\i]}{,}{\RFXxi}{\RFXyi}%
    \IfStrEqCase{#2}{%
      {x}{%
        % -f(x) : (xi, -yi)
        \xdef\RFXxip{\xintfloateval{(\RFXxi)}}%
        \xdef\RFXyip{\xintfloateval{-(\RFXyi)}}%
      }%
      {y}{%
        % f(-x) : (-xi, yi)
        \xdef\RFXxip{\xintfloateval{-(\RFXxi)}}%
        \xdef\RFXyip{\xintfloateval{(\RFXyi)}}%
      }%
      {yx}{%
        % réciproque : (yi, xi)
        \xdef\RFXxip{\xintfloateval{(\RFXyi)}}%
        \xdef\RFXyip{\xintfloateval{(\RFXxi)}}%
      }%
    }%
    \xdef\RFXlistedecaleeinterpo{\RFXlistedecaleeinterpo(\RFXxip,\RFXyip)}%
  }%
}

%====MACRO INTERNE : réflexion d'une liste spline x/y/d § x/y/d §... résultat dans \RFXlistedecaleespline
\NewDocumentCommand\tkzg@reflexion@spline{ m m }{%
  %#1=liste spline originale, #2=axe (x/y/yx)
  \setsepchar[.]{§./}%
  \readlist*\RFXlistepoints{#1}%
  \gdef\RFXlistedecaleespline{}%
  % Détermination du sens de parcours :
  %   Axe=x  : abscisses xi inchangées → ordre naturel
  %   Axe=y  : nouvelles abscisses = -xi → ordre inversé si xi croissants
  %   Axe=yx : scope avec matrix transform
  \IfStrEqCase{#2}{%
    {x}{\edef\RFXboucle{1,...,\RFXlistepointslen}\edef\RFXdernierindex{\RFXlistepointslen}}%
    {y}{%
      % nouvelles abscisses = -xi : si xi croissants → -xi décroissants → inverser
      \itemtomacro\RFXlistepoints[1,1]\RFXxpremier%
      \itemtomacro\RFXlistepoints[\RFXlistepointslen,1]\RFXxdernier%
      \xintifboolexpr{(\RFXxpremier) < (\RFXxdernier)}%
      {\edef\RFXboucle{\RFXlistepointslen,...,1}\def\RFXdernierindex{1}}%
      {\edef\RFXboucle{1,...,\RFXlistepointslen}\edef\RFXdernierindex{\RFXlistepointslen}}%
    }%
  }%
  \foreach \i in \RFXboucle{%
    \itemtomacro\RFXlistepoints[\i,1]\RFXxi%
    \itemtomacro\RFXlistepoints[\i,2]\RFXyi%
    \itemtomacro\RFXlistepoints[\i,3]\RFXdi%
    \IfStrEqCase{#2}{%
      {x}{%
        % -f(x) : (xi, -yi, -di)
        \xdef\RFXxip{\xintfloateval{(\RFXxi)}}%
        \xdef\RFXyip{\xintfloateval{-(\RFXyi)}}%
        \xdef\RFXdip{\xintfloateval{-(\RFXdi)}}%
      }%
      {y}{%
        % f(-x) : (-xi, yi, -di)
        \xdef\RFXxip{\xintfloateval{-(\RFXxi)}}%
        \xdef\RFXyip{\xintfloateval{(\RFXyi)}}%
        \xdef\RFXdip{\xintfloateval{-(\RFXdi)}}%
      }%
    }%
    % § entre les points, mais pas après le dernier
    \ifnum\i=\RFXdernierindex\relax%
      \xdef\RFXlistedecaleespline{\RFXlistedecaleespline\RFXxip/\RFXyip/\RFXdip}%
    \else%
      \xdef\RFXlistedecaleespline{\RFXlistedecaleespline\RFXxip/\RFXyip/\RFXdip §}%
    \fi%
  }%
}

%====Macro auxiliaire : récupère l'élément i (cyclique) d'une liste listofitems
\newcommand\tkzgmod[3][\tkzgmodres]{%
  \xdef#1{\fpeval{trunc(#2 - (#3)*trunc((#2)/(#3),0), 0)}}%
  \ifnum#1<0\relax%
    \xdef#1{\inteval{#1 + (#3)}}%
  \fi%
}
\NewDocumentCommand\itemcycltomacro{ m O{1} m }{%
  \xdef\tmpargcycllist{\fpeval{round(#2,0)}}%
  \ifnum\tmpargcycllist=0\relax%
    \def#3{}%
    \PackageWarning{tkz-grapheur}{itemcycltomacro .: index 0 not available :.}%
  \else%
    \ifnum\tmpargcycllist>0\relax%
      \tkzgmod{#2-1}{\csname\expandafter\@gobble\string#1len\endcsname}%
    \else%
      \tkzgmod{#2}{\csname\expandafter\@gobble\string#1len\endcsname}%
    \fi%
    \xdef\pfltmpidx{\inteval{\tkzgmodres+1}}%
    \itemtomacro#1[\pfltmpidx]{#3}%
  \fi%
}

%====MACRO INTERNE : calcul de f^(k)(a) par différences finies centrées
%   résultat stocké dans \pfltaylorderivk
%   #1 = nom de la fonction xint
%   #2 = ordre k
%   #3 = point a
%   #4 = pas h
\NewDocumentCommand\tkzg@taylor@derive{ m m m m }{%
  \xdef\pfltaylorderivk{%
    \xintfloateval{%
      add(
      (-1)^(j) * binomial(#2,j) * #1((#3) + ((#2)/2 - j)*(#4)),
      j=0..#2
      ) / (#4)^(#2)
    }%
  }%
}

%====MACRO INTERNE : construction de la fonction Taylor d'ordre N
%   définit pfltaylorpoly(x) comme fonction xint
%   #1 = nom de la fonction xint
%   #2 = ordre N
%   #3 = point a
%   #4 = pas h
\NewDocumentCommand\tkzg@taylor@build{ m m m m }{%
  % calcul des coefficients c_k = f^(k)(a) / k!
  % et construction de la somme
  \gdef\pfltaylorexpr{0}%
  \foreach \k in {0,...,#2}{%
    \tkzg@taylor@derive{#1}{\k}{#3}{#4}%
    % terme k : c_k * (x-a)^k
    \xdef\pfltaylorexpr{%
      \pfltaylorexpr + \pfltaylorderivk / factorial (\k) * (x-(#3))^\k%
    }%
  }%
  \xintdeffloatfunc pfltaylorpoly(x) := \pfltaylorexpr ;%
}

%====MACRO INTERNE : graduations automatiques avec magnitude
\NewDocumentCommand\tkzgDeltaGradAuto{sO{0}mmO{\mydeltagrad}}{%
	%* = affiche juste
	%2 = min
	%3 = max
	%4 = nbgrads
	%5 = macro
	\xdef\tmpDeltabrut{\xintfloateval{((#3)-(#2))/(#4)}}%
	\xdef\tmpMagnitude{\xintfloateval{10^(floor(log10(\tmpDeltabrut)))}}%
	\xdef\tmpAlttp{\xintfloateval{(\tmpDeltabrut)/(\tmpMagnitude)}}%\tmpalttp%
	\xintifboolexpr{ \tmpAlttp <= 1.5 }{\xdef\coefftmpgraddelta{1}}{}%
	\xintifboolexpr{ (\tmpAlttp > 1.5) 'and' (\tmpAlttp <= 3) }{\xdef\coefftmpgraddelta{2}}{}%
	\xintifboolexpr{ (\tmpAlttp > 3) 'and' (\tmpAlttp <= 7) }{\xdef\coefftmpgraddelta{5}}{}%
	\xintifboolexpr{ \tmpAlttp > 7 }{\xdef\coefftmpgraddelta{10}}{}%
	\IfBooleanTF{#1}%
		{\xintfloateval{\tmpMagnitude*\coefftmpgraddelta}}%
		{\xdef#5{\xintfloateval{\tmpMagnitude*\coefftmpgraddelta}}}%
}
\NewDocumentCommand\tkzgMaxAjuste{mmm}{%
	%1 = ValMax
	%2 = DeltaGrad
	%3 = macro
	\xdef#3{\xintfloateval{ceil((#1) / (#2)) * (#2)}}%
}
\NewDocumentCommand\tkzgMinAjuste{mmm}{%
	%1 = ValMin
	%2 = DeltaGrad
	%3 = macro
	\xdef#3{\xintfloateval{floor((#1) / (#2)) * (#2)}}%
}

\ExplSyntaxOn
\seq_new:N \l__tkzg_tmpa_seq
\int_new:N \l__tkzg_tmpa_int

%------Get, index
\NewDocumentCommand\tkzggetvaluefromlist{ O{ , } m m O { \resmyelt } }
{
  % #1 = sep
  % #2 = list
  % #3 = index
  % #4 = output macro (non-starred, default \resmyelt)
  \group_begin:
  \seq_set_split:Nne \l__tkzg_tmpa_seq { #1 } { #2 }
  \tl_gset:Ne #4 { \seq_item:Nn \l__tkzg_tmpa_seq { #3 } }
  \group_end:
}
\NewDocumentCommand\tkzglenoflist{ O { , } m O { \resmylen } }
{
  % #1 = sep
  % #2 = list
  % #3 = output macro (non-starred, default \myreslen)
  \group_begin:
  \seq_set_split:Nne \l__tkzg_tmpa_seq { #1 } { #2 }
  \tl_gset:Ne #3 { \seq_count:N \l__tkzg_tmpa_seq }
  \group_end:
}
\NewDocumentCommand\tkzgetvaluefromcycllist{ O { , } m m O { \resmyelt } }
{
  % #1 = sep
  % #2 = list
  % #3 = index
  % #4 = output macro (default \resmyelt)
  \group_begin:
  \seq_set_split:Nne \l__tkzg_tmpa_seq { #1 } { #2 }
  % calcul du modulo
  \int_set:Nn \l__tkzg_tmpa_int
  {
    \int_mod:nn
    { #3 }
    { \seq_count:N \l__tkzg_tmpa_seq }
  }
  % si mod = 0 (index multiple de la longueur) → dernier élément
  \int_compare:nNnT { \l__tkzg_tmpa_int } = { 0 }
  {
    \int_set:Nn \l__tkzg_tmpa_int { \seq_count:N \l__tkzg_tmpa_seq }
  }
  \tl_gset:Ne #4
  {
    \exp_args:NNV
    \seq_item:Nn \l__tkzg_tmpa_seq \l__tkzg_tmpa_int
  }
  \group_end:
}
\ExplSyntaxOff

\endinput