5

I have a pgf shape, and I want the possibility of building it with certain keys which add optional parts to the shape. These keys are drawing the optional parts using the .code pgfkeys parameter. The problem is that when I draw my shape in different places on the page, or with a scale command, these optional parts do not move properly.

How can I get the optional parts to move and scale with the rest of the shape?

Here is my current code:

\documentclass{article}
\usepackage{tikz}
\makeatletter
\pgfkeys{/tikz/east/.code={
    \color{#1}
    \pgfpathcircle{\pgfpoint{1cm}{0cm}}{0.1cm}
    \pgfusepath{fill}}
}
\pgfkeys{/tikz/east/.default=black}
\pgfdeclareshape{my circle}{
    \savedanchor\centerpoint{
        \pgf@x=0pt
        \pgf@y=0pt
    }
    \anchor{center}{\centerpoint}
    \foregroundpath{
        \pgfpathcircle{\pgfpoint{0cm}{0cm}}{1cm}
        \pgfusepath{stroke}
    }
}
\makeatother
\begin{document}
\[
\begin{tikzpicture}
\node [my circle, scale=1, east=blue] at (0cm,1cm) {};
\end{tikzpicture}
\]
\end{document}

Here I am passing the parameter "east=blue", which is supposed to draw a little blue blob on the east side of my circle. I'm drawing the node at (0cm,1cm), but the little blue blob is drawn as if the circle was centred at (0cm,0cm). Here is the output:

enter image description here

The desired output would be for the little blob to be drawn at the easternmost point of the circle shape, regardless of the coordinates the shape is drawn at, and use of the scale and rotate commands.

  • Another way to do it, which would solve the problem, would be to write code within the backgroundpath macro to detect which keys have been passed, and with what arguments. I have tried for hours to do that without success - maybe someone else knows how? – Jamie Vicary Jul 19 '18 at 20:10
2

If you really want to reinvent the wheel, err circle, look it up in the tikz code. ;-) However, I do not think it is necessary here. Here is a proposal that I think does what you want.

\documentclass[tikz,border=3.14mm]{standalone}
\tikzset{my circle/.style={circle,draw,minimum size=2cm,alias=mycirc},
my east/.style={append after command={
             \pgfextra{\fill[#1] (\tikzlastnode.east) circle (1mm);}}}}
\begin{document}
\foreach \X in {0.5,0.55,...,2} % animation just for fun
{\begin{tikzpicture}
\path[use as bounding box] (-2,-1) rectangle (2,3); % just for the animation
\node [my circle, scale=\X,my east=blue] at (0cm,1cm) {};
\end{tikzpicture}}
\end{document}

enter image description here

| improve this answer | |
1

Edit
It really didn't work with scale. This solution does however:

\documentclass[tikz,margin=2mm]{standalone}
\usepackage{tikz}
\makeatletter
\def\blob@east{0}
\tikzset{
    blob east/.code={\def\blob@east{1}\def\blob@east@color{#1}},
    blob east/.default=black,
}
\pgfdeclareshape{my circle}{
    \savedanchor\centerpoint{
        \pgf@x=0pt
        \pgf@y=0pt
    }
    \anchor{center}{\centerpoint}
    \foregroundpath{
        \pgfpathcircle{\pgfpoint{0cm}{0cm}}{1cm}
        \pgfusepath{stroke}
        \ifnum\blob@east=1
            \pgfsetcolor{\blob@east@color}
            \pgfpathcircle{\pgfpoint{1cm}{0cm}}{1mm}
            \pgfusepath{fill}
        \fi
    }
}
\makeatother
\begin{document}
\foreach \Scale in {1,2,3,4}{
    \begin{tikzpicture}
        \path (-5,-4) rectangle (15,6);
        \node [my circle, scale=\Scale, blob east=blue] at (0,1) {};
        \node [my circle, scale=\Scale] at (10,1) {};
    \end{tikzpicture}
}
\end{document}

enter image description here

Old answer
I'm not sure how to do this with the low level \pgf... commands, but if you only want to draw a dot relative to the node you can do it with some higher level commands quite easily.

\documentclass[tikz,margin=2mm]{standalone}
\usepackage{tikz}
\makeatletter
%\pgfkeys{/tikz/east/.code={
%    \color{#1}
%    \pgfpathcircle{\pgfpoint{1cm}{0cm}}{0.1cm}
%    \pgfusepath{fill}}
%}
\tikzset{
    east/.style={
        append after command={
            \pgfextra{
                \fill[shift={(\tikzlastnode)},#1] (1cm,0) circle (0.1cm);
            }
        },
    },
}
\pgfkeys{/tikz/east/.default=black}
\pgfdeclareshape{my circle}{
    \savedanchor\centerpoint{
        \pgf@x=0pt
        \pgf@y=0pt
    }
    \anchor{center}{\centerpoint}
    \foregroundpath{
        \pgfpathcircle{\pgfpoint{0cm}{0cm}}{1cm}
        \pgfusepath{stroke}
    }
}
\makeatother
\begin{document}
\begin{tikzpicture}
\node [my circle, scale=1, east=blue] at (0cm,1cm) {};
\end{tikzpicture}
\end{document}

enter image description here

| improve this answer | |
  • Thanks for this interesting idea! I don't think this would work with the scale command though. – Jamie Vicary Jul 19 '18 at 20:11
  • @JamieVicary You were right about the scale key. The new solution works. – Max Jul 20 '18 at 6:59

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.