# Draw a shape with operation on parameters in Tikz

I want to draw a shape that I want to reuse. This shape is defined by geometrical input parameters (distances, radii) in a newcommand. Thus I want to perform some operations to define for example the center of my shape for example.

Maybe I am not treating thos problem correctly as I also want this shpae to work with the node proprties tu use the anchors and not only the origin of the shape for placement.

Here my small code. Thank you in advance.

\documentclass[border=2mm]{standalone} %<--- standalone
\usepackage{tikz}

\newcommand{\hinge}[3] % #1 = name , #2 = rotation angle
{
\draw[black, line width=1mm] (#1-#3,#2+#3)--++(1,0)--++(0:0) arc(0:180:-1)--++(1,0)--++(0,-2.1)--++(-1,0)--++(0:0) arc(0:180:1)--++(-1,0)--cycle;
}

\begin{document}

\begin{tikzpicture}
\hinge(0,0,1);
\draw[red] (0,0) circle (0.1);
\end{tikzpicture}
\end{document}


I had the same idea as @marmot: you should use a pic for this -- but I really like Ignasi's approach too!

Most of the solutions above do not seem to handle your requirement about node coordinates and the shapes are not styled further. It is easy to do both using pics, which you can read more about in section 18.2 of the tikz manual (version 3.0.1a).

Specifically, you can create something like:

using the code:

\documentclass[border=2mm]{standalone} %<--- standalone
\usepackage{tikz}

\tikzset{
pics/hinge/.style args = {#1,#2}{% name, style
code = {
\draw[black, line width=1mm, #2]
(0,0)--++(1,0)--++(0:0) arc(0:180:-1) node[pos=0.5](#1){}
--++(1,0)--++(0,-2.1)--++(-1,0)--++(0:0) arc(0:180:1)
--++(-1,0)--cycle;
}
}
}

\begin{document}

\begin{tikzpicture}
\draw (4,4) pic{hinge={first,blue}};
\pic at (0,0) {hinge={second,{red,rotate=30}}};
\draw (0,4) pic{hinge={third,scale=0.4}};
\draw[thick,->](first)--(second);
\end{tikzpicture}

\end{document}


As I have shown, you can place a pic using either a \draw command or a \pic command. I have defined a pic called hinge that takes two mandatory arguments:

• the node name, which is in the center of the pic
• and any styling

Both arguments to hinge are mandatory but you can omit one of them by using a comma:

\draw (4,0) pic{hinge={fourth,}};


is perfectly valid -- but be careful because you will get a nasty error and obscure message if you try:

\draw (4,0) pic{hinge={fourth}};


Finally, as pics are drawn relative to the point that they are placed, using \draw or \pic, I dropped your (#1-#3,#2+#3). If this is really needed it is easy enough to add back in as pics can take many arguments, although at some point it becomes easier to use keys.

• Thank you very much all for your fast answer. Pic seems to be dedicated to what I try to do! – Willi Oct 19 '18 at 11:42

I probably misread the question but if you want to give the thing node-like anchors, you may want to use a pic. In the following example, I give the thing the name X and draw a 45 degree line from its north east corner.

\documentclass[border=2mm]{standalone} %<--- standalone
\usepackage{tikz}
\tikzset{pics/.cd,
hinge/.style args={#1/#2/#3}{code={
\draw[black, line width=1mm] (#1-#3,#2+#3)--++(1,0)--++(0:0) arc(0:180:-1)--++(1,0)--++(0,-2.1)--++(-1,0)--++(0:0) arc(0:180:1)--++(-1,0)--cycle;
}}}

\begin{document}
\begin{tikzpicture}
\pic[local bounding box=X] at (0,0) {hinge={0/0/1}};
\draw (X.north east) -- ++ (1,1);
\draw[red] (0,0) circle (0.1);
\end{tikzpicture}
\end{document}


• Ooh, interesting :) – Phelype Oleinik Oct 19 '18 at 11:17
• +1 I had the same idea – Andrew Oct 19 '18 at 11:38

You could also use a rectangular node but with a border and filling based on path picture option.

\documentclass[border=2mm]{standalone} %<--- standalone
\usepackage{tikz}
\usetikzlibrary{positioning}

\begin{document}
\begin{tikzpicture}[hinge/.style 2 args={
path picture={%
\draw[#1]
([xshift=-#2]path picture bounding box.south) arc(180:0:#2)
-|(path picture bounding box.north east)
--([xshift=#2]path picture bounding box.north) arc(0:-180:#2)
-|(path picture bounding box.south west)--cycle;
}},
hinge/.default={}{5mm}
]

\node[minimum width=4cm, minimum height=2cm,
, hinge] (a) {Some text inside};
\node[minimum width=2cm, minimum height=1cm,
, hinge={fill=red!30}{2mm}, above right=0pt of a] (b) {Test};

\node[minimum width=2cm, minimum height=1cm,
, hinge={draw=green,fill=blue!30}{2mm}, right= of a] (c) {Test 2};
\end{tikzpicture}
\end{document}


• Thank you! it seems also an interesting solution! I have to understand the difference between all solutions but it seems to answer my problem! – Willi Oct 19 '18 at 11:45
• I think your solution answers the most of my problems. So again Thank you very much for your time! – Willi Oct 19 '18 at 11:50
• I noticed that the line thickness changes (vertical ones are finer) can this been solved? – Willi Oct 19 '18 at 12:01

When you create a command with \newcommand, the arguments must be given within pairs of braces, so for the command to work you would need to use \hinge{0}{0}{1}. To preserve the usage syntax and keep the command TikZ-like, you can use xparse:

\documentclass[border=2mm]{standalone} %<--- standalone
\usepackage{tikz}
\usepackage{xparse}

\NewDocumentCommand{\hinge}
{ >{ \SplitArgument{2}{,} } r() } % #1 = name , #2 = rotation angle
{%
\hingeMAIN#1%
}
\newcommand\hingeMAIN[3]{%
\draw [black, line width = 1mm]
(#1-#3,#2+#3)--++(1,0)--++(0:0) arc(0:180:-1)--++(1,0)--++(0,-2.1)--++(-1,0)--++(0:0) arc(0:180:1)--++(-1,0)--cycle;
}

\begin{document}

\begin{tikzpicture}
\hinge(0,0,1);
\draw[red] (0,0) circle (0.1);
\end{tikzpicture}
\end{document}


The argument specification >{ \SplitArgument{2}{,} } r() says that there is a required argument delimited by () which will be pre-processed by the \SplitArgument, which will split the input argument in 2+1 items separated by a ,. This command will transform (0,1,2) into {0}{1}{2}, which is then passed to \hingeMAIN, which expects braced arguments and does the drawing. The ; after the \hinge command is not necessary.

• Thank you for your fast answer!!! I feel stupid because of the synthax of my command... anyway, is it the right way to make a macro-shape to reuse in tikz or is there an elegant way? – Willi Oct 19 '18 at 11:08
• I think xparse is the best way to easily create custom-delimited commands. The other way to to that would be \def\hinge(#1,#2,#3){<stuff here>}, but this would be much more fragile than the xparse version, so I think it's as elegant as it can get :) – Phelype Oleinik Oct 19 '18 at 11:11
• My concern was why I could not perform #1+#2 in the drawing but you solved my problem with replacing \hinge(1,2,3) by \inge{1}{2}{3} – Willi Oct 19 '18 at 11:20