
Updated version
My answer is not the shortest and maybe some of the elements that I
use are already defined in a library; I am not aware of.
The drawing is made in three steps: 1) the 3D point of view, 2) the
sphere and 3) the circles (two on the sphere and a third one lying in
the plane of the small circle on the sphere and having the same
center). Now the sphere is constructed through meridians and
parallels, i.e. circles, too.
Every circle is constructed as a pic
to have a cleaner code.
The hidden points on the sphere are detected by computing the inner
product between the viewer vector and the position vector of the
point. See the function opacityOnS
.
The points inside the sphere or behind the sphere are detected by a
mixture of inner products and norm comparisons. See the function
behindS
.
Some more explanations about the elements are used in these three
steps.
In TikZ, the coordinate plane Oxy corresponds to the screen and Oz
points outside the screen, towards the viewer.
The observer is represented by the vector defined by \tox
, \toy
,
and \toz
introduced through the key view
with arguments the
longitude and the latitude. When both are zero, the vector is (0,0,1).
The various circles have similar codes as pic
objects. I
preferred to redefine them depending on the number of arguments
needed. But all these functions make the file tikZSphere.sty
rather long.
The opacity and its opposite are
controlled through the keys unseenS
and seenS
.
The sphere radius is controlled through the key radiusS
. The default value is 1.
Remark. I don't address the question regarding how two circles on
the sphere intersect. I imagine a solution, but it is clumsy; I need
to define the circles (or parts of them) as whole elements (through
the \path
command) to be able to use the option name path
afterward. Maybe some developments as those proposed by user121799
in
Embed a graph on a Sphere with TikZ?
would be useful, but they are above my knowledge.
The code
\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}
And the file 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);
}
}
}
The image from the initial version of the answer
