Tikz 新形状:如何访问/定义锚点

Tikz 新形状:如何访问/定义锚点

我想创建一些新形状以便与 tiKz 一起使用。我面临的问题是如何访问新创建的形状的边缘。

到目前为止我得到了这个:

\documentclass[paper=a4,11pt,parskip=half,twoside]{scrartcl}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[french]{babel}
\usepackage[pdftex]{graphicx}

\usepackage{tikz}
\usepackage{circuitikz}
\usepackage{pgfplots}

\def\convEl{%
    ++(-.5,-.5) -- ++(1,0) -- ++(0,1) -- ++(-1,0) -- cycle
}

\def\convEm{%
    ++(0,0) circle (.5)
}

\def\convMe{%
    ++(-.5,-.5) -- ++(.5,1) -- ++(.5,-1) -- cycle
}

\def\accEn{%
    ++(-.5,-.5) -- ++(.5,0) -- ++(0,1) -- ++(-.5,0) -- cycle ++(0,-1) -- ++(.5,1)
}

\begin{document}

\begin{tikzpicture}
    \filldraw[draw=red,ultra thick,fill=orange] (0,0) \convEl node (a) {};
    \filldraw[draw=red,ultra thick,fill=orange] (2,0) \convEm node (b) {};
    \filldraw[draw=red,ultra thick,fill=orange] (4,0) \convMe;
    \filldraw[draw=red,ultra thick,fill=orange] (6,0) \accEn;
\end{tikzpicture}

\end{document}

好吧,也许我应该与提供的代码进行比较,使其更精确一些。我想访问形状的特定位置,例如底部中心和每侧 +30°/-30° 以连接箭头。这是预期行为的一个小方案。这就是为什么我需要创建/访问更多锚点的原因。如果我画一个简单的矩形,我可以做到,但要使用我需要的新/特殊形状……

箭头连接

答案1

使用 Spike 的方法肯定是可能的,但要定义的形状非常简单,所以我认为有一种最简单的方法。应该归功于 Jake 的回答如何在 tikz 中产生划掉的矩形?,因为在这里我只是改编了一些东西。

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric}

\tikzset{
        orange square/.style={draw=red,ultra thick, fill=orange,%
        minimum width=1cm, minimum height=1cm},%
        orange circle/.style={circle,draw=red,ultra thick, fill=orange,minimum width=1cm},%
        orange triangle/.style={regular polygon, regular polygon sides=3,%
        draw=red,ultra thick, fill=orange,minimum height=1cm},%
        orange rectangle/.style={rectangle,draw=red,ultra thick,%
        fill=orange,minimum height=1cm,minimum width=0.5cm,append after command={                       
            (\tikzlastnode.north east) edge[draw=red,ultra thick,shorten >=1.75\pgflinewidth,
                shorten <=1.75\pgflinewidth,](\tikzlastnode.south west)
            }
        },%
}

\begin{document}
\begin{tikzpicture}[scale=1.75,transform shape]
\node[orange square] (a) at (0,0){};
\node[orange circle] (b) at (2,0){};
\node[orange triangle] (c) at (4,0){};
\node[orange rectangle] (d) at (6,0){};
\draw[->,>=stealth] (a.south) -- (b.west) (b.north) -- (c.north)-- (d.center);
\end{tikzpicture}
\end{document}

结果:

在此处输入图片描述


编辑问题对于更好地理解请求非常有用。在这种情况下,定义一个新的形状可能更好,但这是 Spike 的领域:我为您提供了另一种选择。好的,如果习惯于该calc库,这可能是一种替代方案。

基本提示是regular polygons定义也corner锚定,因此通过以它们为参考,可以访问每个位置而无需定义新的形状。

修改后的示例:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric,calc}

\tikzset{
        orange square/.style={regular polygon, regular polygon sides=4,%
        draw=red,ultra thick, fill=orange,minimum width=1.5cm},%
        orange triangle/.style={regular polygon, regular polygon sides=3,%
        draw=red,ultra thick, fill=orange,minimum height=1.5cm},%
        }

\begin{document}

\begin{tikzpicture}[scale=1.75,transform shape]
\node[orange square,] (e) at (0,-2){};
\node[orange triangle] (f) at (4,-2.165){};

% Display the anchors
\foreach \anchor/\placement in {corner 1/above, corner 2/above, corner 3/below, corner 4/below}
\draw[shift=(e.\anchor)] plot[mark=x] coordinates{(0,0)}node[\placement] {\tiny\texttt{(e.\anchor)}};

\foreach \anchor/\placement in {corner 1/above, corner 2/below, corner 3/below}
\draw[shift=(f.\anchor)] plot[mark=x] coordinates{(0,0)}node[\placement] {\tiny\texttt{(f.\anchor)}};

% Drawing the arrows    
\draw[-latex] ($(e.corner 3)!0.5!(e.corner 4)-(0,1)$)--($(e.corner 3)!0.5!(e.corner 4)$);
\draw[-latex] ($(e.corner 1)!0.2!(e.corner 4)$)--($(f.corner 1)!0.25!(f.corner 2)$);
\draw[-latex] ($(e.corner 1)!0.5!(e.corner 4)$)--($(f.corner 1)!0.525!(f.corner 2)$);
\draw[-latex] ($(e.corner 1)!0.8!(e.corner 4)$)--($(f.corner 1)!0.8!(f.corner 2)$);
\end{tikzpicture}
\end{document}

结果:

在此处输入图片描述

答案2

创建新形状并不容易。它需要准确阅读 tikz 手册(第 75.5 节)并掌握一些 TeX 编程技能。顺便说一句,如果我能做到这一点,那么每个人都可以做到。如果您想创建真正的形状,您可以参考上述手册和其他先前的问题(例如如何在 TikZ 中定义机械约束)。

您给出的前三个示例仅使用样式即可实现。第三个可能需要定义,但考虑到它与矩形非常相似,因此并不难:

\documentclass{scrartcl}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric} %needed for the triangle

\makeatletter    
\pgfdeclareshape{myrectangle}{% taken and modified from page 631 of the manual
  \inheritsavedanchors[from=rectangle] %  this is nearly a rectangle
  \inheritanchorborder[from=rectangle]
  \inheritanchor[from=rectangle]{center}
  \inheritanchor[from=rectangle]{north}
  \inheritanchor[from=rectangle]{south}
  \inheritanchor[from=rectangle]{west}
  \inheritanchor[from=rectangle]{east}
  %  ... and possibly more
  \backgroundpath{%  this is new
    %  store lower right in xa/ya and upper right in xb/yb
    \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
    \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
    %  construct main path
    \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
    \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}
    \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@ya}}
    \pgfpathclose
    %  add diagonal
    \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
 }
}
\pgfdeclareshape{mytriangle}{%
  \inheritsavedanchors[from=circle]
  \inheritanchor[from=circle]{center}
  \anchor{north}{\centerpoint\advance\pgf@y by\radius}
  \anchor{south}{\centerpoint\advance\pgf@y by-\radius}
  %etc...
  \anchor{west}{%
    \centerpoint
    \pgf@xa=\radius
    % y = -1.5*r*tan(alpha)
    \advance\pgf@x by-1\pgf@xa
    \advance\pgf@y by-1.5\pgf@xa
  }
  \anchor{east}{%
    \centerpoint
    \pgf@xa=\radius
    % y = 1.5*r*tan(alpha)
    \advance\pgf@x by1\pgf@xa
    \advance\pgf@y by-1.5\pgf@xa
  }
  \anchor{south west}{%
    \centerpoint
    \pgf@xa=\radius
    \advance\pgf@x by-\pgf@xa
    \advance\pgf@y by-\pgf@xa
  }
  \anchor{south east}{%
    \centerpoint
    \pgf@xa=\radius
    \advance\pgf@x by\pgf@xa
    \advance\pgf@y by-\pgf@xa
  }
  \backgroundpath{%
      \pgf@x=\radius
      \pgfutil@tempdima=\pgf@x%
      \pgf@xb=-\pgf@x%
      \pgf@yb=-\pgf@x%
      \pgf@xc= \pgf@x%
      \pgf@yc=-\pgf@x%
      \centerpoint
      \advance\pgf@xb by\pgf@x
      \advance\pgf@yb by\pgf@y
      \advance\pgf@xc by\pgf@x
      \advance\pgf@yc by\pgf@y
      \pgf@xa=\pgf@x
      \pgf@ya=\pgf@y
      \advance\pgf@ya by\radius%
      \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}%
      \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}%
      \pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yc}}%
      \pgfpathclose%
      \advance\pgf@ya by-\radius%
  }%
}
\makeatother
% now the styles
\tikzset{orangesquare/.style={draw=red,ultra thick, fill=orange,minimum width=1cm, minimum height=1cm},%
         orangecircle/.style={circle,draw=red,ultra thick, fill=orange,minimum width=1cm},%
         orangetriangle/.style={regular polygon, regular polygon sides=3,draw=red,ultra thick, fill=orange,minimum height=1cm},%
         orangetriangle/.style={mytriangle,draw=red,ultra thick, fill=orange,minimum height=1cm}}

\begin{document}
\begin{tikzpicture}
\node[orangesquare] (a) at (0,0){};
\node[orangecircle] (b) at (2,0){};
\node[orangetriangle] (c) at (4,0){};
\node[orangerectangle] (d) at (6,0){};
\draw[->,>=stealth] (a.south) -- (b.west) (b.north) -- (c.north) -- (d.center);
\end{tikzpicture}
\end{document}

在此处输入图片描述

我使用圆形锚点(中心和半径)创建了三角形。如您所见,它与其他形状之间存在差异:最小宽度不考虑线宽。可以修复锚点位置,将其移至形状的外部,但无论如何都需要稍微调整最小尺寸。不幸的是,我不知道如何解决这个问题。也许我会把它作为一个问题发布。

答案3

我提出了另外两种方法来解决所提出的问题。

  • 一个是 tikz 的标准功能,
  • 另一种是沿着描述图片的路径自动创建可寻址节点的方法。

正如您在评论中所问的那样,我还有一个解决三角形底部对齐问题的建议。

您可以在这里看到结果:

访问职位

您可以在这里看到代码:

\documentclass [tikz] {standalone}

\usetikzlibrary{decorations.markings}
\usetikzlibrary{shapes.geometric}

\newcounter{mynodes}

\tikzset{
    my anchors/.style = {
        draw = red
        , ultra thick
        , fill = orange
        , postaction={
            /utils/exec=\setcounter{mynodes}{0}
            , decorate
            , decoration={
                markings,
                mark=between positions 0 and 1 step 3mm with {
                    \coordinate (#1 \themynodes);
                    \node at (#1 \themynodes) {\tiny \themynodes}; \stepcounter{mynodes}
                }
            }
        }
    }
    , degrees/.style = {
        draw = red
        , minimum size = 2cm
        , ultra thick
        , fill = orange
        , anchor = south west
    }
}

\newlength{\shifiting}
\setlength{\shifiting}{3cm}

\begin{document}
    \begin{tikzpicture}[]
        \draw [my anchors = circle 1] (1,1) circle (1);
        \draw [my anchors = square 1, xshift = \shifiting] (0,0) rectangle (2, 2);
        \draw [my anchors = triangle 1, xshift = 2\shifiting] (0,0) -- (1, 2) -- (2,0) -- cycle;
        \draw [my anchors = crossed rectangle 1, xshift = 3\shifiting] (1,2) -- (0, 2) -- (0,0) -- (1,0) -- cycle -- (0,0);

        \draw (circle 1 12) -- (square 1 14) -- (triangle 1 13) -- (crossed rectangle 1 24);

        \node [anchor = south west, minimum size = 2cm] (ref 1) at (0 , 1\shifiting) {};
        \node [circle, degrees, anchor = center] (circle 2) at (ref 1) {};

        \node [degrees] (square 2) at (\shifiting, \shifiting) {};

        \node [anchor = south west, minimum size = 2cm] (ref 2) at (2\shifiting , \shifiting) {};
        \node [degrees, isosceles triangle, rotate = 90, anchor = left corner, isosceles triangle stretches] (triangle 2) at (ref 2.south west) {};
        \node [degrees, minimum width = 1cm] (crossed rectangle 2) at (3\shifiting, \shifiting) {};
        \path [draw = red, ultra thick] (crossed rectangle 2.north east) -- (crossed rectangle 2.south west);

        \draw (circle 2.230) -- (square 2.30) -- (triangle 2.-110) -- (crossed rectangle 2.center);

    \end{tikzpicture}
\end{document}

希望这可以帮助。


编辑

好吧,从对节点对齐的质疑中,我在这里留下另外两个建议,这在某种程度上引出了对对称性问题的考虑。

第一种方法是在每个多边形的边缘进行分割,但对圆必须进行特殊处理。您可以在这里看到结果:

分割边缘

代码如下:

\documentclass [tikz] {standalone}

\usetikzlibrary{decorations.markings}
\usetikzlibrary{shapes.geometric}
\usetikzlibrary{calc}

\newcounter{mynodes}

% node, begin anchor, end anchor, name
\newcommand{\makepoints}[4]{
    \foreach \k in {1, ..., \points}
    {
        \pgfmathsetmacro{\dist}{\k * (1 / (\points + 1))}
        \coordinate (#1 #4 \k) at ($(#1.#2)!\dist!(#1.#3)$);
    }
}

% node, begin degree, end degree, name
\newcommand{\makepointsbydegrees}[4]{
    \foreach \k in {1, ..., \points}
    {
        \pgfmathsetmacro{\step}{(abs(#3) - abs(#2)) / (\points + 1)}
        \pgfmathsetmacro{\step}{ifthenelse(#2 < 0, -\step,)}
        \pgfmathsetmacro{\degree}{#2 + \k * \step}

        \coordinate (#1 #4 \k) at (#1.\degree);
    }
}

\tikzset{
    base/.style = {
        draw = red
        , line join = round
        , line cap = round
        , minimum size = 2cm
        , ultra thick
        , fill = orange
    }
    , ref/.style = {
        , minimum size = 2cm
        , anchor = south west
    }
}

\newlength{\shifiting}
\setlength{\shifiting}{3cm}

\begin{document}
    \begin{tikzpicture}[]
        \pgfmathtruncatemacro{\points}{3}

        % circle
        \node [ref] (ref 1) at (0 , 1\shifiting) {};
        \node [base, circle, anchor = center] (circle) at (ref 1) {};

        \makepointsbydegrees{circle}{-270}{-450}{right}

        % square
        \node [ref] (ref 2) at (\shifiting, \shifiting) {};
        \node [base] (square) at (ref 2) {};

        \makepoints{square}{north east}{south east}{right}
        \makepoints{square}{north west}{south west}{left}


        % triangle
        \node [ref] (ref 3) at (2\shifiting , \shifiting) {};
        \node [base, isosceles triangle, rotate = 90, anchor = left corner, isosceles triangle stretches] (triangle) at (ref 3.south west) {};

        \makepoints{triangle}{east}{left corner}{left}
        \makepoints{triangle}{east}{right corner}{right}


        % crossed retangle
        \node [ref, minimum width = 1cm] (ref 4) at (3\shifiting, \shifiting) {};
        \node [base, minimum width = 1cm] (crossed rectangle) at (ref 4) {};
        \path [base, shorten >= 2pt, shorten <= 2pt] (crossed rectangle.north east) -- (crossed rectangle.south west);

        \makepoints{crossed rectangle}{north west}{south west}{left}


        % lines

        \foreach \i in {1, ..., \points}
        {
            \draw [->] (circle right \i) -- (square left \i);
            \draw [->] (square right \i) -- (triangle left \i);
            \draw [->] (triangle right \i) -- (crossed rectangle left \i);
        }

    \end{tikzpicture}
\end{document}

第二种方法带来了完全不同的范例,使用了 Tikz 提供的更多功能,例如throughmatrix和。在下图中fitintersections您可以看到结果和一些构造线。

外部结构

代码如下:

\documentclass [tikz] {standalone}

\usetikzlibrary{fit}
\usetikzlibrary{intersections}
\usetikzlibrary{calc}
\usetikzlibrary{matrix}
\usetikzlibrary{through}

% node, begin anchor, end anchor, name
\newcommand{\makepoints}[4]{
    \foreach \k in {1, ..., \points}
    {
        \pgfmathsetmacro{\dist}{\k * (1 / (\points + 1))}
        \coordinate (#1 #4 \k) at ($(#1.#2)!\dist!(#1.#3)$);
    }
}

% first path, second path, counter
\newcommand{\intersectpoints}[3]{
    \path [name intersections = {of = #1 and #2, sort by = #2, name = #3, total = \t}] 
        \foreach \s in {1, ..., \t} {
            node [fill, circle, inner sep = 1.5pt] at (#3-\s) {}
        };
}

\tikzset{
    base/.style = {
        draw = red
        , line join = round
        , minimum size = 2cm
        , ultra thick
        , fill = orange
        , name path = #1
    }
    , ref/.style = {
        , minimum size = 2cm
        , anchor = south west
    }
    , cr/.style = {
        , minimum width = 1cm
        , minimum height = 2cm
    }
    , conexion/.style = {
        , ->
        , thick
        , draw = blue
    }
}

\begin{document}
    \begin{tikzpicture}[]

        % number of reference lines
        \pgfmathtruncatemacro{\points}{4}

        \matrix (m) [matrix of nodes, nodes in empty cells, nodes = {ref}]
        {
            & & & & & & \\
        };

        \node [base = circle] at (m-1-1) [circle through={(m-1-1.east)}] {};
        \draw [base = square] (m-1-3.south west) rectangle (m-1-3.north east);
        \draw [base = triangle] (m-1-5.south west) -- (m-1-5.south east) -- (m-1-5.north) -- cycle;

        \node [draw, cr] (cr) at (m-1-7){};
        \draw [base = crossed rectangle] (cr.north east) -- (cr.north west) -- (cr.south west) -- (cr.south east) -- cycle -- (cr.south west);


        % reference rectangle fitting all figures
        \node [draw, dotted, inner sep = 0pt, fit = (m-1-1) (m-1-7)] (outline) {};
        \makepoints{outline}{north west}{south west}{left}
        \makepoints{outline}{north east}{south east}{right}

        % reference lines through figures
        \draw [dotted, name path = path 1] (outline left 1) -- (outline right 1);
        \draw [dotted, name path = path 2] (outline left 2) -- (outline right 2);
        \draw [dotted, name path = path 3] (outline left 3) -- (outline right 3);
        \draw [dotted, name path = path 4] (outline left 4) -- (outline right 4);

        % circle points
        \intersectpoints{circle}{path 1}{c 1}
        \intersectpoints{circle}{path 2}{c 2}
        \intersectpoints{circle}{path 3}{c 3}

        % square points
        \intersectpoints{square}{path 1}{r 1}
        \intersectpoints{square}{path 2}{r 2}
        \intersectpoints{square}{path 3}{r 3}

        % triangle points
        \intersectpoints{triangle}{path 1}{t 1}
        \intersectpoints{triangle}{path 2}{t 2}
        \intersectpoints{triangle}{path 3}{t 3}

        % crossed rectangle
        \intersectpoints{crossed rectangle}{path 1}{cr 1}
        \intersectpoints{crossed rectangle}{path 2}{cr 2}
        \intersectpoints{crossed rectangle}{path 3}{cr 3}

        % lines between circle and square
        \draw [conexion] (c 1-2) -- (r 1-1);
        \draw [conexion] (c 2-2) -- (r 2-1);
        \draw [conexion] (c 3-2) -- (r 3-1);

        % lines between square and triangle
        \draw [conexion] (r 1-2) -- (t 1-1);
        \draw [conexion] (r 2-2) -- (t 2-1);
        \draw [conexion] (r 3-2) -- (t 3-1);

        % lines between triangle and crossed rectangle
        \draw [conexion] (t 1-2) -- (cr 1-2);
        \draw [conexion] (t 2-2) -- (cr 2-2);
        \draw [conexion] (t 3-2) -- (cr 3-1);

    \end{tikzpicture}
\end{document}

希望你喜欢。

相关内容