我的 TikZ 绘图包有一个命令,可以绘制“简单光束”,它基本上是两个任意点之间的矩形。以下代码是该包中的相关部分:
% arara: lualatex
\documentclass{article}
\usepackage{expl3}
\usepackage{xparse}
\usepackage{etoolbox}
\usepackage{tikz}
\usetikzlibrary{calc}
% Sets various configuration parameters
% \strandlibset[module]{options as pgfkeys}
\NewDocumentCommand{\strandlibset}{o m}{
\IfNoValueTF{#1}{
\pgfqkeys{/strandlib}{#2}
}
{
\pgfqkeys{/strandlib/#1}{#2}
}
}
\makeatletter
\newif\if@beam@start@round
\newif\if@beam@start@butt
\newif\if@beam@start@rect
\newif\if@beam@end@round
\newif\if@beam@end@butt
\newif\if@beam@end@rect
\pgfkeys{
/strandlib/beam/.is family,
/strandlib/beam,
thickness/.initial=1mm,
color/.initial=blue,
@style/.style={/tikz, draw=#1, fill=#1!50!white, thick},
start/.is choice,
start/butt/.is if=@beam@start@butt,
start/rect/.is if=@beam@start@rect,
start/round/.is if=@beam@start@round,
start/butt=false,
start/rect=true,
start/round=false,
start=rect,
end/.is choice,
end/butt/.is if=@beam@end@butt,
end/rect/.is if=@beam@end@rect,
end/round/.is if=@beam@end@round,
end/butt=false,
end/rect=true,
end/round=false,
end=rect,
}
% \simplebeam[*both rounded]{start}{end}[additional options]
\NewDocumentCommand{\simplebeam}{s m m o}{%
\begingroup
\IfValueT{#4}{
\strandlibset[beam]{#4}
}
\IfBooleanT{#1}{
\strandlibset[beam]{start=round, end=round}
}
\if@beam@start@butt
\coordinate (beamCentreA) at (#2);
\else
\coordinate (beamCentreA) at ($(#2)!\pgfkeysvalueof{/strandlib/beam/thickness}!180:(#3)$);
\fi
\if@beam@end@butt
\coordinate (beamCentreB) at (#3);
\else
\coordinate (beamCentreB) at ($ (#3)!\pgfkeysvalueof{/strandlib/beam/thickness}!180:(#2)$);
\fi
\coordinate (beamCornerA1) at ($ (beamCentreA)!\pgfkeysvalueof{/strandlib/beam/thickness}!90:(beamCentreB)$);
\coordinate (beamCornerA2) at ($ (beamCentreA)!\pgfkeysvalueof{/strandlib/beam/thickness}!-90:(beamCentreB)$);
\coordinate (beamCornerB1) at ($ (beamCentreB)!\pgfkeysvalueof{/strandlib/beam/thickness}!-90:(beamCentreA)$);
\coordinate (beamCornerB2) at ($ (beamCentreB)!\pgfkeysvalueof{/strandlib/beam/thickness}!90:(beamCentreA)$);
\if@beam@start@round
\if@beam@end@round
\filldraw[/strandlib/beam/@style=\pgfkeysvalueof{/strandlib/beam/color}, rounded corners=\pgfkeysvalueof{/strandlib/beam/thickness}] (beamCornerA1) -- (beamCornerA2) -- (beamCornerB2) -- (beamCornerB1) -- cycle;
\else
\filldraw[/strandlib/beam/@style=\pgfkeysvalueof{/strandlib/beam/color}, rounded corners=\pgfkeysvalueof{/strandlib/beam/thickness}] (beamCornerA1) -- (beamCornerA2) [sharp corners] -- (beamCornerB2) -- (beamCornerB1) [rounded corners=\pgfkeysvalueof{/strandlib/beam/thickness}] -- cycle;
\fi
\else
\if@beam@end@round
\filldraw[/strandlib/beam/@style=\pgfkeysvalueof{/strandlib/beam/color}] (beamCornerA1) -- (beamCornerA2) [rounded corners=\pgfkeysvalueof{/strandlib/beam/thickness}] -- (beamCornerB2) -- (beamCornerB1) [sharp corners] -- cycle;
\else
\filldraw[/strandlib/beam/@style=\pgfkeysvalueof{/strandlib/beam/color}] (beamCornerA1) -- (beamCornerA2) -- (beamCornerB2) -- (beamCornerB1) -- cycle;
\fi
\fi
\endgroup
}
\makeatother
\begin{document}
Variety of options: some round, some not.
\begin{center}
\begin{tikzpicture}
\strandlibset[beam]{color=red}
\simplebeam{0, 0}{4, 0}
\simplebeam{0, 2}{5, 2}[thickness=2mm, start=round, end=round]
\simplebeam{0, 3}{3, 6}[start=butt, end=round]
\end{tikzpicture}
\end{center}
All round!
\begin{center}
\begin{tikzpicture}
\strandlibset[beam]{color=black!50!white, start=round, end=round}
\simplebeam{0, 0}{4, 0}
\simplebeam{0, 2}{5, 2}[thickness=2mm, start=rect, end=rect]
\simplebeam{0, 5}{2, 3}[start=butt, end=round, thickness=1.5mm]
\end{tikzpicture}
\end{center}
\end{document}
我的问题是,如果我全局将梁末端设置为圆形(例如使用\strandlibset[beam]{start=round, end=round}
),那么我无法针对梁的单个实例(例如\simplebeam{A}{B}[end=butt]
)进行更改,因为是@beam@start@round
。true
本质上我需要的是start/.is choice
和end/.is choice
键来关闭其他布尔值:start=butt
应该意味着@start@round = false
和@start@rect = false
。实际发生的是,start=butt
只是设置@start@butt = true
但不会更改其他两个布尔标志。
我怎样才能解决这个问题?
一些能够达到相同结果的替代方法也会被接受,因为嵌套的 if 语句有些尴尬。
答案1
以下是我使用.code
处理程序来管理三个布尔值作为单选按钮(作为唯一选择)的建议:
\documentclass{article}
\usepackage{expl3}
\usepackage{xparse}
\usepackage{etoolbox}
\usepackage{tikz}
\usetikzlibrary{calc}
% Sets various configuration parameters
% \strandlibset[module]{options as pgfkeys}
\NewDocumentCommand{\strandlibset}{o m}{
\IfNoValueTF{#1}{
\pgfqkeys{/strandlib}{#2}
}
{
\pgfqkeys{/strandlib/#1}{#2}
}
}
\makeatletter
\newif\if@beam@start@round
\newif\if@beam@start@butt
\newif\if@beam@start@rect
\newif\if@beam@end@round
\newif\if@beam@end@butt
\newif\if@beam@end@rect
\pgfkeys{
/strandlib/beam/.is family,
/strandlib/beam,
thickness/.initial=1mm,
color/.initial=blue,
@style/.style={/tikz, draw=#1, fill=#1!50!white, thick},
start/.is choice,
start/butt/.code={
\@beam@start@butttrue
\@beam@start@rectfalse
\@beam@start@roundfalse
},
start/rect/.code={
\@beam@start@buttfalse
\@beam@start@recttrue
\@beam@start@roundfalse
},
start/round/.code={
\@beam@start@buttfalse
\@beam@start@rectfalse
\@beam@start@roundtrue
},
end/.is choice,
end/butt/.code={
\@beam@end@butttrue
\@beam@end@rectfalse
\@beam@end@roundfalse
},
end/rect/.code={
\@beam@end@buttfalse
\@beam@end@recttrue
\@beam@end@roundfalse
},
end/round/.code={
\@beam@end@buttfalse
\@beam@end@rectfalse
\@beam@end@roundtrue
},
% initial values
start=rect,
end=rect,
}
% \simplebeam[*both rounded]{start}{end}[additional options]
\NewDocumentCommand{\simplebeam}{s m m o}{%
\begingroup
\IfValueT{#4}{
\strandlibset[beam]{#4}
}
\IfBooleanT{#1}{
\strandlibset[beam]{start=round, end=round}
}
\if@beam@start@butt
\coordinate (beamCentreA) at (#2);
\else
\coordinate (beamCentreA) at ($(#2)!\pgfkeysvalueof{/strandlib/beam/thickness}!180:(#3)$);
\fi
\if@beam@end@butt
\coordinate (beamCentreB) at (#3);
\else
\coordinate (beamCentreB) at ($ (#3)!\pgfkeysvalueof{/strandlib/beam/thickness}!180:(#2)$);
\fi
\coordinate (beamCornerA1) at ($ (beamCentreA)!\pgfkeysvalueof{/strandlib/beam/thickness}!90:(beamCentreB)$);
\coordinate (beamCornerA2) at ($ (beamCentreA)!\pgfkeysvalueof{/strandlib/beam/thickness}!-90:(beamCentreB)$);
\coordinate (beamCornerB1) at ($ (beamCentreB)!\pgfkeysvalueof{/strandlib/beam/thickness}!-90:(beamCentreA)$);
\coordinate (beamCornerB2) at ($ (beamCentreB)!\pgfkeysvalueof{/strandlib/beam/thickness}!90:(beamCentreA)$);
\if@beam@start@round
\if@beam@end@round
\filldraw[/strandlib/beam/@style=\pgfkeysvalueof{/strandlib/beam/color}, rounded corners=\pgfkeysvalueof{/strandlib/beam/thickness}] (beamCornerA1) -- (beamCornerA2) -- (beamCornerB2) -- (beamCornerB1) -- cycle;
\else
\filldraw[/strandlib/beam/@style=\pgfkeysvalueof{/strandlib/beam/color}, rounded corners=\pgfkeysvalueof{/strandlib/beam/thickness}] (beamCornerA1) -- (beamCornerA2) [sharp corners] -- (beamCornerB2) -- (beamCornerB1) [rounded corners=\pgfkeysvalueof{/strandlib/beam/thickness}] -- cycle;
\fi
\else
\if@beam@end@round
\filldraw[/strandlib/beam/@style=\pgfkeysvalueof{/strandlib/beam/color}] (beamCornerA1) -- (beamCornerA2) [rounded corners=\pgfkeysvalueof{/strandlib/beam/thickness}] -- (beamCornerB2) -- (beamCornerB1) [sharp corners] -- cycle;
\else
\filldraw[/strandlib/beam/@style=\pgfkeysvalueof{/strandlib/beam/color}] (beamCornerA1) -- (beamCornerA2) -- (beamCornerB2) -- (beamCornerB1) -- cycle;
\fi
\fi
\endgroup
}
\makeatother
\begin{document}
Variety of options: some round, some not.
\begin{center}
\begin{tikzpicture}
\strandlibset[beam]{color=red}
\simplebeam{0, 0}{4, 0}
\simplebeam{0, 2}{5, 2}[thickness=2mm, start=round, end=round]
\simplebeam{0, 3}{3, 6}[start=butt, end=round]
\end{tikzpicture}
\end{center}
All round!
\begin{center}
\begin{tikzpicture}
\strandlibset[beam]{color=black!50!white, start=round, end=round}
\simplebeam{0, 0}{4, 0}
\simplebeam{0, 2}{5, 2}[thickness=2mm, start=rect, end=rect]
\simplebeam{0, 5}{2, 3}[start=butt, end=round, thickness=1.5mm]
\end{tikzpicture}
\end{center}
\end{document}