如何计算抛物线的顶点给出三个点

时间:2009-04-04 20:30:46

标签: curve-fitting

我有三个形成抛物线的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 ++中进行此计算的实际代码。任何人

9 个答案:

答案 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)

https://ideone.com/y0SxKU运行

#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