Without the extremely cool macros by John Kormylo and the very helpful answer by Torbjørn T. I would not have been able to come this far. My ultimate aim is to make it easy to fake 3D spheres with TikZ. This already works quite well, but I wanted to try a different, arguably more direct approach to draw the relevant objects. Here is my MWE.
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shadings}
% parametrizations from https://tex.stackexchange.com/a/410379/121799
\newcommand{\latitudearc}[4]{% #1=label (optional), #2=latitude
%#3 start angle #4 end angle
\pgfextra{\pgfmathsetmacro{\RX}{\RadiusSphere*cos(#2)} % from https://tex.stackexchange.com/a/410567/121799
\global\let\RX=\RX % from https://tex.stackexchange.com/a/352269/121799
\pgfmathsetmacro{\RY}{\RX*sin(\Clat)}%
\global\let\RY=\RY
\pgfmathsetmacro{\CY}{\RadiusSphere*sin(#2)*cos(\Clat)}
\global\let\CY=\CY
\pgfmathsetmacro{\Xend}{\RX*cos(#4)}
\global\let\Xend=\Xend
\pgfmathsetmacro{\Yend}{\CY+\RY*sin(#4)}
\global\let\Yend=\Yend}%
plot [domain=#3:#4,smooth,#1] ({\RX*cos(\noexpand\x)},{\CY+\RY*sin(\noexpand\x)})
}
% compute ellipse rotation=\ROT, xradius=\RX, arc angle at equator=\LAT
\newcommand{\longitudearc}[4]{% #1=label (optional), #2=longitude
%#3 start angle #4 end angle
\pgfextra{\pgfmathsetmacro{\ROT}{atan2(sin(\Clat)*sin(#2-\Clong),cos(#2-\Clong))}% alpha
\global\let\ROT=\ROT
\pgfmathsetmacro{\LAT}{asin(cos(\Clat)*cos(\ROT))}% north pole theta_n
\global\let\LAT=\LAT
\pgfmathsetmacro{\RX}{\RadiusSphere*tan(\LAT)*tan(\ROT)}% r_x
\global\let\RX=\RX
\pgfmathsetmacro{\DELTAX}{-90+\LAT}
\global\let\DELTAX=\DELTAX
\pgfmathsetmacro{\Xend}{\RX*cos(\ROT)*cos(#4+\DELTAX)-\RadiusSphere*sin(\ROT)*sin(#4+\DELTAX)}
\global\let\Xend=\Xend
\pgfmathsetmacro{\Yend}{\RadiusSphere*cos(\ROT)*sin(#4+\DELTAX)+\RX*sin(\ROT)*cos(#4+\DELTAX)}
\global\let\Yend=\Yend
}
plot[domain=#3:#4,smooth,#1]({\RX*cos(\ROT)*cos(\noexpand\x+\DELTAX)-\RadiusSphere*sin(\ROT)*sin(\noexpand\x+\DELTAX)},
{\RadiusSphere*cos(\ROT)*sin(\noexpand\x+\DELTAX)+\RX*sin(\ROT)*cos(\noexpand\x+\DELTAX)})
}
\newcommand{\hotspot}[3]{% #1=label (optional), #3=latitude, #2=longitude
\pgfextra{\pgfmathsetmacro{\RX}{\RadiusSphere*cos(#3)} % from https://tex.stackexchange.com/a/410567/121799
\global\let\RX=\RX % from https://tex.stackexchange.com/a/352269/121799
\pgfmathsetmacro{\RY}{\RX*sin(\Clat)}%
\global\let\RY=\RY
\pgfmathsetmacro{\CY}{\RadiusSphere*sin(#3)*cos(\Clat)}
\global\let\CY=\CY
\pgfmathsetmacro{\Xloc}{\RX*cos(#2)}
\global\let\Xloc=\Xloc
\pgfmathsetmacro{\Yloc}{\CY+\RY*sin(#2)}
\global\let\Yloc=\Yloc}%
}
\begin{document}
\begin{tikzpicture}
\def\RadiusSphere{4}% sphere radius
\def\Clat{20}% point of view latitude
\def\Clong{-90}% point of view longitude
\shade[ball color = gray!40, opacity = 0.5] (0,0) circle (\RadiusSphere);
\hotspot{0}{-120}{-40}
\filldraw (\Xloc,\Yloc) circle (0.2);
\hotspot{0}{-120}{30}
\filldraw (\Xloc,\Yloc) circle (0.2);
\hotspot{0}{-50}{-40}
\filldraw (\Xloc,\Yloc) circle (0.2);
\hotspot{0}{-50}{30}
\filldraw (\Xloc,\Yloc) circle (0.2);
\begin{scope}
\clip[variable=\x] \longitudearc{blue}{-120}{-40}{30}
%\pgfextra{\hotspot{0}{-50}{-40}} to (\Xloc,\Yloc) % <-NEEDED?
\latitudearc{blue}{30}{-120}{-50} %to ({\Xend},{\Yend})
%\pgfextra{\hotspot{0}{-120}{-40}} to (\Xloc,\Yloc) % <-NEEDED?
\longitudearc{blue}{-50}{30}{-40} %to ({\Xend},{\Yend})
%\pgfextra{\hotspot{0}{-120}{30}} to (\Xloc,\Yloc) % <-NEEDED?
\latitudearc{blue}{-40}{-50}{-120} %to ({\Xend},{\Yend})
%\pgfextra{\hotspot{0}{-50}{30}} to (\Xloc,\Yloc) % <-NEEDED?
-- cycle;
\shade[ball color = blue!40, opacity = 0.5] (0,0) circle (\RadiusSphere);
\end{scope}
\end{tikzpicture}
\end{document}
This is not quite what I wanted. However, if I uncomment the \pgfextra commands in the scope at the bottom, i.e. use the scope
\begin{scope}
\clip[variable=\x] \longitudearc{blue}{-120}{-40}{30}
\pgfextra{\hotspot{0}{-50}{-40}} to (\Xloc,\Yloc) % <-NEEDED?
\latitudearc{blue}{30}{-120}{-50} %to ({\Xend},{\Yend})
\pgfextra{\hotspot{0}{-120}{-40}} to (\Xloc,\Yloc) % <-NEEDED?
\longitudearc{blue}{-50}{30}{-40} %to ({\Xend},{\Yend})
\pgfextra{\hotspot{0}{-120}{30}} to (\Xloc,\Yloc) % <-NEEDED?
\latitudearc{blue}{-40}{-50}{-120} %to ({\Xend},{\Yend})
\pgfextra{\hotspot{0}{-50}{30}} to (\Xloc,\Yloc) % <-NEEDED?
-- cycle;
\shade[ball color = blue!40, opacity = 0.5] (0,0) circle (\RadiusSphere);
\end{scope}
instead, I get:
which is almost precisely what I want. (The upper and lower boundaries are incorrect.) That is, by artificially inserting points into the path, I can get the shape bounded by plots. In the upper figure it seems that TikZ for some reason always "completes" the individual plots by returning to the starting points. Now my question is whether or not there is a way to switch that off.
EDIT: Here is a very minimal example.
\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\begin{scope}
\node[text width=3.5cm] at (1,5){with cycle};
\path[draw,blue,variable=\x,domain=0:2] (0,0) -- plot ({\x},{\x*\x})
plot ({1*(2-\x)},{4*(1-\x)}) -- cycle;
\clip[variable=\x,domain=0:2] (0,0) -- plot ({\x},{\x*\x})
plot ({1*(2-\x)},{4*(1-\x)}) -- cycle;
\fill (0,0) circle (1);
\end{scope}
\begin{scope}[transform canvas={xshift=4cm}]
\node[text width=3.5cm] at (1,5){path closed by hand};
\path[draw,blue,variable=\x,domain=0:2] (0,0) -- plot ({\x},{\x*\x})
plot ({1*(2-\x)},{4*(1-\x)}) -- (0,0);
\clip[variable=\x,domain=0:2] (0,0) -- plot ({\x},{\x*\x})
plot ({1*(2-\x)},{4*(1-\x)}) -- (0,0);
\fill (0,0) circle (1);
\end{scope}
\begin{scope}[transform canvas={xshift=10cm}]
\node[text width=3.5cm] at (1,5){a somewhat more complex example};
\path[draw,blue,variable=\x,domain=0:2] (0,0) -- plot ({\x},{\x*\x})
plot ({1*(2-\x)},{4*(1-\x)})
plot ({-\x},{-4+\x*\x})-- (0,0);
\clip[variable=\x,domain=0:2] (0,0) -- plot ({\x},{\x*\x})
plot ({1*(2-\x)},{4*(1-\x)})
plot ({-\x},{-4+\x*\x})-- (0,0);
\fill (0,0) circle (1);
\draw [red,dashed] (0,0) -- (2,4);
\draw [red,dashed] (0,0) -- (0,-4);
\end{scope}
\end{tikzpicture}
\end{document}
As one can see, the clipping is only correct (or, at least, as I think it should be) in the middle plot where I closed the path by hand. In the right plot, even though I close the path by hand, the clipping is not as it should be, I think. I also added the red dashed lines that seem to suggest that each of the plots form a closed path. But the middle example shows that this is not always case. Is there a way to always have the behavior as in the middle example without adding coordinates by hand?




\longitudearcand\latitudearcare very explicit, you really only need the last lines of those, e.g.plot [domain=#3:#4,smooth,#1] ({\RX*cos(\noexpand\x)},{\CY+\RY*sin(\noexpand\x)}). But thanks for looking into this anyway! – Jan 16 '18 at 02:16\cycleat the end of the sequence. The last plot ends (or, more precisely, is supposed to end) where the first one begins. – Jan 16 '18 at 02:41--between the plots of each clip path to get the correct result (theclipoperation is like afilloperation). – Paul Gaborit Jan 16 '18 at 06:16\clip (0,0) -- plot[variable=\x,domain=0:2] ({\x},{\x*\x}) -- plot[variable=\x,domain=0:2] ({1*(2-\x)},{4*(1-\x)}) -- plot[variable=\x,domain=-2:0] ({\x+2},{4+(\x+2)*(\x+2)})-- (0,0);instead. Here I put--before, between, and after the plot. – Jan 16 '18 at 06:19clipoperation always use thenonzero rule. – Paul Gaborit Jan 16 '18 at 06:51plotbegins by an implicitmove tooperation if not preceding by--(p.326, pgfmanual, v3.0.1a). – Paul Gaborit Jan 16 '18 at 15:09--should be necessary. – Jan 16 '18 at 15:14move tooperation is included even if the coordinates are the same. – Paul Gaborit Jan 16 '18 at 15:54--for reasons that I do not understand. I can put-- (\Xend,\Yend)where\Xendand\Yendare the final coordinates of the last or first coordinates of the next plot, but this does not help. – Jan 16 '18 at 17:09