Latex TikzPgf用参数和锚点的数字来声明形状。

问题描述 投票:2回答:1

我正在用pgf写一些形状,我并不是真的知道所有的东西是如何工作的,但我设法通过文档。

\pgfdeclareshape{reg}{
  % The 'minimum width' and 'minimum height' keys, not the content, determine
  % the size
  \savedanchor\northeast{%
    \pgfmathsetlength\pgf@x{\pgfshapeminwidth}%
    \pgfmathsetlength\pgf@y{\pgfshapeminheight}%
    \pgf@x=0.11\pgf@x
    \pgf@y=0.15\pgf@y
  }
  % This is redundant, but makes some things easier:
  \savedanchor\southwest{%
    \pgfmathsetlength\pgf@x{\pgfshapeminwidth}%
    \pgfmathsetlength\pgf@y{\pgfshapeminheight}%
    \pgf@x=-0.11\pgf@x
    \pgf@y=-0.15\pgf@y
  }
  % Inherit from rectangle
  \inheritanchorborder[from=rectangle]

  % Define same anchor a normal rectangle has
  \anchor{center}{\pgfpointorigin}
  \anchor{north}{\northeast \pgf@x=0pt}
  \anchor{east}{\northeast \pgf@y=0pt}
  \anchor{south}{\southwest \pgf@x=0pt}
  \anchor{west}{\southwest \pgf@y=0pt}
  \anchor{north east}{\northeast}
  \anchor{north west}{\northeast \pgf@x=-\pgf@x}
  \anchor{south west}{\southwest}
  \anchor{south east}{\southwest \pgf@x=-\pgf@x}
  \anchor{text}{
    \pgfpointorigin
    \advance\pgf@x by -.5\wd\pgfnodeparttextbox%
    \advance\pgf@y by -.5\ht\pgfnodeparttextbox%
    \advance\pgf@y by +.5\dp\pgfnodeparttextbox%
  }

  % Define anchors for signal ports

  \anchor{CLK}{
    \pgf@process{\northeast}%
    \pgf@x=0\pgf@x%
    \pgf@y=1\pgf@y%
  }
  \anchor{PC}{
    \pgf@process{\northeast}%
    \pgf@x=-2.5\pgf@x%
    \pgf@y=0\pgf@y%
  }

  \anchor{PCS}{
    \pgf@process{\northeast}%
    \pgf@x=2.5\pgf@x%
    \pgf@y=0\pgf@y%
  }

  % Draw the rectangle box and the port labels
  \backgroundpath{
    % Rectangle box
    \pgfpathrectanglecorners{\southwest}{\northeast}

    % Drawing Triangle for clock input
    % upper left x
    \southwest \pgf@xa=\pgf@x 
    \northeast \pgf@ya=\pgf@y \pgf@yb=\pgf@y \pgf@xb=\pgf@x
    \pgf@anchor@reg@CLK
    \pgf@xc=\pgf@x \pgf@yc=\pgf@y
    \pgfmathsetlength\pgf@x{1.3ex}
    \advance\pgf@xa by .15mm
    \advance\pgf@xb by -.15mm
    \advance\pgf@yc by -\pgf@x
    \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
    \pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yc}}
    \pgfclosepath


    \tikzset{flip flop/port labels} % Use font from this style
    \tikz@textfont



    %Drawing CLK circuit
    \pgf@anchor@reg@CLK
    \pgf@xa=\pgf@x \pgf@ya=\pgf@y
    \pgf@xb=\pgf@x \pgf@yb=\pgf@y
    \pgfmathsetlength\pgf@x{1.8ex}
    \advance\pgf@yb by \pgf@x
    \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
    %Draw clock label
    \pgf@anchor@reg@CLK\pgftext[base,at={\pgfpoint{\pgf@x}{\pgf@y}}]{\raisebox{2.5ex}{CLK}}

    %Drawing PC circuit
    \pgf@anchor@reg@PC
    \pgf@ya=\pgf@y \pgf@yb=\pgf@y \pgf@xa=\pgf@x
    \pgf@anchor@reg@west
    \pgf@xb=\pgf@x 
    %\pgfmathsetlength\pgf@x{2.7ex}
    %\advance\pgf@xb by \pgf@x
    \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
    \pgf@anchor@reg@PC\pgftext[base,at={\pgfpoint{\pgf@x+0.5ex}{\pgf@y}}]{\raisebox{.5ex}{PC}}

    %Drawing PC' circuit
    \pgf@anchor@reg@PCS
    \pgf@ya=\pgf@y \pgf@yb=\pgf@y\pgf@xa=\pgf@x 
    \pgf@anchor@reg@east
    \pgf@xb=\pgf@x 
    %\pgfmathsetlength\pgf@x{2.5ex}
    %\advance\pgf@xb by \pgf@x
    \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
    \pgf@anchor@reg@PCS\pgftext[base,at={\pgfpoint{\pgf@x}{\pgf@y}}]{\raisebox{.5ex}{PC'}}
  }

}

在这里,我创建了一个形状,在外面有一些连接点,它实际上工作得很好。但我真的想在创建这个形状时有一个参数,这样我就可以指定端口的数量。

例如,像这样

\begin{tikzpicture}
    \node [reg,black!50,ports=3] (PC) at (0,0) {};
\end{tikzpicture}

但我在文档中找不到允许自定义参数的内容。另外,我想给锚命名为A1,A2和A3,但我似乎不能在名字中添加数字,即使在文档中明确说像 "1 "和":: "这样的名字应该是没有问题的,但 "A1 "仍然是。

如果有人有任何想法,如何做到这一点,我很感激的帮助。也许还有一些更好的用pgf创建图形的参考资料。

对于编辑tex文件,我使用Overleaf和pdflatex。

编辑:我现在发现你可以用 \pgfkeys 添加参数到形状中,但它们似乎不正确,我真的不知道该怎么做。

\def\microarchbasekey{/tikz/microarch}
\pgfkeys{\microarchbasekey/.is family}

\pgfdeclareshape{mux}{

    \pgfkeys{\microarchbasekey,inputs/.initial=2,spacing/.initial=5}

    \savedmacro{\numpins}{
        \def\numpins{\pgfkeysvalueof{\microarchbasekey/inputs}}
    }

    \saveddimen{\spacing}{
        \pgf@x = \pgfkeysvalueof{\microarchbasekey/spacing}
    }

%a lot of code down there
}

但它给我以下错误

A number should have been here; I inserted `0'.
(If you can't figure out why I needed to see a number,
look up `weird error' in the index to The TeXbook.)

但我找不到缺少的那部分代码。

parameters latex tikz pgf
1个回答
2
投票

也许这个问题更适合在这里讨论。TeXLaTeX网站但无论如何...

关键的事情是以下几点。

  1. 为参数添加键。要注意层次结构。node 下的钥匙。/tikz 家族。

    %
    % better to create a family, but as an example...
    \tikzset{flip flop/port labels/.initial={\tiny}}
    %
    % number of ports
    \tikzset{ports/.initial=4}
    %
    % we need a counter
    \newcount\tmp@a
    
  2. 添加稳定的(链接到特定节点而非通用形状)参数,所有这些参数都是计算锚点位置所需要的。

    % you have to save the relevant parameters as \savedmacro
        \savedmacro\numports{
            \edef\numports{\pgfkeysvalueof{/tikz/ports}}%
        }
        % and \saveddimen
        \saveddimen\pinsdelta{
            % you can't use savedmacros nor savedanchors here (bummer!)
            \edef\numports{\pgfkeysvalueof{/tikz/ports}}%
            \pgfmathsetlength\pgf@x{0.22*\pgfshapeminheight/(\numports+1)}%
        }
    
  3. 在形状定义中,你必须用一个技巧来添加锚点 --- 锚点必须被添加到形状的内部函数中。这很危险,因为开发者可以在将来改变它(已经发生过了),但我不知道有什么其他方法。

    % create input anchors
        % this touch internal things, so beware...
        % anchors are named pgf@anchor@<name-of-the-shape>@<name of the anchors>
        \pgfutil@g@addto@macro\pgf@sh@s@reg{%
            \tmp@a=\numports\relax
            \pgfmathloop%
            \ifnum\pgfmathcounter>\tmp@a%
            \else%
            % assign the anchor "in \pgfmathcounter" to the macro \reg@port with the number as argument
            \expandafter\xdef\csname pgf@anchor@reg@in \pgfmathcounter\endcsname{%
                \noexpand\reg@port{\pgfmathcounter}% defined below
            }%
            % \typeout{YAY\space\pgfmathcounter}
            \repeatpgfmathloop%
        }
    
  4. 定义计算变量锚的具体函数。你必须只使用 \saved... 样的参数,否则,你的锚点将使用参数的最后一个值,而不是用节点指定的正确值。

    \def\reg@port#1{%
        % this macro has the function to return the position of the anchor
        % it must use only \savedanchors and \savedmacros
        % the parameter is the number of the anchor (see above)
        \northeast
        \pgf@x=-\pgf@x
        \pgf@ya=\pgf@y
        \pgfmathsetlength{\pgf@y}{\pgf@ya-(#1+0.5)*\pinsdelta}%
    }
    

现在,我不明白你到底是如何画出你的形状的,所以锚点并不完全在它们应该去的地方,但好吧。

Output

我的完整代码在这里

\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\makeatletter
%
% better to create a family, but as an example...
\tikzset{flip flop/port labels/.initial={\tiny}}
%
% number of ports
\tikzset{ports/.initial=4}
%
% we need a counter
\newcount\tmp@a

\pgfdeclareshape{reg}{

    % you have to save the relevant parameters as \savedmacro
    \savedmacro\numports{
        \edef\numports{\pgfkeysvalueof{/tikz/ports}}%
    }
    % and \saveddimen
    \saveddimen\pinsdelta{
        % you can't use savedmacros nor savedanchors here (bummer!)
        \edef\numports{\pgfkeysvalueof{/tikz/ports}}%
        \pgfmathsetlength\pgf@x{0.22*\pgfshapeminheight/(\numports+1)}%
    }

    % The 'minimum width' and 'minimum height' keys, not the content, determine
    % the size
    \savedanchor\northeast{%
        \pgfmathsetlength\pgf@x{\pgfshapeminwidth}%
        \pgfmathsetlength\pgf@y{\pgfshapeminheight}%
        \pgf@x=0.11\pgf@x
        \pgf@y=0.15\pgf@y
    }
    % This is redundant, but makes some things easier:
    \savedanchor\southwest{%
        \pgfmathsetlength\pgf@x{\pgfshapeminwidth}%
        \pgfmathsetlength\pgf@y{\pgfshapeminheight}%
        \pgf@x=-0.11\pgf@x
        \pgf@y=-0.15\pgf@y
    }
    % Inherit from rectangle
    \inheritanchorborder[from=rectangle]

    % Define same anchor a normal rectangle has
    \anchor{center}{\pgfpointorigin}
    \anchor{north}{\northeast \pgf@x=0pt}
    \anchor{east}{\northeast \pgf@y=0pt}
    \anchor{south}{\southwest \pgf@x=0pt}
    \anchor{west}{\southwest \pgf@y=0pt}
    \anchor{north east}{\northeast}
    \anchor{north west}{\northeast \pgf@x=-\pgf@x}
    \anchor{south west}{\southwest}
    \anchor{south east}{\southwest \pgf@x=-\pgf@x}
    \anchor{text}{
        \pgfpointorigin
        \advance\pgf@x by -.5\wd\pgfnodeparttextbox%
        \advance\pgf@y by -.5\ht\pgfnodeparttextbox%
        \advance\pgf@y by +.5\dp\pgfnodeparttextbox%
    }

    % Define anchors for signal ports

    \anchor{CLK}{
        \pgf@process{\northeast}%
        \pgf@x=0\pgf@x%
        \pgf@y=1\pgf@y%
    }
    \anchor{PC}{
        \pgf@process{\northeast}%
        \pgf@x=-2.5\pgf@x%
        \pgf@y=0\pgf@y%
    }

    \anchor{PCS}{
        \pgf@process{\northeast}%
        \pgf@x=2.5\pgf@x%
        \pgf@y=0\pgf@y%
    }

    % Draw the rectangle box and the port labels
    \backgroundpath{
        % Rectangle box
        \pgfpathrectanglecorners{\southwest}{\northeast}

        % Drawing Triangle for clock input
        % upper left x
        \southwest \pgf@xa=\pgf@x
        \northeast \pgf@ya=\pgf@y \pgf@yb=\pgf@y \pgf@xb=\pgf@x
        \pgf@anchor@reg@CLK
        \pgf@xc=\pgf@x \pgf@yc=\pgf@y
        \pgfmathsetlength\pgf@x{1.3ex}
        \advance\pgf@xa by .15mm
        \advance\pgf@xb by -.15mm
        \advance\pgf@yc by -\pgf@x
        \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
        \pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yc}}
        \pgfclosepath


        \tikzset{flip flop/port labels} % Use font from this style
        \tikz@textfont



        %Drawing CLK circuit
        \pgf@anchor@reg@CLK
        \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \pgf@xb=\pgf@x \pgf@yb=\pgf@y
        \pgfmathsetlength\pgf@x{1.8ex}
        \advance\pgf@yb by \pgf@x
        \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
        %Draw clock label
        \pgf@anchor@reg@CLK\pgftext[base,at={\pgfpoint{\pgf@x}{\pgf@y}}]{\raisebox{2.5ex}{CLK}}

        %Drawing PC circuit
        \pgf@anchor@reg@PC
        \pgf@ya=\pgf@y \pgf@yb=\pgf@y \pgf@xa=\pgf@x
        \pgf@anchor@reg@west
        \pgf@xb=\pgf@x
        %\pgfmathsetlength\pgf@x{2.7ex}
        %\advance\pgf@xb by \pgf@x
        \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
        \pgf@anchor@reg@PC\pgftext[base,at={\pgfpoint{\pgf@x+0.5ex}{\pgf@y}}]{\raisebox{.5ex}{PC}}

        %Drawing PC' circuit
        \pgf@anchor@reg@PCS
        \pgf@ya=\pgf@y \pgf@yb=\pgf@y\pgf@xa=\pgf@x
        \pgf@anchor@reg@east
        \pgf@xb=\pgf@x
        %\pgfmathsetlength\pgf@x{2.5ex}
        %\advance\pgf@xb by \pgf@x
        \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
        \pgf@anchor@reg@PCS\pgftext[base,at={\pgfpoint{\pgf@x}{\pgf@y}}]{\raisebox{.5ex}{PC'}}
    }

    % create input anchors
    % this touch internal things, so beware...
    % anchors are named pgf@anchor@<name-of-the-shape>@<name of the anchors>
    \pgfutil@g@addto@macro\pgf@sh@s@reg{%
        \tmp@a=\numports\relax
        \pgfmathloop%
        \ifnum\pgfmathcounter>\tmp@a%
        \else%
        % assign the anchor "in \pgfmathcounter" to the macro \reg@port with the number as argument
        \expandafter\xdef\csname pgf@anchor@reg@in \pgfmathcounter\endcsname{%
            \noexpand\reg@port{\pgfmathcounter}% defined below
        }%
        % \typeout{YAY\space\pgfmathcounter}
        \repeatpgfmathloop%
    }

}
%
\def\reg@port#1{%
    % this macro has the function to return the position of the anchor
    % it must use only \savedanchors and \savedmacros
    % the parameter is the number of the anchor (see above)
    \northeast
    \pgf@x=-\pgf@x
    \pgf@ya=\pgf@y
    \pgfmathsetlength{\pgf@y}{\pgf@ya-(#1+0.5)*\pinsdelta}%
}
\makeatother

%%% handy macro to show the anchors

\def\showcoord(#1)<#2:#3>{%
    node[circle, red, draw, inner sep=1pt,pin={%
        [red, inner sep=0.5pt, font=\small,
        pin distance=#3cm, pin edge={red, }%
    ]#2:#1}](#1){}}

\begin{document}
\begin{tikzpicture}
    \node [draw,reg,minimum width=3cm, minimum height=3cm, black!50] (PC1) at (0,0) {};
    \path (PC1.north west) \showcoord(NW)<45:0.2>;
    \node [draw, reg,black!50,minimum width=3cm, minimum height=5cm, ports=6, blue] (PC2) at (3,0) {};
    \foreach \p in {1,...,4} \path(PC1.in \p) \showcoord(in \p)<145:0.3>;
    \foreach \p in {1,...,6} \path(PC2.in \p) \showcoord(in \p)<145:0.3>;
\end{tikzpicture}
\end{document}
© www.soinside.com 2019 - 2024. All rights reserved.