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}
up vote 2 down vote accepted

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:

enter image description here

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 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}

enter image description here

  • Ooh, interesting :) – Phelype Oleinik Oct 19 at 11:17
  • +1 I had the same idea – Andrew Oct 19 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}

enter image description here

  • 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 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 at 11:50
  • I noticed that the line thickness changes (vertical ones are finer) can this been solved? – Willi Oct 19 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.

enter image description here

  • 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 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 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 at 11:20

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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