Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

When I create a new shape using pgfdeclareshape, I want to be able to store a length for later reference. I might want to do simple arithmetic on this length later on. Here's a basic attempt:

 \pgfdeclareshape{MyShape}
 {
    \saveddimen\mydimen
    {
        \pgf@x = 10pt
    }
    \backgroundpath
    {
        \pgfpathmoveto
            {\pgfpoint{0pt}{0pt}}
        \pgfpathlineto
            {\pgfpoint{2\mydimen}{0pt}}
        \pgfusepath{stroke}
    }
 }

This is intended to produce a line 20pt long -- but it actually draws a line 210pt long, presumably because \mydimen stores the value 10pt as plan text, not as a dimension.

How can I save dimensional quantities upon shape creation?

share|improve this question

2 Answers 2

up vote 7 down vote accepted

You are right that \pgfdeclareshape saves it as a macro rather than a length. Why this is, I don't know (but I guess that it's because it's easier to create lots of new macros than lots of new lengths). This isn't a problem so long as you are aware of it. You just have to remember to do your mathematics on macros rather than lengths. Fortunately, \pgfpoint passes its arguments through the PGFMath stuff and so all you actually need to do in this example is add a multiplication:

\documentclass{article}

\usepackage{tikz}
\makeatletter
\pgfdeclareshape{MyShape}
 {
    \saveddimen\mydimen
    {
        \pgf@x = 10pt
    }
    \backgroundpath
    {
        \pgfpathmoveto
            {\pgfpoint{0pt}{0pt}}
        \pgfpathlineto
            {\pgfpoint{2*\mydimen}{0pt}}
        \pgfpathmoveto
            {\pgfpoint{0pt}{-5pt}}
        \pgfpathlineto
            {\pgfpoint{2\mydimen}{-5pt}}
        \pgfpathmoveto
            {\pgfpoint{0pt}{-10pt}}
        \pgfpathlineto
            {\pgfpoint{\mydimen}{-10pt}}
        \pgfusepath{stroke}
    }
 }
\makeatother

\begin{document}
\begin{tikzpicture}
\node[MyShape,draw] {};
\end{tikzpicture}
\end{document}

(Ignoring the error about missing anchors!) This produces three lines, the top one is the one you want, the middle is your original one, and the lower one is the "reference" line to show that the top one is, indeed, twice the lower one.

If you were using \pgfqpoint - which is faster than \pgfpoint - then you would have to worry about converting from macros to lengths because that doesn't use PGFMath. In this case, you could do something like:

\pgf@xa=\mydimen\relax
\pgf@xa=2\pgf@xa
\pgfpathmoveto{\pgfqpoint{\pgf@xa}{0pt}}

to get the same effect.

share|improve this answer

The \saveddimens aren't real dimensions as you noted. It would be to much effort and overhead to allocate a dimension register for every shape or even for every node of this shape. You can use \dimexpr\yoursaveddimen\relax to make a real dimension expression out of it which accepts a leading factor for multiplication:

 \pgfdeclareshape{MyShape}{%
    \saveddimen\mydimen{%
        \pgf@x = 10pt%
    }%
    \backgroundpath{%
        \pgfpathmoveto
            {\pgfpoint{0pt}{0pt}}%
        \pgfpathlineto
            {\pgfpoint{2\dimexpr\mydimen\relax}{0pt}}%
        \pgfusepath{stroke}%
    }%
 }%

PS: The relevant internal macros used here are: (line breaks and indention added by me)

\saveddimen:
macro:#1#2->\expandafter \pgfutil@g@addto@macro \csname pgf@sh@s@\shape@name \endcsname
    {\pgf@sh@resaveddimen {#1}{#2}}


\pgf@sh@resaveddimen:
macro:#1#2->{#2\global \pgf@x =\pgf@x }\edef \pgf@sh@marshal
    {\noexpand \pgfutil@g@addto@macro \noexpand \pgf@sh@savedpoints
    {\noexpand \def \noexpand #1{\the \pgf@x }}}\pgf@sh@marshal 

You see that the given macro is defined to the expanded value of \the\pgf@x in \pgf@sh@resaveddimen. If you need this very often, you could redefine this macro to use \dimexpr\the\pgf@x\relax instead. The \dimexpr won't be expanded then and the saved dimension would be a macro with the content of \dimexpr 10pt\relax in your case, which acts like a normal dimension register (on the right side of an assignment I mean).

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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