2

I want to create a triangle shape for flow diagrams, so far I succeeded but the anchors I have defined are badly placed. This seems to be wired as I have just copied and pasted the code from the computation of the background path (see MWE below). So my question is, is there a (hidden) canvas transformation going so that I am computing different things for anchors and for the background path? ATM the angle in the right lower corner is fixed to 60 degrees, as it has to be parallel to other such boxes.

Remark: The in' anchor should be placed on the middle of the bottom line, theout' anchor on the middle of the slanted (right) line. Here also as in other node shapes (notably trapezium) one sees that the end of the connecting line is not fully reaching the border line of the node, but the gap is very small.

Here is the code:

\documentclass{article}
%=======================================================================
% include macros
%-----------------------------------------------------------------------
\usepackage{tikz}
\usetikzlibrary{shapes, shapes.multipart, shapes.geometric}
\tikzstyle{string}=[line width=1.25pt]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% state or program
%
\newlength\progsize
\setlength\progsize{0.2cm}
\newlength\minimumstatesize
\setlength\minimumstatesize{0.4cm}
%%
%%
%%
\makeatletter
\pgfdeclareshape{prog}
{% -- some dimensions
   \saveddimen{\halftextwidth}{%
       \pgf@x=0.5\wd\pgfnodeparttextbox
       % get xsep
       \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/inner xsep}}%
       \advance\pgf@x by \pgf@xc%
       % 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%  
   }
   \saveddimen{\halftextheight}{%
       \pgf@x=0.5\ht\pgfnodeparttextbox
       % get ysep
       \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/inner ysep}}%
       \advance\pgf@x by \pgf@xc%
       % get minimum width
       \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
         \pgf@y=-0.5\ht\pgfnodeparttextbox
         \advance\pgf@y by -0.5\dp\pgfnodeparttextbox
         }
   \anchor{in}{% use triangle corners as computed in \backgroundpath below
         \pgf@xa=\halftextwidth        % (xa)
         \pgf@xb=\pgf@xa
            \pgf@xc=\halftextheight
            \pgf@xc=1.732\pgf@xc
            \advance\pgf@xb by \pgf@xc % (xb)
         \pgf@x=\pgf@xb                % (x) = (xb-xa)/2   
            \advance\pgf@x by -\pgf@xa
            \divide\pgf@x by 2
         %
         %% same code as in \backgroundpath !!!!
         \pgf@ya=2pt                   % (ya)
            \advance\pgf@ya by 0.5\ht\pgfnodeparttextbox
            \advance\pgf@ya by    \dp\pgfnodeparttextbox
            \pgf@y=-\pgf@ya    % (y) = (-ya)
         }
   \anchor{out}{% use trinagle corners as computed in \backgroundpath below
         %% (x)
         \pgf@xa=\halftextwidth        % (xa)
         \pgf@xb=\pgf@xa
            \pgf@xc=\halftextheight
            \pgf@xc=1.732\pgf@xc
            \advance\pgf@xb by \pgf@xc % (xb)
         \pgf@x=\pgf@xb          
            \advance\pgf@x by -\pgf@xa
            \divide\pgf@x by 2         % (x) = (xb-xa)/2
         %% (y)
         \pgf@ya=2pt                     % (ya)
            \advance\pgf@ya by 0.5\ht\pgfnodeparttextbox
            \advance\pgf@ya by    \dp\pgfnodeparttextbox
         \pgf@yc=\pgf@xb                % (yc)
            \advance\pgf@yc by \pgf@xa
            \pgf@yc=1.732\pgf@yc
         \pgf@y=0.5\pgf@yc
            \advance\pgf@y by -0.5\pgf@ya   % (y) = (xc-ya)/2
   }      
   %%
   %%
   \backgroundpath
   {
   %% -- compute the corners (A,B,C) of a trinagle with such that:
   %%    AB horizonlat, AC vertical, and
   %%    A: left bottom angle 90degrees (xa,ya)
   %%    B: right bottom angle 60 degrees (xb,yb=ya)
   %%    C: top angle 30 degrees (xc=xa,yc)
         \pgf@xa=\halftextwidth          % (xa)
         \pgf@ya=2pt                     % (ya)
            \advance\pgf@ya by 0.5\ht\pgfnodeparttextbox
            \advance\pgf@ya by \dp\pgfnodeparttextbox 
         \pgf@xb=\pgf@xa                 % (xb)  (yb=ya)
            \pgf@xc=\halftextheight
            \pgf@xc=1.732\pgf@xc         % tan(Pi/3) ~= 1.732
            \advance\pgf@xb by \pgf@xc
         \pgf@yc=\pgf@xb                 % (yc)  (xc=xa)
            \advance\pgf@yc by \pgf@xa
            \pgf@yc=1.732\pgf@yc
         %
         \pgfpathmoveto{\pgfqpoint{-\pgf@xa}{-\pgf@ya}}
         \pgfpathlineto{\pgfqpoint{-\pgf@xa}{\pgf@yc}}
         \pgfpathlineto{\pgfqpoint{\pgf@xb}{-\pgf@ya}}
         \pgfpathclose
         %\pgfcircle{\centerpoint}{2pt}
   }
}
\makeatother

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%=======================================================================
\begin{document}
%=======================================================================

\[\begin{tikzpicture}
        \node[prog,draw,string,inner xsep=1pt,inner ysep=-1.5pt] (p1) at (0,0.5) {\texttt{t}};
        \node[prog,draw,string,inner xsep=1pt,inner ysep=0pt] (p2) at (1,0.5) {\texttt{p}};
        %
        \draw[string] (p1.in |- 0.2,0) -- (p1.in);
       \draw[string] (p2.in |- 0.2,0) -- (p2.in);
        \draw[string] (p1.out) -- (0.5,1);
        \draw[string] (p2.out) -- (1.5,1);  
\end{tikzpicture}\]
\end{document}

and here is the (wrong) output:

enter image description here

2
  • 2
    Do not use \pgfnodeparttextbox in normal \anchors but only in \savedanchor (or \saveddimen and such). You cannot guarantee that the box is the same as when the node has been created. The \anchor anchors are calculated when they are used and not when the node is created. Oct 1 '13 at 13:19
  • ah, grr, I fell into that pit earlier. Thanks. Oct 1 '13 at 13:38
1

Do not use \pgfnodeparttextbox in normal \anchors but only in \savedanchor, \saveddimen or \savedmacro. There is no guarantee that the box is the same as when the node has been created as the \anchor definitions are first executed and evaluated after the node has been typeset.

In your case, you already have set up the appropriate macros \halftextheight and \halftextwidth that you can use for .5\ht\pgfnodeparttextbox and .5\wd\pgfnodeparttextbox. You just need to add \halftextdepth or something similar.

2
  • is there an example of something that does it "correctly" ?
    – Jason S
    Sep 24 '20 at 21:40
  • @JasonS OP's example uses \pgfnodeparttextbox in the \saveddimens. The macros that are defined with \saveddimen (which takes the value of \pgf@x at the end) and \savedanchor (which takes \pgf@x and \pgf@y) are calculated on the node's creation. All other \anchors are calculated on-the-fly when they are needed, after the creation of the node (for example with (p1.in)). You should only use the "saved" dimensions/anchors here (which are provided by PGF when an anchor is referenced). Please be aware that I don't know whether PGFs has changed anything since 2015. ;) Sep 27 '20 at 23:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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