tikz图片的范围~~(动画中)

tikz图片的范围~~(动画中)

我尝试从代码中修改埃拉托斯特尼筛法的动画(作者:彼得·格里尔): http://www.texample.net/tikz/examples/eratosthenes-sieve/

我所做的就是删除了标题和右侧的文字。

但这里存在一些问题:

  • 第一帧可以正常工作,图片的范围正是我想要的 第一的
    • 但从第二帧开始,图片的范围变小了,你可以看到标题和图片之间有很大的垂直空间 在此处输入图片描述

如何保持图片的范围和第一帧一致?

这是我的代码:

    \documentclass[t]{beamer}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usetheme{default}

\usepackage{geometry}

\usepackage{microtype}%       Allow comma into margin in list of primes
\usepackage{xstring}%         String comparison
\usepackage{tikz}%            Drawing
\usetikzlibrary{calc}%        Coordinate calculations
\usetikzlibrary{backgrounds}% Apply shading on background layer
\usepackage{animate}


\begin{document}



\def\NumOfColumns{10}% See note above if product of  
\def\NumOfRows{10}%    NumOfColumns and NumOfRows > 100.

%% \FramesToHoldAtEnd should be larger than the number of primes
%% so that they can get highlighted at the end of the process
\def\FrameRate{1}%
\def\FramesToHoldAtStart{1}%
\def\FramesToHoldAtEnd{25}% 25 is enough for 10x10


\def\Scale{0.6}% May need tweaking..


\def\PrimeColor{green!80!red}%  Shade for primes found previously
\def\NewPrimeColor{green!80!red}% Shade for prime just found
\def\NewPrimeText{red}%  Color for primes in list
\def\NonPrimeColor{yellow!80!red}%  Shade for non-primes


%% List of Primes is typeset into a \node of this width.
\def\TextWidth{2.0cm}%


% Simplifies code below if we just redefine these two from the
% animate package so that they do don't much.
%\renewenvironment{animateinline}[1]{\begingroup}{\endgroup}% 
%\renewcommand{\newframe}[1][]{\newpage}%




%%% ---------------------------------------------------------------
%%% Should not need to adjust anything below this line
%%%
\pgfmathtruncatemacro{\MaxNumber}{\NumOfRows*\NumOfColumns}%
\pgfmathtruncatemacro{\MaxValue}{sqrt(\MaxNumber)}%

% Choose opacity so that we can have the max number of shades
%\pgfmathsetmacro{\Opacity}{1.0/min(5,\MaxValue-1)}%
\pgfmathsetmacro{\Opacity}{0.4}%

%% The Sieve algorithm requires that once a number is marked
%% as non-prime (i.e., was a multiple of some other number)
%% we don't need to check multiples of that number as they
%% have already been marked as non-prime.
%%
%% Usually one would use an array and set a flag.  But since
%% variables with numbers are difficult with TeX, we can
%% define a node named with the number that is non-prime.
%% Then just check that the node exists to see if it was 
%% marked as non-prime.

\makeatletter
% Mark number as either "Prime" or "NonPrime".
\newcommand*{\MarkNumber}[2][NonPrime]{\node (#1#2) {}}% #1=prefix, #2=num

% https://tex.stackexchange.com/questions/37709/how-can-i-know-if-a-node-is-already-defined
\newcommand{\IfNumberAlreadyMarked}[4][NonPrime]{% #1=prefix, #2=num
\pgfutil@ifundefined{pgf@sh@ns@#1#2}{#4}{#3}%
}

% https://tex.stackexchange.com/questions/20655/how-to-undo-a-def-i-e-need-a-undef-capability
\newcommand*\@nameundef[1]{%
\global\expandafter\let\csname #1\endcsname\@undefined%
}

%% Since we repeat the process from the beginning for the animated
%% version, use this to clear the nodes so that the numbers are
%% not marked as multiples of a number from the previous run.
\newcommand{\ClearAllNumberedNodeNames}{%
\foreach \i in {1,...,\MaxValue}{%
    \@nameundef{pgf@sh@ns@NonPrime\i}%
    \@nameundef{pgf@sh@ns@Prime\i}%
}%
}
\makeatother

%% The Sieve algorithm skips multiples of numbers already marked as
%% non-prime.  So, to number the individual steps, need to use
%% a counter.
%% i.e., Step 4 is processing multiples of 5 (since we skip 4).
\newcounter{StepNumber}%


%%% ---------------------------------------------------------------
%%%
%%%  Titles and Labels
%%%

\newcommand\ListOfPrimes{}
\newcommand\AddToListOfPrimes[2][fill=\PrimeColor]{%
\IfStrEq{\ListOfPrimes}{}{%
    \def\Separator{}%   First member of list of primes
}{%
    \def\Separator{, }% Subsequent member of list of primes
}%
%
\FillCellForGivenNumber[#1]{#2};%
\global\edef\ListOfPrimes{\ListOfPrimes\Separator#2}%
\MarkNumber[Prime]{#2};%
}

\newcommand*{\ClearListOfPrimes}{%
\ClearAllNumberedNodeNames;%
\renewcommand{\ListOfPrimes}{}%
}

%%% ---------------------------------------------------------------

%%%
%%% Step 1: Create a list of integers 2...n
%%%
\newcommand*{\DrawGridWithNumbers}{%
\begin{scope}% Add numbers to each node
    \draw  (0,-1) -- ($(0,-\NumOfRows-1)$);
    \foreach \col in {1,...,\NumOfColumns} {%
        \draw  (\col,-1) -- ($(\col,-\NumOfRows-1)$);

        \draw  (0,-1) -- (\NumOfColumns,-1);
        \foreach \row in {1,...,\NumOfRows}{%
            \pgfmathtruncatemacro{\value}{\col+\NumOfColumns*(\row-1)}
            \IfEq{\value}{1}{
                %% Suppress number 1 from being printed since first  
                %% step of Sieve of Eratosthenes algorithm is to 
                %% create a list of integers 2...n
            }{
                \node at ($(\col,-\row)-(0.5,0.5)$) {\value};
            }
            \draw (0,-\row-1) -- (\NumOfColumns,-\row-1);
        }
    }
\end{scope}

%% Since we just drew the grid we should ensure that none
%% of the numbered nodes exist (i.e., that no numbers
%% are marked as non-prime.  And reset list of primes.

\ClearListOfPrimes;
\ClearAllNumberedNodeNames;

%\ShowListOfPrimesNode;
}

\newcommand*{\FillCellForGivenNumber}[2][]{%
%% #1 = fill options
%% #2 = number
%%
\pgfmathtruncatemacro{\Column}{mod(#2,\NumOfColumns)}%
\IfEq{\Column}{0}{\pgfmathtruncatemacro{\Column}{\NumOfColumns}}{}%
\pgfmathtruncatemacro{\Row}{(#2-1)/\NumOfColumns+1}%

\begin{scope}[on background layer]
    \fill [#1]
        (\Column-1,-\Row) --
        ($(\Column-1,-\Row)+(1,0)$) --
        ($(\Column-1,-\Row)+(1,-1)$) -- 
        (\Column-1,-\Row-1) --
        cycle;
\end{scope}
}



\newcommand*{\ColorMultiplesOf}[2][0]{%
%% If only 1 arg is given (i.e., #1=0), then 
%%     #2 = the multiple for which the coloring is applied
%%
%% If two args are given (i.e., #1 != 0) then
%%     #1 = Value of \MaxMultiple (used for animated version)
%%          In the two arg case we run the entire sequence 
%%          from the beginning up until the multiple #1*#2 
%%          is reached.

\IfEq{#1}{0}{% Run the entire sequence
    \pgfmathtruncatemacro{\MaxMultiple}{\MaxNumber/#2}
}{%            Run sequence up until number given for animating
    \def\MaxMultiple{#1}
}

\foreach \i in {2,...,\MaxMultiple} {
    \pgfmathtruncatemacro{\NonPrimeNumber}{\i*#2}
    \FillCellForGivenNumber[
            fill=\NonPrimeColor, 
            fill opacity=\Opacity
        ]
        {\NonPrimeNumber};
    \MarkNumber[NonPrime]{\NonPrimeNumber};
}
}


\newcommand*{\BuildFrameInternals}[2][0]{%
%% #1 = current multiple to which to build the pattern up to
%%      if #1=0 and #2=\MaxValue, then we are in an end hold frame
%% #2 = number of whose multiples we are eliminating in this step
%%      if #2=1, then only draw grid (provides hold frame at start)

%%\AddTitleNode;% Print Main title if \AnimateSieve is defined

\DrawGridWithNumbers;
\IfEq{#2}{1}{%
    %% This is a hold frame at start so only show grid of numbers
    %%\AddInitialSubTitleNode{#2};
}{%
    \IfEq{#2}{2}{%
        %% No pre-processing steps to be done in this case
    }{%
        %% Since we are eliminating multiples of a number  
        %% other than 2, we need to get the table up to  
        %% the state where all the multiples of 2...(#2-1) 
        %% are eliminated.

        \pgfmathsetmacro{\PreviousMultiple}{#2 - 1}%
        \foreach \n in {2,...,\PreviousMultiple} {%
            \IfNumberAlreadyMarked[NonPrime]{\n}{%
                %% Skip. Multiples are already marked as non-prime
                %% since this number is a multiple of a smaller
                %% prime.
            }{%
                %% This is a prime. Mark it as prime, and mark 
                %% its multiples as non-prime.
                \AddToListOfPrimes[fill=\PrimeColor]{\n};
                \ColorMultiplesOf{\n};
            }
        }
    }

    \IfNumberAlreadyMarked[NonPrime]{#2}{%
        %% Already taken care of in a previous run.  This test
        %% is needed to cover the case where the value of the
        %% sqrt{NumberOfColumns x NumberOfRows) is not prime.
        %% For example: 10x10.
    }{%
        %% Now eliminate the numbers up to the current state
        \AddToListOfPrimes[fill=\NewPrimeColor]{#2};
        \ColorMultiplesOf[#1]{#2};
    }

    %% If we are holding the very final result don't print title.
    %% This is the case when #2=\MaxValue and #1=0.
    %%
    %% Need to do this at the end so that we can access
    %% which numbers have been marked as non-prime.

    \IfEq{#2}{\MaxValue}{%
        %\IfEq{#1}{0}{%
            %% This is the final hold frame
            %%\SubTitleFinal;

            \IfNumberAlreadyMarked[NonPrime]{#2}{%
            }{%
                \IfNumberAlreadyMarked[Prime]{#2}{%
                    %% In this case, #2 is not a new prime so 
                    %% correct its color. So, don't add it to the
                    %% list of primes, but correct ensure its
                    %% color corresponds to an old prime
                    \FillCellForGivenNumber[fill=\PrimeColor]{#2};
                }{%
                    %% In this case, #2 is a new prime so 
                    %% add it to the list of primes,                
                    \AddToListOfPrimes[fill=\NewPrimeColor]{#2};
                }%
            }%

            %% But since this is the final hold frame, we need
            %% to mark all the numbers not already marked as 
            %% non-prime as prime. Do one at at time, so that
            %% this can be seen in the animation.

            \pgfmathtruncatemacro{\StartValue}{\MaxValue+1}%
            \foreach \p in {\StartValue,...,\MaxNumber}{%
                \IfNumberAlreadyMarked[NonPrime]{\p}{%
                    %% This number has been marked as non-prime
                }{%
                    %% This is a prime
                    \IfNumberAlreadyMarked[Prime]{\p}{%
                        %% Already found this prime earlier.
                        %% So ensure it has appropriate fill.
                        \AddToListOfPrimes[fill=\PrimeColor]{\p};%
                    }{%
                        %% New prime: Mark it as such, and 
                        %% break out to complete this frame.
                        \AddToListOfPrimes[fill=\NewPrimeColor]{\p};%
                        \MarkNumber[Prime]{\p};%
                        %%\AddSubTitleNode{};%
                        \breakforeach;%
                    }%
                }%
            }%
        %}{%
            %% Not final hold frame, so normal title
            %%\AddSubTitleNode{#2};%
        %}%
    }{%
        %%\AddSubTitleNode{#2};%
    }%
}%
%%\ShowListOfPrimesNode%
}%



\newcommand*{\BuildFrame}[2][0]{%
%% #1 = current multiple to which to build the pattern up to
%% #2 = number of whose multiples we are eliminating in this step
%%      if #2=1, then only draw grid (provides hold frame at start)
\noindent%
\centering%
\begin{tikzpicture}[yscale=\Scale]%
    \BuildFrameInternals[#1]{#2};
\end{tikzpicture}%
%
}%

\newcommand*{\BuildFinalFrame}{%
\noindent%
\centering%
\begin{tikzpicture}[yscale=\Scale]%
    %%\AddTitleNode;% Print Main title if \AnimateSieve is defined
    %%\AddSubTitleNode{};
    \DrawGridWithNumbers;
    \foreach \p in {2,...,\MaxValue}{%
        \IfNumberAlreadyMarked[NonPrime]{\p}{%
        }{%
            \AddToListOfPrimes[fill=\PrimeColor]{\p};
            \ColorMultiplesOf{\p};
        }%
    }%
    \pgfmathtruncatemacro{\StartValue}{\MaxValue+1}%
    \foreach \p in {\StartValue,...,\MaxNumber}{%
        \IfNumberAlreadyMarked[NonPrime]{\p}{%
            %% This number has already been marked as non-prime
        }{%
            %% This is a prime. Since we are just printing out
            %% the final results we don't distinguish between a
            %% newly found prime and a prime found previously.
            \AddToListOfPrimes[fill=\PrimeColor]{\p};
        }%
    }%

    %\ShowListOfPrimesNode;
\end{tikzpicture}%
%
}

\newcounter{CountK}
\newcounter{CountP}
\newcounter{CurrentMaxMultiplePlusOne}
%



\begin{frame}{Sieve of Eratosthenes}
\begin{animateinline}[autopause,controls, buttonsize=1.2em, buttonbg=1:0.78:0,buttonfg=0.2:0.2:0.2]{\FrameRate}%
    \stepcounter{StepNumber}%
    \setcounter{CountK}{0}%
    \whiledo{\arabic{CountK} < \FramesToHoldAtStart}{%
        \BuildFrame[0]{1}% initial hold frame
        \newframe[\FrameRate]%
        \stepcounter{CountK}%
    }%
    %
    \setcounter{CountK}{2}%
    \whiledo{\numexpr\arabic{CountK}-1 < \MaxValue}{%
        \IfNumberAlreadyMarked[NonPrime]{\arabic{CountK}}{%
            %% \value{CountK} has already been marked as non-prime.
            %% Hence, so so are its multiples, and we can skip it.
        }{%
%% Question 1: Should be able to replace three lines following with
%%             this. But then animation seems to skip the loop below
% \pgfmathsetcounter{CurrentMaxMultiplePlusOne}{1+(\MaxNumber/\arabic{CountK})}%
            \pgfmathtruncatemacro{\MaxMultiple}{\MaxNumber/\arabic{CountK}}%
            \setcounter{CurrentMaxMultiplePlusOne}{\MaxMultiple}%
            \stepcounter{CurrentMaxMultiplePlusOne}%
            %
            \setcounter{CountP}{2}% 
            \stepcounter{StepNumber}%
%% Question 2: Ideally would prefer to use the following syntax
%%             but this does not even compile!!!   But, an indentical
%%             syntax works in the above `\whiledo`, where the value of
%%             \MaxValue was also defined by \pgfmathtruncatemacro
%               \whiledo{\numexpr\arabic{CountP}-1 < \MaxMultiple}{%
            \whiledo{\arabic{CountP} < \arabic{CurrentMaxMultiplePlusOne}}{%            
                \BuildFrame[\theCountP]{\theCountK}%
                \newframe[\FrameRate]%
                \stepcounter{CountP}%
            }%
        }%
        \stepcounter{CountK}%
    }%
    % At end, add hold frames in case we are looping
    %
    % There needs to be enough of these so that each of the
    % primes (those not colored in) get highlighted at each frame.
    %
    \setcounter{CountK}{2}%
    \whiledo{\numexpr\arabic{CountK}-1 < \FramesToHoldAtEnd}{%
        \BuildFrame{\MaxValue}%
        \newframe[\FrameRate]%
        \stepcounter{CountK}%
    }
\end{animateinline}%
\end{frame}
\end{document}

texmf.cnf由于编译代码可能需要更多内存,我只需编辑下的文件C:\texlive\2018\texmf.cnf,并在文件末尾添加以下代码:

main_memory=12435455
extra_mem_top=60000000​
extra_mem_bot=5000000
font_mem_size=5000000
pool_size=5000000
buf_size=5000000

然后编译XeLaTex

相关内容