8

To make an animation (here), I used a found code (here: @Jake answers). It works but not for all increments. It works when increments are 0.02 to 0.02, but not when increments are 0.04 to 0.04, 0.05 to 0.05 or 0.1 to 0.1.

Here with an increment of 0.04, the animation does not make the complete turn:

animation-1

Here, with an increment of 0.02, the animation makes the complete turn but the path is not closed:

animation-2coin-inferieur

First problem:

  • Why doesn't it work with any increment?
  • How do I make the decoration work for any increment?

Edition: By replacing \foreach by \multido the increments do not pose any more problems, the complete turn is carried out.

\multido{\npos=0.00+0.05}{21}{
%\multido{\npos=0.00+0.04}{26}{
%\multido{\npos=0.00+0.1}{11}{
%\foreach \npos  in {0,.1,...,1}{% 
            \begin{tikzpicture}[scale=1]
                \fill[green!40](0,0) rectangle (4,4);
                \draw[start segment=\npos,blue,ultra thick] (0,0) -- (4,0) -- (4,4) -- (0,4) --cycle ;
            \end{tikzpicture} 
 } 

Edition 2: Ruixi Zhang's solution allows you to go around the entire path using a \foreach loop.

%\foreach \x [evaluate =\x as \npos using \x/50] in {0,1,...,50}{% increment of 0.02
%\foreach \x [evaluate =\x as \npos using \x/25] in {0,1,...,25}{% increment of 0.04
\foreach \x [evaluate =\x as \npos using \x/10] in {0,1,...,10}{% increment of 0.1
            \begin{tikzpicture}[scale=1]
                \fill[green!40](0,0) rectangle (4,4);
                \draw[start segment=\npos,blue,ultra thick] (0,0) -- (4,0) -- (4,4) -- (0,4) --cycle ;
            \end{tikzpicture} 

Second problem:

How to close the path?

\documentclass[tikz,border=5mm]{standalone}
\usetikzlibrary{decorations}

\pgfdeclaremetadecoration{start}{initial}{
    \state{initial}[width={\pgfmetadecoratedpathlength*\pgfdecorationsegmentlength},next state=final]{
        \decoration{lineto}
    }
    \state{final}{}
}

\tikzset{start segment/.style={decoration={start,raise=2mm,segment length=#1},decorate}} 

\begin{document}
\foreach \rpos  in {0,.02,.04,...,1}{% 
            \begin{tikzpicture}[scale=1]
                \fill[green!40](0,0) rectangle (4,4);
                \draw[start segment=\rpos,blue,ultra thick] (0,0) -- (4,0) -- (4,4) -- (0,4) --cycle ;
            \end{tikzpicture} 
 } 
\end{document}
  • How do I close it completely?
7

You have to close the path when it is done. (Unfortunately there are some roundings in place. This explains why the check reads >0.999pt instead of =1pt.) One can check with \pgfkeys{/pgf/decoration automaton/if input segment is closepath=...} whether the last segment is the close path segment and then close the path if one is close to its end. This avoids closing paths that are not to be closed. Notice that 0.999pt is an empirical value. If you have a very extreme path in which the close path segment is very short, such as a path (0,0) -- (4,0) -- (4,4) -- (0,4) -- (0,0) --cycle ;, this answer may not work.

As for the question on "any increment": of course, if you use the above and try \foreach \rpos in {0,.03,...,1} ..., say, the contour won't close. However, this is because you instructed TikZ to draw 99% of the path in the last step as the last \rpos is 0.99 (roughly) in this loop. How would TikZ know that it is supposed to close? In this case, one has to add the closing point to the loop and say \foreach \rpos in {0,.03,...,1,0.9999}.

\documentclass[tikz,border=5mm]{standalone}
\usetikzlibrary{decorations}
\pgfkeys{pgf/.cd,
close/.code={\pgfpathclose}}

\pgfdeclaremetadecoration{draw part of a path}{initial}{
    \state{initial}[width={\pgfmetadecoratedpathlength*\pgfdecorationsegmentlength},next state=final]{
        \decoration{lineto}
    }
    \state{final}{\ifdim\pgfdecorationsegmentlength>0.999pt
        \pgfkeys{/pgf/decoration automaton/if input segment is closepath=/pgf/close}
    \fi 
    }
}
%
\tikzset{start segment/.style={decoration={draw part of a path,raise=2mm,segment length=#1},decorate}} 

\begin{document}
\foreach \rpos  in {0,.03,...,1,0.9999}{% 
            \begin{tikzpicture}[scale=1]
                \fill[green!40](0,0) rectangle (4,4);
                \draw[start segment=\rpos,blue,ultra thick] (0,0) -- (4,0) -- (4,4) -- (0,4) --cycle ;
                \begin{scope}[xshift=5cm]
                \fill[red!40](0,0) rectangle (4,4);
                \draw[start segment=\rpos,blue,ultra thick] (0,0) -- (4,0) -- (4,4) -- (0,4);
                \end{scope}
            \end{tikzpicture} 
 } 
\end{document}

enter image description here

This also works properly for \foreach \rpos in {0,.02,...,1,0.9999}{%.

And yes, the path is really closed at the end.

enter image description here

EDITS: I streamlined the code and removed the \typeouts.

  • You are right for an increment of 0.03 since 0.03 x 33 +0.01 =1. And so the foreach loop never reaches 1. But the path does not close with an increment of 0.1 whereas 0.1 x 10 = 1 and the same, with 0.04 whereas 0.04 x 25 =1 – AndréC Aug 14 '18 at 7:31
  • @AndréC I have just tried out myself. The lower part of the code does close both for \foreach \rpos in {0,.1,...,1,0.9999}{% and \foreach \rpos in {0,.04,...,1,0.9999}{% on my TeXLive 2018 distribution. (The upper part can in principle removed.) – user121799 Aug 14 '18 at 13:04
  • 1
    @AndréC Yes, but this is really just one out of two issues. Just compare \draw (0,0) -- (4,0) -- (4,4) -- (0,4) --cycle ; with \draw (0,0) -- (4,0) -- (4,4) -- (0,4) -- (0,0);. That is \pgfpathclose is important, too. – user121799 Aug 14 '18 at 13:13
  • 1
    @AndréC \typeout is irrelevant. It just prints something on your console. I used it for debugging in order to find out what's going on. That's why I wrote "If you tell me to get rid of the \typeouts I'll be happy to do so.", and the offer is still good. (Probably one should also drop the upper part of the answer.) – user121799 Aug 14 '18 at 13:34
  • 1
    @AndréC First of all, I do not know. I would guess, however, that you could do in a state that is not the final state something like state{almost final}[next state=final,if input segment is closepath={next state=close path}]{ } or something along these lines. I would have to research this, but would be happy to do so if you ask me to and tell me what you want to achieve. An even better way would be to ask a new question since this is interesting and examples are still sparse here. – user121799 Aug 20 '18 at 14:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.