互斥的 TikZ .is 选择键

互斥的 TikZ .is 选择键

我的 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@roundtrue本质上我需要的是start/.is choiceend/.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}

相关内容