概括

概括

我想定义一个带有许多锚点的新节点(或者可能是新形状)。具体来说,我需要一个矩形,矩形的顶部和底部最多有 15 个锚点。这是因为我想轻松地绘制如下内容: 两个节点

红点只是可能的锚点位置的示例,它们不应该出现在最终图片中。如果可能的话,所有边缘都应该垂直于节点(但我想这必须作为边缘中的一个选项添加)。

\node[mynode,minimum size=5mm] (A1) at (0,0) {Some Text};
\node[mynode,minimum size=5mm,rotate=-45] (A2) at (-1,-1) {};
\draw (A1.t4) -- (A2.b1);
%OR
%\path (A1.t4) edge [out=90,in=90] (A2.b1);

其中 t4 和 b1 应该代表锚点(如果我理解语法正确的话)。

这是因为我想画出类似http://elishapeterson.wikidot.com/tikz:diagrams

我已经发现了一些类似的东西,但我无法修改它以使其适合我,例如: https://tex.stackexchange.com/a/75515/58947 https://tex.stackexchange.com/a/33156/58947

我认为新的矩形节点可以继承标准矩形的所有结构,但添加 15 个锚点,例如顶部从 t1 到 t15,底部从 b1 到 b15。但欢迎任何建议!!梦想是边缘自动连接到更近的锚点。或者,更好的是,两个锚点之间的距离根据连接到节点的边数而变化(即,如果只有 6 条边连接到节点的顶部,它们将相隔 l/7,其中 l 是矩形长边的长度)

答案1

下面的示例定义了一个新的形状rectangle16。它从形状继承了锚点rectangle,并将锚点t0(= north west) 添加到t16(= north east),并将b0(= south west) 添加到b16(= south east)。

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{topaths}
\usetikzlibrary{calc}
\usetikzlibrary{hobby}

\makeatletter
\newcommand*{\define@anchor@t}[2]{%
  \anchor{t#1}{%
    \pgf@process{\southwest}%
    \pgf@xa=\pgf@x
    \pgf@process{\northeast}%
    \pgf@x=\dimexpr\pgf@xa + (\pgf@x-\pgf@xa)*#1/#2\relax
  }%
}
\newcommand*{\define@anchor@b}[2]{%
  \anchor{b#1}{%
    \pgf@process{\northeast}%
    \pgf@xa=\pgf@x
    \pgf@process{\southwest}%
    \pgf@x=\dimexpr\pgf@x + (\pgf@xa-\pgf@x)*#1/#2\relax
  }%
}
\pgfdeclareshape{rectangle16}{%
  \inheritsavedanchors[from=rectangle]
  \inheritanchorborder[from=rectangle]
  \inheritanchor[from=rectangle]{north}
  \inheritanchor[from=rectangle]{north west}
  \inheritanchor[from=rectangle]{center}
  \inheritanchor[from=rectangle]{west}
  \inheritanchor[from=rectangle]{east}
  \inheritanchor[from=rectangle]{mid}
  \inheritanchor[from=rectangle]{mid west}
  \inheritanchor[from=rectangle]{mid east}
  \inheritanchor[from=rectangle]{base}
  \inheritanchor[from=rectangle]{base west}
  \inheritanchor[from=rectangle]{base east}
  \inheritanchor[from=rectangle]{south}
  \inheritanchor[from=rectangle]{south east}
  \inheritbackgroundpath[from=rectangle]
  \count@=0 %
  \@whilenum\count@<17 \do{%
    \expandafter\define@anchor@t\expandafter{\the\count@}{16}%
    \expandafter\define@anchor@b\expandafter{\the\count@}{16}%
    \advance\count@\@ne
  }%
}
\makeatother

\begin{document}
  \begin{tikzpicture}
    \node[draw,rectangle16] (N)
      {Rectangular node with additional anchors at the top and bottom};
    \foreach \i in {0, ..., 16} {
      \draw[<-, node font=\footnotesize]
        (N.t\i) -- ++(0, .5) node[above] {t\i}
      ;
      \draw[<-, node font=\footnotesize]
        (N.b\i) -- ++(0, -.5) node[below] {b\i}
      ;
    }
    \node[draw, rectangle16] (ST) at (N.center |- 0, -3) {Some Text};
    \draw
      \foreach \i in {1, ..., 14} { (ST.t\i) -- ++(0, .5) }
      (ST.south east) ++(-2, -1)
      node[
        rectangle16,
        draw,
        rotate=-45,
        minimum width=15mm,
        minimum height=5mm,
      ] (R) {}
      (ST.b1) to (R.t4)
    ;
    \draw[use Hobby shortcut]
      (ST.t15)
      -- ([out angle=90]$(ST.t15) + (0, .1)$)
      .. ($(ST.east) + (.5, 0)$)
      .. ([in angle=-90]$(ST.b15) + (0, -.1)$)
      -- (ST.b15)
    ;
    \fill[
      red,
      radius=.5pt,
    ]
      \foreach \i in {0, ..., 16} {
        \foreach \tb in {t, b} {
          (R.\tb\i) circle[]
        }
      }
    ;
  \end{tikzpicture}
\end{document}

结果

概括

下面的示例\declareshaperectxy{<h>}{<v>}用两个参数定义了矩形四条边的水平和垂直锚点数,并用名称 定义了形状 rectangle <h>x<v>。例如,可以使用\declareshaperectxy{16}{8}形状之后,它为顶部、底部、左侧和右侧rectangle 16x8提供了附加锚点。t0t16b0b16l0l8r0r8

\documentclass{article}
\usepackage{tikz}

\makeatletter
\newcommand*{\rectxy@anchor@top}[2]{%
  \anchor{t#1}{%
    \pgf@process{\southwest}%
    \pgf@xa=\pgf@x
    \pgf@process{\northeast}%
    \pgf@x=\dimexpr\pgf@xa + (\pgf@x-\pgf@xa)*#1/#2\relax
  }%
}
\newcommand*{\rectxy@anchor@bottom}[2]{%
  \anchor{b#1}{%
    \pgf@process{\northeast}%
    \pgf@xa=\pgf@x
    \pgf@process{\southwest}%
    \pgf@x=\dimexpr\pgf@x + (\pgf@xa-\pgf@x)*#1/#2\relax
  }%
}
\newcommand*{\rectxy@anchor@left}[2]{%
  \anchor{l#1}{%
    \pgf@process{\northeast}%
    \pgf@ya=\pgf@y
    \pgf@process{\southwest}%
    \pgf@y=\dimexpr\pgf@y + (\pgf@ya-\pgf@y)*#1/#2\relax
  }%
}
\newcommand*{\rectxy@anchor@right}[2]{%
  \anchor{r#1}{%
    \pgf@process{\southwest}%
    \pgf@ya=\pgf@y
    \pgf@process{\northeast}%
    \pgf@y=\dimexpr\pgf@ya + (\pgf@y-\pgf@ya)*#1/#2\relax
  }%
}
\newcommand*{\declareshaperectxy}[2]{%
  \pgfdeclareshape{rectangle #1x#2}{%
    \inheritsavedanchors[from=rectangle]
    \inheritanchorborder[from=rectangle]
    \inheritanchor[from=rectangle]{north}
    \inheritanchor[from=rectangle]{north west}
    \inheritanchor[from=rectangle]{center}
    \inheritanchor[from=rectangle]{west}
    \inheritanchor[from=rectangle]{east}
    \inheritanchor[from=rectangle]{mid}
    \inheritanchor[from=rectangle]{mid west}
    \inheritanchor[from=rectangle]{mid east}
    \inheritanchor[from=rectangle]{base}
    \inheritanchor[from=rectangle]{base west}
    \inheritanchor[from=rectangle]{base east}
    \inheritanchor[from=rectangle]{south}
    \inheritanchor[from=rectangle]{south east}
    \inheritbackgroundpath[from=rectangle]
    \count@=\m@ne
    \@whilenum\count@<#1 \do{%
      \advance\count@\@ne
      \expandafter\rectxy@anchor@top\expandafter{\the\count@}{#1}%
      \expandafter\rectxy@anchor@bottom\expandafter{\the\count@}{#1}%
    }%
    \count@=\m@ne
    \@whilenum\count@<#2 \do{%
      \advance\count@\@ne
      \expandafter\rectxy@anchor@left\expandafter{\the\count@}{#2}%
      \expandafter\rectxy@anchor@right\expandafter{\the\count@}{#2}%
    }%
  }%
}
\makeatother

\declareshaperectxy{16}{8}
\declareshaperectxy{5}{3}

\begin{document}
  \begin{tikzpicture}
    \node[
      draw,
      rectangle 16x8,
      minimum width=80mm,
      minimum height=30mm,
    ] (N) {};
    \foreach \i in {0, ..., 16} {
      \draw[<-, node font=\footnotesize]
        (N.t\i) -- ++(0, .5) node[above] {t\i}
      ;
      \draw[<-, node font=\footnotesize]
        (N.b\i) -- ++(0, -.5) node[below] {b\i}
      ;
    }
    \foreach \i in {0, ..., 8} {
      \draw[<-, node font=\footnotesize]
        (N.l\i) -- ++(-.5, 0) node[left] {l\i}
      ;
      \draw[<-, node font=\footnotesize]
        (N.r\i) -- ++(.5, 0) node[right] {r\i}
      ;
    }
    \node[
      draw,
      rectangle 5x3,
      minimum width=80mm,
      minimum height=30mm,
      at={(0, -55mm)},
    ] (N) {};
    \foreach \i in {0, ..., 5} {
      \draw[<-, node font=\footnotesize]
        (N.t\i) -- ++(0, .5) node[above] {t\i}
      ;
      \draw[<-, node font=\footnotesize]
        (N.b\i) -- ++(0, -.5) node[below] {b\i}
      ;
    }
    \foreach \i in {0, ..., 3} {
      \draw[<-, node font=\footnotesize]
        (N.l\i) -- ++(-.5, 0) node[left] {l\i}
      ;
      \draw[<-, node font=\footnotesize]
        (N.r\i) -- ++(.5, 0) node[right] {r\i}
      ;
    }
  \end{tikzpicture}
\end{document}

结果泛化

答案2

您可以使用标准锚点来定义新点calc

例如我们的节点名为a,因此我们可以定义:

($(a.north west)!.1!(a.north east)$)

这将计算左上角和右上角之间的一个点,该点的坐标用数字表示,从 0 到 1。当然,您可以通过书写来增加这个数字!.47!,这样每边实际上就可以有 100 个坐标。

我说“几乎”是因为除非路径非常细(不太可能),否则同时使用所有 100 条路径是不可行的。不过它们应该足够你使用了。这里有一个动画展示它们(你只能看到 98 条,因为第一条和最后一条出现在节点边界之外,我将它们排除在外):

在此处输入图片描述

输出

图1

代码

\documentclass[tikz,margin=10pt]{standalone}

\usetikzlibrary{calc, positioning}

\begin{document}
\begin{tikzpicture}

    \node[draw] (a) {Some text};


    \draw ($(a.north west)!.1!(a.north east)$) --++ (0,1);
    \draw ($(a.north west)!.2!(a.north east)$) --++ (0,1);
    \draw ($(a.north west)!.3!(a.north east)$) --++ (0,1);
    \draw ($(a.north west)!.4!(a.north east)$) --++ (0,1);
    \draw ($(a.north west)!.42!(a.north east)$) --++ (0,1);
    \draw (a.north) --++ (0,1);
    \draw ($(a.north west)!.6!(a.north east)$) --++ (0,1);
    \draw ($(a.north west)!.7!(a.north east)$) --++ (0,1);
    \draw ($(a.north west)!.8!(a.north east)$) --++ (0,1);
    \draw[rounded corners=6pt] ($(a.north west)!.9!(a.north east)$) --++ (0,.2) --++ (.5,0) 
    --++ (0,-.9) --++ (-.5,0) -- ($(a.south west)!.9!(a.south east)$);

    \node[draw,below left=2 and .5 of a, rotate=-35] (b) {Other text};

    \draw ($(b.north west)!.3!(b.north east)$) edge[bend right] ($(a.south west)!.8!(a.south east)$);

\end{tikzpicture}
\end{document}

答案3

这里有一个通用的使用通用锚点的解决方案。

这样做的好处是它适用于每种形状,而无需定义新的形状。

我们定义一个宏(以及将参数转发给宏的\pgfDeclareGenericAnchorsLinear键),它接受五个参数:define linear anchors

  1. 锚(我们称之为A),
  2. 另一个锚点(我们称之为),
  3. 一个整数(应该已经被评估),
  4. 新锚点的前缀,以及
  5. PGFmath 函数名称。

PGFmath 函数必须有两个且只能有两个参数(参见示例)。

如果 PGFmath 函数求值为0,则锚点A将被选中。如果评估结果为 1,则锚点calc将被选中,其工作原理与

($(<node>.A)!<value>!(<node>.B)$)

此解决方案最适合具有相同数量附加锚点的节点(例如,顶部六个,底部五个,左侧两个)。

如果要逐个节点定义多个附加锚点,则必须进行额外的工作(即将该数字与节点本身一起存储)。

代码

\documentclass[tikz]{standalone}
\makeatletter
\newcommand*\pgfDeclareGenericAnchorsLinear[5]{%
  % #1 = anchor 1
  % #2 = anchor 2
  % #3 = max number (1 ... #3)
  % #4 = name
  % #5 = function name
  \pgfmathloop
    \csname pgfmath#5@\endcsname{\pgfmathcounter}{#3}%
    \edef\pgf@temp{%
      \noexpand\pgfdeclaregenericanchor{#4\space \pgfmathcounter}{%
        \noexpand\pgfpointlineattime
          {+\pgfmathresult}%
          {\noexpand\pgf@sh@reanchor{########1}{#1}}%
          {\noexpand\pgf@sh@reanchor{########1}{#2}}%
      }}%
    \pgf@temp
    \ifnum\pgfmathcounter<#3\relax
  \repeatpgfmathloop}
\makeatother
\pgfset{
  define linear anchors/.code n args=5{\pgfDeclareGenericAnchorsLinear{#1}{#2}{#3}{#4}{#5}},
  declare function={
    funcNormalPadding(\i,\n)=\i/(\n+1);
    funcHalfPadding(\i,\n)=(\i-.5)/(\n);
  }}

\tikzset{
  define linear anchors={north west}{north east}{6}{top}        {funcNormalPadding},
  define linear anchors={south west}{south east}{6}{bottom half}{funcHalfPadding},
  define linear anchors={south west}{south east}{6}{bottom}     {funcNormalPadding},
}
\begin{document}
\begin{tikzpicture}[mynode/.style={draw}]
\node[mynode,minimum size=5mm] (A1) at (0,0) {Some Text};
\node[mynode,minimum size=5mm,rotate=-45] (A2) at (-1,-1) {Teeext};
\foreach \v in {1,...,6}
  \draw (A1.top \v) -- ++ (up:1) (A2.bottom half \v) -- ++ (45:-.25);
\draw (A1.bottom 1) to[out=-90, in=45, looseness=.5] (A2.top 4);
\end{tikzpicture}
\end{document}

输出

在此处输入图片描述

相关内容