你可能不知道,下面的想法circuitikz
是使用to path
Ti 的功能钾Z.现在,我最近简化了功能,使其看起来或多或少运行良好,但我无法让它用于关闭路径。
我准备了一个非常简单的 MWE --- 我定义了一个组件形状,它是一个简单的红色段,并且复制了一条基本的路径构造。正如您在下面的示例中看到的,to[]
当使用元素关闭路径时,常规操作可以完美地(如预期的那样)工作cycle
,而当以类似的方式使用时,我的操作会失败(有时它会在烟花中失败)。
有办法解决吗?在\goforpath
宏中我真的不会改变内部 Ti钾Z 函数,例如建议的这里,出于可维护性的原因(我在包中有一个解决方法,但它是手动的......)。
\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\makeatletter
\pgfdeclareshape{sline}{
\anchor{center}{
\pgfpointorigin
}
\anchor{left}{\pgf@x=-0.2cm\pgf@y=0pt}
\anchor{right}{\pgf@x=0.2cm\pgf@y=0pt}
\backgroundpath{
\pgfscope
\pgfsetcolor{red}
\pgfpathmoveto{\pgfpoint{-0.2cm}{0pt}}
\pgfpathlineto{\pgfpoint{0.2cm}{0pt}}
\pgfusepath{draw}
\endpgfscope
}
}
\def\goforpaths{
coordinate(a) at (\tikztostart)
coordinate(b) at (\tikztotarget)
\pgfextra{
\pgfmathanglebetweenpoints{\pgfpointanchor{a}{center}}{\pgfpointanchor{b}{center}}
\edef\mydirection{\pgfmathresult}%Calculate direction(angle) of path
}
node[sline, rotate=\mydirection](N) at ($(\tikztostart)!0.5!(\tikztotarget)$){}
-- (\tikztostart) -- (N.left) (N.right) -- (\tikztotarget)
}
\tikzset{slineto/.style={/tikz/to path=\goforpaths}}
\makeatother
\begin{document}
\begin{tikzpicture}
% this does not work https://tex.stackexchange.com/questions/97602/tikz-path-labels-and-cycle#comment210067_97602
\draw[ultra thick] (0,0) to[slineto] (0,1) to[slineto] (1,1) to[slineto] (1,0) to[slineto] (0,0) -- cycle;
% nor this (worst):
\draw[ultra thick] (1.5,0) to[slineto] (1.5,1) to[slineto] (2.5,1) to[slineto] (2.5,0) to[slineto] cycle;
% this does work
\draw[ultra thick] (3,0) to[] (3,1) to[] (4,1) to[] (4,0) to[] cycle;
\end{tikzpicture}
\end{document}
更新:这太简单了。
@ZhiyuanLck 的回答对于这种情况是可以的,但请考虑一下,一般来说,节点非常复杂,不可能让它只是“叠加”路径。想想电阻器或发电机或任何东西。
\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\makeatletter
\pgfdeclareshape{szig}{
\anchor{center}{
\pgfpointorigin
}
\anchor{left}{\pgf@x=-0.2cm\pgf@y=0pt}
\anchor{right}{\pgf@x=0.2cm\pgf@y=0pt}
\backgroundpath{
\pgfscope
\pgfsetcolor{red}
\pgfpathmoveto{\pgfpoint{-0.2cm}{-0.0cm}}
\pgfpathlineto{\pgfpoint{-0.1cm}{-0.1cm}}
\pgfpathlineto{\pgfpoint{0.1cm}{0.1cm}}
\pgfpathlineto{\pgfpoint{0.2cm}{0.0cm}}
\pgfsetroundcap
\pgfusepath{draw}
\endpgfscope
}
}
\def\goforpaths{
coordinate(a) at (\tikztostart)
coordinate(b) at (\tikztotarget)
\pgfextra{
\pgfmathanglebetweenpoints{\pgfpointanchor{a}{center}}{\pgfpointanchor{b}{center}}
\edef\mydirection{\pgfmathresult}%Calculate direction(angle) of path
}
node[szig, rotate=\mydirection](N) at ($(\tikztostart)!0.5!(\tikztotarget)$){}
-- (\tikztostart) -- (N.left) (N.right) -- (\tikztotarget)
}
\tikzset{slineto/.style={/tikz/to path=\goforpaths}}
\makeatother
\begin{document}
\begin{tikzpicture}
% this does not work https://tex.stackexchange.com/questions/97602/tikz-path-labels-and-cycle#comment210067_97602
\draw[ultra thick] (0,0) to[slineto] (0,1) to[slineto] (1,1) to[slineto] (1,0) to[slineto] (0,0) -- cycle;
% nor this (worst):
\draw[ultra thick] (1.5,0) to[slineto] (1.5,1) to[slineto] (2.5,1) to[slineto] (2.5,0) to[slineto] cycle;
% this does work
\draw[ultra thick] (3,0) to[] (3,1) to[] (4,1) to[] (4,0) to[] cycle;
\end{tikzpicture}
\end{document}
结果是:
如果我将节点叠加到路径上,红色的“电阻器”将被划掉:
答案1
-- cycle
用于\pgfsyssoftpath@lastmoveto
关闭路径。\pgfsyssoftpath@lastmoveto
通常是 之后的第一个坐标\path
。但还有另一种情况,请考虑以下示例:
\path (0, 0) -- (1, 0) (1, 0) -- (1, 1) -- cycle;
\pgfsyssoftpath@lastmoveto
在(0, 0)
begin 处,但改为(1, 0)
after。我认为上面的代码应该具有与
\path (0, 0) -- (1, 0);
\path (1, 0) -- (1, 1) -- cycle;
因此路径\path (1,0) to[slineto] (0,0) -- cycle;
将扩展为
\path (1, 0) node[sline, rotate=\mydirection](N) at ($(\tikztostart)!0.5!(\tikztotarget)$){}
-- (1, 0) -- (N.left) (N.right) -- (0, 0) -- cycle;`
等于
\path (1, 0) node[sline, rotate=\mydirection](N) at ($(\tikztostart)!0.5!(\tikztotarget)$){}
-- (1, 0) -- (N.left);
\path (N.right) -- (0, 0) -- cycle;
解决方法
只让节点覆盖路径而不是破坏路径。
\def\goforpaths{
coordinate(a) at (\tikztostart)
coordinate(b) at (\tikztotarget)
\pgfextra{
\pgfmathanglebetweenpoints{\pgfpointanchor{a}{center}}{\pgfpointanchor{b}{center}}
\edef\mydirection{\pgfmathresult}%Calculate direction(angle) of path
}
node[sline, rotate=\mydirection](N) at ($(\tikztostart)!0.5!(\tikztotarget)$){}
-- (\tikztotarget)
}
对新要求的一些尝试
我在限制下进行了一些代码破解:全部都有to path
,即没有line to (--)
或edge
。
先声明:这是我能想到的唯一方法,但是我强烈不建议修补原始 tikz 代码!
思路很简单,因为实际上没有to cycle
或 这样的语法,所以我在 后面加了一个需要解析的edge cycle
可解析关键字。当第一次解析时,我保存了起始点(比如)和初始方向(比如)。在每次操作中,还会保存反方向(比如)。所以当最后解析 时,行是由 手动完成的。mycycle
to
to
a
ang1
to
ang2
mycycle
(a) ++(ang1:0.1pt) -- (a) -- (ang2:0.1pt)
如你所见,它非常有限。如果你想mycycle
表现得和 一样cycle
,你必须破解更多命令,这是一个大工作并且可能破坏原有的代码结构
\documentclass[tikz, border=1cm]{standalone}
\usetikzlibrary{calc}
\usepackage{etoolbox}
\usepackage{xpatch}
\makeatletter
\newbool{toclose@first@to}
\xpretocmd{\tikz@@command@path}{
\global\booltrue{toclose@first@to}
}{}{}
\xpretocmd{\tikz@finish}{
\global\boolfalse{toclose@first@to}
}{}{}
% -- mycycle
% \xpatchcmd{\tikz@lineto@mid}{%
% \tikz@scan@one@point{\tikz@@lineto}%
% }{%
% \pgfutil@ifnextchar m{\tikz@myclose}{%
% \tikz@scan@one@point{\tikz@@lineto}%
% }%
% }{}{}
% to/edge mycycle
\xpatchcmd{\tikz@@to@collect}{%
\tikzerror{(, +, coordinate, pic, or node expected}%)
\tikz@@to@or@edge@coordinate()%
}{
\pgfutil@ifnextchar m{
\tikz@myclose
}{
\tikzerror{(, +, coordinate, pic, or node expected}%)
\tikz@@to@or@edge@coordinate()
}
}{}{}
\def\tikz@myclose mycycle{
\tikz@scan@next@command
\tikz@@myclose
}
\def\tikz@@myclose{
\pgfextra{\typeout{iii \toclose@first@direction}}
to[\toclose@style](\toclose@first@moveto)
(\toclose@first@moveto) ++(\toclose@last@direction:0.1pt) --
(\toclose@first@moveto) -- ++(\toclose@first@direction:0.1pt)
}
% \def\tikz@myclose ycycle{\tikz@scan@next@command}
\pgfdeclareshape{szig}{
\anchor{center}{
\pgfpointorigin
}
\anchor{left}{\pgf@x=-0.2cm\pgf@y=0pt}
\anchor{right}{\pgf@x=0.2cm\pgf@y=0pt}
\backgroundpath{
\pgfscope
\pgfsetcolor{red}
\pgfpathmoveto{\pgfpoint{-0.2cm}{-0.0cm}}
\pgfpathlineto{\pgfpoint{-0.1cm}{-0.1cm}}
\pgfpathlineto{\pgfpoint{0.1cm}{0.1cm}}
\pgfpathlineto{\pgfpoint{0.2cm}{0.0cm}}
\pgfsetroundcap
\pgfusepath{draw}
\endpgfscope
}
}
\def\goforpaths{
coordinate(a) at (\tikztostart)
coordinate(b) at (\tikztotarget)
\pgfextra{
\pgfmathanglebetweenpoints{\pgfpointanchor{a}{center}}{\pgfpointanchor{b}{center}}
\edef\mydirection{\pgfmathresult}%Calculate direction(angle) of path
% save start point and start direction
\ifbool{toclose@first@to}{
\xdef\toclose@first@moveto{\tikztostart}
\xdef\toclose@first@direction{\mydirection}
\global\booltrue{toclose@first@to}
}{}
\pgfmathparse{\mydirection+180}
\xdef\toclose@last@direction{\pgfmathresult}
}
node[szig, rotate=\mydirection](N) at ($(\tikztostart)!0.5!(\tikztotarget)$){}
-- (\tikztostart) -- (N.left) (N.right) -- (\tikztotarget)
}
% \tikzset{slineto/.style={/tikz/to path=\goforpaths}}
\def\toset#1#2{%
\gdef\toclose@style{#1}
\tikzset{#1/.style={to path={#2}}}
}
\toset{slineto}{\goforpaths}
\makeatother
\begin{document}
\begin{tikzpicture}
\draw[ultra thick] (0,0) to[slineto] (0,1) to[slineto] (1,1) to[slineto] (1,0) to[slineto] mycycle;
\scoped[xshift=3cm] \draw[ultra thick] (0,0) to[slineto] (1,1) to[slineto] (2,0) to[slineto] mycycle;
\end{tikzpicture}
\end{document}