5

I've come again to pic your interesting brains.

I am trying to make a custom node with a drawing I've made

    \documentclass[tikz, margin=3mm]{standalone}
    \usepackage[utf8]{inputenc}
    \usepackage{pgfplots,tikz}
    \pgfplotsset{compat=1.16}
    \usetikzlibrary{calc}
    
    \tikzset{
      pics/mynodeB/.style={
         code={
            \draw[fill] (0,0.5) circle (1cm);
            \draw[line width=4pt] (0,0) circle (2.2cm) ;
            \pgfmathsetmacro{\AngleA}{52.5}
            \draw[fill] (0,-2) arc (-90:-37.8:2cm) arc (29:66.2:1.8cm) arc (-\AngleA:{-180+\AngleA}:1.2cm)  arc ({180-66.2}:{180-29}:1.8cm) arc ({-180+37.8}:-90:2cm) ;
         }
      },
        cross/.style={path picture={
            \draw[black] let
              \p1 = (path picture bounding box.south),
              \p2 = (path picture bounding box.north),
              \n1 = {veclen((\x2-\x1),(\y2-\y1))}
              in ($(path picture bounding box.south east)!0.5!(path picture bounding box.north west)$) circle (1cm);  % Change is to be made here
        }},
    }
    
    
    \begin{document}
    
      \begin{tikzpicture}
            \draw[fill] (0,0.5) circle (1cm);
            \draw[line width=4pt] (0,0) circle (2.2cm) ;
            \pgfmathsetmacro{\AngleA}{52.5}
            \draw[fill] (0,-2) arc (-90:-37.8:2cm) arc (29:66.2:1.8cm) arc (-\AngleA:{-180+\AngleA}:1.2cm)  arc ({180-66.2}:{180-29}:1.8cm) arc ({-180+37.8}:-90:2cm) ;
            
          \pic[red] at (5,0) {mynodeB};
          \node[cross,minimum size=2cm] at (10,0) {};
      \end{tikzpicture}
    
    \end{document}

It gives this

User pictures

The first is the drawing I'm trying to use. You can see some weird numerical values because I had drawn it using filled circles and some clipping/reversed clipping but it was not working well when I tried to turn it into a node so I approximated the shape with arcs.

The red one is the same drawing done with a "pic" I defined (I don't really know what a pic is, I used a code I found here...). The problem is that a pic is not a node, and I can't use my usual commands to play with it.

The circle on the right is based on a simpler custom node I had made previously. I am trying to make the same drawing than before, but I must not use fixed length (or the shape won't be resized with the node). You can see I have tried in cross/.style evaluating the length \n1 of the node, but if I put \n1 where 1cm is, the circle disappears.

Do you have ideas ?

4
  • 1
    Good evening, I did not understand your problem.
    – AndréC
    Apr 16, 2021 at 20:50
  • I want to use the shape I've drawn as a node. You can criticize what I want to do, give me another way, or you can have an idea why the \n1 doesn't work.
    – LMT-PhD
    Apr 16, 2021 at 21:00
  • If a pic is not a node, it is possible to create nodes in a pic and refer to them. So, depending on the use you will make of this pic, there is a solution to your problem. What will be the use of this pic?
    – AndréC
    Apr 17, 2021 at 5:16
  • 2
    It looks as if you like to make symbols for people. Do you know the relaxed TikZ- library for people? You may check on CTAN for tikzpeople. Apr 17, 2021 at 16:10

3 Answers 3

7

Quite hard to understand what you're looking for, but here's an attempt to answer. Pics are a way to save drawings and be able to reuse them. Hence, you can scale them too (like I did in violet).

A way to name a pic as a node is to give it the parameter local bounding box=A, for example. Then you can use A like a node, especially to place another one next to it, like I did (with the positioning library).

pic as a node

\documentclass[tikz,border=3.14mm]{standalone}
   \usetikzlibrary{positioning}
    
\tikzset{
      mypic/.pic={
            \filldraw (0,0.5) circle (1cm);
            \draw[line width=4pt] (0,0) circle (2.2cm) ;
            \pgfmathsetmacro{\AngleA}{52.5}
            \filldraw (0,-2) arc (-90:-37.8:2cm) arc (29:66.2:1.8cm) arc (-\AngleA:{-180+\AngleA}:1.2cm)  arc ({180-66.2}:{180-29}:1.8cm) arc ({-180+37.8}:-90:2cm) ;
      }
    }
   
    
\begin{document}
    
    \begin{tikzpicture}[on grid]
        \pic[red,local bounding box=A] {mypic};
        \pic[violet,scale=0.5,right=4 cm of A] {mypic};
    \end{tikzpicture}
    
\end{document}
2
  • Thank you for your answer, I'll try it out
    – LMT-PhD
    Apr 17, 2021 at 8:12
  • 1
    +1 but quick question (not OP). What is the advantage of using pic instead if a macro that draws the image every time?
    – Jes
    Apr 17, 2021 at 10:04
4

You were almost there. You only need to introduce a scale factor that allows you to scale the pic without resorting to the scale key because otherwise you may be in trouble if you use the scale key on the node.

\documentclass[tikz, margin=3mm]{standalone}
\usetikzlibrary{calc}
\tikzset{
  pics/mynodeB/.style={
     code={
        \draw[fill] (0,0.5*#1) circle[radius=#1*1cm];
        \draw[line width=#1*4pt] (0,0) circle[radius=#1*2.2cm];
        \pgfmathsetmacro{\AngleA}{52.5}
        \draw[fill] (0,-2*#1) arc[start angle=-90,end angle=-37.8,radius=#1*2cm] 
         arc[start angle=29,end angle=66.2,radius=#1*1.8cm] 
         arc[start angle=-\AngleA,end angle={-180+\AngleA},radius=#1*1.2cm]  
         arc[start angle={180-66.2},end angle={180-29},radius=#1*1.8cm] 
         arc[start angle={-180+37.8},end angle=-90,radius=#1*2cm];
     }
  },pics/mynodeB/.default=1,
    cross/.style={circle,path picture={
        \path let
          \p1 = (path picture bounding box.south west),
          \p2 = (path picture bounding box.north east),
          \n1 = {scalar(veclen(\x2-\x1,\y2-\y1)/4.4cm/sqrt(2))}
          in (path picture bounding box.center)
          pic{mynodeB=\n1};
    }},
}

\begin{document}
\begin{tikzpicture}
    \draw[fill] (0,0.5) circle (1cm);
    \draw[line width=4pt] (0,0) circle (2.2cm) ;
    \pgfmathsetmacro{\AngleA}{52.5}
    \draw[fill] (0,-2) arc (-90:-37.8:2cm) arc (29:66.2:1.8cm) arc (-\AngleA:{-180+\AngleA}:1.2cm)  arc ({180-66.2}:{180-29}:1.8cm) arc ({-180+37.8}:-90:2cm) ;
    \pic[red] at (5,0) {mynodeB};
    \node[cross,minimum size=2cm] (A) at (10,0) {};
    \node[cross,minimum size=2cm,blue] (B) at (14,0) {};
    \draw[thick,orange] (A.45) to[out=45,in=-135] (B.-135);
\end{tikzpicture}
\end{document}

enter image description here

4
  • 1
    Thank you for your answer, it's simple and using a node.
    – LMT-PhD
    Apr 17, 2021 at 8:17
  • Can you help me again, I've tried your solution, I'm quite happy with it, but there is something weird with line width, see for yourself the difference between \draw pic{mynode}; and \node[cross,minimum size=4.4cm] (C) at (5,0) {};
    – LMT-PhD
    Apr 21, 2021 at 21:34
  • Nodes seem to have a circle clip (1cm in diameter) on them
    – LMT-PhD
    Apr 23, 2021 at 6:25
  • The path picture clips against the boundary path, which is a circle. If you choose minimum size=2cm, the radius is 1cm, yes.
    – user240002
    Apr 23, 2021 at 6:28
2

Why not abuse a little bit from path picture? If the node is a circle with minimum size, it's possible measure this size and draw a figure proportional to it.

Following code need some adjustments, but it shows the idea

\documentclass[tikz, margin=3mm]{standalone}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\usetikzlibrary{calc}
    
\tikzset{
    head/.style={circle, draw, path picture={%
        \fill let \p1=($(path picture bounding box.north)-(path picture bounding box.south)$), \n1={veclen(\p1)} in ([yshift=.1*\n1]path picture bounding box.center) circle(0.22*\n1);
        \fill let \p1=($(path picture bounding box.north)-(path picture bounding box.south)$), \n1={veclen(\p1)} in 
        ([shift={(45:.25*\n1)}]path picture bounding box.-135) to[out=-45, in=-135]
        ([shift={(135:.25*\n1)}]path picture bounding box.-45) to[bend right]
        ([shift={(135:.5*\n1)}]path picture bounding box.-45) to[out=-135, in=-45]
        ([shift={(45:.5*\n1)}]path picture bounding box.-135) to[bend right] cycle
        ;
    }}
}

\begin{document}
    
\begin{tikzpicture}

\node[head, minimum size=4cm, draw, blue, line width=1mm] (a) {};

\node[head, minimum size=2cm, draw, green, line width=1mm] at (4,0) (b) {};

\node[head, minimum size=1cm, draw, red] at (4,2) (b) {};

\end{tikzpicture}
    
\end{document}

enter image description here

Update: Reduced code.

Previous code solution can be reduced with the help of Mark Wibrow's "alias" and compacting both fill commands into only one.

\documentclass[tikz, margin=3mm]{standalone}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\usetikzlibrary{calc}
    
\tikzset{
    alias path picture bounding box/.code=\pgfnodealias{#1}{path picture bounding box},
    head/.style={circle, draw, path picture={%
        \tikzset{alias path picture bounding box=@}
        \fill let \p1=($(@.north)-(@.south)$), \n1={veclen(\p1)} in ([yshift=.1*\n1]@.center) circle(0.22*\n1)%;
        ([shift={(45:.25*\n1)}]@.-135) to[out=-45, in=-135]
        ([shift={(135:.25*\n1)}]@.-45) to[bend right]
        ([shift={(135:.5*\n1)}]@.-45) to[out=-135, in=-45]
        ([shift={(45:.5*\n1)}]@.-135) to[bend right] cycle
        ;
    }}
}

\begin{document}
    
\begin{tikzpicture}

\node[head, minimum size=4cm, draw, blue, line width=1mm] (a) {};

\node[head, minimum size=2cm, draw, green, line width=1mm] at (4,0) (b) {};

\node[head, minimum size=1cm, draw, red] at (4,2) (b) {};

\end{tikzpicture}
    
\end{document}
3
  • Thank you for your answer, it removes the use of 'pic'.
    – LMT-PhD
    Apr 24, 2021 at 8:47
  • When I play with that solution the drawback I have is the use of 'let', which you have to copy an paste for every command you use. That gives me some wet programming.
    – LMT-PhD
    Apr 24, 2021 at 9:26
  • 1
    @LMT-PhD With the help of an alias for pathpicture bounding box (see tex.stackexchange.com/a/395641/1952) you can save some typing. And in this particular case, "head" and "body" can be drawn within one command which means only one let expression. See the updated code.
    – Ignasi
    Apr 26, 2021 at 10:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .