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.

I'm having terrible trouble trying to declare a new shape with PGF and would appreciate help. What I would like to achieve is:

enter image description here

where the lighter grey boxes are \nodepart anchors, and the base shape is a rectangle, with a line drawn from the upper left corner to the middle bottom to the upper right corner.

Here is what I've tried:

\catcode`@=11
\pgfdeclareshape{decision}{%
  \inheritsavedanchors[from=rectangle]%
  \inheritanchorborder[from=rectangle]%
  \inheritanchor[from=rectangle]{center}%
  \foreach \anchor in {north,north west,north east,center,west,east,mid,
    mid west,mid east,base,base west,base east,south,south west,south east}{%
    \inheritanchor[from=rectangle]{\anchor}}%
  \nodeparts{text,false,true}%
  \savedanchor{false}{%
    \pgf@x=.1\wd\pgfnodeparttextbox%
    \pgf@y=.1\ht\pgfnodeparttextbox%
  }%
  \savedanchor{true}{%
    \pgf@x=.9\wd\pgfnodeparttextbox%
    \pgf@y=.1\ht\pgfnodeparttextbox%
  }%
  \inheritbackgroundpath[from=rectangle]%
  %\beforebackgroundpath{%
  %  \pgfpathmoveto{\pgfpointadd{\
  %}%
}
\catcode`@=12
\tikz \node[decision] {};
\bye

Trying to compile the above (unfinished) definitions I get an error:

! Missing control sequence inserted.
<inserted text> 
                \inaccessible 
<to be read again> 
                   f
\pgf@sh@savedpoints ...53297pt}{-3.53297pt}}\def f
                                                  alse{\pgfqpoint {0.0pt}{0....

UPDATE

After following @cjorssen's advice in a comment, I changed the first arguments of \savedanchor commands to be a command (i.e., \true, \false), and then I get a different error:

! Missing number, treated as zero.
<to be read again> 
                   \pgfnodepartfalsebox 
\pgfsys@hbox #1->\pgfsys@beginscope \setbox #1
                                              =\hbox {\box #1}\wd #1=0pt\ht ...
share|improve this question
1  
The first argument of \savedanchor should be a command sequence: \savedanchor{\false}. –  cjorssen Nov 3 '11 at 9:34
1  
Quoting the doc (sec Creating multipart ndoes): "for each part of the node, you must have set up one TeX-box". Here you must set a \pgfnodepartfalsebox and a \pgfnodeparttruebox. See examples in pgflibraryshapes.multipart.code.tex. –  cjorssen Nov 3 '11 at 10:38

2 Answers 2

up vote 5 down vote accepted

I improved your code a bit, I see that in the mean time Andrew has already explained everything I was going to in here. I will just add the code, so that you have a starting point.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.multipart}
\begin{document}
\makeatletter
\newbox\pgfnodepartfalsebox
\newbox\pgfnodeparttruebox
\pgfdeclareshape{decision}{%
  \nodeparts{text,false,true}%
  \inheritanchorborder[from=rectangle]%
  \inheritanchor[from=rectangle]{center}%
  \foreach \anchor in {north,north west,north east,center,west,east,mid,
    mid west,mid east,base,base west,base east,south,south west,south east}{%
    \inheritanchor[from=rectangle]{\anchor}}%
  \savedanchor\northeast{
    \pgf@x=.5\wd\pgfnodeparttextbox%
    \advance\pgf@x by\wd\pgfnodeparttruebox%
    \advance\pgf@x by2ex%
    \pgf@y=\ht\pgfnodeparttextbox%
  }
  \savedanchor\centerpoint{%
    \pgf@x=0pt%
    \pgf@y=0pt%
  }
  \savedanchor\southwest{
    \pgf@x=-.5\wd\pgfnodeparttextbox%
    \advance\pgf@x by-\wd\pgfnodepartfalsebox%
    \advance\pgf@x by-2ex%
    \pgf@y=-\ht\pgfnodeparttextbox%
    \advance\pgf@y by-\ht\pgfnodepartfalsebox%
    \advance\pgf@y by-\ht\pgfnodepartfalsebox%
  }
  \savedanchor\falseanchor{%
    \pgf@x=-.5\wd\pgfnodeparttextbox%
    \advance\pgf@x by-\wd\pgfnodepartfalsebox%
    \advance\pgf@x by-2ex%
    \pgf@y=-\ht\pgfnodeparttextbox%
    \advance\pgf@y by-\ht\pgfnodepartfalsebox%
    \advance\pgf@y by-\ht\pgfnodepartfalsebox%
    \advance\pgf@y by.2\ht\pgfnodepartfalsebox%
%     \advance\pgf@x by\wd\pgfnodepartfalsebox%
  }
  \savedanchor\trueanchor{%
    \pgf@y=-\ht\pgfnodeparttextbox%
    \advance\pgf@y by-\ht\pgfnodepartfalsebox%
    \advance\pgf@y by-\ht\pgfnodepartfalsebox%
    \pgf@x=.5\wd\pgfnodeparttextbox%
    \advance\pgf@x by\wd\pgfnodeparttruebox%
    \advance\pgf@x by2ex%
    \advance\pgf@x by-\wd\pgfnodeparttruebox%
    \advance\pgf@y by.2\ht\pgfnodepartfalsebox%
  }
  \anchor{text}{%
    \centerpoint
    \pgf@x=-.5\wd\pgfnodeparttextbox%
    \pgf@y=-.5\ht\pgfnodeparttextbox%
  }
  \anchor{false}{%
    \falseanchor%
  }%
  \anchor{true}{%
    \trueanchor
  }%
  \backgroundpath{%
    \northeast
    \pgf@xa=\pgf@x \pgf@ya=\pgf@y
    \southwest
    \pgf@xb=\pgf@x \pgf@yb=\pgf@y
    \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
    \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}
    \pgfpathclose
    \pgfmathsetlength{\pgf@xc}{.5\pgf@xa+.5\pgf@xb}
    \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
    \pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yb}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}
    \pgfusepath{stroke}
  }%
}

\makeatother

\begin{tikzpicture}
  \node[decision, draw] {text \nodepart{false} false\nodepart{true}true};
\end{tikzpicture}

\end{document}

This looks somewhat like your example:

the new node

You should definitely improve, using keys and making the anchors depend on minimum sizes, inner and outer sep, etc. At least this gives you a starting point from where you can fill in the remaining blanks.

share|improve this answer
    
Whoa! Thank you very much! And here I thought "it's just a rectangle, how hard can it be"... Pretty hard, it seems ;-) –  morbusg Nov 3 '11 at 11:08
1  
You weren't that far off. If you change \savedanchor{true} to \anchor{true} and add the \newbox\pgfnodeparttrue (same for false). Then your code compiles fine. It doesn't draw anything, since you don't have the draw option on the node and there is no text in it, but it compiles. The hard part will be to figure out the exact placement of the different nodeparts. You should definitely look at rectangle split in pgflibraryshapes.multipart.code.tex. It can serve as a great example here (as long as you are not put off by the immense complexity ;)). The manual also covers it on p. 450. –  Roelof Spijker Nov 3 '11 at 11:16

There's a few issues here:

  1. As cjorssen says in the comment, the first argument of \savedanchor has to be a command sequence. I'd go for \<part>anchor.
  2. Saved anchors are not anchors. They then have to be used to define anchors. So you need \anchor{true}{\trueanchor} and likewise (and the true and false anchors have to be defined).
  3. If you're using new parts that haven't been used in other shapes, you need to declare new boxes for them. So you need \newbox\pgfnodeparttruebox and likewise.
  4. You shouldn't inherit your anchors and border from the rectangle shape. These will be defined solely in terms of the text part and not in terms of the whole thing. If you define the north west and south east (I think I have those right) in terms of the new data, then you can inherit the rest of the anchors from the rectangle since all the other anchors (and the background path) are defined in terms of these two.
  5. So the main hassle is going to be figuring out how big the outer rectangle should be given the sizes of the smaller ones. Once you have that, the rest should be plain sailing! (Remember to make things customisable! Use PGF keys whenever you find yourself wanting to specify an arbitrary dimension.)
  6. The code for the circle split multipart node was invaluable to me in figuring out some of the above. I recommend taking a look at it.
share|improve this answer

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.