TikZ 图片的尺寸绘图宏

TikZ 图片的尺寸绘图宏

前言

我使用了很多由tikz-timingpgfplots包提供的环境。我经常为图片中的某些元素指定尺寸tikz。例如,tikztimingtable环境中两个脉冲上升之间的时间延迟。

所以我认为可以定义一个宏,它可以在tikz环境中绘制带有标签、可选投影线和自定义箭头的参数化尺寸线。我不知道如何实现这一点。我希望有人能帮助我实现我的宏。

主要事项

环境中需要使用宏tikz来绘制由三个点定义的尺寸线:

  • 应显示其间维度的两个节点点;
  • 引导线上的一个节点,应沿着该点绘制尺寸线。

宏用法应为:

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

在哪里:

  • A 是tikz名为“A”的节点的坐标,
  • B 代表节点“B”,
  • G 代表位于导向上的节点“G”,
  • “d>.|<” 是设计标记,
  • 标签是标签盒内容,
  • 可选参数是自定义箭头的大小。

设计代币描述

设计标记应与尺寸线图形相似。特殊字符为:

  • “|”或“.”分别表示画或不画投影线;如“.|”表示只画右投影线,“||”表示右投影线和左投影线都画;
  • “>”和“<”分别表示画向右箭头和向左箭头;
  • “d”代表标签放置。

我尝试通过例子来说明我的想法(参见应用的代码和图片)。

代码

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

渲染 三点定义尺寸线示例

PS:欢迎检查语法。

答案1

我自己的解决方案是基于plain-TeX用于有条件执行TikZ指令的宏。

解决方案 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}

解决方案渲染

\hdimline 宏结果

对示例的评论

测试图片包括:

  • 具有命名顶点(A、B、C、D、E 和 F)的多边形,
  • 一些带标签的节点(仅用于将顶点名称放在图片上),
  • 三个预定义引导点(G1、G2 和 G3),
  • 五条维度线实例展示不同的用例,
  • 五个实心圆(每个多边形顶点一个)。

彩色尺寸线用于显示投影线重叠。选择配置标记以消除可能重叠的投影线。尺寸线坐标自动换行以标记内容和配置标记案例。投影线坐标也自动换行以提供小延伸,该延伸基于引导点相对于线起点的位置。线延伸和标签偏移与箭头手半径成比例。

对实施情况的评论

要做的第一件基本事情是构建配置令牌拆分宏。请参阅源代码,\@hdimlinetokensplit宏。建议的宏使用plain-TeX基于决策来依赖无包。它接收几个字符,测试字符数是否为五个,并尝试分解令牌。希望有人提供更方便的解决方案(请参阅 FIXME)。这种模式匹配主要基于这个答案此链接可以提供更好的决策,但我还没有经验来实现这样的事情。标记分析是通过基于这些链接的众多条件结构完成的:

作为这里说(评论也很有趣),PGF/TiKZ上下文应该被环境中断pgfinterruptpicture以保存框中的标签。不幸的是,我无法猜测如何保存当前PGF/TikZ字体属性(颜色)并稍后将它们恢复到带有标签内容的排版框(请参阅源代码,TODO 部分)。可能是之一 这些 链接可以帮忙。pgfkey我应该保存哪一个?

相关内容