2

Preamble

I use a lot of environments provided by tikz-timing and pgfplots packages. Often i specify dimensions for some elements in tikz picture. For example, time delay between rises of two pulses at tikztimingtable environment.

So i thought that one can define i macro which can draw in tikz environment a parameterized dimension line with label, optional projection lines and custom arrows. I have no idea how this could be implemented. And i hope someone help me to implement my macro.

Main matter

Macro should be used in tikz environment to draw dimension line defined by three points:

  • two points of nodes between which dimension should be shown;
  • one point of node on a guide along which dimension line should be drawn.

Marco usage should be:

\hdimline[7.2pt]{A}{B}{G}{d>.|<}{Label}

Where:

  • A is tikz coordinates of node named "A",
  • B is for node "B",
  • G is for node "G" which is on guide,
  • "d>.|<" is design token,
  • Label is label box contents,
  • optional parameter is size of custom arrows.

Design token description

The design token should be similar to graphics of dimension line. Special characters are:

  • "|" or "." mean to draw or not to draw projection line respectively; for example, ".|" is for right projection line only and "||" is for both;
  • ">" and "<" mean to draw right-pointing arrow and left-pointing arrow respectively;
  • "d" is for label placement.

I try to illustrate my idea with examples (see the applied code and picture).

The code

\documentclass[14pt,oneside]{extarticle}
\usepackage[utf8]{inputenc}
\usepackage[T2A]{fontenc}
\usepackage[english]{babel}
\usepackage{color}
\usepackage{amsmath}
\usepackage{tikz}



\begin{document}

% Default arrow segment length is 7.2pt
\newlength{\dimarrowr}
\setlength{\dimarrowr}{7.2pt}

 \begin{figure}[ht!]
  \centering
  \begin{tikzpicture}[line cap=round,line join=round]
   % The picture with two given points
   \fill[gray] (-2,-2)  coordinate(A)
            -- (2,2)    coordinate(B)
                coordinate[midway](C)
            -- (2,-2)
            -- cycle;

   % The points that define each guide
   % on which dimension line should be drawn
   \coordinate (G1) at (0,4);
   \coordinate (G2) at (0,3);

   % Point marks
   \fill (A) circle[radius=2pt];
   \fill (B) circle[radius=2pt];
   \fill (C) circle[radius=2pt];


   % Horizontal dimension;
   % should be used as \hdimline{A}{B}{G1}{|<d>|}[7.2pt]

   % left projection line specified by left "|"
   \draw (A) -- (A |- G1) -- ++(0,{\dimarrowr/3});
   % right projection line specified by right "|"
   \draw (B) -- (B |- G1) -- ++(0,{\dimarrowr/3});

   % left pointing arrow specified by "<"
   \draw (A |- G1) ++(10:{\dimarrowr})
                -- ++(190:{\dimarrowr})
                -- ++(-10:{\dimarrowr}) coordinate (lparrow_right_point);
   % right pointing arrow specified by ">"
   \draw (B |- G1) ++(170:{\dimarrowr})
                -- ++(-10:{\dimarrowr})
                -- ++(190:{\dimarrowr}) coordinate (rparrow_left_point);
   % dimension line with label
   \draw (A |- G1) -- (lparrow_right_point |- G1)
                   -- (rparrow_left_point |- G1)
                       node[midway,above,black] {$l_\text{H1}$}
                   -- (B |- G1);


   % Horizontal dimension;
   % should be used as \hdimline{A}{B}{G1}{.<d>|}[7.2pt]

   % left projection line eliminated by left "."
   % right projection line specified by right "|"
   \draw (C) -- (C |- G2) -- ++(0,{\dimarrowr/3});

   % left pointing arrow specified by "<"
   \draw (A |- G2) ++(10:{\dimarrowr})
                -- ++(190:{\dimarrowr})
                -- ++(-10:{\dimarrowr}) coordinate (lparrow_right_point);
   % right pointing arrow specified by ">"
   \draw (C |- G2) ++(170:{\dimarrowr})
                -- ++(-10:{\dimarrowr})
                -- ++(190:{\dimarrowr}) coordinate (rparrow_left_point);
   % dimension line with label
   \draw (A |- G2) -- (lparrow_right_point |- G2)
                   -- (rparrow_left_point |- G2)
                       node[midway,above,black] {$l_\text{H2}$}
                   -- (C |- G2);
  \end{tikzpicture}
  \caption{Triangle with dimensions (labels inside)}
 \end{figure}



 \begin{figure}[ht!]
  \centering
  \begin{tikzpicture}[line cap=round,line join=round]
   % The picture with two given points
   \fill[gray] (-0.5,-0.5)  coordinate(A)
            -- (0.5,0.5)    coordinate(B)
                coordinate[midway](C)
            -- (0.5,-0.5)
            -- cycle;

   % The points that define each guide
   % on which dimension line should be drawn
   \coordinate (G1) at (0,-1.5);
   \coordinate (G2) at (0,-1);

   % Point marks
   \fill (A) circle[radius=2pt];
   \fill (B) circle[radius=2pt];
   \fill (C) circle[radius=2pt];


   % Horizontal dimension;
   % should be used as \hdimline{A}{B}{G1}{|<>|d}[7.2pt]

   % left projection line specified by left "|";
   \draw (A) -- (A |- G1) -- ++(0,-{\dimarrowr/3});
   % right projection line specified by right "|"
   \draw (B) -- (B |- G1) -- ++(0,-{\dimarrowr/3});

   % left pointing arrow specified by "<"
   \draw (A |- G1) ++(10:{\dimarrowr})
                -- ++(190:{\dimarrowr})
                -- ++(-10:{\dimarrowr}) coordinate (lparrow_right_point);
   % right pointing arrow specified by ">"
   \draw (B |- G1) ++(170:{\dimarrowr})
                -- ++(-10:{\dimarrowr})
                -- ++(190:{\dimarrowr}) coordinate (rparrow_left_point);
   % dimension line with label;
   % currently segment length is 4ex,
   % but should be longer than contents by 1ex
   \draw (A |- G1) -- (B |- G1)
                 -- ++(4ex,0)
                       node[midway,above,black] {$l_\text{H1}$};


   % Horizontal dimension;
   % should be used as \hdimline{A}{B}{G1}{d>.|<}[7.2pt]

   % left projection line eliminated by left "."
   % right projection line specified by right "|"
   \draw (C) -- (C |- G2) -- ++(0,-{\dimarrowr/3});

   % right pointing arrow specified by ">"
   \draw (A |- G2) ++(170:{\dimarrowr})
                -- ++(-10:{\dimarrowr})
                -- ++(190:{\dimarrowr}) coordinate (rparrow_left_point);
   % left pointing arrow specified by "<"
   \draw (C |- G2) ++(10:{\dimarrowr})
                -- ++(190:{\dimarrowr})
                -- ++(-10:{\dimarrowr}) coordinate (lparrow_right_point);
   % dimension line with label
   \draw (rparrow_left_point |- G2)
       ++(-4ex,0)
      -- (rparrow_left_point |- G2)
          node[midway,above,black] {$l_\text{H2}$}
      -- (lparrow_right_point |- G2)
    -- ++({\dimarrowr/2},0);
  \end{tikzpicture}
  \caption{Triangle with dimensions (labels outside)}
 \end{figure}
\end{document}

Rendering Three-point defined dimension line examples

PS: Grammar check is welcome.

  • Maybe this answer gives you what you need. – user194703 Apr 12 at 21:04
  • Thank you! tikz-dimline is interesting package, but it won't solve my problem. tikz-dimline provide no variant with outside labels (see fig. 2 in my question). Moreover original arrowheads provided by package have incorrect graphics to me (the head of arrow should tap projection line). Maybe i should break my question in a few simple questions. – akj Apr 12 at 21:44
  • The answer avoids tikz-dimline. – user194703 Apr 12 at 23:42
  • I am sorry. I looked through the answer and i can tell that referenced solution does not fit my request. I will try to update my question when i get a partial solution. May be answer pointed by you will be helpful. – akj Apr 13 at 19:56
1

My own solution is based on plain-TeX macros which are used for conditional execution of TikZ instructions.

Solution MWE

\documentclass[14pt,oneside]{extarticle}
\usepackage[utf8]{inputenc}
\usepackage[T2A]{fontenc}
\usepackage[english]{babel}
\usepackage{color}
\usepackage{amsmath}
\usepackage{tikz}



% This macro is for error message output
\newcommand{\hdimlineerror}[1]{%
 \GenericError{               }%
              {LaTeX Error: #1}%
              {See usage of hdimline command}%
              {Your command was ignored}%
}



% Horizontal dimension line drawing macro
% Usage: \hdimline[7.2pt]{A}{B}{G}{d>.|<}{Label}
%           where 7.2pt is default arrow radius,
%                     A is left node,
%                     B is right node,
%                     G is guide node,
%                 d>.|< is configuration token and
%                 Label is label box contents
% Configuration token defines positions of elements:
%                     d is for dimension label,
%                     < is for left pointing arrow,
%                     > is for right pointing arrow,
%                     | is for left or right projection line,
%                     . is for absent projection line
\makeatletter
\newcommand{\hdimline}[6][7.2pt]{%
 % Definition for horizontal dimension line elements positions
 \ifcsname c@hdimlineposd\endcsname
 \else
  \newcount\hdimlineposd
  \newcount\hdimlineposlpa
  \newcount\hdimlineposrpa
  \newcount\hdimlineposll
  \newcount\hdimlineposrl
 \fi
 \hdimlineposd=0
 \hdimlineposlpa=0
 \hdimlineposrpa=0
 \hdimlineposll=0
 \hdimlineposrl=0

 % Get elements positions
 % FIXME: Ugly pattern matching
 \@hdimlinetokensplit#5\empty\empty\empty\empty\empty\empty\@nil

 % Save label to box
 \ifdefined\hdimlinebox
 \else
  \newsavebox{\hdimlinebox}
 \fi
 \begin{pgfinterruptpicture}%
  \begin{lrbox}{0\null\global\setbox\hdimlinebox}%
   % TODO: I don't know how to restore TikZ node label color
   \tikz@textfont%
   \color{black}\strut%
   #6%
  \end{lrbox}%
 \end{pgfinterruptpicture}

 % Draw left projection line
 \path (#2); \pgfgetlastxy{\hdimlinelastx}{\hdimlineprevy}
 \path (#4); \pgfgetlastxy{\hdimlinelastx}{\hdimlinelasty}
 \ifdim \hdimlineprevy<\hdimlinelasty
  \def\hdimlineextendmul{1}
 \else
  \def\hdimlineextendmul{-1}
 \fi
 \ifnum\hdimlineposll>0
  \draw (#2) -- (#2 |-, \hdimlinelasty+#1/3*\hdimlineextendmul);
 \fi

 % Draw right projection line
 \path (#3); \pgfgetlastxy{\hdimlinelastx}{\hdimlineprevy}
 \path (#4); \pgfgetlastxy{\hdimlinelastx}{\hdimlinelasty}
 \ifdim \hdimlineprevy<\hdimlinelasty
  \def\hdimlineextendmul{1}
 \else
  \def\hdimlineextendmul{-1}
 \fi
 \ifnum\hdimlineposrl>0
  \draw (#3) -- (#3 |-, \hdimlinelasty+#1/3*\hdimlineextendmul);
 \fi

 % Draw arrows
 \ifnum\hdimlineposlpa<\hdimlineposrpa
  % left pointing arrow specified by "<"
  \draw (#2 |- #4) ++(10:{#1})
                -- ++(190:{#1})
                -- ++(-10:{#1}) coordinate (lparrow_right_point);
  % right pointing arrow specified by ">"
  \draw (#3 |- #4) ++(170:{#1})
                -- ++(-10:{#1})
                -- ++(190:{#1}) coordinate (rparrow_left_point);
  \def\hdimlineoffsetmul{0}
 \else
  % right pointing arrow specified by ">"
  \draw (#2 |- #4) ++(170:{#1})
                -- ++(-10:{#1})
                -- ++(190:{#1}) coordinate (rparrow_left_point);
  % left pointing arrow specified by "<"
  \draw (#3 |- #4) ++(10:{#1})
                -- ++(190:{#1})
                -- ++(-10:{#1}) coordinate (lparrow_right_point);
  \def\hdimlineoffsetmul{1}
 \fi

 % Draw dimension line
 \ifnum\hdimlineposd=1
  \ifnum\hdimlineoffsetmul=0
   \draw (#2 |- #4)
       ++(-\wd\hdimlinebox -#1,0)
    -- ++(\wd\hdimlinebox +#1/2,0)
          node[midway,above] {\usebox\hdimlinebox}
      -- (#2 |- #4)
      -- (#3 |- #4);
  \else
   \draw (rparrow_left_point |- #4)
       ++(-\wd\hdimlinebox -#1/2,0)
      -- (rparrow_left_point |- #4)
          node[midway,above] {\usebox\hdimlinebox}
      -- (lparrow_right_point |- #4)
    -- ++(#1/2,0);
  \fi
 \fi
 \ifnum\hdimlineposd=3
  \ifnum\hdimlineoffsetmul=0
   \draw (#2 |- #4)
      -- (#3 |- #4)
          node[midway,above] {\usebox\hdimlinebox};
  \else
   \draw (rparrow_left_point |- #4)
       ++(-#1/2,0)
      -- (rparrow_left_point |- #4)
      -- (lparrow_right_point |- #4)
          node[midway,above] {\usebox\hdimlinebox}
    -- ++(#1/2,0);
  \fi
 \fi
 \ifnum\hdimlineposd=5
  \ifnum\hdimlineoffsetmul=0
   \draw (#2 |- #4)
      -- (#3 |- #4)
    -- ++(#1/2,0)
    -- ++(\wd\hdimlinebox +#1/2,0)
          node[midway,above] {\usebox\hdimlinebox};
  \else
   \draw (rparrow_left_point |- #4)
       ++(-#1/2*\hdimlineoffsetmul,0)
      -- (rparrow_left_point |- #4)
      -- (lparrow_right_point |- #4)
    -- ++(\wd\hdimlinebox +#1/2,0)
          node[midway,above] {\usebox\hdimlinebox};
  \fi
 \fi
}
\makeatother


\makeatletter
% Configuration token split macro
% FIXME: Ugly pattern matching
\def\@hdimlinetokensplit#1#2#3#4#5#6\@nil{%
 % Check token length
 \if #5\empty
  \hdimlineerror{Token should be 5 characters long}
 \else
  \if #6\empty
  \else
   \hdimlineerror{Token should be 5 characters long}
  \fi
 \fi

 % Check if "d" specified
 \ifcsname c@hdimlinespecified\endcsname
 \else
  \newcount\hdimlinespecified
 \fi
 \hdimlinespecified=0
 \if #1d \advance \hdimlinespecified by 1 \hdimlineposd=1 \fi
 \if #2d \advance \hdimlinespecified by 1 \fi
 \if #3d \advance \hdimlinespecified by 1 \hdimlineposd=3 \fi
 \if #4d \advance \hdimlinespecified by 1 \fi
 \if #5d \advance \hdimlinespecified by 1 \hdimlineposd=5 \fi
 \ifnum\hdimlinespecified=1
  \ifnum \hdimlineposd=0
   \hdimlineerror{No label specified in configuration token}
  \fi
 \else
  \hdimlineerror{Incorrect configuration token}
 \fi

 % Check if "<" specified
 \hdimlinespecified=0
 \if #1< \advance \hdimlinespecified by 1 \fi
 \if #2< \advance \hdimlinespecified by 1 \hdimlineposlpa=2 \fi
 \if #3< \advance \hdimlinespecified by 1 \hdimlineposlpa=3 \fi
 \if #4< \advance \hdimlinespecified by 1 \hdimlineposlpa=4 \fi
 \if #5< \advance \hdimlinespecified by 1 \hdimlineposlpa=5 \fi
 \ifnum\hdimlinespecified=1
  \ifnum \hdimlineposlpa=0
   \hdimlineerror{Incorrect configuration token}
  \fi
 \else
  \hdimlineerror{Incorrect configuration token}
 \fi

 % Check if ">" specified
 \hdimlinespecified=0
 \if #1> \advance \hdimlinespecified by 1 \hdimlineposrpa=1 \fi
 \if #2> \advance \hdimlinespecified by 1 \hdimlineposrpa=2 \fi
 \if #3> \advance \hdimlinespecified by 1 \hdimlineposrpa=3 \fi
 \if #4> \advance \hdimlinespecified by 1 \hdimlineposrpa=4 \fi
 \if #5> \advance \hdimlinespecified by 1 \fi
 \ifnum\hdimlinespecified=1
  \ifnum \hdimlineposrpa=0
   \hdimlineerror{Incorrect configuration token}
  \fi
 \else
  \hdimlineerror{Incorrect configuration token}
 \fi

 % Check if "|" or "." specified
 \hdimlinespecified=0
 \ifnum\hdimlineposd=1
  \if #2| \advance \hdimlinespecified by 1 \hdimlineposll=2 \fi
  \if #2. \advance \hdimlinespecified by 1 \fi
  \if #3| \advance \hdimlinespecified by 1 \hdimlineposll=3 \fi
  \if #3. \advance \hdimlinespecified by 1 \fi
  \if #4| \advance \hdimlinespecified by 1 \hdimlineposrl=4 \fi
  \if #4. \advance \hdimlinespecified by 1 \fi
  \if #5| \advance \hdimlinespecified by 1 \hdimlineposrl=5 \fi
  \if #5. \advance \hdimlinespecified by 1 \fi
 \fi
 \ifnum\hdimlineposd=3
  \if #1| \advance \hdimlinespecified by 1 \hdimlineposll=1 \fi
  \if #1. \advance \hdimlinespecified by 1 \fi
  \if #2| \advance \hdimlinespecified by 1 \hdimlineposll=2 \fi
  \if #2. \advance \hdimlinespecified by 1 \fi
  \if #4| \advance \hdimlinespecified by 1 \hdimlineposrl=4 \fi
  \if #4. \advance \hdimlinespecified by 1 \fi
  \if #5| \advance \hdimlinespecified by 1 \hdimlineposrl=5 \fi
  \if #5. \advance \hdimlinespecified by 1 \fi
 \fi
 \ifnum\hdimlineposd=5
  \if #1| \advance \hdimlinespecified by 1 \hdimlineposll=1 \fi
  \if #1. \advance \hdimlinespecified by 1 \fi
  \if #2| \advance \hdimlinespecified by 1 \hdimlineposll=2 \fi
  \if #2. \advance \hdimlinespecified by 1 \fi
  \if #3| \advance \hdimlinespecified by 1 \hdimlineposrl=3 \fi
  \if #3. \advance \hdimlinespecified by 1 \fi
  \if #4| \advance \hdimlinespecified by 1 \hdimlineposrl=4 \fi
  \if #4. \advance \hdimlinespecified by 1 \fi
 \fi
 \ifnum\hdimlinespecified=2
 \else
  \hdimlineerror{Incorrect configuration token}
 \fi
}
\makeatother



\begin{document}
 \begin{figure}[ht!]
  \centering
  \begin{tikzpicture}[line cap=round,line join=round]
   \begin{scope}[gray,semithick,%
                 line cap=round, line join=round,%
                 every node/.append style=black,%
                 font=\rmfamily\scriptsize]
    % The picture with few given points
    \fill[lightgray] (-1,-0.5)   coordinate (A)
                  -- (1,0.5)     coordinate (B)
                  -- (3,0.5)     coordinate (C)
                  -- (3,-1)      coordinate (D)
                  -- (2.5,-1.5)  coordinate (E)
                  -- (2,-0.5)    coordinate (F)
                  -- cycle;

    % Node names
    \node[shift=(135:8pt)] at (A) {$A$};
    \node[shift=( 45:8pt)] at (B) {$B$};
    \node[shift=( 45:8pt)] at (C) {$C$};
    \node[shift=( 45:8pt)] at (D) {$D$};
    \node[shift=(330:8pt)] at (E) {$E$};
    \node[shift=(225:8pt)] at (F) {$F$};

    % The points that define each guide
    % on which dimension line should be drawn
    \coordinate (G1) at (0,1);
    \coordinate (G2) at (0,-2);
    \coordinate (G3) at (0,-2.5);

    % Dimensions
    \hdimline[14pt]{A}{C}{G1 |-, 2}{|<d>|}{$l_\text{AC}$}
    \begin{scope}[red]
     \hdimline{A}{B}{G1}{.<d>|}{$l_\text{AB}$}
    \end{scope}
    \hdimline{F}{D}{G3}{|<>|d}{$l_\text{FD}$}
    \begin{scope}[blue]
     \hdimline{A}{F}{0,-2.25}{d|<>.}{$l_\text{AF}$}
    \end{scope}
    \begin{scope}[green]
     \hdimline{F}{E}{G2}{d>.|<}{$l_\text{FE}$}
    \end{scope}

    % Point marks
    \foreach \n in {A,...,F} 
     \fill[black] (\n) circle[radius=1.5pt];

   \end{scope}
  \end{tikzpicture}
  \caption{Polygon with dimensions}
 \end{figure}
\end{document}

Solution rendering

\hdimline macro result

Comments to example

Test picture consists of:

  • polygon with named vertices (A, B, C, D, E and F),
  • few nodes with labels (just to put vertex names on picture),
  • three predefined guide points (G1, G2 and G3),
  • five dimension line instances showing different use cases,
  • five filled circles (one for each polygon vertex).

Colored dimension lines are used to show projection line overlapping. Configuration tokens selected to eliminate projection lines that can overlap. Dimension line coordinates automatically wrapped to label content and configuration token cases. Projection line coordinates also automatically wrapped to provide small extension which is based on position of guide point relative to line start point. Line extensions and label offsets are proportional to arrow hand radius.

Comments to implementation

First basic thing to be done was to construct configuration token split macro. See source, \@hdimlinetokensplit macro. Proposed macro uses plain-TeX based deсision to rely on no package. It receives few characters, tests if number of characters is five, and tries to decompose token. Hope someone provide more convenient solution (see FIXME). This pattern matching based mostly on this answer. This link can provide better decision, but i am still inexperienced to implement such things. Token analysis is done by numerous conditional structures based on these links:

As it said here (comments are interesting too), PGF/TiKZ context should be interrupted by pgfinterruptpicture environment to save label in box. Unfortunately i can't guess how to save current PGF/TikZ font properties (color) and restore them later to typeset box with label contents (see source, TODO section). May be one of these links can help. Which pgfkey should i save?

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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