定义一个接受“循环”作为目标的“路径”函数?

定义一个接受“循环”作为目标的“路径”函数?

你可能不知道,下面的想法circuitikz是使用to pathTi 的功能Z.现在,我最近简化了功能,使其看起来或多或少运行良好,但我无法让它用于关闭路径。

我准备了一个非常简单的 MWE --- 我定义了一个组件形状,它是一个简单的红色段,并且复制了一条基本的路径构造。正如您在下面的示例中看到的,to[]当使用元素关闭路径时,常规操作可以完美地(如预期的那样)工作cycle,而当以类似的方式使用时,我的操作会失败(有时它会在烟花中失败)。

有办法解决吗?\goforpath宏中我真的不会改变内部 TiZ 函数,例如建议的这里,出于可维护性的原因(我在包中有一个解决方法,但它是手动的......)。

\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可解析关键字。当第一次解析时,我保存了起始点(比如)和初始方向(比如)。在每次操作中,还会保存反方向(比如)。所以当最后解析 时,行是由 手动完成的。mycycletotoaang1toang2mycycle(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}

相关内容