Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

my custom made shape triangle does not recognize the fill color (or stroke color), if set as an option like fill=green, say. It does recognize the fill option though. I seem to miss some initialization code (though I use \tikz@mode). The same problem is true for setting the color of the border of the shape.

The code in an executable file looks like:

\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}

The result looks like: output example

I have to work on the \anchorborder bit too, but I guess I can do that myself, as it works already on one side of the triangle.

Any help and explanation why my code is wrong is greatly appreciated.

share|improve this question

1 Answer 1

up vote 8 down vote accepted

There is no need to use \tikz@mode@fill or the layers (which caused the colour to be lost), or \pgfusepath. PGF takes care of those things automatically.

\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}
share|improve this answer
    
great, thanks! I used layers before and need to check that too now, I guess. –  Bertfried Fauser Jan 8 '13 at 17:07
    
@BertfriedFauser: I converted your non-answer to a comment. Please only use answer posts for solutions to the the question and comments for commenting on questions and answers. Note that you only get the possibility to add comments since you got 50rep, so you couldn't see the comment link before. –  Martin Scharrer Jan 8 '13 at 17:15
    
@Martin Scharrer, sorry for the misuse of the answer field, I forgot to login to I could not see the tag to click. (Ups I can use only one @User) [@]Jake, yes the answer is satisfactory and I have marked it as such. –  Bertfried Fauser Jan 9 '13 at 12:33

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.