# How to use \pgftransformcm and \inheritsavedanchors in a new shape (batman) from an ellipse

I try to make this shape but I have several problem.

1. First to place the logo inside the ellipse, I used \pgftransformcm{1}{0}{0}{1}{\centerpoint} perhaps there is a better solution. I need to use \pgftransformcm{-1}{0}{0}{1}{\centerpoint} at the end because the text is inverted but with all the transformations I lost the baseline and the text is misplaced. This is the main question

2. I try to use \inheritsavedanchors but without success

3. To get some good results, I think it's important to keep a ratio between height and width but how do this ?

4. Perhaps the calculations are bad but I prefer to understand how I need to do before remake all the calculations. It's possible to use the ratio height/width to get better results.

Here the long code, results are fine when I fixed the dimensions.

\documentclass{article}
\usepackage{tikz,fullpage}
\usetikzlibrary{shapes}
\begin{document}
\thispagestyle{empty}
\makeatletter
\newdimen\batmanx
\newdimen\batmany

\tikzset{     shape example/.style={
color=black!30,
draw,
fill=yellow!30,
line width=.5cm,
inner xsep=2.5cm,
inner ysep=0.5cm}
}

\pgfdeclareshape{batman}
{
\savedanchor\centerpoint{%
\pgf@x=.5\wd\pgfnodeparttextbox%
\pgf@y=.5\ht\pgfnodeparttextbox%
}
%
% Caculate height radius''
%
\pgf@y=.5\ht\pgfnodeparttextbox%
\pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/inner ysep}}%
%
% Caculate width radius''
%
\pgf@x=.5\wd\pgfnodeparttextbox%
\pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/inner xsep}}%
%
%
\pgf@x=1.4142136\pgf@x%
\pgf@y=1.4142136\pgf@y%
%
%
\pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/minimum height}}%
\ifdim\pgf@y<.5\pgf@yc%
\pgf@y=.5\pgf@yc%
\fi%
%
%
\pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/minimum width}}%
\ifdim\pgf@x<.5\pgf@xc%
\pgf@x=.5\pgf@xc%
\fi%
%
%
\pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}%
\pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}%
}
% Anchors
\anchor{center}{\centerpoint}
\anchor{mid}{\centerpoint\pgfmathsetlength\pgf@y{.5ex}}
\anchor{base}{\centerpoint\pgf@y=0pt}
\anchor{north}
{
\pgf@ya=\pgf@y%
\pgf@process{\centerpoint}
}
\anchor{south}
{
\pgf@ya=\pgf@y%
\pgf@process{\centerpoint}
}
\anchor{west}
{
\pgf@xa=\pgf@x%
\pgf@process{\centerpoint}
}
\anchor{mid west}
{%
\pgf@xa=\pgf@x%
\pgf@process{\centerpoint}
\pgfmathsetlength\pgf@y{.5ex}
}
\anchor{base west}
{%
\pgf@xa=\pgf@x%
\pgf@process{\centerpoint}
\pgf@y=0pt
}
\anchor{north west}
{
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@process{\centerpoint}
}
\anchor{south west}
{
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@process{\centerpoint}
}
\anchor{east}
{%
\pgf@xa=\pgf@x%
\pgf@process{\centerpoint}
}
\anchor{mid east}
{%
\pgf@xa=\pgf@x%
\pgf@process{\centerpoint}
\pgfmathsetlength\pgf@y{.5ex}
}
\anchor{base east}
{%
\pgf@xa=\pgf@x%
\pgf@process{\centerpoint}
\pgf@y=0pt
}
\anchor{north east}
{
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@process{\centerpoint}
}
\anchor{south east}
{
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@process{\centerpoint}
}
\anchorborder{
\edef\pgf@marshal{%
\noexpand\pgfpointborderellipse
{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}
}%
\pgf@marshal%
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\centerpoint%
}

%
% Background path
%
\backgroundpath
{
\pgfutil@tempdima=\pgf@x%
\pgfutil@tempdimb=\pgf@y%
\pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}%
\pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}%
\batmanx=\pgfutil@tempdima%
\batmany=\pgfutil@tempdimb%
\pgfpathellipse{\centerpoint}
{\pgfqpoint{\pgfutil@tempdima}{0pt}}
{\pgfqpoint{0pt}{\pgfutil@tempdimb}}%
\pgfsetfillopacity{.5}
\pgfsetfillcolor{yellow}
\pgfusepath{fill,stroke}
\pgfsetlinewidth{0.05\pgfutil@tempdima}%
\pgfutil@tempdima=0.90\pgfutil@tempdima%
\pgfutil@tempdimb=0.90\pgfutil@tempdimb%
\pgfpathellipse{\centerpoint}{\pgfqpoint{\pgfutil@tempdima}{0pt}}
{\pgfqpoint{0pt}{\pgfutil@tempdimb}}%
\pgfusepath{stroke}
\pgfsetlinewidth{0.4 pt}
\pgftransformcm{1}{0}{0}{1}{\centerpoint}
\pgfpathmoveto{\pgfpoint{0 cm}{0.66\batmany}}
\pgfpathlineto{\pgfqpoint{0.07\batmanx}{0.66\batmany}}
\pgfpathlineto{\pgfqpoint{0.14\batmanx}{0.793\batmany}}
\pgfpathcurveto{\pgfqpoint{0.17\batmanx}{0.317\batmany}}
{\pgfqpoint{0.186\batmanx}{0.24\batmany}}
{\pgfqpoint{0.28\batmanx}{0.24\batmany}}
\pgfpathcurveto{\pgfqpoint{0.42\batmanx}{0.24\batmany}}
{\pgfqpoint{0.42\batmanx}{0.537\batmany}}
{\pgfqpoint{0.28\batmanx}{0.756\batmany}}
\pgfpatharcto{0.84\batmanx}{0.80\batmany}{0}{0}{0}
{\pgfqpoint{0.457\batmanx}{-0.683\batmany}}
\pgfpathcurveto{\pgfqpoint{0.56\batmanx}{-0.488\batmany}}
{\pgfqpoint{0.56\batmanx}{0 cm}}
{\pgfqpoint{0.314\batmanx}{-0.44\batmany}}
\pgfpathcurveto{\pgfqpoint{0.214\batmanx}{-0.24\batmany}}
{\pgfqpoint{0.14\batmanx}{-0.24\batmany}}
{\pgfqpoint{0 cm}{-0.78\batmany}}
\pgftransformcm{-1}{0}{0}{1}{\pgfpointorigin}
\pgfpathcurveto{\pgfpoint{0.14\batmanx}{-0.24\batmany}}
{\pgfpoint{0.214\batmanx}{-0.24\batmany}}
{\pgfpoint{0.314\batmanx}{-0.44\batmany}}
\pgfpathcurveto{\pgfpoint{0.56\batmanx}{0 cm}}
{\pgfpoint{0.56\batmanx}{-0.488\batmany}}
{\pgfpoint{0.457\batmanx}{-0.683\batmany}}
\pgfpatharcto{0.84\batmanx}{0.80\batmany}{0}{0}{1}
{\pgfpoint{0.28\batmanx}{0.756\batmany}}
\pgfpathcurveto{\pgfpoint{0.42\batmanx}{0.537\batmany}}
{\pgfpoint{0.42\batmanx}{0.24\batmany}}
{\pgfpoint{0.28\batmanx}{0.24\batmany}}%
\pgfpathcurveto{\pgfqpoint{0.186\batmanx}{0.24\batmany}}
{\pgfqpoint{0.17\batmanx}{0.317\batmany}}
{\pgfqpoint{0.14\batmanx}{0.793\batmany}}
\pgfpathlineto{\pgfqpoint{0.07\batmanx}{0.66\batmany}}%
\pgfpathmoveto{\pgfpoint{0 cm}{0.66\batmany}}
\pgfsetfillopacity{1}%
\pgfsetfillcolor{black}%
\pgfusepath{fill,stroke}
\pgftransformcm{-1}{0}{0}{1}{\centerpoint}%
\pgfsetlinewidth{0.4pt}%
}
}

\Huge
\begin{tikzpicture}
\node[name=s,shape=batman,minimum height=8.2cm,minimum width=14cm] {\color{red}Batman\vrule width 1pt height 2cm};
\foreach \anchor/\placement in
{north west/above left, north/above, north east/above right,
west/left, center/above, east/right,
mid west/right, mid/above, mid east/left,
base west/left, base/below, base east/right,
south west/below left, south/below, south east/below right,
text/left, 10/right, 130/above}
\draw[shift=(s.\anchor)] plot[mark=x] coordinates{(0,0)}
node[\placement] {\color{red}\scriptsize\texttt{(s.\anchor)}};
\end{tikzpicture}

\end{document}


With the next code the results are correct

  \begin{tikzpicture}
\node[draw,shape=batman,minimum height=4.1cm,minimum width=7cm,text=white] (A) {\Large Bat me up};

\node[draw,shape=batman,minimum height=8.2cm,minimum width=14cm,text=white] (B) at ([yshift=-12cm]A) {\Huge Bat me down  };
\draw [red,ultra thick,double,->](A) --(B);
\end{tikzpicture}


and with

  \begin{tikzpicture}
\node[draw,shape=batman,text=white] (A) {\Large Bat me up};

\node[draw,shape=batman,text=white] (B) at ([yshift=-3cm]A) {\Huge  Bat me down  };
\draw [red,ultra thick,double,->](A) --(B);
\end{tikzpicture}


it's very bad (ratio text etc.)

-
Wonderful, might I suggest the following anchors: left/right top/bottom wing, tail, left/right horn(et). The transformcm needs additional work as it does not handle nested transforms, as such you need a group to be sure to not disturb any user transforms. – zeroth Mar 9 '12 at 22:54
Wonderfull ? no there are a lot of problems . I need first to place correctly the text "Batman", so I need to understand how transformcm works. – Alain Matthes Mar 9 '12 at 23:09
I think these shapes do not require aspect ratios. One characteristic length should define all. \pgftransformcm{a}{b}{c}{d}{coord} works as a matrix vector product. Every vector in the 2D plane, suppose x=(x1 \\ x2), is computed as [a &c \\ b &d]*(x1\\ x2) + (coord1 \\ coord2). In my transformation I just use the matrix [-1 &0 \\ 0 &1](x1\\x2)+( 0\\ 0) so only horizontal component of the vector gets affected. – percusse Mar 10 '12 at 0:09
Also you can use \pgftransformshift{\centerpoint} for your first question. If you use \begin{pgfscope} .... \end{scope} inside the backgroundpath code, the transformations don't affect the textbox. So you can remove the last transformation. – percusse Mar 10 '12 at 2:33
@zeroth Not enough time to look seriously at the answer. You are right about \inheritsavedanchors. – Alain Matthes Mar 13 '12 at 7:44

You need to contain your transforms, pgf does its own transform to place its node, so you need to respect that. This is where it goes wrong as you transform on top of another transform.

You can avoid this by placing a group right before your first \pgftransformcm and an end group at the bottom of your backgroundpath.

  %
% Background path
%
\backgroundpath
{
% commented out...
% interesting drawing...
% commented out...
\bgroup
\pgftransformcm{1}{0}{0}{1}{\centerpoint}
\pgfpathmoveto{\pgfpoint{0 cm}{0.66\batmany}}
\pgfpathlineto{\pgfqpoint{0.07\batmanx}{0.66\batmany}}
\pgfpathlineto{\pgfqpoint{0.14\batmanx}{0.793\batmany}}
\pgfpathcurveto{\pgfqpoint{0.17\batmanx}{0.317\batmany}}
{\pgfqpoint{0.186\batmanx}{0.24\batmany}}
{\pgfqpoint{0.28\batmanx}{0.24\batmany}}
...
...
...
\pgfpathmoveto{\pgfpoint{0 cm}{0.66\batmany}}
\pgfsetfillopacity{1}%
\pgfsetfillcolor{black}%
\pgfusepath{fill,stroke}
\egroup
\pgfsetlinewidth{0.4pt}%
}


Then your text will display at the text anchor.

On regards of maintaing a certain aspect ratio, you should calculate a height and a width. Check which has been given by the user and then calculate the ratio from either one of them, according to any prescribed method. This can be done by simple if and checks, something equivalent with the following, which cat be extended to your needs:

    % Calculate height, this example puts a minimum height of the
% shape dependent on the text contained.
\pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/batman/minimum height}}%
\pgf@y=2\ht\pgfnodeparttextbox%
\ifdim\pgf@y<\pgf@ya%
\pgf@y=\pgf@ya%
\fi%
% do more computational work...
...
% You could do checks of aspect ratio, which I would recommend:
\pgf@ya=.25\pgf@x
\pgf@xa=4\pgf@y%
\ifdim\pgf@yc<\pgf@ya%
\pgf@y=\pgf@ya%
\fi%
\ifdim\pgf@xc<\pgf@xa%
\pgf@x=\pgf@xa%
\fi%


Further I will agree with percusse, you should try to circumvent the transformcm as you strictly do not need it.

You can use:

 \pgftransformshift{\centerpoint}


for your first transformcm and:

 \pgftransformxscale{-1}


for your second transformcm.

I applied the remarks and the code given by zeroth (my host) Firstly, I used a TeX group to limit the action of some transformations, then I remove transformcmand I used the more simpler macros \pgftransformshift{\centerpoint} and \pgftransformxscale{-1}. zeroth gave me the idea to keep a good ratio between height and width and finally a fine answer of Jake gaves me the last key to use inherited shape.

\documentclass[landscape]{scrartcl}
\usepackage{tikz,fullpage}
\usetikzlibrary{shapes}
\begin{document}
\thispagestyle{empty}
\makeatletter
\newdimen\batmanx
\newdimen\batmany

\tikzset{ shape example/.style={
color=black!30,
draw,
fill=yellow!30,
line width=.5cm,
inner xsep=2.5cm,
inner ysep=0.5cm}
}

\pgfdeclareshape{batman}
{
\inheritsavedanchors[from=ellipse]
\inheritanchorborder[from=ellipse]
%
\savedanchor\centerpoint{%
\pgf@x=.5\wd\pgfnodeparttextbox%
\pgf@y=.5\ht\pgfnodeparttextbox%
}
\pgf@x=.5\wd\pgfnodeparttextbox%
\pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/inner xsep}}%
\pgf@x=1.4142136\pgf@x%
\pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/minimum width}}%
\ifdim\pgf@x<.5\pgf@xc%
\pgf@x=.5\pgf@xc%
\fi%
% good ratio
\pgf@y=0.586\pgf@x
\pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/minimum height}}%
\ifdim\pgf@y<.5\pgf@yc%
\pgf@y=.5\pgf@yc%
\fi%
\pgf@x=1.707\pgf@y
\pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}%
\pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}%
}
% Anchors
\inheritanchor[from=ellipse]{center}
\inheritanchor[from=ellipse]{mid}
\inheritanchor[from=ellipse]{base}
\inheritanchor[from=ellipse]{north}
\inheritanchor[from=ellipse]{south}
\inheritanchor[from=ellipse]{west}
\inheritanchor[from=ellipse]{mid west}
\inheritanchor[from=ellipse]{base west}
\inheritanchor[from=ellipse]{north west}
\inheritanchor[from=ellipse]{south west}
\inheritanchor[from=ellipse]{east}
\inheritanchor[from=ellipse]{mid east}
\inheritanchor[from=ellipse]{base east}
\inheritanchor[from=ellipse]{north east}
\inheritanchor[from=ellipse]{south east}
% Background path
\backgroundpath
{
\pgfutil@tempdima=\pgf@x%
\pgfutil@tempdimb=\pgf@y%
\pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}%
\pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}%
\batmanx=\pgfutil@tempdima%
\batmany=\pgfutil@tempdimb%
\pgfpathellipse{\centerpoint}
{\pgfqpoint{\pgfutil@tempdima}{0pt}}
{\pgfqpoint{0pt}{\pgfutil@tempdimb}}%
\pgfsetfillopacity{.5}
\pgfsetfillcolor{yellow}
\pgfusepath{fill,stroke}
\pgfsetlinewidth{0.05\pgfutil@tempdima}%
\pgfutil@tempdima=0.90\pgfutil@tempdima%
\pgfutil@tempdimb=0.90\pgfutil@tempdimb%
\pgfpathellipse{\centerpoint}{\pgfqpoint{\pgfutil@tempdima}{0pt}}
{\pgfqpoint{0pt}{\pgfutil@tempdimb}}%
\pgfusepath{stroke}
\pgfsetlinewidth{0.4 pt}
\bgroup
\pgftransformshift{\centerpoint}
\pgfpathmoveto{\pgfpoint{0 cm}{0.66\batmany}}
\pgfpathlineto{\pgfqpoint{0.07\batmanx}{0.66\batmany}}
\pgfpathlineto{\pgfqpoint{0.14\batmanx}{0.793\batmany}}
\pgfpathcurveto{\pgfqpoint{0.17\batmanx}{0.317\batmany}}
{\pgfqpoint{0.186\batmanx}{0.24\batmany}}
{\pgfqpoint{0.28\batmanx}{0.24\batmany}}
\pgfpathcurveto{\pgfqpoint{0.42\batmanx}{0.24\batmany}}
{\pgfqpoint{0.42\batmanx}{0.537\batmany}}
{\pgfqpoint{0.28\batmanx}{0.756\batmany}}
\pgfpatharcto{0.84\batmanx}{0.80\batmany}{0}{0}{0}
{\pgfqpoint{0.457\batmanx}{-0.683\batmany}}
\pgfpathcurveto{\pgfqpoint{0.56\batmanx}{-0.488\batmany}}
{\pgfqpoint{0.56\batmanx}{0 cm}}
{\pgfqpoint{0.314\batmanx}{-0.44\batmany}}
\pgfpathcurveto{\pgfqpoint{0.214\batmanx}{-0.24\batmany}}
{\pgfqpoint{0.14\batmanx}{-0.24\batmany}}
{\pgfqpoint{0 cm}{-0.78\batmany}}
\pgftransformxscale{-1}
\pgfpathcurveto{\pgfpoint{0.14\batmanx}{-0.24\batmany}}
{\pgfpoint{0.214\batmanx}{-0.24\batmany}}
{\pgfpoint{0.314\batmanx}{-0.44\batmany}}
\pgfpathcurveto{\pgfpoint{0.56\batmanx}{0 cm}}
{\pgfpoint{0.56\batmanx}{-0.488\batmany}}
{\pgfpoint{0.457\batmanx}{-0.683\batmany}}
\pgfpatharcto{0.84\batmanx}{0.80\batmany}{0}{0}{1}
{\pgfpoint{0.28\batmanx}{0.756\batmany}}
\pgfpathcurveto{\pgfpoint{0.42\batmanx}{0.537\batmany}}
{\pgfpoint{0.42\batmanx}{0.24\batmany}}
{\pgfpoint{0.28\batmanx}{0.24\batmany}}%
\pgfpathcurveto{\pgfqpoint{0.186\batmanx}{0.24\batmany}}
{\pgfqpoint{0.17\batmanx}{0.317\batmany}}
{\pgfqpoint{0.14\batmanx}{0.793\batmany}}
\pgfpathlineto{\pgfqpoint{0.07\batmanx}{0.66\batmany}}%
\pgfpathlineto{\pgfpoint{0 cm}{0.66\batmany}}
\pgfsetfillopacity{1}%
\pgfsetfillcolor{black}%
\pgfusepath{fill,stroke}
\egroup
\pgfsetlinewidth{0.4pt}%
}
}

{\Huge
\begin{center}
\begin{tikzpicture}
\node[name=s,shape=batman,minimum height=8cm] {\color{red}Batman\vrule width 1pt height 2cm};
\foreach \anchor/\placement in
{north west/above left, north/above, north east/above right,
west/left, center/above, east/right,
mid west/right, mid/above, mid east/left,
base west/left, base/below, base east/right,
south west/below left, south/below, south east/below right,
text/left, 10/right, 130/above}
\draw[shift=(s.\anchor),color=red] plot[mark=x] coordinates{(0,0)}
node[\placement] {\color{red}\scriptsize\texttt{(s.\anchor)}};
\end{tikzpicture}
\end{center}
}

\newpage
\begin{tikzpicture}
\node[draw,shape=batman,
text=yellow] (A) {\Large Bat me up};

\node[draw,shape=batman,
minimum width=14cm,
text=yellow] (B) at ([yshift=-8cm]A) {\Huge Bat me down  };
\draw [red,ultra thick,double,->](A) --(B);
\end{tikzpicture}
\end{document}


In the next picture I used minimum height=8cm

and for the last one, for the first node I used nothing and for the second one minimum width=14cm.

Todo : perhaps verify some calculations to draw the shape.

-
Thanks you very much percusse and zeroth. The result is very fine. Finally I used TeX's group and for the ratio. I imposed \pgf@y=0.586\pgf@x. It's the initial ratio that I used for the picture. I need to clean the code, some adjustments are no longer needed. I upload the code here : altermundus.com/SandBox – Alain Matthes Mar 13 '12 at 9:55
I found how to use with  \inheritsavedanchors with the excellent answer from Jake here : tex.stackexchange.com/questions/24615/… – Alain Matthes Mar 13 '12 at 10:13
@Altermundus Well I did nothing special, it is your hard work completely. Thank you for creating this monster :) – percusse Mar 13 '12 at 14:18
@percusse you gave good remarks and comments ! – Alain Matthes Mar 13 '12 at 14:45