Checking to see if 3 points are on the same line - pseudocode

I want to know a piece of a code which can actually tell me if 3 points in a 2D space are on the same line or not. A pseudo-code is also sufficient but Python is better.

You can check if the area of the ABC triangle is 0:
[ Ax * (By - Cy) + Bx * (Cy - Ay) + Cx * (Ay - By) ] / 2
Of course, you don't actually need to divide by 2.

This is C++, but you can adapt it to python:
bool collinear(int x1, int y1, int x2, int y2, int x3, int y3) {
return (y1 - y2) * (x1 - x3) == (y1 - y3) * (x1 - x2);
}
Basically, we are checking that the slopes between point 1 and point 2 and point 1 and point 3 match. Slope is change in y divided by change in x, so we have:
y1 - y2 y1 - y3
------- = --------
x1 - x2 x1 - x3
Cross multiplying gives (y1 - y2) * (x1 - x3) == (y1 - y3) * (x1 - x2);
Note, if you are using doubles, you can check against an epsilon:
bool collinear(double x1, double y1, double x2, double y2, double x3, double y3) {
return fabs((y1 - y2) * (x1 - x3) - (y1 - y3) * (x1 - x2)) <= 1e-9;
}

y - y0 = a(x-x0) (1) while a = (y1 - y0)/(x1 - x0) and A(x0, y0) B(x1, y1) C(x2, y2). See whether C statisfies (1). You just replace the appropriate values.
Details

Read this, and use it to find the equation of a line through the first two points. Follow the instructions to find m and b. Then for your third point, calculate mx + b - y. If the result is zero, the third point is on the same line as the first two.

Rule 1: In any linear 2d space, two points are always on the same line.
Take 2 points and build an equation that represents a line through them.
Then check if the third point is also on that line.
Good luck.

Related

Need help simulating a basic Missile - Target Simulation (Algorithm - prefered Qbasic)

i was given a homework to simulate a Guided missile following a target.
Answers in diffrent languages accepted. i just need to understand how to develop the right algorithm.
Problem Definition:
A target is seen at some (x,y) coordinates with constant speed V2 both taken as input by the user.
At this time a missile is launched at (0,0) with a user defined V1 constant speed to hit the target.
The target has to pass x=500 to escape the missile and should also keep a secure distance from the missile.
Develop a program to simulate this progress
If i let the target fly straight without considering the location of the missile it works fine. But considering the missiles location it flies in a weird way.
I wrote this code but the problem is that if the target arrives at around x=499 it just flies upwards and never crosses x=500.
My code so far (Qbasic):
CLS
SCREEN 12
WINDOW (-50, 600)-(600, -50)
LINE (0, 0)-(500, 0)
LINE (0, 500)-(0, 0)
INPUT "Speed of Missile, v1=", v1
INPUT "Speed of target, v2=", v2
INPUT "Coordinate x of the plane, x=", x2
INPUT "Coordinate y of the plane, y=", y2
CIRCLE (x2, y2), 1
x = 500: y = y2
xx1 = 0: yy1 = 0
xx2 = x2: yy2 = y2
dlt = 0.05
x1 = 0
y1 = 0
draww:
LINE (xx1, yy1)-(x1, y1), 3
LINE (xx2, yy2)-(x2, y2), 1
xx1 = x1: yy1 = y1: xx2 = x2: yy2 = y2
x1 = x1 + dlt * v1 * (xx2 - xx1) / SQR((xx2 - xx1) ^ 2 + (yy2 - yy1) ^ 2)
y1 = y1 + dlt * v1 * (yy2 - yy1) / SQR((xx2 - xx1) ^ 2 + (yy2 - yy1) ^ 2)
x2 = x2 + dlt * v2 * (x - xx2) / SQR((x - xx2) ^ 2 + (yy2 - yy1) ^ 2)
y2 = y2 + dlt * v2 * (yy2 - yy1) / SQR((x - xx2) ^ 2 + (yy2 - yy1) ^ 2)
Delay! = TIMER
DO
LOOP UNTIL TIMER - Delay! > 0
IF x2 >= x GOTO escaped
IF x1 > x2 GOTO caught
GOTO draww
caught: PRINT "Target was hit": GOTO endd
escaped: PRINT "Target escaped"
endd: END
Some weird results i get with this code:
http://prntscr.com/q8e0z1
http://prntscr.com/q8e1bn
How can i accomplish to keep some distance from the missile while flying towards x=500

Efficiently list every unique pair of points in a grid

Seemingly an easy problem, I am looking for an algorithm to list every unique pair of points in a grid that are not collinear with the origin. The trick is to somehow avoid all the different symmetries and coincidences. This is what I have so far:
for( int x1 = 0; x1 <= s; x1++ ){
for( int y1 = 0; y1 <= s; y1++ ){
if( x1 == 0 && y1 == 0 ) continue; // P1 is coincident with origin
for( int x2 = x1; x2 <= s; x2++ ){
for( int y2 = 0; y2 <= s; y2++ ){
if( x1 == x2 && y2 >= y1 ) continue;
if( x1 * y2 == x2 * y1 ) continue; // points are collinear with origin
// this is a valid point
}
}
}
}
Enumerate all unique pairs (by defining an order on the grid points) and disregard those that are aligned with the origin.
def Pair(X0, Y0, X1, Y1):
if X0 * Y1 != X1 * Y0:
# Non collinear with the origin
Accept(X0, Y0, X1, Y1)
# Enumerate all (X0, Y0)
for X0 in range(NX):
for Y0 in range(NY):
# Enumerate all (X1, Y1) > (X0, Y0) in the lexicographical sense
# 1) X1 == X0, Y1 > Y0
X1= X0
for Y1 in range(Y0 + 1, NY):
Pair(X0, Y0, X1, Y1)
# 2) X1 > X0
for X1 in range(X0 + 1, NX):
for Y1 in range(NY):
Pair(X0, Y0, X1, Y1)
Or, better:
# Enumerate all (X0, Y0)
for X0 in range(NX):
for Y0 in range(NY):
# Enumerate all (X1, Y1) > (X0, Y0) in the lexicographical sense
for X1 in range(X0, NX):
for Y1 in range(0 if X1 > X0 else Y0 + 1, NY):
if X0 * Y1 != X1 * Y0:
# Non collinear with the origin
Accept(X0, Y0, X1, Y1)

find center of circle when three points are given

I studied this link and coded accordingly but getting Wrong Answer for the example explained in the link,
During solving the equation, I subtracted equation 2 from equation 1 and equation 3 from equation 2 and then proceed further. Please check link for clarification.
My code is:
include<stdio.h>
int is_formCircle(float a1,float b1,float a2,float b2,float a3,float b3) {
float p1=a2-a1;
float p2=a3-a2;
float p3=b2-b1;
float p4=b3-b2;
float alpha=(a1+a2)*(a1-a2) + (b1+b2)*(b1-b2);
float beta =(a2+a3)*(a2-a3) + (b2+b3)*(b2-b3);
float y1=p1*beta - p2*alpha;
float y2=p2*p3 - p1*p4;
if(y2==0 || y1==0) return 1;
float y=y1/y2;
float x1 = 2*p4*y + beta;
float x2 = 2*p2;
float x = x1/x2;
printf("x=%f y=%f\n",x,y);
return 0;
}
int main() {
float a1,a2,a3,a4,b1,b2,b3,b4;
a1=4.0;
b1=1.0;
a2=-3.0;
b2=7.0;
a3=5.0;
b3=-2.0;
is_formCircle(a1,b1,a2,b2,a3,b3);
return 0;
}
MY another Code:
#include<stdio.h>
int is_formCircle(float a1,float b1,float a2,float b2,float a3,float b3) {
float mid1,mid2,mid3,mid4,m1,m2,D,Dx,Dy,x,y;
mid1 = a1+(a2-a1)/2;
mid2 = b1+(b2-b1)/2;
mid3 = a2+(a3-a2)/2;
mid4 = b2+(b3-b2)/2;
m1=(b2-b1)/(a2-a1);
m2=(b3-b2)/(a3-a2);
m1=-1*m1;
m2=-1*m2;
D=m2-m1;
Dx=mid2-(m1*mid1) + (mid3*m2) - mid4;
Dy=(m1*(mid3*m2-mid4))-(m2*(mid1*m1-mid2));
x=Dx/D;
y=Dy/D;
printf("%f %f",x,y);
return 0;
}
int main() {
float a1,a2,a3,b1,b2,b3;
a1=4.0;
b1=1.0;
a2=-3.0;
b2=7.0;
a3=5.0;
b3=-2.0;
is_formCircle(a1,b1,a2,b2,a3,b3);
return 0;
}
Why my code giving Wrong Answer?
I have to say, if you're following the link you listed, it would've helped to keep the variable names the same. We could understand the algorithm much better seeing x1, y1, x2, y2, x3, y3 instead of p1, p2, p3, p4, alpha and beta. In fact, I don't see much in your algorithm that matches the link. I'm not trying to be as harsh as the comments were (and if you're worried about switching float to double, that was a perfectly good case for a typedef), but debugging algorithms is easiest when you don't have to convert variable names.
I would recommend simply using what they give you for h and k in the link, which is namely done by calculating determinants of 3x3 matrices. You can find lots of references for that.
I'd make two functions, as follows:
float calculateH(float x1, float y1, float x2, float y2, float x3, float y3) {
float numerator = (x2*x2+y2*y2)*y3 - (x3*x3+y3*y3)*y2 -
((x1*x1+y1*y1)*y3 - (x3*x3+y3*y3)*y1) +
(x1*x1+y1*y1)*y2 - (x2*x2+y2*y2)*y1;
float denominator = (x2*y3-x3*y2) -
(x1*y3-x3*y1) +
(x1*y2-x2*y1);
denominator *= 2;
return numerator / denominator;
}
float calculateK(float x1, float y1, float x2, float y2, float x3, float y3) {
float numerator = x2*(x3*x3+y3*y3) - x3*(x2*x2+y2*y2) -
(x1*(x3*x3+y3*y3) - x3*(x1*x1+y1*y1)) +
x1*(x2*x2+y2*y2) - x2*(x1*x1+y1*y1);
float denominator = (x2*y3-x3*y2) -
(x1*y3-x3*y1) +
(x1*y2-x2*y1);
denominator *= 2;
return numerator / denominator;
}
Then your is_formCircle would simply be:
float is_formCircle(float x1, float y1, float x2, float y2, float x3, float y3) {
float h = calculateH(x1, y1, x2, y2, x3, y3);
float k = calculateK(x1, y1, x2, y2, x3, y3);
printf("x=%f y=%f\n",h,k);
}
There are tons of ways to optimize this, and there's a chance I typoed any of the determinant calculations, but it should get you going.
The solution that was given in the link is a "blind" solution, i.e., you know the equation, boom solve it.
However, if you understand more deeply what is behind the scene, you will be able to:
Write a more readable, reliable, flexible code.
Debug easily.
What happen when you substract equation 1 from equation 2? You actually try to find the equation of the straight line describing those points which are equidistant from the point 1 and the point 2. Then, you do the same with point 2 and 3. Finally, you find the intersection between these to lines, which gives you the center of the circle.
How do you describe the straight line of the points equidistant to the point 1 and 2? You take the point that is in the middle of the two, and go in the direction perpendicular to the direction between point 1 and 2.
If this is not absolutly clear, take a paper and draw an example: put points 1,2 and 3, find the two lines and find the intersection.
Now that you understood everything, reshape your code with two functions, on that find the line equidistant between two points, another one which compute the intersection between two lines...
After your edit, the code looked better, although it was not simple to understand. I think that the mistake is when you solve for the intersection of the two lines, do not forget that you are under parametric form:
Dx = (mid4-mid2) - m2*(mid3-mid1);
lambda=Dx/D;
x = mid1 + lambda*m1;
y = mid2 + lambda*1.0;
Checked graphically using Matlab.

Algorithm to find local minimum by parabolic interpolation of three points [duplicate]

I have three X/Y points that form a parabola. I simply need to calculate what the vertex of the parabola is that goes through these three points. Preferably a quick way as I have to do a LOT of these calculations!
The "Ask A Scientist" website provides this answer:
The general form of a parabola is given by the equation: A * x^2 + B * x + C = y where A, B, and C are arbitrary Real constants. You have three pairs of points that are (x,y) ordered pairs. Substitute the x and y values of each point into the equation for a parabola. You will get three LINEAR equations in three unknowns, the three constants. You can then easily solve this system of three equations for the values of A, B, and C, and you'll have the equation of the parabola that intersects your 3 points. The vertex is where the first derivative is 0, a little algebra gives: ( -B/2A , C - B^2/4A ) for the vertex.
It would be nice to see actual code that does this calculation in C# or C++. Anybody?
Thanks David, I converted your pseudocode to the following C# code:
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);
}
This is what I wanted. A simple calculation of the parabola's vertex. I'll handle integer overflow later.
This is really just a simple linear algebra problem, so you can do the calculation symbolically. When you substitute in the x and y values of your three points, you'll get three linear equations in three unknowns.
A x1^2 + B x1 + C = y1
A x2^2 + B x2 + C = y2
A x3^2 + B x3 + C = y3
The straightforward way to solve this is to invert the matrix
x1^2 x1 1
x2^2 x2 1
x3^2 x3 1
and multiply it by the vector
y1
y2
y3
The result of this is... okay, not exactly all that simple ;-) I did it in Mathematica, and here are the formulas in pseudocode:
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
Alternatively, if you wanted to do the matrix math numerically, you'd typically turn to a linear algebra system (like ATLAS, though I'm not sure if it has C#/C++ bindings).
In any case, once you have the values of A, B, and C as calculated by these formulas, you just have to plug them into the expressions given in the question, -B / 2A and C - B^2/4A, to calculate the coordinates of the vertex.1
Note that if the original three points have coordinates that make denom a very large or very small number, doing the calculation directly might be susceptible to significant numerical error. In that case it might be better to modify it a bit, to avoid dividing by the denominators where they would cancel out anyway:
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)
and then the coordinates of the vertex are -b / 2a and (c - b^2 / 4a) / denom. There are various other situations that might benefit from "tricks" like this, such as if A is very large or very small, or if C is nearly equal to B^2 / 4A so that their difference is very small, but I think those situations vary enough that a full discussion would be better left for case-by-case followup questions.
Converting all of this to code in the language of your choice is left as an exercise for the reader. (It should be pretty trivial in any language that uses standard infix operator syntax, e.g. as AZDean showed in C#.)
1In the initial version of the answer I thought this would be obvious, but it seems there are a lot of people who like having it mentioned explicitly.
You get the following three equations by direct substitution:
A*x1^2+B*x1+C=y1
A*x2^2+B*x2+C=y2
A*x3^2+B*x3+C=y3
You can solve this by noting that this is equivalent to the matrix product:
[x1^2 x1 1] [A] [y1]
|x2^2 x2 1|*|B| = |y2|
[x3^2 x3 1] [C] [y3]
So you can get A,B, and C by inverting the matrix and multiplying the inverse with the vector on the right.
I see that while I've been posting this John Rasch has linked to tutorial that goes into more depth on actually solving the matrix equation, so you can follow those instructions to get the answer. Inverting a 3x3 matrix is quite easy, so this shouldn't be too tough.
Here is a code in Fortran that implements #david-z and #AZDean's solution:
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
I've done something similar to #piSHOCK's answer, also based on #AZDean's code. If you need to run it heavily (or to use it in Matlab like me), this might be the fastest one.
My assumption is that 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 * xExtr % which is equal to y2 + b*b / a
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)
This smells like homework. "Ask a Scientist" is right on. Say your 3 points are (x1, y1), (x2, y2), and (x3, y3). Then, you get three linear equations:
| M11 M12 M13 | | A | | Z1 |
| M21 M22 M23 | * | B | = | Z2 |
| M31 M32 M33 | | C | | Z3 |
Where M11 = x12, M12 = x1, M13 = 1, Z1 = y1, and similarly for the other two rows using (x2, y2) and (x3, y3) in place of (x1, y1).
Solving this system of 3 equations will give you a solution for A, B, and C.
Running at 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;
}
I have added a couple of unit tests for negative going peaks: running live at https://ideone.com/WGK90S

How to calculate the vertex of a parabola given three points

I have three X/Y points that form a parabola. I simply need to calculate what the vertex of the parabola is that goes through these three points. Preferably a quick way as I have to do a LOT of these calculations!
The "Ask A Scientist" website provides this answer:
The general form of a parabola is given by the equation: A * x^2 + B * x + C = y where A, B, and C are arbitrary Real constants. You have three pairs of points that are (x,y) ordered pairs. Substitute the x and y values of each point into the equation for a parabola. You will get three LINEAR equations in three unknowns, the three constants. You can then easily solve this system of three equations for the values of A, B, and C, and you'll have the equation of the parabola that intersects your 3 points. The vertex is where the first derivative is 0, a little algebra gives: ( -B/2A , C - B^2/4A ) for the vertex.
It would be nice to see actual code that does this calculation in C# or C++. Anybody?
Thanks David, I converted your pseudocode to the following C# code:
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);
}
This is what I wanted. A simple calculation of the parabola's vertex. I'll handle integer overflow later.
This is really just a simple linear algebra problem, so you can do the calculation symbolically. When you substitute in the x and y values of your three points, you'll get three linear equations in three unknowns.
A x1^2 + B x1 + C = y1
A x2^2 + B x2 + C = y2
A x3^2 + B x3 + C = y3
The straightforward way to solve this is to invert the matrix
x1^2 x1 1
x2^2 x2 1
x3^2 x3 1
and multiply it by the vector
y1
y2
y3
The result of this is... okay, not exactly all that simple ;-) I did it in Mathematica, and here are the formulas in pseudocode:
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
Alternatively, if you wanted to do the matrix math numerically, you'd typically turn to a linear algebra system (like ATLAS, though I'm not sure if it has C#/C++ bindings).
In any case, once you have the values of A, B, and C as calculated by these formulas, you just have to plug them into the expressions given in the question, -B / 2A and C - B^2/4A, to calculate the coordinates of the vertex.1
Note that if the original three points have coordinates that make denom a very large or very small number, doing the calculation directly might be susceptible to significant numerical error. In that case it might be better to modify it a bit, to avoid dividing by the denominators where they would cancel out anyway:
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)
and then the coordinates of the vertex are -b / 2a and (c - b^2 / 4a) / denom. There are various other situations that might benefit from "tricks" like this, such as if A is very large or very small, or if C is nearly equal to B^2 / 4A so that their difference is very small, but I think those situations vary enough that a full discussion would be better left for case-by-case followup questions.
Converting all of this to code in the language of your choice is left as an exercise for the reader. (It should be pretty trivial in any language that uses standard infix operator syntax, e.g. as AZDean showed in C#.)
1In the initial version of the answer I thought this would be obvious, but it seems there are a lot of people who like having it mentioned explicitly.
You get the following three equations by direct substitution:
A*x1^2+B*x1+C=y1
A*x2^2+B*x2+C=y2
A*x3^2+B*x3+C=y3
You can solve this by noting that this is equivalent to the matrix product:
[x1^2 x1 1] [A] [y1]
|x2^2 x2 1|*|B| = |y2|
[x3^2 x3 1] [C] [y3]
So you can get A,B, and C by inverting the matrix and multiplying the inverse with the vector on the right.
I see that while I've been posting this John Rasch has linked to tutorial that goes into more depth on actually solving the matrix equation, so you can follow those instructions to get the answer. Inverting a 3x3 matrix is quite easy, so this shouldn't be too tough.
Here is a code in Fortran that implements #david-z and #AZDean's solution:
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
I've done something similar to #piSHOCK's answer, also based on #AZDean's code. If you need to run it heavily (or to use it in Matlab like me), this might be the fastest one.
My assumption is that 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 * xExtr % which is equal to y2 + b*b / a
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)
This smells like homework. "Ask a Scientist" is right on. Say your 3 points are (x1, y1), (x2, y2), and (x3, y3). Then, you get three linear equations:
| M11 M12 M13 | | A | | Z1 |
| M21 M22 M23 | * | B | = | Z2 |
| M31 M32 M33 | | C | | Z3 |
Where M11 = x12, M12 = x1, M13 = 1, Z1 = y1, and similarly for the other two rows using (x2, y2) and (x3, y3) in place of (x1, y1).
Solving this system of 3 equations will give you a solution for A, B, and C.
Running at 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;
}
I have added a couple of unit tests for negative going peaks: running live at https://ideone.com/WGK90S

Resources