3

In the answer to this question TikZ decorations: How to draw a closed path little by little? @marmot uses this option of the decoration automaton in a way that I don't understand very well but that works perfectly thanks to pgf keys.

\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}} 

Indeed, according to the manual it is an option of the decoration automaton and as such it should be used as follows: \state{final}[if input segment is closepath=\closepath]{} but then the path is no longer closed.

The manual says:

/pgf/decoration automaton/if input segment is closepath= < options > (no default)

This key checks whether the current input segment is a closepath operation. If so, the <options> get executed; otherwise nothing happens. You can use this option to handle a closepath in some special way, for instance, switching to a new state in which \pgfpathclose is executed.

First question:

Why does writing state{final}[if input segment is closepath=\pgfpathclose]{} not work?

Question 2:

  • How to use this option to change the state of the decoration automaton as indicated by the manual?
  • How do I use “is input segment is closepath=< options>”?

Translated with www.DeepL.com/Translator

  • 1
    I asked a partner question here, so that doubles the chance that an expert reads this. ;-) – user121799 Aug 21 '18 at 20:15
  • @marmot +1 nice question – AndréC Aug 21 '18 at 21:22
3

Let me try to give you an answer that helps you a bit to understand what is going on. The main point is that I was sort of lucky when I gave you the previous answer. (OK, I also tried other things that did not work and then presented the one thing that did work. Yet writing this partial answer made it clear to me that I was not aware of some important things when I wrote the other answer.) I try to address your questions by rewriting my code in such a way that the decoration switches to a separate state when on the close path segments. I added several \typeouts in order to illustrate what's going on. Everything works in the way I thought it would except that

now the path does not close despite \pgfpathclose gets executed.

This what I mean by "I was very lucky when I wrote my previous answer". Why does closing not work here? Well, this is because one has to distinguish between meta decorations and decorations, i.e. between

\pgfdeclaredecoration

where if input segment is closepath is defined, and

\pgfdeclaremetadecoration

which the code is based on. (No, I do not think it is a good idea to do the same with a plain decoration because it will be very hard, at least, to make it work with general paths that are composed of straight lines of arbitrary lengths. If one had a quantization rule for the lengths of the line segments, that would be possible.) What this partial answer does here is to mix the two. This is the reason why the full path in \pgfkeys{/pgf/decoration automaton/if input segment is closepath=...} is needed. This does work in the sense that the automaton will switch to a new state, called close, when it is on the close path segment. Then it checks if it is almost at the end, and if so, it does something. However, contrary to my naive expectations, a naive \pgfpathclose does not work here. Unfortunately, I am not able to provide you with a cleaner working answer than in my previous answer (where I was quite lucky). I sort of understand why it worked there: the code switches to "ordinary decoration" mode and injects a \pgfpathclose there. I wish I could make it cleaner. Here is the code.

\documentclass[tikz,border=5mm]{standalone}
\usetikzlibrary{decorations}    
\pgfdeclaremetadecoration{draw part of a path}{initial}{

\state{initial}[width={\pgfmetadecoratedpathlength*\pgfdecorationsegmentlength},next
state=almost final]{
        \decoration{lineto}
    } %/pgf/decoration automaton/if input segment is closepath=/pgf/close
    \state{almost final}[next state=final,
    /pgf/decoration automaton/if input segment is closepath={next
    state=close}]{%
    \typeout{almost\space final}}
    \state{close}[next state=final]{
    \typeout{I'm\space on\space close\space path\space segment\space and\space
    have\space decorated\space\the\pgfdecorationsegmentlength}
    \ifdim\pgfdecorationsegmentlength>0.999pt
        \typeout{gonna\space close}
        \pgfpathclose % <- does not work this way
    \fi}
    \state{final}{}
}
%
\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}

Partial summary:

  • You may mix to some extent decoration stuff with meta decoration stuff but you need to be lucky that it works in the way you wish it would.
  • This part of the TikZ magic seems not to be fully explored on this site, but there are certainly others who understand that much better and will be able to give you a better answer. Since I did not see Jake answering questions, I hope that @cfr and/or @percusse and/or Mark Wibrow and/or @Max see this nice question and provide an answer from which both of us can learn. ;-)

EDIT: I actually think there is a chance that the problem is deeper than outlined above. Consider the MWE

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

\begin{document}
\foreach \rpos  in {0,.03,...,1,1.1}{% 
            \begin{tikzpicture}[scale=1]
                \fill[green!40](0,0) rectangle (4,4);
                \draw[dash pattern=on \rpos*16cm off 16cm,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[dash pattern=on \rpos*16cm off 16cm,blue,ultra thick] (0,0) -- (4,0) -- (4,4) -- (0,4);
                \end{scope}
            \end{tikzpicture} 
 } 
\end{document}

No decorations, nothing but a dash pattern to have the same effect. The final path of the first boundary is not closed

enter image description here

even though there the on phase is longer than the path. So for some reason TikZ does not even close this path. (If that would have worked, it would have been the basis a much simpler solution, one only would have to replace the hard coded 16cm by some \pgfdecoratedpathlength that can be read off as described e.g. here.) Of course, you could always close this simple path by hand:

\draw[dash pattern=on \rpos*16cm off 16cm,blue,ultra thick]
            (0,0) -- (4,0) -- (4,4) -- (0,4) -- (0,-\pgflinewidth/2) -- cycle;

but personally I would then think that my previous working solution is better even if I cannot rewrite it in the way you suggest.

  • 1
    And here is an example using if input segment is closepath. – user121799 Aug 21 '18 at 4:05
  • 1
    @AndréC It certainly is. You "only" have to redraw the whole thing using some small steps. However, I think that it won't work in general. Let's say the step size is 1.5mm. Then your path (0,0) -- (4,0) -- (4,4) -- (0,4) --cycle won't look like a square, rather the corners will be cut a little bit. Of course, you may adjust the step size on a case by case basis. – user121799 Aug 21 '18 at 9:11
  • 1
    @AndréC I thought I had a much simpler proposal using dash pattern. Very surprisingly (to me) it has the same problem as you originally had. Weird. – user121799 Aug 21 '18 at 11:05
  • 1
    There is an animation in French here, but it also doesn't close the path blog.dorian-depriester.fr/latex/les-animations-sous-latex – AndréC Aug 21 '18 at 17:31
  • 1
    @AndréC Yes. (Interestingly this post is using \pgfdeclaredecoration{ignore}{final}{ \state{final}{} }, which I first saw in one of Jake's answers. Naively I'd expect that one should add \pgfdeclaredecoration{close}{final}{ \state{final}{\pgfpathclose} } but I was unable to make that work. My current view is that, even though we do not fully understand why, my other answer does work (or doesn't it?). So one may use it until some true TikZ expert finds something better. What do you think? – user121799 Aug 21 '18 at 17:38

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.