(It is a long comment, not an answer) Last year, due to low accuracy of TikZ and its limitation for 3D figures, I wrote a plain Asymptote module for both 2D and 3D, named it ESgeometry.asy
. Instead of using geometric constructions, it concentrated on using barycentric coordinates
(signed area
, signed length
) and avaiable dot
, cross products
. Of course it included usual commands such as incenter
, inradius
, circumcenter
, circumradius
, .... I minimalized the number of commands by using only 2 main one: ESpoint
and ESlength
.
triple O=ESpoint("circumcenter",A,B,C,D);
real R=ESlength("circumradius",A,B,C,D);
The code has not been cleaned yet. I am going to do it soon.
// 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));