%%%
% Modèle Barres cumulatifs.
%%%
\def\filedateBarreCumul{2025/11/01}%
\def\fileversionBarreCumul{0.1}%
\message{-- \filedateBarreCumul\space v\fileversionBarreCumul}%
%
\makeatletter
\setKVdefault[BarreCumul]{Longueur=5cm,ListeCouleurs={},TexteInitial=Quantité,Parts={},Vertical=false,Numerotation=false,Pleines,Hauteur=1cm}

\NewDocumentCommand\ModeleCumulatif{som}{%
  \useKVdefault[BarreCumul]%
  \setKV[BarreCumul]{#2}%
  \IfBooleanTF{#1}{%
    \PfC@BuildBarreCumulRef{#3}%
  }{%
    \PfC@BuildBarreCumul{#3}%
  }%
}%

\NewDocumentCommand\PfC@BuildBarreCumul{m}{%
  \mplibforcehmode
  \begin{Geometrie}[Cadre="aucun"]
    numeric nume[],deno[],nbparts[];
    string Texte[];
    boolean Parts[],Vertical,Numerotation,Pleines;
    Vertical=\useKV[BarreCumul]{Vertical};
    Pleines=\useKV[BarreCumul]{Pleines};
    Numerotation=\useKV[BarreCumul]{Numerotation};
    if Vertical: Anglenum=-90 else:Anglenum=0 fi;
    %
    vardef LectureInfo(text info)=
      nbbarre:=0;
      for p_=info:
        nbbarre:=nbbarre+1;
        if (nbbarre mod 3)=1:
          nume[(nbbarre div 3)+1]=p_;
        elseif (nbbarre mod 3)=2:
          deno[(nbbarre div 3)+1]=p_;
        else:
          Texte[(nbbarre div 3)]=p_;
        fi;
      endfor;
    enddef;
    LectureInfo(#1);  
    nbbarre:=(nbbarre/3);
    color Coul[];
    \ifemptyKV[BarreCumul]{ListeCouleurs}{%
      for k=0 upto nbbarre:
        Coul[k]=white;
        Parts[k]=false;
      endfor;
    }{%
      nbcol:=0;
      for p_=\useKV[BarreCumul]{ListeCouleurs}:
        if color p_:
          Coul[nbcol]=p_;
        else:
          Coul[nbcol]=white;
        fi;
        Parts[nbcol]=false;
        nbcol:=nbcol+1;
      endfor;
      for k=nbcol upto nbbarre:
        Coul[k]=white;
        Parts[k]=false;
      endfor;
    }%
    \ifemptyKV[BarreCumul]{Parts}{}{%
      nbparts:=1;
      for p_=\useKV[BarreCumul]{Parts}:
        if known p_:
          Parts[nbparts]:=true;
          parts[nbparts]=p_;
        fi;
        nbparts:=nbparts+1;
      endfor;
    }%
    pair A[][];
    A[0][1]=(0,0);
    A[0][2]-A[0][1]=\useKV[BarreCumul]{Longueur}*(1,0);
    A[0][3]-A[0][2]=\useKV[BarreCumul]{Hauteur}*(0,1);
    A[0][4]-A[0][3]=A[0][1]-A[0][2];
    fill polygone(A[0][1],A[0][2],A[0][3],A[0][4]) withcolor Coul[0];
    trace polygone(A[0][1],A[0][2],A[0][3],A[0][4]);
    label(TEX("\useKV[BarreCumul]{TexteInitial}"),iso(A[0][1],A[0][3]));
    for k=1 upto nbbarre:
      A[k][1]=A[k-1][1]+\useKV[BarreCumul]{Hauteur}*(0,-1);
      A[k][2]-A[k][1]=A[k-1][2]-A[k-1][1];
      A[k][4]=A[k-1][1];
      A[k][3]-A[k][2]=A[k][4]-A[k][1];
      % Si le nume est < deno, on sépare en deux l'affichage
      drawoptions(dashed evenly);
      trace chemin((nume[k]/deno[k])[A[k][1],A[k][2]],A[k][2],A[k][3],(nume[k]/deno[k])[A[k][4],A[k][3]]);
      for l=nume[k]+1 upto deno[k]-1:
        trace (l/deno[k])[A[k][1],A[k][2]]--(l/deno[k])[A[k][4],A[k][3]];
      endfor;
      drawoptions();
      fill polygone(A[k][1],(nume[k]/deno[k])[A[k][1],A[k][2]],(nume[k]/deno[k])[A[k][4],A[k][3]],A[k][4]) withcolor Coul[k];
      trace polygone(A[k][1],(nume[k]/deno[k])[A[k][1],A[k][2]],(nume[k]/deno[k])[A[k][4],A[k][3]],A[k][4]) if Parts[k]:withpen pencircle scaled 2 fi;
      for l=1 upto nume[k]-1:
        trace (l/deno[k])[A[k][1],A[k][2]]--(l/deno[k])[A[k][4],A[k][3]];
      endfor;
      % Si le booléen Parts est à true, on affiche des « blocs »
      if Parts[k]:
      for l=parts[k] step parts[k] until (nume[k]-1):
        trace (l/deno[k])[A[k][1],A[k][2]]--(l/deno[k])[A[k][4],A[k][3]] withpen pencircle scaled 2;
      endfor;
      fi;
      % On affiche le contenu des parts
      if Pleines:
      for l=1 upto nume[k]:
        label(TEX(Texte[k]),iso(((l-1)/deno[k])[A[k][1],A[k][2]],(l/deno[k])[A[k][4],A[k][3]]));
        endfor;
      fi;
      % On numérote ?
      if Numerotation:
        label.lft(TEX("(L"&decimal(k)&")") rotated (Anglenum),iso(A[k][1],A[k][4]));
      fi;
      A[k][2]:=(nume[k]/deno[k])[A[k][1],A[k][2]];
      A[k][3]:=(nume[k]/deno[k])[A[k][4],A[k][3]];
    endfor;
    if Vertical:
      picture RetiensPicture;
      RetiensPicture=currentpicture;
      currentpicture:=nullpicture;
      trace rotation(RetiensPicture,A[0][4],90);
    fi;
  \end{Geometrie}
}%

\NewDocumentCommand\PfC@BuildBarreCumulRef{m}{%
  \mplibforcehmode%
  \begin{Geometrie}[Cadre="aucun"]
    numeric nume[],deno[],nbparts[];
    string Texte[];
    boolean Parts[],Vertical,Numerotation,Pleines;
    Vertical=\useKV[BarreCumul]{Vertical};
    Pleines=\useKV[BarreCumul]{Pleines};
    Numerotation=\useKV[BarreCumul]{Numerotation};
    if Vertical: Anglenum=-90 else:Anglenum=0 fi;
    %
    vardef LectureInfo(text info)=
      nbbarre:=0;
      for p_=info:
        nbbarre:=nbbarre+1;
        if (nbbarre mod 3)=1:
          nume[(nbbarre div 3)+1]=p_;
        elseif (nbbarre mod 3)=2:
          deno[(nbbarre div 3)+1]=p_;
        else:
          Texte[(nbbarre div 3)]=p_;
        fi;
      endfor;
    enddef;
    LectureInfo(#1);  
    nbbarre:=(nbbarre/3);
    color Coul[];
    \ifemptyKV[BarreCumul]{ListeCouleurs}{%
      for k=0 upto nbbarre:
        Coul[k]=white;
        Parts[k]=false;
      endfor;
    }{%
      nbcol:=0;
      for p_=\useKV[BarreCumul]{ListeCouleurs}:
        if color p_:
          Coul[nbcol]=p_;
        else:
          Coul[nbcol]=white;
        fi;
        Parts[nbcol]=false;
        nbcol:=nbcol+1;
      endfor;
      for k=nbcol upto nbbarre:
        Coul[k]=white;
        Parts[k]=false;
      endfor;
    }%
    \ifemptyKV[BarreCumul]{Parts}{}{%
      nbparts:=1;
      for p_=\useKV[BarreCumul]{Parts}:
        if known p_:
          Parts[nbparts]:=true;
          parts[nbparts]=p_;
        fi;
        nbparts:=nbparts+1;
      endfor;
    }%
    pair A[][];
    A[0][1]=(0,0);
    A[0][2]-A[0][1]=\useKV[BarreCumul]{Longueur}*(1,0);
    A[0][3]-A[0][2]=\useKV[BarreCumul]{Hauteur}*(0,1);
    A[0][4]-A[0][3]=A[0][1]-A[0][2];
    fill polygone(A[0][1],A[0][2],A[0][3],A[0][4]) withcolor Coul[0];
    trace polygone(A[0][1],A[0][2],A[0][3],A[0][4]);
    label(TEX("\useKV[BarreCumul]{TexteInitial}"),iso(A[0][1],A[0][3]));
    for k=1 upto nbbarre:
      A[k][1]=A[k-1][1]+\useKV[BarreCumul]{Hauteur}*(0,-1);
      A[k][2]-A[k][1]=A[0][2]-A[0][1];
      A[k][4]=A[k-1][1];
      A[k][3]-A[k][2]=A[0][3]-A[0][2];
      % Si le nume est < deno, on sépare en deux l'affichage
      drawoptions(dashed evenly);
      trace chemin((nume[k]/deno[k])[A[k][1],A[k][2]],A[k][2],A[k][3],(nume[k]/deno[k])[A[k][4],A[k][3]]);
      for l=nume[k]+1 upto deno[k]-1:
        trace (l/deno[k])[A[k][1],A[k][2]]--(l/deno[k])[A[k][4],A[k][3]];
      endfor;
      drawoptions();
      fill polygone(A[k][1],(nume[k]/deno[k])[A[k][1],A[k][2]],(nume[k]/deno[k])[A[k][4],A[k][3]],A[k][4]) withcolor Coul[k];
      trace polygone(A[k][1],(nume[k]/deno[k])[A[k][1],A[k][2]],(nume[k]/deno[k])[A[k][4],A[k][3]],A[k][4]) if Parts[k]:withpen pencircle scaled 2 fi;
      for l=1 upto nume[k]-1:
        trace (l/deno[k])[A[k][1],A[k][2]]--(l/deno[k])[A[k][4],A[k][3]];
      endfor;
      % Si le booléen Parts est à true, on affiche des « blocs »
      if Parts[k]:
      for l=parts[k] step parts[k] until (nume[k]-1):
        trace (l/deno[k])[A[k][1],A[k][2]]--(l/deno[k])[A[k][4],A[k][3]] withpen pencircle scaled 2;
      endfor;
      fi;
      % On affiche le contenu des parts
      if Pleines:
      for l=1 upto nume[k]:
        label(TEX(Texte[k]),iso(((l-1)/deno[k])[A[k][1],A[k][2]],(l/deno[k])[A[k][4],A[k][3]]));
        endfor;
      fi;
      % On numérote ?
      if Numerotation:
        label.lft(TEX("(L"&decimal(k)&")") rotated (Anglenum),iso(A[k][1],A[k][4]));
      fi;
      A[k][2]:=(nume[k]/deno[k])[A[k][1],A[k][2]];
      A[k][3]:=(nume[k]/deno[k])[A[k][4],A[k][3]];
    endfor;
    if Vertical:
      picture RetiensPicture;
      RetiensPicture=currentpicture;
      currentpicture:=nullpicture;
      trace rotation(RetiensPicture,A[0][4],90);
    fi;
  \end{Geometrie}
}%
\makeatother