21

Given two co-ordinates say, X.south east and X.south west, is it possible to determine the length or the vector between the two?

In the MWE the width, has been calculated using traditional TeX techniques, but is obviously a bit of a wasted effort as PGF probably did all these calculations already.

enter image description here

\documentclass{article}
\usepackage{pgf,tikz}
\makeatletter
\begin{document}
\def\convert@cx#1{\the#1}
\newlength\xheight@cx
\newlength\xlength@cx
\newlength\xdepth@cx
\newlength\xtotal@cx
\newsavebox{\fontbox}
%
\def\drawfontbox#1{%
  {\upshape\Huge
   \savebox{\fontbox}{#1}
   \pgfmathsetlength{\xheight@cx}{\ht\fontbox}
   \pgfmathsetlength{\xlength@cx}{\wd\fontbox}
   \pgfmathsetlength{\xdepth@cx}{\dp\fontbox}
   \pgfmathsetlength{\xtotal@cx}{\xdepth@cx+\xheight@cx}
  \begin{tikzpicture}[scale=1]
    \node[rectangle,draw,inner sep=0pt,outer sep=0pt] (X){#1};
    \draw[red, line width=0.4pt] (X.text)  circle(1pt)[fill=red] -- (X.base east);
    \draw[|<->|,>=latex] ([yshift=5pt] X.north west)
       --([yshift=5pt] X.north east) node [above=-5pt,midway,
       font={\tiny}]{width = \convert@cx{\xlength@cx}};
    % draw the xheight
    \draw[|<->|,>=latex]([xshift=-5pt]X.base west)
          --([xshift=-5pt] X.north west)
          node [left,midway,font={\tiny}] {x-height=\convert@cx{\xheight@cx}};
%   draw depth
    \draw[-|,>=latex]([xshift=-5pt]X.base west)
          --([xshift=-5pt] X.south west)
          node [left,midway,font={\tiny}] {depth=\convert@cx{\xdepth@cx}};
    \draw[<-,>=latex]([xshift=-5pt]X.south west)
          --++(0,-8pt);
%   draw total height
%
\draw[|<->|,>=latex]([xshift=5pt]X.north east)
          --([xshift=5pt] X.south east)
          node [right,midway,font={\tiny}] {height=\convert@cx{\xtotal@cx}};
  \end{tikzpicture}}
}
\drawfontbox{QWERTY}
\end{document}
yannisl
  • 117,160
  • 1
    Does \veclen not work in this context? – Peter Grill Jun 02 '12 at 15:34
  • 1
    @PeterGrill \veclen might or might not work, but currently it is neither in my memory nor in my vocabulary. Maybe you can provide an answer? – yannisl Jun 02 '12 at 15:38
  • 1
    \veclen gives the "length" of the vector. You get the coordinates of the vector with TeX : \pgfpointdiff{\pgfpointanchor{A}{anchor}}{\pgfpointanchor{B}{anchor}} in \pgf@x and \pgf@y. Another possibility is ($(b)-(a)$) for example \node (c) at ($(b)-(a)$) {c}; – Alain Matthes Jun 02 '12 at 15:43
  • @Altermundus Thanks a lot will check them in the manual. – yannisl Jun 02 '12 at 15:46
  • \pgfpointdiff{⟨start ⟩}{⟨end ⟩} Returns the difference vector ⟨end⟩ − ⟨start⟩. – Alain Matthes Jun 02 '12 at 15:47
  • I'm getting impatient about your end product. I think we are seeing the bits and pieces about your grand design. :) – percusse Jun 02 '12 at 16:42

4 Answers4

19

An example with let and veclen:

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
\coordinate (a) at (0,0);
\coordinate (b) at (4,2);
\draw let
  \p1 = (a),
  \p2 = (b),
  \n1 = {veclen((\x2-\x1),(\y2-\y1))}
in
  (a) to[sloped,above] node{\n1} (b);
\end{tikzpicture}

\end{document}

enter image description here

An adaption of your original code:

enter image description here

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\def\drawfontbox#1{%
 \begin{tikzpicture}[%
  MyArr/.style={|<->|,>=latex},
  MyLabel/.style={font={\tiny}}]
    \node[rectangle,draw,inner sep=0pt,outer sep=0pt] (X){\Huge #1};
    \draw 
      let
        \p1 = (X.base west),
        \p2 = (X.south west),
        \p3 = (X.south east),
        \p4 = (X.north west),
        \p5 = (X.north east),
        \n1 = {veclen(\x5-\x4,\y5-\y4)}, % width 
        \n2 = {veclen(\x5-\x3,\y5-\y3)}, % height
        \n3 = {veclen(\x4-\x1,\y4-\y1)}, % x-height
        \n4 = {veclen(\x2-\x1,\y2-\y1)}  % depth
      in
        ([yshift=5pt] X.north west)
          edge[MyArr] node [above=-1pt,MyLabel]{width = \n1}
          ([yshift=5pt] X.north east)
        ([xshift=-5pt]X.base west)
          edge[MyArr] node [left,MyLabel] {x-height=\n3}
          ([xshift=-5pt] X.north west)
        ([xshift=-5pt]X.base west)
          edge[-|,>=latex] node [left,MyLabel] {depth=\n4}
          ([xshift=-5pt] X.south west)
        ([xshift=5pt]X.north east)
          edge[MyArr] node [right,MyLabel] {height=\n2}
          ([xshift=5pt] X.south east)
          ;
    \draw[red, line width=0.4pt] (X.text)  circle(1pt)[fill=red] -- (X.base east);
\end{tikzpicture}
}
\begin{document}
 \drawfontbox{QWERTY}

 \drawfontbox{Lorem Ipsum}

 \drawfontbox{What?}
\end{document}
Torbjørn T.
  • 206,688
11

Perhaps this answer will be useful, i f you want the dimensions of a TeX box

\documentclass{article}
\usepackage{tikz}

\begin{document}  
\newsavebox{\ftbox} 
\savebox{\ftbox}{\Huge QWERTY}

 \pgfmathparse{width("\usebox\ftbox")} \pgfmathresult

 \pgfmathparse{height("\usebox\ftbox")} \pgfmathresult

 \pgfmathparse{depth("\usebox\ftbox")} \pgfmathresult  
\end{document} 

enter image description here

Alain Matthes
  • 95,075
  • the same is possible with simple TeX commands: \the\wd\ftbox, 
\the\ht\ftbox, and \the\dp\ftbox ... –  Jun 02 '12 at 17:40
  • Yes Herbert, you are right but it's only to note the existence of these functions and it's possible to use these functions in other cases. For example width("qwerty") it's not necessary to use the box. – Alain Matthes Jun 02 '12 at 17:55
11

And as Altermundus commented, yet another one to use with arbitrary rectangular nodes :) Add more custom lengths as you wish.

\documentclass{article}
\usepackage{tikz}
\makeatletter
\newcommand{\anchordistances}[1]{
\pgfpointdiff{\pgfpointanchor{#1}{base}}{\pgfpointanchor{#1}{south}}\pgfmathsetmacro{\mydepth}{veclen(\pgf@x,\pgf@y)}
\pgfpointdiff{\pgfpointanchor{#1}{north west}}{\pgfpointanchor{#1}{north east}}\pgfmathsetmacro{\mywidth}{veclen(\pgf@x,\pgf@y)}
\pgfpointdiff{\pgfpointanchor{#1}{south west}}{\pgfpointanchor{#1}{north west}}\pgfmathsetmacro{\myheight}{veclen(\pgf@x,\pgf@y)}
\pgfpointdiff{\pgfpointanchor{#1}{base}}{\pgfpointanchor{#1}{north}}\pgfmathsetmacro{\myxheight}{veclen(\pgf@x,\pgf@y)}
}
\makeatother

\begin{document} \begin{tikzpicture} \node[draw,inner sep=0,outer sep=0] (X) {\upshape\Huge QWERTY}; \draw[red, line width=0.4pt] (X.text) circle(1pt)[fill=red] -- (X.base east); \anchordistances{X}

% draw the xheight
\draw[|&lt;-&gt;|,&gt;=latex]([xshift=-5pt]X.base west)
      --([xshift=-5pt] X.north west)
      node [left,midway,font={\tiny}] {x-height=\myxheight};
\draw[-|,&gt;=latex]([xshift=-5pt]X.base west)
      --([xshift=-5pt] X.south west)
      node [left,midway,font={\tiny}] {depth=\mydepth};
\draw[&lt;-,&gt;=latex]([xshift=-5pt]X.south west)
      --++(0,-8pt);

\draw[|<->|,>=latex] ([yshift=5pt] X.north west) --([yshift=5pt] X.north east) node [above,midway, font={\tiny}]{width = \mywidth}; \draw[|<->|,>=latex]([xshift=5pt]X.north east) --([xshift=5pt] X.south east) node [right,midway,font={\tiny}] {height=\myheight};
\end{tikzpicture} \end{document}

enter image description here

Hmm, I forgot the pt units.

percusse
  • 157,807
9
\documentclass{article}
\def\getVLength(#1,#2)(#3,#4){%
  \directlua{tex.print(math.sqrt((#3-#1)^2+(#4-#2)^2))}}

\begin{document}
\getVLength(0,0)(4,2)  
\end{document}

run with lualatex