当 TikZ 中线条出现在另一个对象后面时格式化线条属性

当 TikZ 中线条出现在另一个对象后面时格式化线条属性

我正在使用该tikz-3dplot-circleofsphere包使用 tikz-3dplot 绘制球体的圆圈。考虑文档中的以下 MWE:

\documentclass{standalone}
\usepackage{tikz-3dplot-circleofsphere}
\begin{document}
  \centering
  \def\r{3}
  \tdplotsetmaincoords{60}{125}
  \begin{tikzpicture}[tdplot_main_coords]
    \draw[tdplot_screen_coords,thin,black!30] (0,0,0) circle (\r);
    \foreach \a in {-75,-60,...,75}
      {\tdplotCsDrawLatCircle[thin,black!29]{\r}{\a}}
    \foreach \a in {0,15,...,165}
      {\tdplotCsDrawLonCircle[thin,black!29]{\r}{\a}}

    \tdplotCsDrawGreatCircle[red,thick,/.style={opacity=0}]{4}{105}{-23.5}
  \end{tikzpicture}
\end{document}

生成以下图像

图像

如何才能让红色虚线显示出来仅有的在球体后面。也就是说,在这种情况下,我选择的红色圆圈的半径大于球体的半径。

答案1

在此处输入图片描述

更新后的版本

我的回答不是最简短的,也许我使用的某些元素已经在库中定义;我不知道。

绘图分为三个步骤:1)3D 视角,2)球体,3)圆(球体上有两圆,第三个圆位于球体小圆的平面上,圆心相同)。现在球体也是通过经线和纬线构造的,也就是圆。

每个圆圈的构建都是为了pic拥有更清晰的代码。

通过计算观察者向量和点的位置向量的内积来检测球面上的隐藏点。请参阅函数opacityOnS

通过内积和范数比较的混合来检测球体内部或球体后面的点。参见函数 behindS

这三个步骤中使用了有关元素的更多解释。

  1. 在 TikZ 中,坐标平面对应于屏幕和盎司 指向屏幕外,朝向观看者。

  2. \tox观察者由、定义的向量表示\toy,并\toz通过带有参数经度和纬度的键引入view。当两者都为零时,向量为(0,0,1)

  3. 各种圆圈具有与pic对象类似的代码。我更喜欢根据所需参数的数量重新定义它们。但所有这些函数都会使文件变得tikZSphere.sty相当长。

  4. 不透明度及其对立面通过键unseenS和来控制seenS

  5. 球体半径通过 键控制radiusS。默认值为 1。

评论。我没有解决球体上两个圆如何相交的问题。我设想了一个解决方案,但它很笨拙;我需要将圆(或圆的一部分)定义为整个元素(通过命令\path),以便能够name path 在之后使用该选项。也许可以进行一些改进,就像用户121799使用 TikZ 在球体上嵌入图形? 会很有用,但是它们超出了我的知识范围。

代码

\documentclass[11pt, border=1.5cm]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc, math}
\usepackage{tikZSphere}

\begin{document}

\begin{tikzpicture}[view={-35}{27}, radiusS=2.5]
  % meridians and parallels
  \begin{scope}[black!50, seenS=.7, unseenS=.25, very thin]
    \foreach \l in {15, 30, ..., 360}{ \path pic {meridian={\l}}; }
    \foreach \l in {-75, -60, ..., 75}{ \path pic {parallel={\l}}; }
  \end{scope}
  
  \path[unseenS=.32] pic[magenta, thick] {bigCircleOnS={80:70}};
  \path[unseenS=.32] pic[blue, thick] {circleOnS={80:70 at distance -.85}};
  \path[unseenS=.25] pic[blue, thick] {circle3d={80:70:4 at distance -.85}};
  
  \path[seenS=.9] pic[orange] {axesForS={1.75}};
\end{tikzpicture}
\end{document}

以及文件tikZsphere.sty

\tikzset{%
  view/.style 2 args={%
    z={({-sin(#1)}, {-cos(#1)*sin(#2)})},
    x={({cos(#1)}, {-sin(#1)*sin(#2)})},
    y={(0, {cos(#2)})},
    evaluate={%
      \tox={sin(#1)*cos(#2)};
      \toy={sin(#2)};
      \toz={cos(#1)*cos(#2)};
    }
  }
}

\pgfkeys{/tikz/.cd,
  seenS/.store in=\seenS,
  seenS=1
}
\pgfkeys{/tikz/.cd,
  unseenS/.store in=\unseenS,
  unseenS=.2
}
\pgfkeys{/tikz/.cd,
  radiusS/.store in=\radiusS,
  radiusS=1
}
\pgfkeys{/tikz/.cd,
  samplesCOnS/.store in=\samplesCOnS,
  samplesCOnS=36
}

\tikzmath{%  opacities and samples
  function opacityOnS(\px, \py, \pz) {%
    \res = \px*\tox + \py*\toy + \pz*\toz; % inner product of posV and obsrerver
    if \res>0 then {return \seenS;} else {return \unseenS;};
  };
  function behindS(\px, \py, \pz, \r) {%
    \sppo = \px*\tox + \py*\toy + \pz*\toz; % inner product of pos.vect and obsrerver
    \npsq = \px*\px + \py*\py + \pz*\pz; % norm of pos.vect^2
    \nvsq = \npsq -\sppo*\sppo; % norm of pos,vect's projection^2
    if \sppo<0 then {%
      if \nvsq -\r*\r<.05 then {return \unseenS;} else {return \seenS;};
    } else {%
      if \npsq -\r*\r<.05 then {return \unseenS;} else {return \seenS;};
    };
  };
  function stepsCOnS(\r, \k) {return ceil(\r*(\k-6)/\radiusS+6);};
}

\tikzset{
  pics/axesForS/.style={%
    code={
      \tikzmath{%
        real \b;
        \b = {#1*\radiusS};
      }
      \foreach \i in {.1, .2, ..., \b}{%
        \draw[opacity={behindS(\i-.05, 0, 0, \radiusS)}] (\i-.1, 0, 0) -- (\i, 0, 0);
        \path (\b, 0, 0) ++(.4, 0, 0) node[scale=.9] {$x$};
        \draw[opacity={behindS(0, \i-.05, 0, \radiusS)}] (0, \i-.1, 0) -- (0, \i, 0);
        \path (0, \b, 0) ++(0, .4, 0) node[scale=.9] {$y$};
        \draw[opacity={behindS(0, 0, \i-.05, \radiusS)}] (0, 0, \i-.1) -- (0, 0, \i);
        \path (0, 0, \b) ++(0, 0, .4) node[scale=.9] {$z$};
      }
    }
  },
  pics/meridian/.style = {% longitude, number of points
    code={
      \tikzmath{
        real \pax, \pay, \paz, \pbx, \pby, \pbz, \cosl, \sinl;
        integer \N;
        \cosl = \radiusS*cos(#1);
        \sinl = \radiusS*sin(#1);
        \N = int(\samplesCOnS/2);
      }
      \foreach \k [evaluate=\k as \bz using {180*(\k/\N -.5)},
      evaluate=\k as \az using {180*((\k-1)/\N -.5)}] in {1, ..., \N}{
        \tikzmath{
          \pax = \cosl*cos(\az);
          \pay = \radiusS*sin(\az);
          \paz = \sinl*cos(\az);
          \pbx = \cosl*cos(\bz);
          \pby = \radiusS*sin(\bz);
          \pbz = \sinl*cos(\bz);
        }
        \draw[opacity={opacityOnS(\pax, \pay, \paz)}]
        (\pax, \pay, \paz) -- (\pbx, \pby, \pbz);
      }
    }
  },
  pics/parallel/.style = {% latitude, number of points
    code={
      \tikzmath{
        integer \N;
        real \pax, \pay, \paz, \pbx, \pby, \pbz, \cosl, \sinl;
        \cosl = \radiusS*cos(#1);
        \sinl = \radiusS*sin(#1);
        \N = stepsCOnS(\radiusS*cos(#1), \samplesCOnS);
      }
      \foreach \j [evaluate=\j as \by using {360*(\j/\N)},
      evaluate=\j as \ay using {360*((\j-1)/\N)}] in {1, ..., \N}{
        \tikzmath{
          \pax = cos(\ay)*\cosl;
          \paz = sin(\ay)*\cosl;
          \pbx = cos(\by)*\cosl;
          \pbz = sin(\by)*\cosl;
        }
        \draw[opacity={opacityOnS(\pbx, \sinl, \pbz)}]
        (\pax, \sinl, \paz) -- (\pbx, \sinl, \pbz);
      }
    }
  }
}


%%%% other circles

\tikzmath{
  function Cx(\t) {
    return \r*\ux*cos(\t) + \r*\vx*sin(\t) + \d*\nx;
  };  
  function Cy(\t) {
    return \r*\vy*sin(\t) + \d*\ny;
  };  
  function Cz(\t) {
    return \r*\uz*cos(\t) + \r*\vz*sin(\t) + \d*\nz;
  };
}
\tikzset{
  pics/circle3d/.style args={#1:#2:#3 at distance #4}{% 
    code={
      \tikzmath{
        integer \N;
        \N = {stepsCOnS(\radiusS, 3*\samplesCOnS)};
        \nx = cos(#2)*sin(#1);
        \ny = sin(#2);
        \nz = cos(#2)*cos(#1);
        \ux = cos(#1);
        \uz = -sin(#1);
        \vx = -sin(#2)*sin(#1);
        \vy = cos(#2);
        \vz = -sin(#2)*cos(#1);
        \d = #4;
        \r = #3;
      }
      \foreach \j [evaluate=\j as \t using {360*(\j/\N)},
      evaluate=\j as \s using {360*((\j-1)/\N)}] in {1, ..., \N}{
        \tikzmath{
          \pax = Cx(\s); 
          \pay = Cy(\s);
          \paz = Cz(\s);
          \pbx = Cx(\t);
          \pby = Cy(\t);
          \pbz = Cz(\t);
        }
        \draw[opacity={%
          behindS((\pax+\pbx)/2, (\pay+\pby)/2, (\paz+\pbz)/2, \radiusS)}]
        (\pax, \pay, \paz) -- (\pbx, \pby, \pbz);
      }
    }    
  },
  pics/bigCircleOnS/.style args={#1:#2}{% 
    code={
      \tikzmath{
        integer \N;
        \N = {stepsCOnS(\radiusS, \samplesCOnS)};
        \nx = cos(#2)*sin(#1);
        \ny = sin(#2);
        \nz = cos(#2)*cos(#1);
        \ux = cos(#1);
        \uz = -sin(#1);
        \vx = -sin(#2)*sin(#1);
        \vy = cos(#2);
        \vz = -sin(#2)*cos(#1);
        \d = 0;
        \r = \radiusS;
      }
      \foreach \j [evaluate=\j as \t using {360*(\j/\N)},
      evaluate=\j as \s using {360*((\j-1)/\N)}] in {1, ..., \N}{
        \tikzmath{
          \pax = Cx(\s); 
          \pay = Cy(\s);
          \paz = Cz(\s);
          \pbx = Cx(\t);
          \pby = Cy(\t);
          \pbz = Cz(\t);
        }
        \draw[opacity={opacityOnS((\pax+\pbx)/2, (\pay+\pby)/2, (\paz+\pbz)/2)}]
        (\pax, \pay, \paz) -- (\pbx, \pby, \pbz);
      }
    }    
  },
  pics/bigCircleOnS/.default={0:90},
  pics/circleOnS/.style args={#1:#2 at distance#3}{% 
    code={
      \tikzmath{
        integer \N;
        \N = {stepsCOnS(\radiusS, \samplesCOnS)};
        \nx = cos(#2)*sin(#1);
        \ny = sin(#2);
        \nz = cos(#2)*cos(#1);
        \ux = cos(#1);
        \uz = -sin(#1);
        \vx = -sin(#2)*sin(#1);
        \vy = cos(#2);
        \vz = -sin(#2)*cos(#1);
        \d = #3;
        \r = sqrt(\radiusS*\radiusS-\d*\d);
      }
      \foreach \j [evaluate=\j as \t using {360*(\j/\N)},
      evaluate=\j as \s using {360*((\j-1)/\N)}] in {1, ..., \N}{
        \tikzmath{
          \pax = Cx(\s); 
          \pay = Cy(\s);
          \paz = Cz(\s);
          \pbx = Cx(\t);
          \pby = Cy(\t);
          \pbz = Cz(\t);
        }
        \draw[opacity={opacityOnS((\pax+\pbx)/2, (\pay+\pby)/2, (\paz+\pbz)/2)}]
        (\pax, \pay, \paz) -- (\pbx, \pby, \pbz);
      }
    }    
  }

答案初始版本中的图片 在此处输入图片描述

答案2

这只是为了获取球体后面的虚线。我不知道从哪里来的,tikz-3dplot-circleofsphere所以我无法用它测试。相反,我画了一个球体的轮廓(它是一个椭圆形)并使用它。

这使用spath3库在轨道路径与边界路径的相交处进行分割,然后以不同的风格渲染各个部分。

轨道在经过边界圆后分裂

\documentclass{article}
%\url{https://tex.stackexchange.com/q/551460/86}
\usepackage{tikz}
\usetikzlibrary{spath3, intersections}

\begin{document}

\begin{tikzpicture}

\path[
  rotate=45,
  spath/save=boundary
] (0,0) circle[
  x radius={3*sqrt(1 + 2*.385^2)},
  y radius=3
];

\path[
  spath/save=orbital,
  y = {(1,0,0)},
  x = {(0,0,1)}
] (0,0) circle[radius=5];

\tikzset{
  spath/remove empty components={orbital},
  spath/split at intersections with={orbital}{boundary},
  spath/join components={orbital}{1,4},
  spath/get components of={orbital}\cpts
}

\draw[
  red,
  ultra thick,
  dashed,
  spath/use=\getComponentOf\cpts{1}
];

\draw[
  blue,
  ultra thick,
  spath/use=boundary];

\draw[
  red,
  ultra thick,
  spath/use=\getComponentOf\cpts{2}
];

\end{tikzpicture}
\end{document}

相关内容