I want to draw shapes looks like 15 degrees tilted-semi-sphere and there are circles, placed in a triangular shaped array, on the base area. Then these circles are projected onto surface of sphere.
I can drive small circles on the base-plane. However, projections of circles have different shapes. Therefore I don't know how to solve it. I think, there are cylindrical holes and I must find their intersections on the surface of sphere.
Thank you all for your response. I wonder is there any way to specify centers of circles or projections in cartesian and not in polar coordinates. Since it is difficult to specify polar coordinates of each small circles, shown below, in an automatic way, in other words using \foreach command.
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{pgfplots}
\newcommand\pgfmathsinandcos[3]{%
\pgfmathsetmacro#1{sin(#3)}%
\pgfmathsetmacro#2{cos(#3)}%
}
\newcommand\LongitudePlane[3][current
plane]{%
\pgfmathsinandcos\sinEl\cosEl{#2} % elevation
\pgfmathsinandcos\sint\cost{#3} % azimuth
\tikzset{#1/.estyle={cm={\cost,\sint*\sinEl,0,\cosEl,(0,0)}}}
}
\newcommand\LatitudePlane[3][current plane]{%
\pgfmathsinandcos\sinEl\cosEl{#2} % elevation
\pgfmathsinandcos\sint\cost{#3} % latitude
\pgfmathsetmacro\yshift{\cosEl*\sint}
\tikzset{#1/.estyle={cm={\cost,0,0,\cost*\sinEl,(0,\yshift)}}} %
}
\newcommand\DrawLongitudeCircle[2][2]{
\LongitudePlane{\angEl}{#2}
\tikzset{current plane/.prefix style={scale=#1}}
% angle of "visibility"
\pgfmathsetmacro\angVis{atan(sin(#2)*cos(\angEl)/sin(\angEl))} %
\draw[current plane,dotted] (\angVis:1) arc (\angVis:180:1);
\draw[current plane,dotted] (\angVis+90:1) arc (\angVis+90:0:1);
}
\newcommand\DrawLatitudeCircle[2][3]{
\LatitudePlane{\angEl}{#2}
\tikzset{current plane/.prefix style={scale=#1}}
\pgfmathsetmacro\sinVis{sin(#2)/cos(#2)*sin(\angEl)/cos(\angEl)}
\pgfmathsetmacro\angVis{asin(min(1,max(\sinVis,-1)))}
\draw[current plane,dotted] (\angVis:1) arc (\angVis:-\angVis-180:1);
\draw[current plane,dotted] (180-\angVis:1) arc (180-\angVis:\angVis:1);
}
\newcommand\DrawMidCircle[2][4]{
\LatitudePlane{\angEl}{#2}
\tikzset{current plane/.prefix style={scale=#1}}
\pgfmathsetmacro\sinVis{sin(#2)/cos(#2)*sin(\angEl)/cos(\angEl)}
% angle of "visibility"
\pgfmathsetmacro\angVis{asin(min(1,max(\sinVis,-1)))}
\draw[current plane] (\angVis:1) arc (\angVis:-\angVis-180:1);
\draw[current plane] (180-\angVis:1) arc (180-\angVis:\angVis:1);
}
\newcommand\DrawAxis[2][5]{
\LongitudePlane{\angEl}{#2}
\tikzset{current plane/.prefix style={scale=#1}}
% angle of "visibility"
\pgfmathsetmacro\angVis{atan(sin(#2)*cos(\angEl)/sin(\angEl))} %
\draw[current plane] (1,0) -- (-1,0);
}
\newcommand\DrawSmallCircle[2][6]{
\LatitudePlane{\angEl}{0}
\tikzset{current plane/.prefix style={scale=1}}
\pgfmathsetmacro\sinVis{sin(0)/cos(0)*sin(\angEl)/cos(\angEl)}
% angle of "visibility"
\pgfmathsetmacro\angVis{asin(min(1,max(\sinVis,-1)))}
\pgfmathsetmacro\x{(#1*2*\r)*cos(\angRot)-(#2*2*\r*cos(30))*sin(\angRot)}
\pgfmathsetmacro\y{(#1*2*\r)*sin(\angRot)+(#2*2*\r*cos(30))*cos(\angRot)}
\draw[current plane,green!85!black, fill=green!85!black, fill opacity=0.25] ($(\x,\y)+(0:\r)$) arc (\angVis:360+\angVis:\r);
}
\newcommand\DrawSmallCircleShift[2][7]{
\LatitudePlane{\angEl}{0}
\tikzset{current plane/.prefix style={scale=1}}
\pgfmathsetmacro\sinVis{sin(0)/cos(0)*sin(\angEl)/cos(\angEl)}
% angle of "visibility"
\pgfmathsetmacro\angVis{asin(min(1,max(\sinVis,-1)))}
\pgfmathsetmacro\x{(#1*2*\r+\r)*cos(\angRot)-(#2*2*\r*cos(30))*sin(\angRot)}
\pgfmathsetmacro\y{(#1*2*\r+\r)*sin(\angRot)+(#2*2*\r*cos(30))*cos(\angRot)}
\draw[current plane,green!85!black, fill=green!85!black, fill opacity=0.25] ($(\x,\y)+(0:\r)$) arc (\angVis:360+\angVis:\r);
}
\begin{document}
\begin{tikzpicture}
\def\R{4}
\def\r{0.35}
\def\angRot{30}
\node (C) at (0,0) {};
\draw (C) -- (0,1);
\def\angEl{20} % elevation angle
\LongitudePlane{\angEl}{\angRot}
\tikzset{current plane/.prefix style={scale=\R}}
% angle of "visibility"
\pgfmathsetmacro\angVis{atan(sin(\angRot)*cos(\angEl)/sin(\angEl))} %
\draw[current plane] (-1,0) node[below left]{$u$} -- (1,0);
\draw[current plane] (0,0,0) -- (0,1,0);
\LongitudePlane{\angEl}{90+\angRot}
\tikzset{current plane/.prefix style={scale=\R}}
% angle of "visibility"
\pgfmathsetmacro\angVis{atan(sin(90+\angRot)*cos(\angEl)/sin(\angEl))} %
\draw[current plane] (-1,0) node[below right]{$v$} -- (1,0);
\foreach \n in {0,-2}
{\foreach \m in {-4,-3,...,0}
{\DrawSmallCircle[\m]{\n}}}
\foreach \n in {-1,-3}
{\foreach \m in {-5,-4,...,-1}
{\DrawSmallCircleShift[\m]{\n}}}
\foreach \n in {-4}
{\foreach \m in {-3,...,0}
{\DrawSmallCircle[\m]{\n}}}
\foreach \n in {-5}
{\foreach \m in {-3,-2,-1}
{\DrawSmallCircleShift[\m]{\n}}}
\draw[current plane] (0,0,0) -- (0,1,0);
\foreach \t in {0,10,...,80} { \DrawLatitudeCircle[\R]{\t} }
\foreach \t in {0} { \DrawMidCircle[\R]{\t} }
\foreach \t in {0,\angRot,...,150} { \DrawLongitudeCircle[\R]{\t} }
\end{tikzpicture}
\end{document}
Best Answer
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 TikZplot
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 thanveclen
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.
And here's a version using layers and Cartesian rather than polar coordinates for the circles: