Projection of Circle onto Spherical Surface
Well, no prizes for speed (not just because there is some duplication of calculations: TikZ is slow for this kind of stuff), but this shows one way of doing it. I expect asymptote/PSTricks could do it quicker, but I don't see any other way of doing it in TikZ.
The maths is straightforward "back-of-the-envelope" trigonometry (in this case literally). The only "insight" is to draw the circles manually.
EDIT 1 inspired by Jake's missing (at the time of writing) PGF Plots answer, I've changed most of the \foreach
statements to TikZ plot
commands which makes things a bit quicker.
EDIT 2 changed the critical function to sqrt(\R^2-(\cx+\r*cos(\t))^2-(\cy+\r*sin(\t))^2)
as this provides better accuracy than veclen
when the circles get near to the edge.
EDIT 3 a second version has been added which uses layers to add both circles at the same time.
\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[x=(-30:4cm),y=(30:4cm),z=(90:4cm)]
\def\R{1}
\draw (-\R,0,0) -- (\R,0,0);
\draw (0,-\R,0) -- (0,\R,0);
\draw (0,0,0) -- (0,0,\R);
\draw plot [domain=0:360, samples=60, variable=\i]
(\R*cos \i, \R*sin \i, 0) -- cycle;
\def\r{0.075}
\foreach \cr in {0.3, 0.5, 0.7, 0.9}
\foreach \ca [evaluate={\cx=\cr*cos \ca; \cy=\cr*sin \ca;}]in {-90,-60,-30,0,30, 60, 90}
\draw [green!85!black, fill=green!85!black, fill opacity=0.25]
plot [domain=0:360, samples=40, variable=\i]
(\cx+\r*cos \i, \cy+\r*sin \i, 0) -- cycle;
\foreach \i in {0, 30,...,150}
\draw [dotted] plot [domain=-90:90, samples=30, variable=\j]
(\R*cos \i*sin \j,\R*sin \i*sin \j, \R*cos \j);
\foreach \j in {0, 15,...,90}
\draw [dotted] plot [domain=0:360, samples=60, variable=\i]
(\R*cos \i*sin \j,\R*sin \i*sin \j, \R*cos \j);
\foreach \cr in {0.3, 0.5, 0.7, 0.9}
\foreach \ca [evaluate={\cx=\cr*cos \ca; \cy=\cr*sin \ca;}]in {-90,-60,-30,0,30, 60, 90}
\draw [red, fill=red, fill opacity=.25]
plot [domain=0:360, samples=40, variable=\t]
(\cx+\r*cos \t,\cy+\r*sin \t, {sqrt(\R^2-(\cx+\r*cos(\t))^2-(\cy+\r*sin(\t))^2)})
-- cycle;
\end{tikzpicture}
\end{document}
And here's a version using layers and Cartesian rather than polar coordinates for the circles:
\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\pgfdeclarelayer{dome floor}
\pgfdeclarelayer{dome}
\pgfdeclarelayer{dome surface}
\pgfsetlayers{dome floor,main,dome,dome surface}
\def\addcircle#1#2#3#4{%
\begingroup%
\pgfmathparse{#1}\let\R=\pgfmathresult
\pgfmathparse{#2}\let\cx=\pgfmathresult
\pgfmathparse{#3}\let\cy=\pgfmathresult
\pgfmathparse{#4}\let\r=\pgfmathresult
\begin{pgfonlayer}{dome floor}
\draw [blue!45!black, fill=blue!45, fill opacity=0.25]
plot [domain=0:360, samples=40, variable=\i]
(\cx+\r*cos \i, \cy+\r*sin \i, 0) -- cycle;
\end{pgfonlayer}
\begin{pgfonlayer}{dome surface}
\draw [red!75!black, fill=red!75, fill opacity=0.25]
plot [domain=0:360, samples=60, variable=\t]
(\cx+\r*cos \t,\cy+\r*sin \t, {sqrt(max(\R^2-(\cx+\r*cos(\t))^2-(\cy+\r*sin(\t))^2, 0))})
-- cycle;
\end{pgfonlayer}
\endgroup%
}
\begin{tikzpicture}[x=(-30:1cm),y=(30:1cm),z=(90:1cm)]
\def\R{6}
\begin{pgfonlayer}{dome floor}
\draw (-\R,0,0) -- (\R,0,0);
\draw (0,-\R,0) -- (0,\R,0);
\draw plot [domain=0:360, samples=90, variable=\i]
(\R*cos \i, \R*sin \i, 0) -- cycle;
\end{pgfonlayer}
\draw (0,0,0) -- (0,0,\R);
\begin{pgfonlayer}{dome surface}
\foreach \i in {0, 30,...,150}
\draw [dotted] plot [domain=-90:90, samples=60, variable=\j]
(\R*cos \i*sin \j,\R*sin \i*sin \j, \R*cos \j);
\foreach \j in {0, 15,...,90}
\draw [dotted] plot [domain=0:360, samples=60, variable=\i]
(\R*cos \i*sin \j,\R*sin \i*sin \j, \R*cos \j);
\end{pgfonlayer}
\def\r{0.5}
\foreach \m [evaluate={\N=max(-4, \m-7);}]in {0,...,5}{
\foreach \n in {0,-1,...,\N}
{\addcircle{\R}{\m*sin 60}{\n-mod(abs(\m),2)*\r}{\r}}}
\end{tikzpicture}
\end{document}
Asymptote
solution. It uses a function (from the Wiki)
to calculate the curve of intersection. Adjust the placement
of the circles as needed. s.asy
:
size(300,300);
size3(300,300,300);
import graph3;
currentprojection=orthographic(-5,-4,2,center=true);
guide3 sphere_x_cyl(real a, real r, real R, int n=10){
// return a closed curve of the Sphere–cylinder intersection (top part)
// only for the case when a cylinder is completely inside
// except special case when the x-shift a=0
assert(a>0,"***** Positive a expected.");
real b=(R^2-r^2-a^2)/(2a);
guide3 g;
int n=30;
real phi, dphi;
phi=0;
dphi=360/n;
triple t;
for(int i=0;i<n;++i){
t=(r*Cos(phi),r*Sin(phi),sqrt(2a*(b+r*Cos(phi))));
g=g--t;
phi+=dphi;
}
g=g--cycle;
return g;
}
void Draw3(guide3 g,pen p=currentpen){
draw(project(g),p);
}
void FillDraw3(guide3 g,pen fillPen=currentpen, pen linePen=nullpen){
filldraw(project(g),fillPen,linePen);
}
int nr=11;
real r=1;
real R=nr*r;
real a; // distance between the centers
triple O=(0,0,0);
guide3 circ(triple sh=O, real r){
guide3 uc=(r,0,0)..(0,r,0)..(-r,0,0)..(0,-r,0)..cycle;
return shift(sh)*uc;
}
guide3 semicirc(triple sh=O, real r){
guide3 uc=(r,0,0)..(0,r,0)..(-r,0,0);
return shift(sh)*uc;
}
guide3 Parallel(real h, real R){
return circ((0,0,h),sqrt(R^2-h^2));
}
pen dashed=linetype(new real[] {4,3}); // set up dashed pattern
pen dashCircPen=gray(0.4)+dashed+opacity(1)+0.32pt;
pen boldLine=darkblue+1.2pt;
pen floorCircPen=olive+opacity(0.75);
pen sphereSpotPen=blue+opacity(0.382);
Draw3(O--(0,0,R),boldLine);
Draw3(O--(R,0,0),boldLine);
Draw3(O--(0,R,0),boldLine);
Draw3(O--(-R,0,0),boldLine);
Draw3(O--(0,-R,0),boldLine);
Draw3(circ(R),boldLine);
real h=0;
real dphi=10;
real phi=dphi;
for(int i=1;i<9;++i){
h=R*Sin(phi);
Draw3(Parallel(h,R),dashCircPen);
phi+=dphi;
}
for(int i=0;i<6;++i){
Draw3(rotate(30*i,(0,0,1))*rotate(90,(1,0,0))*semicirc(R),dashCircPen);
}
int nd=floor((nr-1)/2);
transform3 tr;
for(int j=0;j<3;++j){
a=2r;
for(int i=0;i<nd;++i){
tr=rotate(60*j,(0,0,1))*shift((-a,0,0));
FillDraw3(tr*circ(r),floorCircPen,red);
FillDraw3(tr*sphere_x_cyl(a,r,R),sphereSpotPen);
a+=2r;
}
}
FillDraw3(circ(r),floorCircPen,red);
FillDraw3(shift((0,0,sqrt(R^2-r^2)))*circ(r),sphereSpotPen);
To get a standalone s.pdf
run asy -f pdf s.asy
.
Here's a way of doing this using PGFPlots:
\documentclass{article}
\usepackage{pgfplots}
\begin{document}
\begin{tikzpicture}
\begin{axis}[hide axis, axis equal, samples=15]
\foreach \posx/\posy in {0/-0.1, 0.6/0.1, 0.6/-0.4, 0.1/-0.7}{
\addplot3 [red, thick, domain=0:360, samples=20] (
{cos(x)*0.2+\posx},
{sin(x)*0.2+\posy},
{0}
);
}
\addplot3 [surf, gray, faceted color=gray, opacity=0.5, samples=20, z buffer=sort, domain=0:360, y domain=0:1] ({cos(x)*y},{sin(x)*y},
{sqrt(1-(cos(x)*y)^2-(sin(x)*y)^2))});
\foreach \posx/\posy in {0/-0.1, 0.6/0.1, 0.6/-0.4, 0.1/-0.7}{
\addplot3 [red, thick, domain=0:360, samples=20] (
{cos(x)*0.2+\posx},
{sin(x)*0.2+\posy},
{sqrt(1-((cos(x)*0.2+\posx))^2-((sin(x)*0.2+\posy))^2))}
);
}
\end{axis}
\end{tikzpicture}
\end{document}