3

Consider the following code (more or less this):

\documentclass{article}

\usepackage{lmodern}
\usepackage[
  hmargin=2.4cm,
  vmargin=3cm
]{geometry}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{animate}


\def\rS{0.3}                             % The Sun's radius.
\def\Earthangle{30}                      % Angle with respect to horizontal.
\def\rE{0.1}                             % The Earth's radius.
                                         % Major radius of the Earth's elliptical orbit = 1.
\def\eE{0.25}                            % Excentricity of the Earth's elliptical orbit.
\pgfmathsetmacro\bE{sqrt(1 - \eE^2)}     % Minor radius of the Earth's elliptical orbit.
\def\Moonangle{-45}                      % Angle with respect to horizontal.
\pgfmathsetmacro\rM{0.5*\rE}             % The Moon's radius.
\pgfmathsetmacro\aM{2.5*\rE}             % Major radius of the Moon's elliptical orbit.
\def\eM{0.4}                             % Excentricity of the Earth's elliptical orbit.
\pgfmathsetmacro\bM{\aM*sqrt(1 - \eM^2)} % Minor radius of the Moon's elliptical orbit.
\def\offsetM{30}                         % Angle offset between the major axes of the Earth's and the Moon's orbits.

% This function computes the direction in which light hits the Earth.
\pgfmathdeclarefunction{f}{1}{%
  \pgfmathparse{%
    (-\eE + cos(#1) <  0) * (180 + atan(\bE*sin(#1)/(-\eE + cos(#1))))
    +
    (-\eE + cos(#1) >= 0) * atan(\bE*sin(#1)/(-\eE + cos(#1)))
  }
}

% This function computes the distance between the Earth and the Sun,
% which is used to calculate the varying radiation intensity on the Earth.
\pgfmathdeclarefunction{d}{1}{%
  \pgfmathparse{sqrt((-\eE + cos(#1))^2 + (\bE*sin(#1))^2)}
}

\def\animation#1{%
\begin{tikzpicture}[scale=5]
   % Changing parameters for animation.
   \pgfmathsetmacro{\Earthangle}{\iA} 
   \pgfmathsetmacro{\Moonangle}{12*\iA} 

  % Draw the elliptical path of the Earth.
  \draw[thin, color=gray] (0, 0) ellipse (1 and \bE);

  % Draw the Sun at the right-hand-side focus.
  \shade[%
    inner color=yellow!70,%
    outer color=orange!70,%
  ]({sqrt(1 - \bE^2)}, 0) circle (\rS);

  % Draw the Earth at \Earthangle.
  \pgfmathsetmacro{\radiation}{100*(1 - \eE)/d(\Earthangle)^2}
  \colorlet{Earthlight}{yellow!\radiation!blue}
  \shade[%
    top color=Earthlight,%
    bottom color=blue!75!black,%
    shading angle={90 + f(\Earthangle)},%
  ]({cos(\Earthangle)}, {\bE*sin(\Earthangle)}) circle (\rE);
  %\draw ({cos(\Earthangle)}, {\bE*sin(\Earthangle) - \rE}) node[below] {Earth};

  % Draw the Moon's (circular) orbit and the Moon at \Moonangle.
  \draw[%
    thin,%
    color=gray,%
    rotate around={{\offsetM}:({cos(\Earthangle)}, {\bE*sin(\Earthangle)})}%
  ]({cos(\Earthangle)}, {\bE*sin(\Earthangle)}) ellipse ({\aM} and {\bM});

  % Makes a path (Moon)-(Sun), e.g., the vector pointing from the Sun to the Moon.
  \path ($({cos(\Earthangle) + \aM*cos(\Moonangle)*cos(\offsetM)
            - \bM*sin(\Moonangle)*sin(\offsetM)},%
           {\bE*sin(\Earthangle) + \aM*cos(\Moonangle)*sin(\offsetM)
            + \bM*sin(\Moonangle)*cos(\offsetM)}) - ({sqrt(1 - \bE^2)}, 0)$);
  % Get the components of that vector.
  \pgfgetlastxy{\myx}{\myy}
  % Computing the inclination angle.
  \pgfmathsetmacro{\moonshadinangleangle}{-90 + atan2(\myx, \myy)}

  \shade[%
    top color=black!90,%
    bottom color=black!10,%
    shading angle=\moonshadinangleangle,%
  ]({cos(\Earthangle) + \aM*cos(\Moonangle)*cos(\offsetM)
     - \bM*sin(\Moonangle)*sin(\offsetM)},%
    {\bE*sin(\Earthangle) + \aM*cos(\Moonangle)*sin(\offsetM)
     + \bM*sin(\Moonangle)*cos(\offsetM)}) circle (\rM);
\end{tikzpicture}
}

\pagestyle{empty}

\begin{document}

\begin{figure}[htbp]
\centering
 \begin{animateinline}[
   poster=first,
   controls,
   loop
 ]{10}
  \multiframe{360}{iA=1+1}{\animation{\iA}}
 \end{animateinline}
\end{figure}

\end{document}

output

When I run the animation, the Earth's orbit around the Sun is not constant. How do I solve this?

Update

Here is what I ended up with:

\documentclass{article}

\usepackage{lmodern}
\usepackage[
  hmargin=2.4cm,
  vmargin=3cm
]{geometry}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{animate}


\def\rS{0.3}                             % The Sun's radius.
\def\Earthangle{30}                      % Angle with respect to horizontal.
\def\rE{0.1}                             % The Earth's radius.
                                         % Major radius of the Earth's elliptical orbit = 1.
\def\eE{0.25}                            % Excentricity of the Earth's elliptical orbit.
\pgfmathsetmacro\bE{sqrt(1 - \eE^2)}     % Minor radius of the Earth's elliptical orbit.
\def\Moonangle{-45}                      % Angle with respect to horizontal.
\pgfmathsetmacro\rM{0.5*\rE}             % The Moon's radius.
\pgfmathsetmacro\aM{2.5*\rE}             % Major radius of the Moon's elliptical orbit.
\def\eM{0.4}                             % Excentricity of the Earth's elliptical orbit.
\pgfmathsetmacro\bM{\aM*sqrt(1 - \eM^2)} % Minor radius of the Moon's elliptical orbit.
\def\offsetM{30}                         % Angle offset between the major axes of the Earth's and the Moon's orbits.

% This function computes the direction in which light hits the Earth.
\pgfmathdeclarefunction{f}{1}{%
  \pgfmathparse{%
    (-\eE + cos(#1) <  0) * (180 + atan(\bE*sin(#1)/(-\eE + cos(#1))))
    +
    (-\eE + cos(#1) >= 0) * atan(\bE*sin(#1)/(-\eE + cos(#1)))
  }
}

% This function computes the distance between the Earth and the Sun,
% which is used to calculate the varying radiation intensity on the Earth.
\pgfmathdeclarefunction{d}{1}{%
  \pgfmathparse{sqrt((-\eE + cos(#1))^2 + (\bE*sin(#1))^2)}
}

\def\animation#1{%
\begin{tikzpicture}[scale=5]
 \useasboundingbox (-1.28,-1.24) rectangle (1.30,1.28);
   % Changing parameters for animation.
   \pgfmathsetmacro{\Earthangle}{#1} 
   \pgfmathsetmacro{\Moonangle}{12*#1} 

  % Draw the elliptical path of the Earth.
  \draw[thin, color=gray] (0, 0) ellipse (1 and \bE);

  % Draw the Sun at the right-hand-side focus.
  \shade[%
    inner color=yellow!70,
    outer color=orange!70
  ]({sqrt(1 - \bE^2)}, 0) circle (\rS);

  % Draw the Earth at \Earthangle.
  \pgfmathsetmacro{\radiation}{100*(1 - \eE)/d(\Earthangle)^2}
  \colorlet{Earthlight}{yellow!\radiation!blue}
  \shade[%
    top color=Earthlight,%
    bottom color=blue!75!black,%
    shading angle={90 + f(\Earthangle)},%
  ]({cos(\Earthangle)}, {\bE*sin(\Earthangle)}) circle (\rE);
  %\draw ({cos(\Earthangle)}, {\bE*sin(\Earthangle) - \rE}) node[below] {Earth};

  % Draw the Moon's (circular) orbit and the Moon at \Moonangle.
  \draw[%
    thin,%
    color=gray,%
    rotate around={{\offsetM}:({cos(\Earthangle)}, {\bE*sin(\Earthangle)})}%
  ]({cos(\Earthangle)}, {\bE*sin(\Earthangle)}) ellipse ({\aM} and {\bM});

  % Makes a path (Moon)-(Sun), e.g., the vector pointing from the Sun to the Moon.
  \path ($({cos(\Earthangle) + \aM*cos(\Moonangle)*cos(\offsetM)
            - \bM*sin(\Moonangle)*sin(\offsetM)},%
           {\bE*sin(\Earthangle) + \aM*cos(\Moonangle)*sin(\offsetM)
            + \bM*sin(\Moonangle)*cos(\offsetM)}) - ({sqrt(1 - \bE^2)}, 0)$);
  % Get the components of that vector.
  \pgfgetlastxy{\myx}{\myy}
  % Computing the inclination angle.
  \pgfmathsetmacro{\moonshadinangleangle}{-90 + atan2(\myx, \myy)}

  \shade[%
    top color=black!90,%
    bottom color=black!10,%
    shading angle=\moonshadinangleangle,%
  ]({cos(\Earthangle) + \aM*cos(\Moonangle)*cos(\offsetM)
     - \bM*sin(\Moonangle)*sin(\offsetM)},%
    {\bE*sin(\Earthangle) + \aM*cos(\Moonangle)*sin(\offsetM)
     + \bM*sin(\Moonangle)*cos(\offsetM)}) circle (\rM);
\end{tikzpicture}
}

\pagestyle{empty}

\begin{document}

\begin{figure}[htbp]
\centering
 \begin{animateinline}[poster=first,controls,loop]{10}
  \multiframe{360}{iA=1+1}{\animation{\iA}}
 \end{animateinline}
\end{figure}

\end{document}
3
  • 3
    Mmh, scrambled eggs! The problem is that animate will put all frames in the box of the size of the first frame. You need to establish a bounding box in the TikZ picture that will encompass all frames, or you overlay the earth, the moon and the moon’s path around the earth (which will have them protrude outside of the animation’s box). Take a look at page 8 of the manual: “A short note on the tikzpicture environment: …” and the \useasboundingbox example (you can also just add any path at the end). Oct 23, 2013 at 14:29
  • @Qrrbrbirlbel I will try and fiddle around with it. If you will make as answer, I'll accept it. (Btw. you are more than welcome to come of with an actual bounding box implementation for me; I'm not quite sure I understand how to use the instructions in the manual, but I will try. :() Oct 23, 2013 at 14:37
  • 1
    I have added an answer and gave a few points regarding the coordinate’s of the bounding box (calculate it or guess it). By the way, you are defining \animation with one argument which you correctly pass but in the definition itself you are using \iA instead of #1. Oct 23, 2013 at 15:28

1 Answer 1

8

The problem is that animate will put all frames in the box of the size of the first frame. You need to establish a bounding box in the TikZ picture that will encompass all frames.

This has also been discussed in the animate manual on page 8:

A short note on the tikzpicture environment: Unlike pspicture, the tikzpicture environment is able to determine its size from the graphical objects it encloses. However, this may result in differently sized frames of a sequence, depending on the size and position of the graphical objects. Thus, in order to ensure that all frames of the sequence be displayed at the same scale in the animation widget, a common bounding box should be shared by the frames. A bounding box can be provided by means of an invisible rectangle object:

begin={
  \begin{tikzpicture}
  \useasboundingbox (... , ...) rectangle (... , ...);
},
end={\end{tikzpicture}}

Now, one could calculate the minimum size of the bounding box by all the variables you have: the path of the Earth, the path of the Moon and the Moon’s radius should make the smallest bounding box but you actually can subtract from that something because the Moon’s path is rotated and Sun, Earth and Moon aren’t necessarily aligned in one straight line at those crucial points in the animation.

I just added

\useasboundingbox (-1.3, -1.25) rectangle (1.3, 1.25);

and it looks good to me. The path used with the use as bounding box option can be any path and you can also draw it (so that you can see where rectangle actually is).

2
  • 1
    I found the parameters \useasboundingbox (-1.28,-1.24) rectangle (1.30,1.28); to be good. Now the problem is that I'm not sure where to put the actual code; is it just after rectangle (... , ...), i.e., inside begin={...},? (That would be line between line 3 and 4 above.) Oct 23, 2013 at 15:30
  • @SvendTveskæg begin and end are keys from animate which can be used to define common code for every frame but you don’t use that. Either way, \useasboundingbox has to be placed inside the TikZ picture. You can place it at the start or at the end but there you will need to issue \pgfresetboundingbox. use as bounding box acts like every other path too only that \tikzset{overlay} (kind of) will be set for every following path. As long as you don’t have elements of this rectangle you could just use \path. Oct 23, 2013 at 15:37

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.