前言
我使用了很多由tikz-timing
和pgfplots
包提供的环境。我经常为图片中的某些元素指定尺寸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}
解决方案渲染
对示例的评论
测试图片包括:
- 具有命名顶点(A、B、C、D、E 和 F)的多边形,
- 一些带标签的节点(仅用于将顶点名称放在图片上),
- 三个预定义引导点(G1、G2 和 G3),
- 五条维度线实例展示不同的用例,
- 五个实心圆(每个多边形顶点一个)。
彩色尺寸线用于显示投影线重叠。选择配置标记以消除可能重叠的投影线。尺寸线坐标自动换行以标记内容和配置标记案例。投影线坐标也自动换行以提供小延伸,该延伸基于引导点相对于线起点的位置。线延伸和标签偏移与箭头手半径成比例。
对实施情况的评论
要做的第一件基本事情是构建配置令牌拆分宏。请参阅源代码,\@hdimlinetokensplit
宏。建议的宏使用plain-TeX
基于决策来依赖无包。它接收几个字符,测试字符数是否为五个,并尝试分解令牌。希望有人提供更方便的解决方案(请参阅 FIXME)。这种模式匹配主要基于这个答案。
此链接可以提供更好的决策,但我还没有经验来实现这样的事情。标记分析是通过基于这些链接的众多条件结构完成的:
作为这里说(评论也很有趣),PGF/TiKZ
上下文应该被环境中断pgfinterruptpicture
以保存框中的标签。不幸的是,我无法猜测如何保存当前PGF/TikZ
字体属性(颜色)并稍后将它们恢复到带有标签内容的排版框(请参阅源代码,TODO 部分)。可能是之一 这些 链接可以帮忙。pgfkey
我应该保存哪一个?