3

I'm working on writing a simple package to define some drawing tasks that I commonly do in my work. There are a number of symbols that are reused frequently and I'd like to add them as custom nodes. I've looked at pgf/tikz node custom shape and Creating node shapes; I found both useful, as well as read chapter 49.5 on declaring new shapes from the tikz/pgf manual (in particular, the example on page 335. Both were very informative. However, I'm still having a problem and I suspect it's simple.

Here are the snippets of code that are relevant to the issue:

    \tikzset{leverage/.initial={}}

    \pgfdeclareshape{circle player}{
        \inheritsavedanchors[from=circle]
        \inheritanchorborder[from=circle]
        \inheritanchor[from=circle]{center}
        \inheritanchor[from=circle]{south}
        \inheritanchor[from=circle]{west}
        \inheritanchor[from=circle]{north}
        \inheritanchor[from=circle]{east}

        \inheritbackgroundpath[from=circle]
        \beforebackgroundpath{
            % get and set options
            \pgfkeys{/tikz/leverage/.get=\tmp}
            \expandafter\tikzset\expandafter{\tmp}
            \tikz@options

        % get north and south coordinates
        \north \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \south \pgf@xb=\pgf@x \pgf@yb=\pgf@y

        % draw the line starting from north
        \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
        \pgfpathclose
        }
    }
    \begin{tikzpicture}
    \node[circle player, draw=black] at (240,90) {};
    \end{tikzpicture}

The shape declaration is occurring in the .sty file (wherein I shouldn't need \makeatletter or \makeatother, and haven't had any issues with that), along with the declaration of the leverage option (which is currently not being used, but will be in the future). I've verified that the .sty file is working by writing other commands, using \usepackage in the preamble of my document, and executing those commands. The issue seems to be centered on the declaration of new shapes for nodes. I cannot suss out why there is an issue; I consistently get undefined control sequence when trying to use a newly defined node shape.

What am I missing? It's probably very simple.

  • 1
    I get an Undefined control sequence for \north. What is the \north command? Did you define it? – Phelype Oleinik Mar 29 '18 at 13:42
  • 1
    circle shape doesn't have a \savedanchor named north. You have to redefine it – percusse Mar 29 '18 at 13:46
  • I think I see what you're going at, but I'm still confused. The example from the manual uses a line \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y which is what I used as a prototype for finding the coordinates. However, I cannot get even this line to execute in my file (same issue - undefined control sequence). – EvRoHa Mar 29 '18 at 14:14
  • 1
    Just a comment that shows how fast the pgfmanual is growing: in the 2017 version of the pgfmanual this is section 101.5, which starts on p. 1033. Maybe you want to have a quick look there? – user121799 Mar 29 '18 at 14:15
  • 3
    \southwest is a saved anchor of rectangle but \north is not of circle shape. – percusse Mar 29 '18 at 14:19
4

I don't know what it is supposed to do with beforebackgroundpath but this one at least compiles to a vertical line.

\documentclass[tikz, border=1cm]{standalone}
\makeatletter
\pgfdeclareshape{circle player}{
    \inheritsavedanchors[from=circle]
    \inheritanchorborder[from=circle]
    \inheritanchor[from=circle]{center}
    \inheritanchor[from=circle]{south}
    \inheritanchor[from=circle]{west}
    \inheritanchor[from=circle]{north}
    \inheritanchor[from=circle]{east}

    \inheritbackgroundpath[from=circle]
    \saveddimen\radius{%
      \pgf@ya=.5\ht\pgfnodeparttextbox%
      \advance\pgf@ya by.5\dp\pgfnodeparttextbox%
      \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/inner ysep}}%
      \advance\pgf@ya by\pgf@yb%
      \pgf@xa=.5\wd\pgfnodeparttextbox%
      \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/inner xsep}}%
      \advance\pgf@xa by\pgf@xb%
      \pgf@process{\pgfpointnormalised{\pgfqpoint{\pgf@xa}{\pgf@ya}}}%
      \ifdim\pgf@x>\pgf@y\c@pgf@counta=\pgf@x\ifnum\c@pgf@counta=0\relax%
          \else%
            \divide\c@pgf@counta by 255\relax\pgf@xa=16\pgf@xa\relax%
            \divide\pgf@xa by\c@pgf@counta \pgf@xa=16\pgf@xa\relax%
          \fi%
        \else%
          \c@pgf@counta=\pgf@y\ifnum\c@pgf@counta=0\relax\else%
            \divide\c@pgf@counta by 255\relax\pgf@ya=16\pgf@ya\relax%
            \divide\pgf@ya by\c@pgf@counta \pgf@xa=16\pgf@ya\relax\fi%
      \fi%
      \pgf@x=\pgf@xa%
      \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/minimum width}}%  
      \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/minimum height}}%  
      \ifdim\pgf@x<.5\pgf@xb \pgf@x=.5\pgf@xb \fi%
      \ifdim\pgf@x<.5\pgf@yb \pgf@x=.5\pgf@yb \fi%
      \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}%  
      \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}%  
      \ifdim\pgf@xb<\pgf@yb%
        \advance\pgf@x by\pgf@yb%
      \else%
        \advance\pgf@x by\pgf@xb%
      \fi%
    }%
    \backgroundpath{%
    \centerpoint\advance\pgf@y by\radius%
    \pgf@xa=\pgf@x \pgf@ya=\pgf@y%
    \centerpoint\advance\pgf@y by-\radius%
    \pgf@xb=\pgf@x \pgf@yb=\pgf@y%
    \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}%
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}%
    }%
}
\makeatother

\begin{document}
    \begin{tikzpicture}
    \node[circle player, draw=black] at (240pt,90pt) {};
    \end{tikzpicture}
\end{document}
3

I was wondering about the same thing as @percusse. Assuming that you only want to draw a circle with a vertical line from north to south, this would also do the job.

\documentclass{standalone}
\usepackage{tikz}
\tikzset{circle player/.style={circle,append after command={%
\pgfextra{\draw (\tikzlastnode.north)--(\tikzlastnode.south);}}}}
\begin{document}
    \tikzset{leverage/.initial={}}
    \begin{tikzpicture}
    \node[circle player, draw=black] at (240,90) {};
    \end{tikzpicture}
\end{document}

And just flashing out @percusse'd comment (THANKS!):

\documentclass{standalone}
\usepackage{tikz}
\tikzset{circle player/.style={circle,
path picture = {
\draw
(path picture bounding box.north) -- (path picture bounding box.south);
                                                   }}}
\begin{document}
    \tikzset{leverage/.initial={}}
    \begin{tikzpicture}
    \node[circle player, draw=blue] at (240,90) {};
    \end{tikzpicture}
\end{document}
  • 1
    path picture would be enough otherwise you need to make sure the line doesn't inherit all the properties of the path – percusse Mar 29 '18 at 14:56
1

Based on the observations of others, I was able to solve my problem with the following code. I had to manually find the north and south, when I had assumed they were saved anchors.

\pgfdeclareshape{circle player}{
    \inheritsavedanchors[from=circle]
    \inheritanchorborder[from=circle]
    \inheritanchor[from=circle]{center}
    \inheritanchor[from=circle]{south}
    \inheritanchor[from=circle]{west}
    \inheritanchor[from=circle]{north}
    \inheritanchor[from=circle]{east}

    \inheritbackgroundpath[from=circle]

    \beforebackgroundpath{

        % get and set options
        \pgfkeys{/tikz/leverage/.get=\tmp}
        \expandafter\tikzset\expandafter{\tmp}
        \tikz@options

        % get the center and radius
        \radius \pgf@xa=\pgf@x
        \centerpoint \pgf@xb=\pgf@x \pgf@yb=\pgf@y

        % draw line from north to south
        \advance\pgf@yb by\pgf@xa
        \pgfpathmoveto{\pgfpoint{\pgf@xb}{\pgf@yb}}
        \advance\pgf@yb by -2\pgf@xa
        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
        \pgfusepath{draw}
    }
}

Thanks!

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.