TikZ 图形上的相对阴影

TikZ 图形上的相对阴影

请欣赏以下来自 Jubobs 的非常漂亮的 TikZ 太阳-地球-月球系统绘图(见这里):

代码

\documentclass{article}

\usepackage{lmodern}
\usepackage{tikz}

\begin{document}

\begin{tikzpicture}[scale=2.5]
  \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.7*\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)}
  }

  % 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[%
    top color=yellow!70,%
    bottom color=red!70,%
    shading angle={45},%
  ]({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,%
    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});
  \shade[%
    top color=black!70,%
    bottom color=black!30,%
    shading angle={45},%
  ]({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}

\end{document}

输出

输出

问题

我非常希望月亮的阴影(即月亮图中最暗的部分)位于太阳的对面,无论地球和月亮相对于太阳的位置如何。有人能帮我做到这一点吗?(我不了解 TikZ,所以这是一个“请帮我做”的问题;抱歉!)

更新

以下是 Tom Bombadil 的回答,使用动画animate包裹。

\documentclass{article}

\usepackage[
  hmargin=2.4cm,
  vmargin=3cm
]{geometry}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{lmodern}
\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}

答案1

基本上,回答这个问题让我回到了我的学生时代,做了一些向量代数;)

代码(动画就绪)

\documentclass[tikz,border=2mm]{standalone}
\usetikzlibrary{calc}
\usepackage{lmodern}

\begin{document}

\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.7*\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)}
  }


%\foreach \x in {1,...,360}
%{
\begin{tikzpicture}[scale=2.5]
%   % changing parameters for animation
%   \pgfmathsetmacro{\Earthangle}{\x} 
%   \pgfmathsetmacro{\Moonangle}{12*\x} 

  % 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,%
    %shading angle={45},%
  ]({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});

    % make a path (moon)-(sun), e.g. the vector pointing from sun to 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}
      % compute 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);

%   %dummy path to keep the size constant for animation 
%   \path (-1.5,-1.5) rectangle (1.5,1.5);
\end{tikzpicture}
%}

\end{document}

输出

在此处输入图片描述

动画片

链接(~750kB)

相关内容