有更新,见下文
我正在设计 mosfet 符号,应该可以翻转。翻转的关键在于与定位库应该保持不变,例如,将镜像节点放置在镜像节点的右侧应该与放置在“正常”节点右侧的“正常”节点保持相同的距离。为此,我考虑使用.is if
处理程序并相应地替换锚点和背景路径。在使用原始代码尝试此操作时,我可以更改路径,但不能更改锚点。在为此处的问题创建 MWE 时,我做错了什么,所以现在 .is if 处理程序什么也不做。现在我很困惑。有人能给我指出正确的方向吗?
注意:我知道xscale=-1
镜像节点的解决方案,但这需要手动覆盖节点的相关锚点。我想避免这种情况,并且我愿意接受各种(优雅/易于使用的)解决方案。
以下是 MWE:
\documentclass[parskip=half]{scrartcl}
\pagestyle{empty}
\usepackage{tikz}
\usetikzlibrary{positioning}
\newif\ifmirrorshape
\pgfkeys{
/tikz/mirror/.is if=mirrorshape
}
\pgfdeclareshape{testshape}
{
\ifmirrorshape
\savedanchor{\center}{
\pgfpointorigin
}
\savedanchor{\left}{
\pgfpointadd{\pgfpointorigin}{\pgfpoint{0.5cm}{0cm}}
}
\savedanchor{\upperright}{
\pgfpointadd{\pgfpointorigin}{\pgfpoint{-0.5cm}{0.5cm}}
}
\savedanchor{\lowerright}{
\pgfpointadd{\pgfpointorigin}{\pgfpoint{-0.5cm}{-0.5cm}}
}
\anchor{center}{\center}
\anchor{north}{\pgfpointadd{\pgfpointorigin}{\pgfpoint{0cm}{0.25cm}}}
\anchor{south}{\pgfpointadd{\pgfpointorigin}{\pgfpoint{0cm}{-0.25cm}}}
\anchor{west}{\left}
\anchor{east}{\pgfpointadd{\pgfpointorigin}{\pgfpoint{-0.5cm}{0cm}}}
\else
\savedanchor{\center}{
\pgfpointorigin
}
\savedanchor{\left}{
\pgfpointadd{\pgfpointorigin}{\pgfpoint{-0.5cm}{0cm}}
}
\savedanchor{\upperright}{
\pgfpointadd{\pgfpointorigin}{\pgfpoint{0.5cm}{0.5cm}}
}
\savedanchor{\lowerright}{
\pgfpointadd{\pgfpointorigin}{\pgfpoint{0.5cm}{-0.5cm}}
}
\anchor{center}{\center}
\anchor{north}{\pgfpointadd{\pgfpointorigin}{\pgfpoint{0cm}{0.25cm}}}
\anchor{south}{\pgfpointadd{\pgfpointorigin}{\pgfpoint{0cm}{-0.25cm}}}
\anchor{west}{\left}
\anchor{east}{\pgfpointadd{\pgfpointorigin}{\pgfpoint{0.5cm}{0cm}}}
\fi
\backgroundpath{
\pgfpathmoveto{\left}
\pgfpathlineto{\upperright}
\pgfpathlineto{\lowerright}
\pgfpathclose
\pgfusepath{stroke}
}
}
\begin{document}
\begin{tikzpicture}[every node/.style={align=center}]
\node[testshape] (s1) at(0, 0) { };
\node[red, testshape, right=of s1, mirror] { };
\end{tikzpicture}
\end{document}
更新:
我对 @cfr 的回答进行了进一步的了解,但仍然不太正确。我需要的是根据“镜像状态”放置锚点(外部可见,我不关心内部)。
以下是一个例子:
\newif\ifmirrorshape
\pgfkeys{
/tikz/mirror/.is if=mirrorshape
}
\pgfdeclareshape{testshape}
{
\savedanchor{\center}{
\pgfpointorigin
}
\savedanchor{\left}{
\pgfpointadd{\pgfpointorigin}{\pgfpoint{-0.5cm}{0cm}}
}
\savedanchor{\right}{
\pgfpointadd{\pgfpointorigin}{\pgfpoint{0.5cm}{0cm}}
}
\savedanchor{\upperright}{
\pgfpointadd{\pgfpointorigin}{\pgfpoint{0.5cm}{0.5cm}}
}
\savedanchor{\lowerright}{
\pgfpointadd{\pgfpointorigin}{\pgfpoint{0.5cm}{-0.5cm}}
}
\savedanchor{\upperleft}{
\pgfpointadd{\pgfpointorigin}{\pgfpoint{-0.5cm}{0.5cm}}
}
\savedanchor{\lowerleft}{
\pgfpointadd{\pgfpointorigin}{\pgfpoint{-0.5cm}{-0.5cm}}
}
\anchor{center}{\center}
\anchor{north}{\pgfpointadd{\pgfpointorigin}{\pgfpoint{0cm}{0.25cm}}}
\anchor{south}{\pgfpointadd{\pgfpointorigin}{\pgfpoint{0cm}{-0.25cm}}}
\anchor{right}{\right}
\anchor{left}{\left}
\anchor{west}{\left}
\anchor{east}{\right}
\backgroundpath{
\ifmosfetmirror
\pgfpathmoveto{\right}
\pgfpathlineto{\upperleft}
\pgfpathlineto{\lowerleft}
\else
\pgfpathmoveto{\left}
\pgfpathlineto{\upperright}
\pgfpathlineto{\lowerright}
\fi
\pgfpathclose
\pgfusepath{stroke}
}
}
测试用例:
\begin{tikzpicture}[every node/.style={align=center}]
\node[testshape] (s1) { };
\node[testshape, mirror, right=of s1] (s2) { };
\end{tikzpicture}
我尝试以不同的方式放置 \savedanchor(不起作用):
\ifmirrorshape
\savedanchor...
\else
\savedanchor...
\fi
我试图在 \deferredanchor 中更改锚点(不起作用):
\deferredanchor{...}{\ifmirrorshape ... \else ... \fi}
我不知道如何解决这个问题,如能得到任何帮助我将不胜感激。
答案1
我认为您正在尝试使用在使用时不合法的方法。特别是,您需要区分定义形状时执行的代码和调用形状时执行的代码。
请注意,为了使定位按预期工作,我认为您希望将west
和east
锚点放置在西边和东边,而不是在节点镜像时翻转。
保存镜像敏感锚点的关键在于仔细考虑何时执行哪些代码。
\documentclass[border=10pt,multi,tikz]{standalone}
\usetikzlibrary{positioning}
\newif\ifmirrorshape
\tikzset{
mirror me/.is if=mirrorshape
}
\makeatletter
\newdimen\pgf@testxb
\newdimen\pgf@testxa
\pgfdeclareshape{testshape}
{
\savedanchor{\center}{%
\pgfpointorigin
}%
\anchor{center}{\center}
\anchor{north}{%
\pgfpointorigin
\pgf@x=0pt
\pgf@y=2.5mm
}%
\anchor{south}{%
\pgfpointorigin
\pgf@x=0pt
\pgf@y=-2.5mm
}%
\anchor{west}{%
\pgfpointorigin
\pgf@x=-5mm
\pgf@y=0pt
}%
\anchor{east}{%
\pgfpointorigin
\pgf@x=5mm
\pgf@y=0pt
}%
\savedanchor{\apex}{%
\pgfpointorigin
\ifmirrorshape
\pgf@x=5mm
\else
\pgf@x=-5mm
\fi
\pgf@y=0pt
}%
\savedanchor{\base}{%
\pgfpointorigin
\ifmirrorshape
\pgf@x=-5mm
\else
\pgf@x=5mm
\fi
\pgf@y=0pt
}%
\savedanchor{\upbase}{%
\pgfpointorigin
\ifmirrorshape
\pgf@x=-5mm
\else
\pgf@x=5mm
\fi
\pgf@y=5mm
}%
\savedanchor{\downbase}{%
\pgfpointorigin
\ifmirrorshape
\pgf@x=-5mm
\else
\pgf@x=5mm
\fi
\pgf@y=-5mm
}%
\deferredanchor{apex}{%
\apex
}%
\deferredanchor{base}{%
\base
}%
\deferredanchor{upper base}{%
\upbase
}%
\deferredanchor{lower base}{%
\downbase
}%
\backgroundpath{%
\ifmirrorshape
\pgf@testxa=5mm
\pgf@testxb=-5mm
\else
\pgf@testxa=-5mm
\pgf@testxb=5mm
\fi
\pgfpathmoveto{\pgfpoint{\pgf@testxa}{0pt}}%
\pgfpathlineto{\pgfpoint{\pgf@testxb}{5mm}}%
\pgfpathlineto{\pgfpoint{\pgf@testxb}{-5mm}}%
\pgfpathclose
}%
}
\makeatother
\begin{document}
\begin{tikzpicture}[every node/.style={align=center}]
\node [testshape, draw, minimum size=15mm] (s1) at (0,0) { };
\node (s2) [red, mirror me, testshape, draw, right=15mm of s1, minimum size=15mm] { };
\foreach \i/\k/\l in {center/below/gray,north/above/gray,south/below/gray,west/left/gray,east/right/gray,apex/above/blue!50!cyan,base/above/magenta,upper base/above/orange,lower base/below/green!50!black}
\foreach \j in {1,2}
\path [fill, fill opacity=.5, text opacity=1, draw opacity=1, \l] (s\j.\i) circle (1pt) node [\k, font=\tiny, \l] {\i};
\end{tikzpicture}
\end{document}
\backgroundpath
不应该绘制或填充任何东西。如果总是要绘制路径,则\beforebackgroundpath
应该使用。虽然手册没有说明原因,但这不可能是灵活性的问题:绘制路径\beforebackgroundpath
与绘制路径一样不灵活\backgroundpath
。我怀疑有些情况下绘制路径\backgroundpath
会做错事,因为绘制是在节点构造的不同点完成的。因此,除非你的 TikZ 代码从不将某些技术与你的自定义节点混合使用,否则描边这条路径可能会在某些时候导致令人讨厌的意外。这些技术不需要非常奇特。如果将节点作为的一部分进行描边,则以下任何一种方法都无法正常工作\backgroundpath
:
fill=yellow
drop shadow
(当然,无论如何我都不想在没有填充的情况下使用它)
当然,更多奇特的事物也可能会失败。