32

Why does rotating a tikzpicture with a circle alter the height and width of the bounding box, and is there a way to not have this effect?

The MWE below yields:

Enter image description here

Code:

\documentclass{article}
\usepackage{tikz}
\usepackage{xstring}

\newcommand*{\DrawBoundingBox}[1][]{%
    \draw [red]
    ([shift={(-5pt,-5pt)}]current bounding box.south west)
    rectangle
    ([shift={(5pt,+5pt)}]current bounding box.north east);

  % https://tex.stackexchange.com/questions/418499/
  %         align-tikzpictures-at-internal-bounding-box-with-text-below-it
  \coordinate (X) at (current bounding box.south);
  \tikzset{baseline={(X)}} % X is the alignment point

    \IfStrEq{#1}{}{}{%
        \node [below, anchor=north,  align=center,
            baseline=0pt, thin, shift only, solid,
        ]
            at (current bounding box.south)
            {#1\strut};
    }%
}

\newcommand*{\MyCircle}[2][]{%
    %% #1 = tikz picture options
    %% #2 = text
    \begin{tikzpicture}
        \draw [fill=yellow!20, draw=black, #1] (0,0) circle (1.0cm);
        \DrawBoundingBox[#2]
    \end{tikzpicture}%
}


\begin{document}
\section{Height Changes}
\noindent
    \MyCircle[fill=green!25]{rotate=0}~%
    \MyCircle[fill=cyan!40, rotate=20]{rotate=20}~%
    \MyCircle[fill=orange!40, rotate=60]{rotate=60}%

\section{Width Changes}
\par\noindent\MyCircle[fill=green!25]{rotate=0}%
\par\noindent\MyCircle[fill=cyan!40, rotate=20]{rotate=20}%
\end{document}
  • 6
    The control points of the Bézier curves are taken into account and a circle is composed of 4 Bézier curves. – Paul Gaborit Apr 13 '18 at 5:15
  • @PaulGaborit PDF has has a low level circle command, no ? Why TikZ is using Bézier approximation here ? – Kpym Apr 13 '18 at 13:35
  • 2
    @Kpym PDF does not provide a circle command... – Paul Gaborit Apr 13 '18 at 14:14
  • @PaulGaborit really ? PS has arc command, and I thought that PDF has it too ... strange. – Kpym Apr 13 '18 at 14:20
  • 2
    @Kpym Internally, the arc command uses Bézier curves (at least in ghostscript). ;-) – Paul Gaborit Apr 13 '18 at 14:50
37

A circle is drawn by four Bézier curves. The control points of the Bézier curves are taken into account to compute the bounding box:

\documentclass[tikz]{standalone}
\usetikzlibrary{decorations.pathreplacing}
\begin{document}
\begin{tikzpicture}[>=stealth, every node/.style={midway, sloped, font=\tiny},
  decoration={show path construction,
    moveto code={},
    lineto code={},
    curveto code={
      \fill[red] (\tikzinputsegmentsupporta) circle(.5pt);
      \fill[red] (\tikzinputsegmentsupportb) circle(.5pt);
      \fill[blue] (\tikzinputsegmentfirst) circle(.5pt);
      \fill[blue] (\tikzinputsegmentlast) circle(.5pt);
      \draw[blue,->] (\tikzinputsegmentfirst) -- (\tikzinputsegmentsupporta);
      \draw[blue,->] (\tikzinputsegmentlast) -- (\tikzinputsegmentsupportb);
      \draw [black] (\tikzinputsegmentfirst) .. controls
      (\tikzinputsegmentsupporta) and (\tikzinputsegmentsupportb)
      ..(\tikzinputsegmentlast);
    },
    closepath code={},
  }]
  \draw [help lines] grid (6,3);
  \begin{scope}[local bounding box=lbb]
    \path [decorate,rotate around={0:(1.5,1.5)}] (1.5,1.5) circle(1);
    \draw[red] (lbb.north west) rectangle (lbb.south east);
  \end{scope}
  \begin{scope}[local bounding box=lbb]
    \path [decorate,rotate around={30:(4.5,1.5)}] (4.5,1.5) circle(1);
    \draw[red] (lbb.north west) rectangle (lbb.south east);
  \end{scope}
\end{tikzpicture}
\end{document}

enter image description here

  • 1
    Congratulations!! I was just looking up show path constructions. – user121799 Apr 13 '18 at 5:47
  • 1
    Is it a bug, that Bézier control points are taken into account for the bounding box? If not, do you know the reason behind this decision? – T. Verron Apr 13 '18 at 9:12
  • 5
    @T.Verron It's not a bug (see p.124, pgfmanual, v3.0.1a)! The reason is undoubtedly efficiency. To work around this feature, you can try my answer to question tikz bounding box / cropping: too much space for curves. – Paul Gaborit Apr 13 '18 at 9:41
  • @PaulGaborit and Marmot congratulations for excellent code and Grill for excellent answer. +1 – Sebastiano Apr 13 '18 at 10:11
17

I guess that you are using not the appropriate means to rotate the circles. If you use transform canvas instead, none of the issues arises. UPDATE I forgot to put transform canvas to the third circle.

\documentclass{article}
\usepackage{tikz}
\usepackage{xstring}

\newcommand*{\DrawBoundingBox}[1][]{%
    \draw [red]
    ([shift={(-5pt,-5pt)}]current bounding box.south west)
    rectangle
    ([shift={(5pt,+5pt)}]current bounding box.north east);

  % https://tex.stackexchange.com/questions/418499/
  %         align-tikzpictures-at-internal-bounding-box-with-text-below-it
  \coordinate (X) at (current bounding box.south);
  \tikzset{baseline={(X)}} % X is the alignment point

    \IfStrEq{#1}{}{}{% 
        \node [below, anchor=north,  align=center, 
            baseline=0pt, thin, shift only, solid,
        ] 
            at (current bounding box.south)
            {#1\strut};
    }%
}

\newcommand*{\MyCircle}[2][]{%
    %% #1 = tikz picture options
    %% #2 = text
    \begin{tikzpicture}
        \draw [fill=yellow!20, draw=black, #1] (0,0) circle (1.0cm);
        \draw [#1] (-1,0) -- (1,0); % added to see that the transformatio does
                                    % something
        \DrawBoundingBox[#2]
    \end{tikzpicture}%
}

\begin{document}
\section{No Height Changes}
\noindent
    \MyCircle[fill=green!25]{rotate=0}~%
    \MyCircle[fill=cyan!40, transform canvas={rotate=20}]{rotate=20}~%
    \MyCircle[fill=orange!40, transform canvas={rotate=60}]{rotate=60}%

\section{No Width Changes}
\par\noindent\MyCircle[fill=green!25]{rotate=0}%
\par\noindent\MyCircle[fill=cyan!40, transform canvas={rotate=20}]{rotate=20}%

\end{document}

enter image description here

(I added a line in order to show that this transformation does indeed rotate the circles, which is hard to see otherwise ;-)

  • 2
    So, what is the difference between rotate=x and transform canvas={rotate=x} and when would one want to use rotate=x instead of transform canvas={rotate=x}? – Peter Grill Apr 13 '18 at 5:08
  • 1
    @PeterGrill The height change is because I forgot to put transform canvas in the third circle. – user121799 Apr 13 '18 at 5:42
  • 1
    @Tarass now both do, I just forgot transform canvas there. – user121799 Apr 13 '18 at 5:46
  • 11
    +1 people have been trying to square the circle a long time. – David Carlisle Apr 13 '18 at 7:51
  • 5
    transform canvas doesn't update the bounding box that's why. But usually other funny things happen if you don't use it carefully. – percusse Apr 13 '18 at 9:07

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.