3

Here is my more or less minimal example where I draw a ‘document’ shape with a little folded corner. Values are hardcoded to decrease the size of the example.

My problem is that in beforebackgroundpath, I clearly give commands to draw one thick red stroke, then move a bit lower and draw another, thinner black one. However, only the thick red line is drawn.

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

\makeatletter
\pgfdeclareshape{document}{
    \inheritsavedanchors[from=rectangle]
    \inheritanchorborder[from=rectangle]
    \inheritanchor[from=rectangle]{center}
    \inheritanchor[from=rectangle]{north}
    \inheritanchor[from=rectangle]{north east}
    \inheritanchor[from=rectangle]{east}
    \inheritanchor[from=rectangle]{south east}
    \inheritanchor[from=rectangle]{south}
    \inheritanchor[from=rectangle]{south west}
    \inheritanchor[from=rectangle]{west}
    \inheritanchor[from=rectangle]{north west}
    \backgroundpath{
        \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
        % main shape
        \pgf@xc=\pgf@xb
        \advance\pgf@xc by-10pt
        \pgf@yc=\pgf@yb
        \advance\pgf@yc by-5pt
        \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
        \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}}
        \pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yb}}
        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yc}}
        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}
        \pgfpathclose
        % fold
        \pgfpathmoveto{\pgfpoint{\pgf@xb}{\pgf@yc}}
        \pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yc}}
        \pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yb}}
    }
    \beforebackgroundpath{
        \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
        % lines
        \advance\pgf@xa by+5pt
        \advance\pgf@xb by-5pt
        \pgfmathsetlength\pgf@yc{(\pgf@yb-\pgf@ya)/8}
        \pgf@ya=\pgf@yb
        \advance\pgf@ya by-10pt
        \pgf@xc=.3\pgf@xb
        \pgfsetstrokecolor{red}
        \pgfsetlinewidth{4pt}
        \advance\pgf@ya by-\pgf@yc
        \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
        \pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@ya}}
        \pgfusepath{stroke}
        \pgfsetstrokecolor{black}
        \pgfsetlinewidth{2pt}
        \advance\pgf@ya by-\pgf@yc
        \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}
        \pgfusepath{stroke}
    }
}
\makeatother

\begin{document}

\begin{tikzpicture}
    \node[document,draw,text width=3cm,minimum height=5cm] {};
\end{tikzpicture}

\end{document}

1 Answer 1

7

The problem is that \pgf@xb gets overwritten by \pgfusepath{stroke}, so you draw a line of length 0pt. You need to set \pgf@xb afterwards, for example

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

\makeatletter
\pgfdeclareshape{document}{
    \inheritsavedanchors[from=rectangle]
    \inheritanchorborder[from=rectangle]
    \inheritanchor[from=rectangle]{center}
    \inheritanchor[from=rectangle]{north}
    \inheritanchor[from=rectangle]{north east}
    \inheritanchor[from=rectangle]{east}
    \inheritanchor[from=rectangle]{south east}
    \inheritanchor[from=rectangle]{south}
    \inheritanchor[from=rectangle]{south west}
    \inheritanchor[from=rectangle]{west}
    \inheritanchor[from=rectangle]{north west}
    \backgroundpath{
        \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
        % main shape
        \pgf@xc=\pgf@xb
        \advance\pgf@xc by-10pt
        \pgf@yc=\pgf@yb
        \advance\pgf@yc by-5pt
        \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
        \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}}
        \pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yb}}
        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yc}}
        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}
        \pgfpathclose
        % fold
        \pgfpathmoveto{\pgfpoint{\pgf@xb}{\pgf@yc}}
        \pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yc}}
        \pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yb}}
    }
    \beforebackgroundpath{
        \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
        % lines
        \advance\pgf@xa by+5pt
        \advance\pgf@xb by-5pt
        \pgfmathsetlength\pgf@yc{(\pgf@yb-\pgf@ya)/8}%
        \pgf@ya=\pgf@yb
        \advance\pgf@ya by-10pt
        \pgf@xc=.3\pgf@xb
        \pgfsetstrokecolor{red}%
        \pgfsetlinewidth{4pt}
        \advance\pgf@ya by-\pgf@yc
        \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}%
        \pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@ya}}%
        \typeout{before pgfusepath: xb=\the\pgf@xb}%
        \pgfusepath{stroke}%
        \typeout{after pgfusepath: xb=\the\pgf@xb}%
        \pgfsetstrokecolor{black}%
        \pgfsetlinewidth{2pt}
        \advance\pgf@ya by-\pgf@yc
        \pgf@xb=2\pgf@xc
        \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}%
        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}%
        \pgfusepath{stroke}%
    }
}
\makeatother

\begin{document}

\begin{tikzpicture}
    \node[document,draw,text width=3cm,minimum height=5cm] {};
\end{tikzpicture}

\end{document}

enter image description here

5
  • Isn't there an easier way to draw such a simple picture? Or do I miss something?
    – Keks Dose
    Oct 29, 2021 at 13:10
  • 1
    @KeksDose Of course there is a simpler way to draw such a picture but question concerns a node shape, which has a lot of additional features.
    – user255043
    Oct 29, 2021 at 15:18
  • Thank you, this indeed fixes my problem. I should have noticed this in the PGF manual: ‘Attention: PGF uses these registers to perform path operations. For reasons of efficiency, path commands do not always guard them.’
    – bp99
    Oct 31, 2021 at 11:15
  • Are there better ‘best practices’ to declare shapes other than the way I present in my question, ie setting \pgf@{x,y}{a,b,c} and drawing paths between points with coordinates constructed from these values? I sometimes also use \@tempdim{a,b} when I run out of registers. Is this the preferred way? I find it often very hard to follow which register currently contains what and which can be reused without realizing one will need it again later.
    – bp99
    Oct 31, 2021 at 11:19
  • 1
    @bp99 I do not know what the recommended way is. However, if you look at the pgf libraries of shapes, you can see that sometimes extra local macros are defined, e.g. in pgflibraryshapes.callouts.code.tex one has \xpathradius and \ypathradius. That is, in order to just "remember" a length you do not need necessarily a length register, but can also use a local macro. However, I am not claiming that this is the "better" or "preferred" way.
    – user255043
    Oct 31, 2021 at 15:43

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.