% Copyright 2019 by Mark Wibrow
%
% This file may be distributed and/or modified
%
% 1. under the LaTeX Project Public License and/or
% 2. under the GNU Public License.
%
% See the file doc/generic/pgf/licenses/LICENSE for more details.

\usepgfmodule{decorations}%


% Options for shape decorations

\pgfkeys{
  /pgf/decoration/.cd,
  shape/.initial=circle,
  anchor/.initial=center,
  shape start width/.initial=2.5pt,
  shape start height/.initial=2.5pt,
  shape end width/.initial=2.5pt,
  shape end height/.initial=2.5pt,
  shape sep/.store in=\pgf@lib@shapedecoration@sep,
  shape sloped/.is if=pgfshapedecorationsloped,
  shape scaled/.is if=pgfshapedecorationscaled,
  shape evenly spread/.store in=\pgf@lib@shapedecoration@spread,
  shape start size/.style={%
    shape start width={#1},
    shape start height={#1}%
  },%
  shape end size/.style={%
    shape end width={#1},
    shape end height={#1}%
  },%
  shape size/.style={%
    shape start size={#1},
    shape end size={#1}%
  },%
  shape width/.style={%
    shape start width={#1},
    shape end width={#1}
  },
  shape height/.style={%
    shape start height={#1},
    shape end height={#1}
  }
}%

\def\pgf@lib@shapedecoration@sep{.25cm, between centers}%
\newif\ifpgfshapedecorationsloped
\pgfshapedecorationslopedtrue
\newif\ifpgfshapedecorationscaled
\let\pgf@lib@shapedecoration@spread\pgfutil@empty%



% triangle decoration

\pgfdeclaredecoration{triangles}{init}
{%
  \state{init}[width=+0pt,next state=triangle,persistent precomputation={
    \pgfmathparse{\pgfkeysvalueof{/pgf/decoration/shape start width}}
    \edef\pgf@lib@dec@ssw{\pgfmathresult pt}
    \pgfmathparse{\pgfkeysvalueof{/pgf/decoration/shape start height}/2}
    \edef\pgf@lib@dec@ssh{\pgfmathresult pt}
  }]{}%
  \state{triangle}[switch if less than=+\pgfdecorationsegmentlength to last,
                   width=+\pgfdecorationsegmentlength]
  {
    \pgfpathmoveto{\pgfqpoint{0pt}{\pgf@lib@dec@ssh}}
    \pgfpathlineto{\pgfqpoint{\pgf@lib@dec@ssw}{0pt}}
    \pgfpathlineto{\pgfqpoint{0pt}{-\pgf@lib@dec@ssh}}
    \pgfpathclose
  }%
  \state{last}[switch if less than=\pgf@lib@dec@ssw to skip,
               width=\pgfdecoratedremainingdistance,next state=final]
  {
    \pgfpathmoveto{\pgfqpoint{0pt}{\pgf@lib@dec@ssh}}
    \pgfpathlineto{\pgfqpoint{\pgf@lib@dec@ssw}{0pt}}
    \pgfpathlineto{\pgfqpoint{0pt}{-\pgf@lib@dec@ssh}}
    \pgfpathclose
  }%
  \state{skip}[width=\pgfdecoratedremainingdistance]
  {}%
  \state{final}
  {
    \pgfpathmoveto{\pgfpointdecoratedpathlast}
  }%
}%




% crosses decoration

\pgfdeclaredecoration{crosses}{init}
{%
  \state{init}[width=+0pt,next state=crosses,persistent precomputation={
    \pgfmathparse{\pgfkeysvalueof{/pgf/decoration/shape start width}/2}
    \edef\pgf@lib@dec@ssw{\pgfmathresult pt}
    \pgfmathparse{\pgfkeysvalueof{/pgf/decoration/shape start height}/2}
    \edef\pgf@lib@dec@ssh{\pgfmathresult pt}
  }]{}%
  \state{crosses}[switch if less than=+\pgfdecorationsegmentlength to last,
                  width=+\pgfdecorationsegmentlength]
  {
    \pgfpathmoveto{\pgfqpoint{-\pgf@lib@dec@ssw}{\pgf@lib@dec@ssh}}
    \pgfpathlineto{\pgfqpoint{\pgf@lib@dec@ssw}{-\pgf@lib@dec@ssh}}
    \pgfpathmoveto{\pgfqpoint{-\pgf@lib@dec@ssw}{-\pgf@lib@dec@ssh}}
    \pgfpathlineto{\pgfqpoint{\pgf@lib@dec@ssw}{\pgf@lib@dec@ssh}}
  }%
  \state{last}[width=+\pgfdecoratedremainingdistance]
  {
    \pgfpathmoveto{\pgfqpoint{-\pgf@lib@dec@ssw}{\pgf@lib@dec@ssh}}
    \pgfpathlineto{\pgfqpoint{\pgf@lib@dec@ssw}{-\pgf@lib@dec@ssh}}
    \pgfpathmoveto{\pgfqpoint{-\pgf@lib@dec@ssw}{-\pgf@lib@dec@ssh}}
    \pgfpathlineto{\pgfqpoint{\pgf@lib@dec@ssw}{\pgf@lib@dec@ssh}}
  }%
  \state{final}{
    \pgfpathmoveto{\pgfpointdecoratedpathlast}
  }%
}%






% The shape background decoration
%
% The shape background decoration adds repeated instances of
% the background path of a specified shape along the path. The shape
% must have been declared  by \pgfdeclareshape. If a shape has
% specialized keys (e.g. the number of points on a star, or the apex
% angle the isosceles triangle), these can be specified in the usual manner.
%
% The separation between shapes in the path can be specified and can
% be between the center of the shape or the border of the shape.
%
% The height and width of the shape can be independently or
% simultaneously scaled (linearly) along the path. It is also
% possible to prevent the shapes being sloped parallel to the
% path.

% internal if
\newif\ifpgf@lib@shapedecoration@betweenborders

\edef\pgf@lib@shapedecoration@initialise{0pt}%

\pgfdeclaredecoration{shape backgrounds}{initialise}
{%
  \state{initialise}
  [
    width=+\pgf@lib@shapedecoration@initialise,
    next state=shape,
    persistent precomputation=
    {
      %
      % \egroup ends the group started by the automaton before executing
      % a decoration state. This prevents the need for (most) \global variables.
      %
      %
      % Check the shape exists.
      %
      \pgfutil@ifundefined{pgf@sh@bg@\pgfkeysvalueof{/pgf/decoration/shape}}{%
        \pgferror{I do not know the shape `\pgfkeysvalueof{/pgf/decoration/shape}',
          so I cannot use it in a decoration. Check if its library been loaded or if you
          simply mistyped the name}}{}%
      %
      % Calculate a `default' path size.
      %
      \pgfinterruptpath%
        \pgfinterruptboundingbox%
          \pgftransformreset%
          \pgf@relevantforpicturesizetrue%
          %
          % This size of this shape is unimportant, but it should
          % be just large/small enough to avoid huge errors when
          % calculating the scaling factors later on.
          %
          \pgfkeys{/pgf/inner sep=50pt, /pgf/minimum size=1pt}% Arbitrary lengths.
          \setbox\pgfnodeparttextbox\hbox{}% Assume shape does nothing special if box is empty.
          \let\pgf@sh@savedmacros\pgfutil@empty%
          \let\pgf@sh@savedpoints\pgfutil@empty%
          \csname pgf@sh@s@\pgfkeysvalueof{/pgf/decoration/shape}\endcsname%
          \pgf@sh@savedpoints%
          \pgf@sh@savedmacros%
          %
          % Save the macros and points.
          %
          \expandafter\gdef\expandafter\pgf@lib@shapedecoration@points\expandafter{\pgf@sh@savedpoints}%
          \expandafter\gdef\expandafter\pgf@lib@shapedecoration@macros\expandafter{\pgf@sh@savedmacros}%
          \csname pgf@sh@bg@\pgfkeysvalueof{/pgf/decoration/shape}\endcsname%
          %
          % Save the dimensions of the shape path.
          %
          \pgf@x\pgf@picmaxx%
          \pgf@y\pgf@picmaxy%
          \advance\pgf@x-\pgf@picminx%
          \advance\pgf@y-\pgf@picminy%
          \xdef\pgf@lib@shapedecoration@shapepathsize{%
            \noexpand\pgf@x\the\pgf@x%
            \noexpand\pgf@y\the\pgf@y%
          }%
        \endpgfinterruptboundingbox%
      \endpgfinterruptpath%
      %
      \edef\pgf@lib@shapedecoration@beforeshape{0pt}%
      \edef\pgf@lib@shapedecoration@aftershape{0pt}%
      %
      \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/decoration/shape start width}}%
      \edef\pgf@lib@shapedecoration@startwidth{\the\pgf@x}%
      \edef\pgf@lib@shapedecoration@width{\the\pgf@x}%
      \pgf@x-\pgf@x%
      \pgfmathaddtolength\pgf@x{\pgfkeysvalueof{/pgf/decoration/shape end width}}%
      \edef\pgf@lib@shapedecoration@widthchange{\the\pgf@x}%
      %
      \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/decoration/shape start height}}%
      \edef\pgf@lib@shapedecoration@initialheight{\the\pgf@y}%
      \edef\pgf@lib@shapedecoration@height{\the\pgf@y}%
      \pgf@y-\pgf@y%
      \pgfmathaddtolength\pgf@y{\pgfkeysvalueof{/pgf/decoration/shape end height}}%
      \edef\pgf@lib@shapedecoration@heightchange{\the\pgf@y}%
      %
      % Calculate the sep.
      %
      \ifx\pgf@lib@shapedecoration@spread\pgfutil@empty%
        %
        % Not spreading, so easy:
        %
        \def\pgf@lib@shapedecoration@borderstext{between borders}%
        \afterassignment\pgf@lib@shapedecoration@setkeyword%
        \expandafter\pgf@x\pgf@lib@shapedecoration@sep,\pgf@stop%
        \edef\pgf@lib@shapedecoration@sep{\the\pgf@x}%
      \else%
        %
        % Spreading (a bit of a nuiscence actually).
        %
        \def\pgf@lib@shapedecoration@borderstext{by borders}%
        \afterassignment\pgf@lib@shapedecoration@setkeyword%
        \expandafter\c@pgf@counta\pgf@lib@shapedecoration@spread,\pgf@stop%
        \ifpgf@lib@shapedecoration@betweenborders%
          %
          % Ok. The required sep between borders is:
          %
          % (r -(n-1)((a+b)/2))/(n-1)
          %
          % r = decoration length (here, the remaining distance)
          % a = initial width
          % b = end width
          % n = the number of shapes
          %
          \ifnum\c@pgf@counta>1\relax%
            \advance\c@pgf@counta-1\relax%
            \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/decoration/shape start width}}%
            \ifpgfshapedecorationscaled%
              \pgfmathaddtolength\pgf@x{\pgfkeysvalueof{/pgf/decoration/shape end width}}%
            \else%
              \advance\pgf@x\pgf@x%
            \fi%
            \pgf@x.5\pgf@x% (a+b)/2
            \multiply\pgf@x-\c@pgf@counta% -(n-1)((a+b)/2)
            \advance\pgf@x\pgfdecoratedremainingdistance%
            \divide\pgf@x\c@pgf@counta%
            \pgf@x.9999\pgf@x% Hackery to control some native TeX inaccuracies.
            %
            % Unfortunately if the shape is scaled, and evenly spread by borders,
            % it is necessary to do something a bit different to control for
            % (most) inaccuracies.
            %
            \ifpgfshapedecorationscaled%
              \pgf@xa\pgf@lib@shapedecoration@widthchange\relax%
              \divide\pgf@xa\c@pgf@counta%
              \edef\pgf@lib@shapedecoration@specialwidth{\the\pgf@xa}%
            \fi%
          \else%
            \pgf@lib@shapedecoration@betweenbordersfalse%
            \pgf@x\pgfdecoratedremainingdistance%
            \ifnum\c@pgf@counta=1\relax%
              \pgf@y.5\pgf@x%
              \edef\pgf@lib@shapedecoration@initialise{\the\pgf@y}%
            \else%
              \advance\pgf@x5pt\relax% An arbitrary value >0pt.
              \edef\pgf@lib@shapedecoration@initialise{\the\pgf@x}%
            \fi%
          \fi%
        \else%
          %
          % Between centers.
          %
          \pgf@x\pgfdecoratedremainingdistance%
          \ifnum\c@pgf@counta>1\relax%
            \advance\c@pgf@counta-1\relax%
            \divide\pgf@x\c@pgf@counta\relax%
          \else%
            \ifnum\c@pgf@counta=1\relax%
              \pgf@y.5\pgf@x%
              \edef\pgf@lib@shapedecoration@initialise{\the\pgf@y}%
            \else%
              \advance\pgf@x5pt\relax% An arbitrary value >0pt.
              \edef\pgf@lib@shapedecoration@initialise{\the\pgf@x}%
            \fi%
          \fi%
        \fi%
        \edef\pgf@lib@shapedecoration@sep{\the\pgf@x}%
      \fi%
    }]
  {}%
  \state{before shape}
  [
    width=\pgf@lib@shapedecoration@beforeshape-1sp,
    next state=shape,
    persistent precomputation=
    {
      \ifpgfshapedecorationscaled%
        \ifpgf@lib@shapedecoration@betweenborders%
          \ifx\pgf@lib@shapedecoration@spread\pgfutil@empty%
            %
            % Not so straightforward. The required ratio is given by
            %
            % R = (c+W/2)/(c+r-.5*w)
            %
            % c = completed distance
            % r = remaining distance
            % W = initial width
            % w = the change in width (i.e., end - start)
            %
            \pgf@x\pgfdecoratedcompleteddistance%
            \advance\pgf@x\pgfdecoratedremainingdistance%
            \pgf@xa\pgf@lib@shapedecoration@startwidth\relax%
            \pgf@xa.5\pgf@xa%
            \advance\pgf@xa\pgfdecoratedcompleteddistance% c+W/2
            %
            \pgf@xb\pgf@lib@shapedecoration@widthchange\relax%
            \pgf@xb-.5\pgf@xb%
            \advance\pgf@xb\pgf@x% c+r-.5*w
            %
            \pgfmathdivide@{\pgfmath@tonumber{\pgf@xa}}{\pgfmath@tonumber{\pgf@xb}}%
          \fi%
        \else%
          %
          % Easy peasy. The required ratio is
          %
          % R = c / (c+r)
          %
          \pgf@y\pgfdecoratedcompleteddistance%
          \advance\pgf@y\pgfdecoratedremainingdistance%
          \pgfmathdivide@{\pgfmath@tonumber{\pgfdecoratedcompleteddistance}}{\pgfmath@tonumber{\pgf@y}}%
        \fi%
        %
        % Get the new width.
        %
        \ifx\pgf@lib@shapedecoration@spread\pgfutil@empty%
          \pgf@x\pgf@lib@shapedecoration@widthchange\relax%
          \pgf@x\pgfmathresult\pgf@x%
          \advance\pgf@x\pgf@lib@shapedecoration@startwidth\relax%
        \else%
          \ifpgf@lib@shapedecoration@betweenborders%
            %
            % Special case when decoration is scaled, and evenly spread by borders.
            %
            \pgf@x\pgf@lib@shapedecoration@width\relax%
            \advance\pgf@x\pgf@lib@shapedecoration@specialwidth\relax%
            \pgf@xa\pgf@x%
            \advance\pgf@xa-\pgf@lib@shapedecoration@startwidth\relax%
            \pgf@xb\pgf@lib@shapedecoration@widthchange\relax%
            \pgfmathdivide@{\pgfmath@tonumber{\pgf@xa}}{\pgfmath@tonumber{\pgf@xb}}%
          \else%
            \pgf@x\pgf@lib@shapedecoration@widthchange\relax%
            \pgf@x\pgfmathresult\pgf@x%
            \advance\pgf@x\pgf@lib@shapedecoration@startwidth\relax%
          \fi%
        \fi%
        \edef\pgf@lib@shapedecoration@width{\the\pgf@x}%
        %
        % New height = R*h + H
        %
        \pgf@y\pgf@lib@shapedecoration@heightchange\relax%
        \pgf@y\pgfmathresult\pgf@y%
        \advance\pgf@y\pgf@lib@shapedecoration@initialheight\relax%
        \edef\pgf@lib@shapedecoration@height{\the\pgf@y}%
      \fi%
      %
      \ifpgf@lib@shapedecoration@betweenborders%
        \pgf@x\pgf@lib@shapedecoration@width\relax%
        \pgf@x.5\pgf@x%
        \edef\pgf@lib@shapedecoration@beforeshape{\the\pgf@x}%
      \else%
        \def\pgf@lib@shapedecoration@beforeshape{0pt}%
      \fi%
    }]
  {}%
  \state{shape}[width=+0sp,next state=after shape]
  {
    \ifpgfshapedecorationsloped%
    \else%
      \pgftransformrotate{-\pgfdecoratedangle}%
    \fi%
    %
    % Scale the path when it is actually drawn.
    %
    \pgf@lib@shapedecoration@shapepathsize%
    \pgfutil@tempdima\pgf@x%
    \pgfutil@tempdimb\pgf@y%
    \pgf@xa\pgf@lib@shapedecoration@width\relax%
    \pgf@xb\pgfutil@tempdima%
    \pgfmathdivide@{\pgfmath@tonumber{\pgf@xa}}{\pgfmath@tonumber{\pgf@xb}}%
    \expandafter\pgftransformxscale\expandafter{\pgfmathresult}%
    %
    \pgf@ya\pgf@lib@shapedecoration@height\relax%
    \pgf@yb\pgfutil@tempdimb%
    \pgfmathdivide@{\pgfmath@tonumber{\pgf@ya}}{\pgfmath@tonumber{\pgf@yb}}%
    \expandafter\pgftransformyscale\expandafter{\pgfmathresult}%
    %
    % Move to the center anchor.
    %
    \pgf@lib@shapedecoration@points%
    \pgf@lib@shapedecoration@macros%
    \pgftransformshift{%
      \pgf@sh@reanchor{\pgfkeysvalueof{/pgf/decoration/shape}}{\pgfkeysvalueof{/pgf/decoration/anchor}}%
      \pgf@x-\pgf@x%
      \pgf@y-\pgf@y%
    }%
    %
    % And draw the shape path.
    %
    \csname pgf@sh@bg@\pgfkeysvalueof{/pgf/decoration/shape}\endcsname%
  }%
  \state{after shape}
  [
    width=\pgf@lib@shapedecoration@aftershape-1sp,
    next state=sep,
    persistent precomputation=
    {
      \ifpgf@lib@shapedecoration@betweenborders%
        \pgf@x\pgf@lib@shapedecoration@width\relax%
        \pgf@x.5\pgf@x%
        \edef\pgf@lib@shapedecoration@aftershape{\the\pgf@x}%
      \else%
        \edef\pgf@lib@shapedecoration@aftershape{0pt}%
      \fi%
    }
  ]
  {}%
  \state{sep}[width=\pgf@lib@shapedecoration@sep,next state=before shape,
              persistent precomputation=\def\pgf@lib@shapedecoration@beforeshape{0pt}]
  {}%
  \state{final}
  {
    \pgfpathmoveto{\pgfpointdecoratedpathlast}%
  }%
}%

\def\pgf@lib@shapedecoration@setkeyword,{%
  \pgfutil@ifnextchar\pgf@stop{\def\pgf@temp{}\pgf@lib@@@shapedecoration@setkeyword}{\pgf@lib@@shapedecoration@setkeyword}%
}%
\def\pgf@lib@@shapedecoration@setkeyword#1,{\def\pgf@temp{#1}\pgf@lib@@@shapedecoration@setkeyword}%
\def\pgf@lib@@@shapedecoration@setkeyword\pgf@stop{%
  \ifx\pgf@temp\pgf@lib@shapedecoration@borderstext%
    \pgf@lib@shapedecoration@betweenborderstrue%
  \else%
    \pgf@lib@shapedecoration@betweenbordersfalse%
  \fi%
}%



\endinput
