我有三个形成抛物线的X / Y点。我只需要计算抛物线的顶点是通过这三个点的。最好快速一点,因为我必须做很多这些计算!
“Ask A Scientist”网站提供this answer:
抛物线的一般形式由下式给出:A * x ^ 2 + B * x + C = y其中A,B和C是任意实常数。你有三对点是(x,y)有序对。将每个点的x和y值替换为抛物线的等式。您将得到三个未知数的三个LINEAR方程,即三个常数。然后,您可以轻松地为A,B和C的值三个方程式求解这个系统,并且您将得到与您的3个点相交的抛物线方程。顶点是一阶导数为0的位置,一个小代数给出了顶点的(-B / 2A,C - B ^ 2 / 4A)。
很高兴看到在C#或C ++中进行此计算的实际代码。任何人
答案 0 :(得分:29)
感谢David,我将您的伪代码转换为以下C#代码:
public static void CalcParabolaVertex(int x1, int y1, int x2, int y2, int x3, int y3, out double xv, out double yv)
{
double denom = (x1 - x2) * (x1 - x3) * (x2 - x3);
double A = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / denom;
double B = (x3*x3 * (y1 - y2) + x2*x2 * (y3 - y1) + x1*x1 * (y2 - y3)) / denom;
double C = (x2 * x3 * (x2 - x3) * y1 + x3 * x1 * (x3 - x1) * y2 + x1 * x2 * (x1 - x2) * y3) / denom;
xv = -B / (2*A);
yv = C - B*B / (4*A);
}
这就是我想要的。抛物线顶点的简单计算。我稍后会处理整数溢出。
答案 1 :(得分:22)
这实际上只是一个简单的线性代数问题,因此您可以象征性地进行计算。当你用三个点的x和y值代替时,你会得到三个未知数的三个线性方程。
A x1^2 + B x1 + C = y1
A x2^2 + B x2 + C = y2
A x3^2 + B x3 + C = y3
解决这个问题的直接方法是反转矩阵
x1^2 x1 1
x2^2 x2 1
x3^2 x3 1
并将其乘以向量
y1
y2
y3
结果是......好吧,不是那么简单;-)我在Mathematica中做过,这里是伪代码的公式:
denom = (x1 - x2)(x1 - x3)(x2 - x3)
A = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / denom
B = (x3^2 * (y1 - y2) + x2^2 * (y3 - y1) + x1^2 * (y2 - y3)) / denom
C = (x2 * x3 * (x2 - x3) * y1 + x3 * x1 * (x3 - x1) * y2 + x1 * x2 * (x1 - x2) * y3) / denom
或者,如果你想用数字方式进行矩阵数学运算,你通常会转向线性代数系统(如ATLAS,虽然我不确定它是否有C#/ C ++绑定)。
答案 2 :(得分:2)
通过直接替换得到以下三个等式:
A*x1^2+B*x1+C=y1
A*x2^2+B*x2+C=y2
A*x3^2+B*x3+C=y3
你可以通过注意这等于矩阵乘积来解决这个问题:
[x1^2 x1 1] [A] [y1]
|x2^2 x2 1|*|B| = |y2|
[x3^2 x3 1] [C] [y3]
所以你可以通过反转矩阵并将逆与右边的矢量相乘得到A,B和C.
我看到,在我发布这篇文章的时候,John Rasch已经链接到了更深入地解决矩阵方程的教程,所以你可以按照这些说明来得到答案。反转3x3矩阵非常容易,所以这不应该太难。
答案 3 :(得分:2)
以下是Fortran中实现@ david-z和@ AZDean解决方案的代码:
subroutine parabola_vertex(x1, y1, x2, y2, x3, y3, xv, yv)
real(dp), intent(in) :: x1, y1, x2, y2, x3, y3
real(dp), intent(out) :: xv, yv
real(dp) :: denom, A, B, C
denom = (x1 - x2) * (x1 - x3) * (x2 - x3)
A = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / denom
B = (x3**2 * (y1 - y2) + x2**2 * (y3 - y1) + x1**2 * (y2 - y3)) / denom
C = (x2 * x3 * (x2 - x3) * y1 + x3 * x1 * (x3 - x1) * y2 + &
x1 * x2 * (x1 - x2) * y3) / denom
xv = -B / (2*A)
yv = C - B**2 / (4*A)
end subroutine
答案 4 :(得分:1)
这闻起来像家庭作业。 “问科学家”是对的。假设您的3个点是(x1,y1),(x2,y2)和(x3,y3)。然后,您得到三个线性方程式:
| M11 M12 M13 | | A | | Z1 | | M21 M22 M23 | * | B | = | Z2 | | M31 M32 M33 | | C | | Z3 |
其中M 11 = x 1 2 ,M 12 = x 1 ,M 13 = 1,Z 1 = y 1 ,对于使用(x2,y2)和(x3)的其他两行类似,y3)代替(x1,y1)。
解决这个由3个方程组成的系统将为您提供A,B和C的解决方案。
答案 5 :(得分:1)
我做了类似于@ piSHOCK的回答,同样基于@ AZDean的代码。如果你需要大量运行它(或者像我一样在Matlab中使用它),这可能是最快的。
我的假设是x1 == -1, x2 == 0, x3 == 1
。
a = y2 - ( y1 + y3) / 2 % opposite signal compared to the original definition of A
b = (y3 - y1) / 4 % half of the originally defined B
xExtr = b / a
yExtr = y2 + b * yExtr % which is equal to y2 + b*b / a
答案 6 :(得分:0)
rgb = AddTextToImage(I,str,position);
答案 7 :(得分:0)
#include <iostream>
using namespace std;
// calculate the vertex of a parabola given three points
// https://stackoverflow.com/q/717762/16582
// @AZDean implementation with given x values
void CalcParabolaVertex(int x1, int y1, int x2, int y2, int x3, int y3, double& xv, double& yv)
{
double denom = (x1 - x2) * (x1 - x3) * (x2 - x3);
double A = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / denom;
double B = (x3*x3 * (y1 - y2) + x2*x2 * (y3 - y1) + x1*x1 * (y2 - y3)) / denom;
double C = (x2 * x3 * (x2 - x3) * y1 + x3 * x1 * (x3 - x1) * y2 + x1 * x2 * (x1 - x2) * y3) / denom;
xv = -B / (2*A);
yv = C - B*B / (4*A);
}
// @piSHOCK immplementation assuming regular x values ( wrong!!! )
void CalcParabolaVertex2( int y1, int y2, int y3, double& xv, double& yv)
{
double d1 = y1 - y2;
double d2 = y1 - y3;
double a = -d1 + 0.5 * d2;
double b = 2 * d1 - 0.5 * d2;
double c = -y1;
xv = -0.5 * b / a;
yv = c - 0.25 * b * b / a;
}
// corrected immplementation assuming regular x values
void CalcParabolaVertex3( int y1, int y2, int y3, double& xv, double& yv)
{
double d1 = y1 - y2;
double d2 = y1 - y3;
double a = d1 - 0.5 * d2;
double b = -2 * d1 + 0.5 * d2;
double c = y1;
xv = -0.5 * b / a;
yv = c - 0.25 * b * b / a;
}
int main() {
double xv, yv;
CalcParabolaVertex( 0, 100, 1, 500, 2, 200, xv, yv );
cout << xv <<" "<< yv << "\n";
CalcParabolaVertex2( 100, 500, 200, xv, yv );
cout << xv <<" "<< yv << "\n";
CalcParabolaVertex3( 100, 500, 200, xv, yv );
cout << xv <<" "<< yv << "\n";
return 0;
}
我为负向峰值添加了一些单元测试:以https://ideone.com/WGK90S实时运行
答案 8 :(得分:-1)
如果您假设x1 == 0, x2 == 1, x3 == 2
,例如在将曲线局部拟合到某个均匀采样信号时,那么@AZDean的代码将简化为:
d1 = y1 - y2
d2 = y1 - y3
a = d1 - 0.5 * d2
b = -2 * d1 + 0.5 * d2
c = y1
xVertex = -0.5 * b / a
yVertex = c - 0.25 * b * b / a