asymptote 内置了求取复系数的一元二次方程的例程:
故考虑直接求取 f(z) = (z-a)(z-b)(z-c) 的导数 f(z) = 3z^{2} - 2(a + b + c) + (ab + bc + ca) 的两个根,然后根据椭圆的定义,求出椭圆的半长轴即可。
代码如下:
// settings.render=8; settings.outformat="png";
settings.outformat="pdf";
unitsize(1cm); dotfactor = 3;
import geometry; defaultpen(/* fontsize(8pt) */linewidth(0.8pt));
/*======== 定义(Define)/计算(Calculate) =========*/
// f(z) = (z-a)*(z-b)*(z-c)
pair a = (-3,0), b = (2,-2), c = (0,4);
point A = a, B = b, C = c; triangle t = triangle(A, B, C);
// f'(z) = 3*z^3 - 2*(a+b+c)*z + (a*b + b*c + c*a)
pair[] f1f2 = quadraticroots((pair)3, -2(a+b+c), (a*b+b*c+c*a));
point F1 = f1f2[0], F2 = f1f2[1];
point Ma = midpoint(t.BC);
// Ma 是椭圆 ell 上的点,根据椭圆定义得到 |MaF1| + |MaF2| = 2a
real a = (length(Ma-F1) + length(Ma-F2)) / 2;
ellipse ell = ellipse(F1, F2, a);
/*======== 绘制(Draw) =========*/
draw(t); draw(ell); dot(F1); dot(F2);
label("$A$", A, SW); label("$B$", B, SE);
/*======== 标注(Label) =========*/
label("$C$", C, N);
label("$F_{1}$", F1, W); label("$F_{2}$", F2, E); 使用仿射变换略施小计可以避免复杂的求根操作:
\documentclass{standalone}
\usepackage{luadraw}
\usepackage[svgnames]{xcolor}
\usepackage{fourier-otf}
\begin{document}
\begin{luadraw}{name=steiner_inellipse}
local ld = luadraw
local cpx = ld.cpx
local g = ld.graph:new{window={-1,6,-1,4},size={10,10}
}
local i, Z = cpx.I, cpx.Z
local sqrt, pi = math.sqrt, math.pi
local A0,B0,C0 = Z(-1,0), Z(1,0), Z(0,sqrt(3))
local A,B,C = Z(0,0), Z(5,0), Z(1,3)
local MA1 = {A0, B0-A0, C0-A0}
local MA2 = {A, B-A, C-A}
local M = ld.composematrix(MA2, ld.invmatrix(MA1))
local In, r = ld.incircle(A0,B0,C0)
g:Savematrix();g:Setmatrix(M)
g:Dpolyline({A0,B0,C0}, true)
g:Dpolyline(ld.circle({In,r}), true, "semithick,magenta")
g:Restorematrix()
g:Dlabel(
"$A$",A,{pos="SW"},
"$B$",B,{pos="SE"},
"$C$",C,{pos="N"}
)
g:Show()
\end{luadraw}
\end{document}这里用到的原理是,deepseek告诉我「三角形之于其内切斯坦纳椭圆的关系」,正如「一个等边三角形之于其内切圆的关系」。因此只要知道「A0B0C0」到「ABC」的仿射矩阵(代码中以基矩阵作为媒介),便可以对内切圆进行仿射变换M,立刻得到目标的内切椭圆...
