30

Is it possible to define in TikZ a new decoration or something like that, such that it is possible to write something like:

\draw[dim={text,above}] (A) -- (B);
\draw[dim={text,below}] (C) -- (D);

or even better

\draw (A) dim[text,above] (B);
\draw (C) dim[text,below] (C);

to get something like this:

dim

It's important that the text is sloped.

If possible I would prefer the second syntax, because then I could easily combine such path's:

\draw (A) dim[text,above] (B) -- (C) -- (D) dim[text] (E) dim[text,below] (F) -- circle;
6
  • possible duplicate of Dimensioning of a technical drawing in TikZ
    – Jake
    Dec 11, 2011 at 12:34
  • 1
    It's not a duplicate because the object I want is slightly different, because I want a special syntax and because I want to have the label sloped
    – student
    Dec 11, 2011 at 12:53
  • I agree that it isn't a duplicate, just a related question. Having a dim option might be possible, but having a dim path command is not possible (as long you don't rewrite TikZ internal path parser). Dec 11, 2011 at 12:59
  • You can also do this via defining a new decoration with |-| type of arrows. See this question "Line segments with text in the middle in TikZ" and answers for different solutions.
    – percusse
    Dec 11, 2011 at 17:19
  • @percusse But how to get the double lines for my case?
    – student
    Dec 11, 2011 at 17:37

3 Answers 3

32

Update

The result looks fine but perhaps the code can be improved.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations,decorations.markings,decorations.text}

\begin{document}
 \pgfkeys{/pgf/decoration/.cd,
      distance/.initial=10pt
}  

\pgfdeclaredecoration{add dim}{final}{
\state{final}{% 
\pgfmathsetmacro{\dist}{5pt*\pgfkeysvalueof{/pgf/decoration/distance}/abs(\pgfkeysvalueof{/pgf/decoration/distance})} 
          \pgfpathmoveto{\pgfpoint{0pt}{0pt}}             
          \pgfpathlineto{\pgfpoint{0pt}{2*\dist}}   
          \pgfpathmoveto{\pgfpoint{\pgfdecoratedpathlength}{0pt}} 
          \pgfpathlineto{\pgfpoint{(\pgfdecoratedpathlength}{2*\dist}}
           \pgfusepath{stroke} 
          \pgfsetdash{{0.1cm}{0.1cm}{0.1cm}{0.1cm}}{0cm}     
          \pgfsetarrowsstart{latex}
          \pgfsetarrowsend{latex}  
          \pgfpathmoveto{\pgfpoint{0pt}{\dist}}
          \pgfpathlineto{\pgfpoint{\pgfdecoratedpathlength}{\dist}} 
          \pgfusepath{stroke} 
          \pgfsetdash{}{0pt}
          \pgfpathmoveto{\pgfpoint{0pt}{0pt}}
          \pgfpathlineto{\pgfpoint{\pgfdecoratedpathlength}{0pt}}
}}

\tikzset{dim/.style args={#1,#2}{decoration={add dim,distance=#2},
                decorate,
                postaction={decorate,decoration={text along path,
                                                 raise=#2,
                                                 text align={align=center},
                                                 text={#1}}}}}

\begin{tikzpicture}
\coordinate (A) at (0,0);
\coordinate (B) at (4,2);
\coordinate (C) at (8,-2);

\draw[dim={5 cm,10pt,}]  (A) --  (B);
\draw[dim={7 cm,-15pt}]  (B) --  (C); 

\draw[fill=gray] (A) circle(2pt); 
\draw[fill=gray] (B) circle(2pt);
\draw[fill=gray] (C) circle(2pt);   
\end{tikzpicture}

\end{document} 

enter image description here

Update : possible with edge

\draw (A) edge [dim={5 cm,10pt}]  (B) 
          edge[dim={7 cm,-15pt}]  (C)
       (B)edge[dim={4 cm,+10pt}]  (C);  

enter image description here

10
  • 1
    Great. Is it possible to adjust this such that one can write something like \draw (A) dim[text,above] (B) -- (C) -- (D) dim[text] (E) dim[text,below] (F) -- circle;
    – student
    Dec 11, 2011 at 19:38
  • @user4011 No it's impossible because decoration is applied to the whole path; you can use edge like in my update code. Dec 11, 2011 at 20:22
  • Alain, thanks for this great answer. However, I cannot label the dimension line with a mathematical symbol. As soon as type in $a$ for exmaple, the macro does weird stuff. Is there any way to fix this?
    – Ingo
    Jun 5, 2013 at 8:13
  • I'm using pdflatex and had to terminate the application manually after passing a math symbol to the macro as a label...
    – John Chris
    Nov 21, 2014 at 16:51
  • @AlainMatthes can you fix some problem in your sty. Here is the link in my question. tex.stackexchange.com/questions/381401/… Jul 20, 2017 at 8:23
15

Here is a solution, via to path, that allows to use the second required syntax:

enter image description here

\documentclass[tikz,margin=2mm]{standalone}
\usetikzlibrary{calc}
\tikzset{
  dim above/.style={to path={\pgfextra{
        \pgfinterruptpath
        \draw[>=latex,|<->|] let
        \p1=($(\tikztostart)!2mm!90:(\tikztotarget)$),
        \p2=($(\tikztotarget)!2mm!-90:(\tikztostart)$)
        in(\p1) -- (\p2) node[pos=.5,sloped,above]{#1};
        \endpgfinterruptpath
      }(\tikztostart) -- (\tikztotarget) \tikztonodes
    }
  },
  dim below/.style={to path={\pgfextra{
        \pgfinterruptpath
        \draw[>=latex,|<->|] let 
        \p1=($(\tikztostart)!2mm!90:(\tikztotarget)$),
        \p2=($(\tikztotarget)!2mm!-90:(\tikztostart)$)
        in (\p1) -- (\p2) node[pos=.5,sloped,below]{#1};
        \endpgfinterruptpath
      }(\tikztostart) -- (\tikztotarget) \tikztonodes
    }
  },
}

\begin{document}
\begin{tikzpicture}
  \draw (0,0) to[dim above=text] (4,-2) to[dim below=other text](0,-4);
\end{tikzpicture}
\end{document}

Improved version by removing (\tikztostart)

To get a continuous path (to fill it for example), you can use:

\documentclass[tikz,margin=2mm]{standalone}
\usetikzlibrary{calc}
\tikzset{
  dim above/.style={to path={\pgfextra{
        \pgfinterruptpath
        \draw[line width=.4pt,>=latex,|<->|] let 
        \p1=($(\tikztostart)!2mm!90:(\tikztotarget)$),
        \p2=($(\tikztotarget)!2mm!-90:(\tikztostart)$)
        in (\p1) -- (\p2) node[text=,pos=.5,sloped,above]{#1};
        \endpgfinterruptpath
      } -- (\tikztotarget) \tikztonodes
    }
  },
  dim below/.style={to path={\pgfextra{
        \pgfinterruptpath
        \draw[line width=.4pt,>=latex,|<->|] let 
        \p1=($(\tikztostart)!2mm!90:(\tikztotarget)$),
        \p2=($(\tikztotarget)!2mm!-90:(\tikztostart)$)
        in (\p1) -- (\p2) node[text=,pos=.5,sloped,below]{#1};
        \endpgfinterruptpath
      } -- (\tikztotarget) \tikztonodes
    }
  }
}

\begin{document}
\begin{tikzpicture}
  \path[draw=blue,text=red,line width=1pt,fill=orange!50,line cap=round,line join=round]
  (0,0)
  to[dim above=first text] (4,-1) node[right] {A}
  to[dim below=second text](-3,-4) node[below left] {B}
  to[dim above=third text] (0,0) node[above=1mm]{C};
\end{tikzpicture}
\end{document}

enter image description here

1
10

In the interim, for whomever might be interested in a pstricks version of this style, which presents a pretty straight-forward way of rotating text labels between paths:

enter image description here

\documentclass{article}
\usepackage{pstricks,pstricks-add}% http://www.tug.org/PSTricks/main.cgi/
\begin{document}
\begin{pspicture}(10,5)
  \pcline{-}(0,0)(3,2)
  \pcline[offset=12pt]{|-|}(0,0)(3,2)
  \ncput*[nrot=:U]{Length}

  \pcline{-}(5,1)(8,0)
  \pcline[offset=-12pt]{|<->|}(5,1)(8,0)
  \nbput[nrot=:U]{Text}
\end{pspicture}
\end{document}

It requires the traditional latex -> dvips -> ps2pdf or xelatex compiling sequence (unless you're using auto-pst-pdf).

1
  • 1
    |<*->|* and |*-|* give more precise ends. Nov 13, 2013 at 5:11

You must log in to answer this question.

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