我正在尝试绘制一个通过A, B, C, D
四面体的四个点的球体ABCD
。在此代码中,球心为(0,0,0
,球半径为a*sqrt(3)
。
\documentclass[border=2mm]{standalone}
\usepackage{tikz,tikz-3dplot}
\begin{document}
\tdplotsetmaincoords{120}{55}
\begin{tikzpicture}[tdplot_main_coords,declare function={a=3;}]
\path
(a,a,a) coordinate (B)
(a,-a,-a) coordinate (D)
(-a,a,-a) coordinate (C)
(-a,-a,a) coordinate (A);
\draw[dashed] (A) -- (B) (A) -- (C) (A) -- (D) (B) -- (C) -- (D) (D) -- (B);
\node[circle, fill, inner sep=1pt, label={90:$A$}] at (A) {};
\node[circle, fill, inner sep=1pt, label={60:$B$}] at (B) {};
\node[circle, fill, inner sep=1pt, label={-90:$C$}] at (C) {};
\node[circle, fill, inner sep=1pt, label={90:$D$}] at (D) {};
\draw[tdplot_screen_coords] (0,0,0) circle [radius = a*sqrt(3)];
\end{tikzpicture}
\end{document}
如果我没有球心的坐标,我该如何构造中心并绘制球体?
答案1
我们可以基于 John Kormylo 构建,“中心也将位于每个边的垂直平分线(平面)的交点处。” 在此代码中,中心也将位于每个面的垂直线的交点处,并穿过每个面的外接圆中心。
\documentclass[border=2mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{3dtools}% https://github.com/marmotghost/tikz-3dtools
\begin{document}
\begin{tikzpicture}[line cap=butt,line join=round,3d/install view={phi=235,theta=70,psi=60},declare function={a=3;}]
\path
(a,a,a) coordinate (B)
(a,-a,-a) coordinate (D)
(-a,a,-a) coordinate (C)
(-a,-a,a) coordinate (A);
\path[3d/circumcircle center={A={(A)},B={(B)},C={(C)}}] coordinate (X);
\path[3d/circumcircle center={A={(A)},B={(B)},C={(D)}}] coordinate (Y);
\path[overlay,3d coordinate={(myn1)=(A)-(B)x(A)-(C)},
3d coordinate={(myn2)=(D)-(A)x(D)-(B)}];
\path[3d/line with direction={(myn1) through (X) named d1},
3d/line with direction={(myn2) through (Y) named d2}];
\path[3d/intersection of={d1 with d2}] coordinate (T);
\pgfmathsetmacro{\myR}{sqrt(TD("(T)-(A)o(T)-(A)"))} ;
\draw[3d/screen coords] (T) circle[radius=\myR];
\draw[dashed] (A) -- (B) (A) -- (C) (A) -- (D) (B) -- (C) -- (D) (D) -- (B);
\path foreach \p/\g in {B/90,C/-90,A/90,D/0,T/0}
{ (\p) node[circle,fill,inner sep=1pt,label=\g:{{$\p$}}]{}};
\end{tikzpicture}
\end{document}
有了3dtools
,我们可以使用
\path[3d/circumsphere center={A={(A)},B={(B)},C={(C)},D={(D)}}] coordinate (I);
那么,I 就是球体的中心。
\documentclass[border=2mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{3dtools}% https://github.com/marmotghost/tikz-3dtools
\begin{document}
\begin{tikzpicture}[line cap=butt,line join=round,
3d/install view={phi=235,theta=70,psi=60},declare function={a=3;}]
\path
(a,a,a) coordinate (B)
(a,-a,-a) coordinate (D)
(-a,a,-a) coordinate (C)
(-a,-a,a) coordinate (A);
\path[3d/circumsphere center={A={(A)},B={(B)},C={(C)},D={(D)}}]
coordinate (I);
\pgfmathsetmacro{\myR}{sqrt(TD("(I)-(A)o(I)-(A)"))} ;
\draw[3d/screen coords] (I) circle[radius=\myR];
\path foreach \p/\g in {B/90,C/-90,A/90,D/0,I/0}
{ (\p) node[circle,fill,inner sep=1pt,label=\g:{{$\p$}}]{}};
\draw[dashed] (A) -- (B) (A) -- (C) (A) -- (D) (B) -- (C) -- (D) (D) -- (B);
\end{tikzpicture}
\end{document}
答案2
(这是一条长评论,不是答案)去年,由于 TikZ 的精度低以及对 3D 图形的限制,我为 2D 和 3D 编写了一个普通的 Asymptote 模块,将其命名为ESgeometry.asy
。它不使用几何构造,而是专注于使用barycentric coordinates
(signed area
,signed length
)和可用的dot
,cross products
。当然,它包括常用命令,例如incenter
,inradius
,circumcenter
,circumradius
,... 。我通过使用仅 2 个主要命令来最小化命令数量:ESpoint
和ESlength
。
triple O=ESpoint("circumcenter",A,B,C,D);
real R=ESlength("circumradius",A,B,C,D);
代码还没有清理。我很快就会清理。
// a part of ESgeometry.asy (for both 2D and 3D)
triple barycentric(triple A, triple B=(0,0,0), triple C=(0,0,0), triple D=(0,0,0), real a=1, real b=0, real c=0,real d=0){
return (a*A+b*B+c*C+d*D)/(a+b+c+d);
}
//////////////////////////////////////////////
// Compute signed area in 3D
real SignedArea(triple A, triple B, triple C){
return sgn(dot(cross(A,B),C))*abs(cross(B-A,C-A))/2;
}
// Compute (positive) area in 3D
real Area(triple A, triple B, triple C){
return abs(cross(B-A,C-A))/2;
}
triple ESpoint(string name="", triple A, triple B, triple C, triple D){
if (name=="circumcenter") {
triple O1=(abs(A-D))^2*cross(B-D,C-D);
triple O2=(abs(B-D))^2*cross(C-D,A-D);
triple O3=(abs(C-D))^2*cross(A-D,B-D);
real V=dot(A-D,cross(B-D,C-D));
return D+(O1+O2+O3)/(2*V);
}
else if (name=="incenter") {return barycentric(A,B,C,D,Area(B,C,D),Area(C,D,A),Area(D,A,B),Area(A,B,C));}
else if (name=="centroid") {return barycentric(A,B,C,D,1,1,1,1);}
else return (0,0,0);
}
triple ESpoint(string name="", triple A, triple B, triple C){
real a=abs(B-C), b=abs(C-A), c=abs(A-B);
if (name=="footbisector") {return barycentric(A,B,C,0,b,c);}
else if (name=="footaltitude") {return barycentric(A,B,C,0,1/(a^2+c^2-b^2),1/(a^2+b^2-c^2));}
else if (name=="incenter") {return barycentric(A,B,C,a,b,c);}
else if (name=="centroid") {return barycentric(A,B,C,1,1,1);}
else return (0,0,0);
}
///////////////////////////
unitsize(1cm);
import three;
import solids; // only for better sphere, Circle
triple B=(0,0,0), A=(5,-.5,2), C=(1,3.5,3), D=(1,1,6);
draw(A--B--C--cycle^^D--A^^D--B^^D--C);
label("$A$",A,plain.W);
label("$B$",B,plain.S);
label("$C$",C,plain.E);
label("$D$",D,plain.N);
triple I=ESpoint("incenter",A,B,C,D); dot(I,red);
triple Id=ESpoint("incenter",A,B,C); dot(Id,red);
triple I1=ESpoint("footbisector",A,B,C); dot(I1); draw(A--I1);
triple I2=ESpoint("footaltitude",Id,B,C); dot(I2); draw(Id--I2);
draw(Circle(Id,abs(Id-I2),normal=cross(A-B,A-C)));
real r=abs(I-(I+reflect(A,B,C)*I)/2);
revolution b=sphere(I,r);
draw(surface(b),yellow+opacity(.5));
// the foot of different bisectors
triple Fa=ESpoint("bisectorfoot",A,B,C); dot(Fa,red);
triple Fd=ESpoint("bisectorfoot",D,B,C); dot(Fd,blue);
triple circumcenter(triple A, triple B, triple C, triple D){
triple O1=(abs(A-D))^2*cross(B-D,C-D);
triple O2=(abs(B-D))^2*cross(C-D,A-D);
triple O3=(abs(C-D))^2*cross(A-D,B-D);
real V=dot(A-D,cross(B-D,C-D));
return D+(O1+O2+O3)/(2*V);
}
triple O=ESpoint("circumcenter",A,B,C,D);
revolution Oabcd=sphere(O,abs(O-D));
draw(surface(Oabcd),green+opacity(.3));
dot(A^^B^^C^^D,red);
triple M=barycentric(A,C,.5,.5);
draw(D--M);
triple Mg=barycentric(A,C,D,1,1,1);
dot(Mg,orange);
triple Atest=barycentric(B,1/2); draw(D--Atest);
//draw(shift(D)*surface(plane(A,C)),blue);
//draw(surface(A--B--C--cycle),blue+opacity(.5));
//draw(surface(B--C--D--cycle),red+opacity(.5));
//draw(surface(C--D--A--cycle),magenta+opacity(.5));