圆锥曲线齐次式(homogeneous form)是,所有系数乘上非0常数
后等式仍然成立。
坐标转换
圆锥曲线标准形式的x轴与长半轴重合,y轴与短半轴重合。考虑圆锥曲线有倾斜的情况,其中心点坐标为,长半轴与 x 轴的夹角为 θ,则点
对应到标准形式坐标系下为点
,这个坐标转换是后面所有推导的前置条件。
椭圆标准形式和齐次式之间的参数转换
中心点坐标为,长半轴与 x 轴的夹角为 θ的椭圆标准方程为:
展开后与齐次式做对比,可得
利用前三式对后三式进行转化,可得
齐次式到标准形式的参数转换
利用D、E相关的两个等式解得
前三式推得,而
,因此
,解得
进一步分析可知才是长半轴对应的倾角(
是短半轴与x轴的夹角)
将代入方程组,得到
综上,最终结果为
标准形式到齐次式的参数转换
同样可得,取
直接可解出
编程实践上一般取,此时
双曲线标准形式和齐次式之间的参数转换
中心点坐标为,实半轴与 x 轴的夹角为 θ的双曲线标准方程为:
展开后与齐次式做对比,可得
利用前三式对后三式进行转化,可得
齐次式到标准形式的参数转换
同椭圆齐次式到标准形式的参数转换推导,可得
进一步分析可知才是实半轴对应的倾角(
是虚半轴与x轴的夹角)
将代入方程组,得到
综上,最终结果为
标准形式到齐次式的参数转换
同样可得,取
直接可解出
编程实践上一般取,此时
抛物线标准形式和齐次式之间的参数转换
顶点点坐标为,焦距为f,对称轴与 x 轴的夹角为 θ的抛物线标准方程为:
展开后与齐次式做对比,可得
利用前三式对后三式进行转化,可得
齐次式到标准形式的参数转换
由前三式得,利用抛物线齐次式的性质
可将
的
和
都消去,得到
,这时候如果
,则需要将
加上180度,使得
记、
则
,可将
的二次项都消去,得到
解方程组可得
标准形式到齐次式的参数转换
同样可得,取
直接可解出
C++编程实践
这里给出圆锥曲线标准形式和齐次式之间的参数转换的C++代码
#include <cmath>
#define DBL long double
void ellipse_homogeneous(DBL a, DBL b, DBL t, DBL x, DBL y, DBL (&c)[6]) {
// 根据椭圆的长短半轴、倾斜角度和中心坐标计算椭圆一般式的系数
DBL si = sin(t), co = cos(t);
c[0] = si/b*si/b + co/a*co/a; c[1] = 2.*(1./a/a - 1./b/b)*si*co; c[2] = co/b*co/b + si/a*si/a;
c[3] = -2.*c[0]*x - c[1]*y; c[4] = -2.*c[2]*y - c[1]*x; c[5] = -(c[3]*x + c[4]*y)/2. - 1.;
}
void ellipse_params(DBL (&c)[6], DBL &a, DBL &b, DBL &t, DBL &x, DBL &y) {
// 根据椭圆一般式的系数计算长短半轴、倾斜角度和中心坐标
if (c[0] < 0) for (int i=0; i<6; ++i) c[i] = -c[i];
DBL p = 4.*c[0]*c[2] - c[1]*c[1], q = sqrt((c[0]-c[2])*(c[0]-c[2]) + c[1]*c[1]);
DBL r = 2.*((c[0]*c[4]*c[4] - c[1]*c[3]*c[4] + c[2]*c[3]*c[3])/p - c[5]);
a = sqrt(r / (c[0]+c[2]-q)); b = sqrt(r / (c[0]+c[2]+q)); t = atan2(q - c[0] + c[2], c[1]);
x = (c[1]*c[4] - 2.*c[2]*c[3]) / p; y = (c[1]*c[3] - 2.*c[0]*c[4]) / p;
}
void parabola_homogeneous(DBL x, DBL y, DBL f, DBL t, DBL (&c)[6]) {
// 根据抛物线的顶点坐标、焦距和倾斜角度计算抛物线一般式的系数
DBL si = sin(t), co = cos(t);
c[0] = si*si; c[1] = -2*si*co; c[2] = co*co; c[3] = -2*c[0]*x-c[1]*y-4*f*co;
c[4] = -2*c[2]*y-c[1]*x-4*f*si; c[5] = c[0]*x*x + c[1]*x*y + c[2]*y*y + 4*f*x*co + 4*f*y*si;
}
void parabola_params(DBL (&c)[6], DBL &x, DBL &y, DBL &f, DBL &t) {
// 根据抛物线一般式的系数计算顶点坐标、焦距和倾斜角度
t = atan2(2.*c[0], -c[1]);
DBL co = cos(t), si = sin(t), s = (c[0]+c[2])*co, t = (c[0]+c[2])*si;
f = (c[1]*c[4]-2.*c[2]*c[3]) / (8.*c[2]*s-4.*c[1]*t);
if (f < 0.) t = atan2(-2.*c[0], c[1]), f = -f, si = -si, co = -co, s = -s, t = -t;
DBL d1 = c[3] + 4.*f*s, e1 = c[4] + 4.*f*t; s = 4.*f*s - d1/2.; t = 4.*f*t - e1/2.;
x = (c[1]*c[5] + d1*t) / (c[1]*s - 2*c[0]*t); y = -(2.*c[0]*x + d1) / c[1];
}
void hyperbola_homogeneous(DBL a, DBL b, DBL t, DBL x, DBL y, DBL (&c)[6]) {
// 根据双曲线的实半轴、虚半轴、倾斜角度和中心坐标计算双曲线一般式的系数
DBL si = sin(t), co = cos(t);
c[0] = co/a*co/a - si/b*si/b; c[1] = 2.*(1./a/a + 1./b/b)*si*co; c[2] = si/a*si/a - co/b*co/b;
c[3] = -(2.*c[0]*x + c[1]*y); c[4] = -(2.*c[2]*y + c[1]*x); c[5] = -(c[3]*x + c[4]*y)/2. - 1.;
}
void hyperbola_params(DBL (&c)[6], DBL &a, DBL &b, DBL &t, DBL &x, DBL &y) {
// 根据双曲线一般式的系数计算长短半轴、倾斜角度和中心坐标
DBL p = 4.*c[0]*c[2] - c[1]*c[1], q = sqrt((c[0]-c[2])*(c[0]-c[2]) + c[1]*c[1]);
DBL r = 2.*((c[0]*c[4]*c[4] - c[1]*c[3]*c[4] + c[2]*c[3]*c[3])/p - c[5]);
a = sqrt(r / (q+c[0]+c[2])), b = sqrt(r / (q-c[0]-c[2])); t = atan2(c[2]-c[0]+q, c[1]);
x = (c[1]*c[4] - 2.*c[2]*c[3]) / p; y = (c[1]*c[3] - 2.*c[0]*c[4]) / p;
}