Points (A) (B) (A') and (B') are not the edges of the cylinder, but rather the points where the visible edge of the sphere (circle) and the visible edge of of the cylinder (ellipse) intersect, which depend on the viewing angles.
Points (C) and (D) represent the visible right and left edges.
\documentclass[12pt,border=3mm]{standalone}
\usepackage{fouriernc}
\usepackage{tikz}
\usepackage{tkz-euclide}
\usetkzobj{all}
\usepackage{tikz-3dplot}
\usetikzlibrary{calc,backgrounds}
\begin{document}
\def\myangle{70}%
\tdplotsetmaincoords{\myangle}{0}%
\begin{tikzpicture}[scale=1,tdplot_main_coords]
\pgfmathsetmacro{\r}{2*sqrt(3)}% sphere radius=4, cylendar height=4
\path% common coordinates
(0,0,-2) coordinate (O)
(0,0,0) coordinate (I)
(0,0,2) coordinate (O')
(O) ++(0:\r) coordinate (C)% right edge
(O) ++(180:\r) coordinate (D);% left edge
\draw[dashed,thick] (C)-- ++(0,0,4) (D)-- ++(0,0,4);
\draw[dashed] (O)--(O');
\begin{scope}[tdplot_screen_coords, on background layer]
\fill[ball color=orange!70, opacity=1.0] (I) circle (4);
\end{scope}
\pgfmathsetmacro{\mynumer}{2*cos(\myangle)}
\pgfmathsetmacro{\mydenom}{\r*sin(\myangle)}
\pgfmathsetmacro{\quadrant}{ifthenelse(abs(\mynumer)<abs(\mydenom), 0,
ifthenelse(\mynumer>0, 1, 2))}% 0=side, 1=top, 2=bottom
\ifcase\quadrant
\pgfmathsetmacro{\intercept}{asin(\mynumer/\mydenom)}
\path
(O) ++(-\intercept:\r) coordinate (A)
(O) ++(-180+\intercept:\r) coordinate (B)
(O') ++(\intercept:\r) coordinate (A')
(O') ++(180-\intercept:\r) coordinate (B');
\draw [thick] (B) arc (-180+\intercept:-\intercept:\r);
\draw [thick, dashed] (A) arc (-\intercept:180+\intercept:\r);
\draw [thick] (B') arc (-180-\intercept:\intercept:\r);
\draw [thick, dashed] (A') arc (\intercept:180-\intercept:\r);
\foreach \v/\position in {I/left,O/below,O'/above,A/below,B/below,A'/left,B'/left} {
\draw[draw =black, fill=black] (\v) circle (1.2pt) node [\position=0.2mm] {$\v$};
}
\or% top
\path
(C) coordinate (A)
(D) coordinate (B)
(A) ++(0,0,4) coordinate (A')
(B) ++((0,0,4) coordinate (B');
\draw [thick] (O') circle (\r);
\draw [thick, dashed] (O) circle (\r);
\foreach \v/\position in {I/left,O/below,O'/above,A/below,B/below,A'/left,B'/left} {
\draw[draw =black, fill=black] (\v) circle (1.2pt) node [\position=0.2mm] {$\v$};
}
\or% bottom
\path
(C) coordinate (A)
(D) coordinate (B)
(A) ++(0,0,4) coordinate (A')
(B) ++((0,0,4) coordinate (B');
\draw [thick,dashed] (O') circle (\r);
\draw [thick] (O) circle (\r);
\foreach \v/\position in {I/left,O/below,O'/above,A/below,B/below,A'/left,B'/left} {
\draw[draw =black, fill=black] (\v) circle (1.2pt) node [\position=0.2mm] {$\v$};
}
\fi
\draw[dashed] (O)--(A) (I) --(A);
\tkzMarkRightAngle[size = 0.3](I,O,A);
\end{tikzpicture}
\end{document}
Here is a little tool box that allows you to protect
some (closed) path. It is based on the links mentioned in the code (and possibly more). The important pieces are
\begin{scope}
\tikzset{protect=\rectA}
\draw[thick,use path=\rectB];
\draw[thick] (I) -- (M);
\tikzset{protect=\rectB}
\draw[thick,use path=\lineA];
\end{scope}
where the paths \rectA
, \rectB
and \lineA
have been used before and saved with save path
. \tikzset{protect=\rectA}
"protects" the interior of the \rectA
path, and likewise for \rectB
.
\documentclass[border=2mm,tikz]{standalone}
\usepackage{tikz-3dplot}
\usetikzlibrary{3dtools}
% based on
% https://tex.stackexchange.com/a/38995/121799
% https://tex.stackexchange.com/a/76216
% https://tex.stackexchange.com/a/59168/194703
% https://tex.stackexchange.com/q/448920/194703
\makeatletter
\tikzset{
reuse path/.code={\pgfsyssoftpath@setcurrentpath{#1}}
}
\tikzset{even odd clip/.code={\pgfseteorule},
protect/.code={
\clip[overlay,even odd clip,reuse path=#1]
(-16383.99999pt,-16383.99999pt) rectangle (16383.99999pt,16383.99999pt);
}}
\makeatother
\tikzset{intersection of line trough/.code args={#1 and #2 with plane containing #3 and normal #4}{%
\pgfmathsetmacro{\ltest}{abs(TD("#2o#4")-TD("#1o#4"))}%
\ifdim\ltest pt<0.01pt
\message{Plane and line are parallel!^^J}
\pgfmathsetmacro{\myd}{0}
\else
\pgfmathsetmacro{\myd}{(TD("#3o#4")-TD("#1o#4"))/(TD("#2o#4")-TD("#1o#4"))}%
\fi
\pgfmathsetmacro{\myP}{TD("#1+\myd*#2-\myd*#1")}%
\pgfkeysalso{insert path={%
(\myP)
}}
}}
\begin{document}
\tdplotsetmaincoords{60}{65}
\begin{tikzpicture}[scale=1,tdplot_main_coords,line join = round, line cap = round, declare function={a = 3;b = 4;}]
\path
(0,0,b+2) coordinate (M)
(0,0,-b) coordinate (N);
\begin{scope} [canvas is xy plane at z=0]
\draw[dashed,save path=\rectB] (-a,-a) rectangle (a,a);
\end{scope}
\begin{scope} [canvas is xy plane at z=a]
\draw[thick,save path=\rectA] (-a,-a) rectangle (a,a);
\end{scope}
\draw[dashed,save path=\lineA] (M) -- (N) ;
\path[overlay][intersection of line trough={(M) and (N) with plane containing (0,0,0) and normal (0,0,1)}] coordinate (I);
\path[overlay][intersection of line trough={(M) and (N) with plane containing (0,0,a) and normal (0,0,1)}] coordinate (J);
\begin{scope}
\tikzset{protect=\rectA}
\draw[thick,use path=\rectB];
\draw[thick] (I) -- (M);
\tikzset{protect=\rectB}
\draw[thick,use path=\lineA];
\end{scope}
\foreach \p in {M,N,I,J}
\draw[fill=black] (\p) circle (1pt);
\foreach \p/\g in {M/90,N/-90,I/0,J/0}
\path (\p)+(\g:3mm) node{$\p$};
\draw[thick] (M) -- (J);
\end{tikzpicture}
\end{document}
It turns out that for some (to me obscure) reasons it can happen in some cases that the insanely large bounding box is too large. However, for most practical applications something more "modest" like
\tikzset{even odd clip/.code={\pgfseteorule},
protect/.code={
\clip[overlay,even odd clip,reuse path=#1]
(-6383.99999pt,-6383.99999pt) rectangle (6383.99999pt,6383.99999pt);
}}
will be more than sufficient.
Best Answer
You can use 3dtools
Or