pgfdeclareshape:如何识别填充颜色?

pgfdeclareshape:如何识别填充颜色?

如果将自定义形状triangle设置为 之类的选项,则无法识别填充颜色(或描边颜色)fill=green。但它可以识别填充选项。我似乎遗漏了一些初始化代码(尽管我使用了\tikz@mode)。设置形状边框的颜色也存在同样的问题。

可执行文件中的代码如下所示:

\documentclass{article}
\usepackage{amsmath,amsfonts,amssymb,tikz}
\usetikzlibrary{shapes}
\usetikzlibrary{arrows,backgrounds}
\usetikzlibrary{decorations.pathreplacing}
\usetikzlibrary{decorations.markings}
\pgfdeclarelayer{foreground}
\pgfdeclarelayer{background}
\pgfsetlayers{main,foreground,background}
%
\newenvironment{pic}[1][]%
{\begin{aligned}\begin{tikzpicture}[#1]}%
{\end{tikzpicture}\end{aligned}}
%
% Styles
\tikzstyle{string}=[line width=1.25pt]
%%%%%%%%%%%%
% Triangle
\newlength\stateheight
\setlength\stateheight{0.6cm}
\newlength\minimumstatewidth
\setlength\minimumstatewidth{0.8cm}
\newif\ifhflip\pgfkeys{/tikz/hflip/.is if=hflip}
%%
%%
%%
\makeatletter
%%
%%  triangle shape for states in categorical quantum computation
%%     -- Based on some code by Chris Heunen,
%%     -- expanded by BF.
%%
%%  options:  hflip   (horizonatlly flipps the triangle)
%%
\pgfdeclareshape{triangle}
{% -- some dimensions
     \saveddimen{\halfbaselength}{%
         \pgf@x=0.5\wd\pgfnodeparttextbox
         % get xsep
         \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/inner xsep}}%
         \advance\pgf@x by \pgf@xc%
         % get \ht of textbox, add to baselength 
         \advance\pgf@x by \ht\pgfnodeparttextbox
         % get minimum width
         \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/minimum width}}%
         \divide\pgf@xb by 2
         \ifdim\pgf@x<\pgf@xb%
             % yes, too small. Enlarge...
             \pgf@x=\pgf@xb%
         \fi%
     }
     %
     % do NOT split code here \halfbaselinelength is pased on in \pgf@x 
     %
     \saveddimen\triangleheight{%
         % \pgf@x    contains \halfbaselength
         %get ysep
         \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/inner ysep}}%
         \advance\pgf@x by \pgf@xc%
         %get minimum height
         \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/minimum height}}%
         \divide\pgf@xb by 2
         \ifdim\pgf@x<\pgf@xb%
             %yes, too small. Enlarge...
             \pgf@x=\pgf@xb%
         \fi%
     }
     % -- anchors
     \savedanchor\centerpoint{%  midpoint on base line
         \pgf@x=0pt 
         \pgf@y=0pt
     }
     \anchor{center}{\centerpoint}
     \anchor{text}{%
         % horrizontal midpoint of pgfnodeparttextbox
         \pgf@x=-0.5\wd\pgfnodeparttextbox
         % vertical positioning (dependent on hflip flag)
         \ifhflip
            \pgf@y=-1.2\ht\pgfnodeparttextbox
            \advance\pgf@y by \dp\pgfnodeparttextbox
            \advance\pgf@y by -3pt
         \else
            \pgf@y=\dp\pgfnodeparttextbox
            \advance\pgf@y by -\dp\pgfnodeparttextbox
            \advance\pgf@y by 4pt
         \fi
     }
     \anchor{left}{%
        \pgf@x=-\halfbaselength
        \pgf@y=0pt
     }
     \anchor{right}{%
        \pgf@x=\halfbaselength
        \pgf@y=0pt
     }
     \anchor{tip}{%
        \pgf@x=0pt
        \ifhflip
           \pgf@y=-\triangleheight
        \else
           \pgf@y=\triangleheight
        \fi 
     }
     \anchor{a}{%
        \pgf@x=-\halfbaselength
        \divide\pgf@x by 2
        \pgf@y=0pt
     }
     \anchor{b}{%
        \pgf@x=\halfbaselength
        \divide\pgf@x by 2
        \pgf@y=0pt
     }
    %% -- draw the outline of the triangle
    %% -- fill the triangle if necessary
    \backgroundpath
    {
      \tikz@mode     %% set stuff
      \tikz@options  %% needed??
      % -- draw mode
      \iftikz@mode@draw
        \begin{pgfonlayer}{foreground}
          \pgf@xa=\halfbaselength
          \pgf@ya=\triangleheight 
      \ifhflip
            \pgfpathmoveto{\pgfqpoint{0pt}{-\pgf@ya}}
          \pgfpathlineto{\pgfqpoint{-\pgf@xa}{0pt}}
          \pgfpathlineto{\pgfqpoint{\pgf@xa}{0pt}}
          \pgfpathclose
      \else 
            \pgfpathmoveto{\pgfqpoint{0pt}{\pgf@ya}}
           \pgfpathlineto{\pgfqpoint{-\pgf@xa}{0pt}}
           \pgfpathlineto{\pgfqpoint{\pgf@xa}{0pt}}
           \pgfpathclose
          \fi
          \pgfusepath{stroke}
        \end{pgfonlayer}
      \fi
      % -- fill mode
      \iftikz@mode@fill
        \begin{pgfonlayer}{background}
          \pgf@xa=\halfbaselength
          \pgf@ya=\triangleheight 
      \ifhflip
            \pgfpathmoveto{\pgfqpoint{0pt}{-\pgf@ya}}
          \pgfpathlineto{\pgfqpoint{-\pgf@xa}{0pt}}
          \pgfpathlineto{\pgfqpoint{\pgf@xa}{0pt}}
          \pgfpathclose
      \else 
            \pgfpathmoveto{\pgfqpoint{0pt}{\pgf@ya}}
          \pgfpathlineto{\pgfqpoint{-\pgf@xa}{0pt}}
          \pgfpathlineto{\pgfqpoint{\pgf@xa}{0pt}}
          \pgfpathclose
          \fi
          \pgfusepath{fill}
        \end{pgfonlayer}
      \fi
    }
    \anchorborder
     {%  -- works only on the base line (yet)
      %  -- range restricted to 0..100
      % fetch key
      \pgfkeysgetvalue{/pgf/shape border rotate}{\rotate}%
      %
      % Save x and y.
      %
      \edef\externalx{\the\pgf@x}%
      \edef\externaly{\the\pgf@y}%
      %
      % Adjust the location of the external 
      % point relative to \centerpoint.
      %
      \centerpoint%
      \pgf@xa\externalx\relax%
      \pgf@ya\externaly\relax%
      \advance\pgf@xa\pgf@x%
      \advance\pgf@ya\pgf@y%
      \edef\externalx{\the\pgf@xa}%
      \edef\externaly{\the\pgf@ya}%
      %
      % Get the angle of the external point to the \centerpoint.
      %
      \pgfmathanglebetweenpoints{\centerpoint}{\pgfqpoint{\externalx}{\externaly}}%
      \pgfmathsubtract@{\pgfmathresult}{\rotate}%
      \ifdim\pgfmathresult pt<0pt\relax%
     \pgfmathadd@{\pgfmathresult}{360}%
      \fi%
      \let\externalangle\pgfmathresult%
      %
      % left tip
      %
      \pgf@xc=-\halfbaselength
      \pgf@yc=0pt
      %
      %  we use a border parameter in the range 0..100 to parametrize
      %  the base line from left to right, 50 is the center
      %  hence \externalangle/50 gives the multiplicator for the
      %  \halfbaseline   (2\halfbaseline is the length of the baseline)
      %
      \pgfmathdivide@{\externalangle}{50}
      \pgfmathparse{\halfbaselength*\pgfmathresult}
      \advance\pgf@xc by \pgfmathresult pt%
      %
      % set the anchor point
      %
      \pgf@y=0pt
      \pgf@x=\pgf@xc
    }
}
\makeatother

\begin{document}

\begin{align*}
  \begin{pic}
    \node (o1) at (0,1) {};
    \node (o2) at (1,1) {};
    \node (o3) at (2,1) {};
    \node[triangle,draw,blue,string,hflip] (t1) at (0,0) {};
    \node[triangle,fill=blue!40,string,hflip] (t2) at (1,0) {};
    \node[triangle,draw,fill=green,string,hflip] (t3) at (2,0) {};
    \draw[blue] (o1) to (t1.center);
    \draw (o2) to (t2.center);
    \draw (o3) to (t3.75) (o3) to (t3.25); % tests anchorborder
  \end{pic}
\end{align*}
\end{document}

结果如下: 输出示例

我还必须处理 \anchorborder 位,但我想我可以自己做,因为它已经在三角形的一侧起作用了。

非常感谢任何帮助以及对我的代码错误原因的解释。

答案1

无需使用\tikz@mode@fill或 图层(这会导致颜色丢失)或\pgfusepath。PGF 会自动处理这些事情。

\documentclass{article}
\usepackage{amsmath,amsfonts,amssymb,tikz}
\usetikzlibrary{shapes}
\usetikzlibrary{arrows,backgrounds}
\usetikzlibrary{decorations.pathreplacing}
\usetikzlibrary{decorations.markings}
\pgfdeclarelayer{foreground}
\pgfdeclarelayer{background}
\pgfsetlayers{main,foreground,background}
%
\newenvironment{pic}[1][]%
{\begin{aligned}\begin{tikzpicture}[#1]}%
{\end{tikzpicture}\end{aligned}}
%
% Styles
\tikzstyle{string}=[line width=1.25pt]
%%%%%%%%%%%%
% Triangle
\newlength\stateheight
\setlength\stateheight{0.6cm}
\newlength\minimumstatewidth
\setlength\minimumstatewidth{0.8cm}
\newif\ifhflip\pgfkeys{/tikz/hflip/.is if=hflip}
%%
%%
%%
\makeatletter
%%
%%  triangle shape for states in categorical quantum computation
%%     -- Based on some code by Chris Heunen,
%%     -- expanded by BF.
%%
%%  options:  hflip   (horizonatlly flipps the triangle)
%%
\pgfdeclareshape{triangle}
{% -- some dimensions
     \saveddimen{\halfbaselength}{%
         \pgf@x=0.5\wd\pgfnodeparttextbox
         % get xsep
         \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/inner xsep}}%
         \advance\pgf@x by \pgf@xc%
         % get \ht of textbox, add to baselength 
         \advance\pgf@x by \ht\pgfnodeparttextbox
         % get minimum width
         \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/minimum width}}%
         \divide\pgf@xb by 2
         \ifdim\pgf@x<\pgf@xb%
             % yes, too small. Enlarge...
             \pgf@x=\pgf@xb%
         \fi%
     }
     %
     % do NOT split code here \halfbaselinelength is pased on in \pgf@x 
     %
     \saveddimen\triangleheight{%
         % \pgf@x    contains \halfbaselength
         %get ysep
         \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/inner ysep}}%
         \advance\pgf@x by \pgf@xc%
         %get minimum height
         \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/minimum height}}%
         \divide\pgf@xb by 2
         \ifdim\pgf@x<\pgf@xb%
             %yes, too small. Enlarge...
             \pgf@x=\pgf@xb%
         \fi%
     }
     % -- anchors
     \savedanchor\centerpoint{%  midpoint on base line
         \pgf@x=0pt 
         \pgf@y=0pt
     }
     \anchor{center}{\centerpoint}
     \anchor{text}{%
         % horrizontal midpoint of pgfnodeparttextbox
         \pgf@x=-0.5\wd\pgfnodeparttextbox
         % vertical positioning (dependent on hflip flag)
         \ifhflip
            \pgf@y=-1.2\ht\pgfnodeparttextbox
            \advance\pgf@y by \dp\pgfnodeparttextbox
            \advance\pgf@y by -3pt
         \else
            \pgf@y=\dp\pgfnodeparttextbox
            \advance\pgf@y by -\dp\pgfnodeparttextbox
            \advance\pgf@y by 4pt
         \fi
     }
     \anchor{left}{%
        \pgf@x=-\halfbaselength
        \pgf@y=0pt
     }
     \anchor{right}{%
        \pgf@x=\halfbaselength
        \pgf@y=0pt
     }
     \anchor{tip}{%
        \pgf@x=0pt
        \ifhflip
           \pgf@y=-\triangleheight
        \else
           \pgf@y=\triangleheight
        \fi 
     }
     \anchor{a}{%
        \pgf@x=-\halfbaselength
        \divide\pgf@x by 2
        \pgf@y=0pt
     }
     \anchor{b}{%
        \pgf@x=\halfbaselength
        \divide\pgf@x by 2
        \pgf@y=0pt
     }
    %% -- draw the outline of the triangle
    %% -- fill the triangle if necessary
    \backgroundpath
    {
      % -- draw mode
          \pgf@xa=\halfbaselength
          \pgf@ya=\triangleheight 
      \ifhflip
            \pgfpathmoveto{\pgfqpoint{0pt}{-\pgf@ya}}
          \pgfpathlineto{\pgfqpoint{-\pgf@xa}{0pt}}
          \pgfpathlineto{\pgfqpoint{\pgf@xa}{0pt}}
          \pgfpathclose
      \else 
            \pgfpathmoveto{\pgfqpoint{0pt}{\pgf@ya}}
           \pgfpathlineto{\pgfqpoint{-\pgf@xa}{0pt}}
           \pgfpathlineto{\pgfqpoint{\pgf@xa}{0pt}}
           \pgfpathclose
      \fi
    }
    \anchorborder
     {%  -- works only on the base line (yet)
      %  -- range restricted to 0..100
      % fetch key
      \pgfkeysgetvalue{/pgf/shape border rotate}{\rotate}%
      %
      % Save x and y.
      %
      \edef\externalx{\the\pgf@x}%
      \edef\externaly{\the\pgf@y}%
      %
      % Adjust the location of the external 
      % point relative to \centerpoint.
      %
      \centerpoint%
      \pgf@xa\externalx\relax%
      \pgf@ya\externaly\relax%
      \advance\pgf@xa\pgf@x%
      \advance\pgf@ya\pgf@y%
      \edef\externalx{\the\pgf@xa}%
      \edef\externaly{\the\pgf@ya}%
      %
      % Get the angle of the external point to the \centerpoint.
      %
      \pgfmathanglebetweenpoints{\centerpoint}{\pgfqpoint{\externalx}{\externaly}}%
      \pgfmathsubtract@{\pgfmathresult}{\rotate}%
      \ifdim\pgfmathresult pt<0pt\relax%
     \pgfmathadd@{\pgfmathresult}{360}%
      \fi%
      \let\externalangle\pgfmathresult%
      %
      % left tip
      %
      \pgf@xc=-\halfbaselength
      \pgf@yc=0pt
      %
      %  we use a border parameter in the range 0..100 to parametrize
      %  the base line from left to right, 50 is the center
      %  hence \externalangle/50 gives the multiplicator for the
      %  \halfbaseline   (2\halfbaseline is the length of the baseline)
      %
      \pgfmathdivide@{\externalangle}{50}
      \pgfmathparse{\halfbaselength*\pgfmathresult}
      \advance\pgf@xc by \pgfmathresult pt%
      %
      % set the anchor point
      %
      \pgf@y=0pt
      \pgf@x=\pgf@xc
    }
}
\makeatother

\begin{document}

\begin{align*}
  \begin{pic}
    \node (o1) at (0,1) {};
    \node (o2) at (1,1) {};
    \node (o3) at (2,1) {};
    \node[triangle,draw,blue,string,hflip] (t1) at (0,0) {};
    \node[triangle,fill=blue!40,string,hflip] (t2) at (1,0) {};
    \node[triangle,draw,fill=green,string,hflip] (t3) at (2,0) {};
    \draw[blue] (o1) to (t1.center);
    \draw (o2) to (t2.center);
    \draw (o3) to (t3.75) (o3) to (t3.25); % tests anchorborder
  \end{pic}
\end{align*}
\end{document}

相关内容