18

放物線を形成する 3 つの X/Y ポイントがあります。この 3 点を通る放物線の頂点を計算するだけです。私はこれらの計算をたくさんしなければならないので、できれば簡単な方法です!

「Ask A Scientist」ウェブサイトには、次の回答が記載されています。

放物線の一般的な形式は次の式で与えられます: A * x^2 + B * x + C = y ここで、A、B、および C は任意の実数定数です。(x,y) 順序付けられたペアである点の 3 つのペアがあります。各点の x 値と y 値を放物線の方程式に代入します。3 つの未知数、3 つの定数で 3 つの線形方程式が得られます。次に、A、B、および C の値について、この 3 つの方程式系を簡単に解くことができ、3 つの点と交差する放物線の方程式が得られます。頂点は、一次導関数が 0 の場所です。小さな代数は、頂点に対して ( -B/2A , C - B^2/4A ) を与えます。

C# または C++ でこの計算を行う実際のコードを確認できれば幸いです。誰か?

4

8 に答える 8

33

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);
}

これが私が欲しかったものです。放物線の頂点の簡単な計算。後で整数オーバーフローを処理します。

于 2009-04-04T21:16:09.110 に答える
25

これは実際には単純な線形代数の問題なので、計算を記号的に行うことができます。3 つの点の x 値と y 値を代入すると、3 つの未知数で 3 つの線形方程式が得られます。

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++ バインディングがあるかどうかはわかりません) を使用します。

いずれにせよ、これらの式で計算されたAB、およびの値をC取得したら、それらを質問で指定された式に差し込むだけ-B / 2AC - B^2/4A、頂点の座標を計算できます。1

元の 3 点の座標がdenom非常に大きな数または非常に小さな数になる場合、直接計算を行うと、重大な数値エラーが発生する可能性があることに注意してください。その場合、分母で割ることを避けるために、少し変更する方が良いかもしれません。

denom = (x1 - x2)(x1 - x3)(x2 - x3)
a = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2))
b = (x3^2 * (y1 - y2) + x2^2 * (y3 - y1) + x1^2 * (y2 - y3))
c = (x2 * x3 * (x2 - x3) * y1 + x3 * x1 * (x3 - x1) * y2 + x1 * x2 * (x1 - x2) * y3)

そして、頂点の座標は-b / 2a(c - b^2 / 4a) / denomです。このような「トリック」の恩恵を受ける可能性のある状況は他にもさまざまあります。たとえば、Aが非常に大きいか非常に小さい場合、またはCがほぼ等しいB^2 / 4Aために差が非常に小さい場合などです。ケースバイケースのフォローアップの質問のために残しておいたほうがよいでしょう。

これらすべてを選択した言語のコードに変換することは、読者の課題として残されています。(たとえばAZDean が C# で示したように、標準の中置演算子構文を使用する言語では、かなり簡単なはずです。)


1回答の最初のバージョンでは、これは明らかだと思いましたが、明示的に言及することを好む人がたくさんいるようです。

于 2009-04-04T20:45:54.427 に答える
3

直接代入すると、次の 3 つの方程式が得られます。

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 行列の反転は非常に簡単なので、それほど難しいことではありません。

于 2009-04-04T20:42:10.597 に答える
2

@david-z と @AZDean のソリューションを実装する Fortran のコードを次に示します。

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
于 2014-05-02T22:28:13.623 に答える
1
def vertex(x1,x2,x3,y1,y2,y3):
    '''Given three pairs of (x,y) points return the vertex of the
         parabola passing through the points. Vectorized and common expression reduced.'''
    #Define a sequence of sub expressions to reduce redundant flops
    x0 = 1/x2
    x4 = x1 - x2
    x5 = 1/x4
    x6 = x1**2
    x7 = 1/x6
    x8 = x2**2
    x9 = -x7*x8 + 1
    x10 = x0*x1*x5*x9
    x11 = 1/x1
    x12 = x3**2
    x13 = x11*x12
    x14 = 1/(x0*x13 - x0*x3 - x11*x3 + 1)
    x15 = x14*y3
    x16 = x10*x15
    x17 = x0*x5
    x18 = -x13 + x3
    x19 = y2*(x1*x17 + x14*x18*x6*x9/(x4**2*x8))
    x20 = x2*x5
    x21 = x11*x20
    x22 = x14*(-x12*x7 + x18*x21)
    x23 = y1*(-x10*x22 - x21)
    x24 = x16/2 - x19/2 - x23/2
    x25 = -x17*x9 + x7
    x26 = x0*x1*x14*x18*x5
    x27 = 1/(-x15*x25 + y1*(x20*x7 - x22*x25 + x7) + y2*(-x17 + x25*x26))
    x28 = x24*x27
    return x28,x15 + x22*y1 + x24**2*x27 - x26*y2 + x28*(-x16 + x19 + x23)
于 2017-04-13T13:45:26.217 に答える
0

これは宿題の匂いがします。「科学者に聞く」は正しいです。あなたの3点が(x1、y1)、(x2、y2)、および(x3、y3)であるとしましょう。次に、次の 3 つの線形方程式が得られます。

| | M 11 M 12 M 13 | | | あ | | | Z1 | _
| | M 21 M 22 M 23 | * | | ビ | = | Z 2 |
| | 中313233 | | | シー | | | Z 3 |

ここで、M 11 = x 1 2、M 12 = x 1、M 13 = 1、Z 1 = y 1であり、他の 2 行についても同様に (x1、 y1)。

この 3 つの連立方程式を解くと、A、B、C の解が得られます。

于 2009-04-04T20:39:58.450 に答える