iOS: How to determine whether three CGPoints lie in a straight line - algorithm

I have two given CGPoints A and B and one another CGPoint C as obtained from within touchesEnded event.
I want to determine whether the three points lie in a straight line for which I have used the below given formula:
For point A(x1, y1), B(x2, y2) and C(x3, y3)
x1(y2 - y3) + x2 (y3-y1) + x3(y1-y2) = 0
But the formula doesn't helpful at all.
is there any other way of determining collinearity of three points in iOS
Thanks
arnieterm

This is not really an iOS question, or even a programming question -- it's an algorithm question.
I'm not sure if the algorithm you were given is correct -- see the cross-product answer given in comments for what I think of as the correct answer. In what way do you find your formula not helpful? Here it is in code, btw. (code typed in browser, not checked):
CGPoint p1;
CGPoint p2;
CGPoint p3;
const float closeEnough = 0.00001; // because floats rarely == 0
float v1 = p1.x * (p2.y - p3.y);
float v2 = p2.x * (p3.y - p1.y);
float v3 = p3.x * (p1.y - p2.y);
if (ABS(v1 + v2 + v3) < closeEnough)
{
// your algorithm is true
}

Related

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.

Linear interpolation along a "Bresenham line"

I'm using linear interpolation for animating an object between two 2d coordinates on the screen. This is pretty close to what I want, but because of rounding, I get a jagged motion. In ASCII art:
ooo
ooo
ooo
oo
Notice how it walks in a Manhattan grid, instead of taking 45 degree turns. What I'd like is linear interpolation along the line which Bresenham's algorithm would have created:
oo
oo
oo
oo
For each x there is only one corresponding y. (And swap x/y for a line that is steep)
So why don't I just use Bresenham's algorithm? I certainly could, but that algorithm is iterative, and I'd like to know just one coordinate along the line.
I am going to try solving this by linearly interpolating the x coordinate, round it to the pixel grid, and then finding the corresponding y. (Again, swap x/y for steep lines). No matter how that solution pans out, though, I'd be interested in other suggestion and maybe previous experience.
Bresenham's algorithm for lines was introduced to draw a complete line a bit faster than usual approaches. It has two major advantages:
It works on integer variables
It works iteratively, which is fast, when drawing the complete line
The first advantage is not a great deal, if you calculate only some coordinates. The second advantage turns out as a disadvantage when calculating only some coordinates. So after all, there is no need to use Bresenham's algorithm.
Instead, you can use a different algorithm, which results in the same line. For example the DDA (digital differential analyzer). This is basically, the same approach you mentioned.
First step: Calculate the slope.
m = (y_end - y_start) / (x_end - x_start)
Second step: Calculate the iteration step, which is simply:
i = x - x_start
Third step: Calculate the coresponding y-value:
y = y_start + i * m
= y_start + (x - x_start) * (y_end - y_start) / (x_end - x_start)
Here's the solution I ended up with:
public static Vector2 BresenhamLerp(Vector2 a, Vector2 b, float percent)
{
if (a.x == b.x || Math.Abs(a.x - b.x) < Math.Abs(a.y - b.y))
{
// Didn't do this part yet. Basically, we just need to recurse
// with x/y swapped and swap result on return
}
Vector2 result;
result.x = Math.Round((1-percent) * a.x + percent * b.x);
float adjustedPercent = (result.x - a.x + 0.5f) / (b.x - a.x);
result.y = Math.Round((1-adjustedPercent) * a.y + adjustedPercent * b.y);
return result;
}
This is what I just figured out would work. Probably not the most beautiful interpolations, but it is just a 1-2 float additions per iteration on the line with a one-time precalculation. Works by calculating the number of steps on a manhattan matrix.
Ah, and it does not yet catch the case when the line is vertical (dx = 0)
This is the naive bresenham, but the iterations could in theory only use integers as well. If you want to get rid of the float color value, things are going to get harder because the line might be longer than the color difference, so delta-color < 1.
void Brepolate( uint8_t* pColorBuffer, uint8_t cs, float xs, float ys, float zs, uint8_t ce, float xe, float ye, float ze )
{
float nColSteps = (xe - xs) + (ye - ys);
float fColInc = ((float)cs - (float)ce) / nColSteps;
float fCol = cs;
float dx = xe - xs;
float dy = ye - ys;
float fCol = cs;
if (dx > 0.5)
{
float de = fabs( dy / dx );
float re = de - 0.5f;
uint32_t iY = ys;
uint32_t iX;
for ( uint32_t iX = xs;
iX <= xe;
iX++ )
{
uint32_t off = surf.Offset( iX, iY );
pColorBuffer[off] = fCol;
re += de;
if (re >= 0.5f)
{
iY++;
re -= 1.0f;
fCol += fColInc;
}
fCol += fColInc;
}
}
}

Calculate direction angle from two vectors?

Say I have two 2D vectors, one for an objects current position and one for that objects previous position. How can I work out the angular direction of travel?
This image might help understand what I'm after:
(image) http://files.me.com/james.ingham/crcvmy
The direction vector of travel will be the difference of the two position vectors,
d = (x1, y1) - (x, y) = (x1 - x, y1 - y)
Now when you ask for the direction angle, that depends what direction you want to measure the angle against. Is it against the x axis? Go with Radu's answer. Against an arbitrary vector? See justjeff's answer.
Edit: To get the angle against the y-axis:
tan (theta) = (x1 -x)/(y1 - y)
the tangent of the angle is the ratio of the x-coordinate of the difference vector to the y-coordinate of the difference vector.
So
theta = arctan[(x1 - x)/(y1 - y)]
Where arctan means inverse tangent. Not to be confused with the reciprocal of the tangent, which many people do, since they're both frequently denoted tan^-1. And make sure you know whether you're working in degrees or radians.
If you're in C (or other language that uses the same function set) then you're probably looking for the atan2() function. From your diagram:
double theta = atan2(x1-x, y1-y);
That angle will be from the vertical axis, as you marked, and will be measured in radians (God's own angle unit).
Be careful to use atan2 to avoid quadrant issues and division by zero. That's what it's there for.
float getAngle(CGPoint ptA, CGPoint ptOrigin, CGPoint ptB)
{
CGPoint A = makeVec(ptOrigin, ptA);
CGPoint B = makeVec(ptOrigin, ptB);
// angle with +ve x-axis, in the range (−π, π]
float thetaA = atan2(A.x, A.y);
float thetaB = atan2(B.x, B.y);
float thetaAB = thetaB - thetaA;
// get in range (−π, π]
while (thetaAB <= - M_PI)
thetaAB += 2 * M_PI;
while (thetaAB > M_PI)
thetaAB -= 2 * M_PI;
return thetaAB;
}
However, if you don't care about whether it's a +ve or -ve angle, just use the dot product rule (less CPU load):
float dotProduct(CGPoint p1, CGPoint p2) { return p1.x * p2.x + p1.y * p2.y; }
float getAngle(CGPoint A, CGPoint O, CGPoint B)
{
CGPoint U = makeVec(O, A);
CGPoint V = makeVec(O, B);
float magU = vecGetMag(U);
float magV = vecGetMag(V);
float magUmagV = magU * magV; assert (ABS(magUmagV) > 0.00001);
// U.V = |U| |V| cos t
float cosT = dotProduct(U, V) / magUmagV;
float theta = acos(cosT);
return theta;
}
Note that in either code section above, if one ( or both ) vectors are close to 0 length this is going to fail. So you might want to trap that somehow.
Still not sure what you mean by rotation matrices, but this is a simple case of getting an azimuth from a direction vector.
The complicated answer:
Normally you should pack a few conversion/utility functions with your 2D vectors: one to convert from X,Y (carthesian) to Theta,R (polar coordinates). You should also support basic vector operations like addition, substraction and dot product.
Your answer in this case would be:
double azimuth = (P2 - P1).ToPolarCoordinate().Azimuth;
Where ToPolarCoordinate() and ToCarhtesianCoordinate() are two reciprocal functions switching from one type of vector to another.
The simple one:
double azimuth = acos ((x2-x1)/sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1));
//then do a quadrant resolution based on the +/- sign of (y2-y1) and (x2-x1)
if (x2-x1)>0 {
if (y2-y1)<0 { azimuth = Pi-azimuth; } //quadrant 2
} else
{ if (y2-y1)> 0 { azimuth = 2*Pi-azimuth;} //quadrant 4
else { azimuth = Pi + azimuth;} //quadrant 3
}

How to calculate an angle from three points? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 4 years ago.
Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
Lets say you have this:
P1 = (x=2, y=50)
P2 = (x=9, y=40)
P3 = (x=5, y=20)
Assume that P1 is the center point of a circle. It is always the same.
I want the angle that is made up by P2 and P3, or in other words the angle that is next to P1. The inner angle to be precise. It will always be an acute angle, so less than -90 degrees.
I thought: Man, that's simple geometry math. But I have looked for a formula for around 6 hours now, and only find people talking about complicated NASA stuff like arccos and vector scalar product stuff. My head feels like it's in a fridge.
Some math gurus here that think this is a simple problem? I don't think the programming language matters here, but for those who think it does: java and objective-c. I need it for both, but haven't tagged it for these.
If you mean the angle that P1 is the vertex of then using the Law of Cosines should work:
arccos((P122
+ P132 - P232) / (2 *
P12 * P13))
where P12 is the length of the segment from P1 to P2, calculated by
sqrt((P1x -
P2x)2 +
(P1y -
P2y)2)
It gets very simple if you think it as two vectors, one from point P1 to P2 and one from P1 to P3
so:
a = (p1.x - p2.x, p1.y - p2.y)
b = (p1.x - p3.x, p1.y - p3.y)
You can then invert the dot product formula:
to get the angle:
Remember that just means:
a1*b1 + a2*b2 (just 2 dimensions here...)
The best way to deal with angle computation is to use atan2(y, x) that given a point x, y returns the angle from that point and the X+ axis in respect to the origin.
Given that the computation is
double result = atan2(P3.y - P1.y, P3.x - P1.x) -
atan2(P2.y - P1.y, P2.x - P1.x);
i.e. you basically translate the two points by -P1 (in other words you translate everything so that P1 ends up in the origin) and then you consider the difference of the absolute angles of P3 and of P2.
The advantages of atan2 is that the full circle is represented (you can get any number between -π and π) where instead with acos you need to handle several cases depending on the signs to compute the correct result.
The only singular point for atan2 is (0, 0)... meaning that both P2 and P3 must be different from P1 as in that case doesn't make sense to talk about an angle.
Let me give an example in JavaScript, I've fought a lot with that:
/**
* Calculates the angle (in radians) between two vectors pointing outward from one center
*
* #param p0 first point
* #param p1 second point
* #param c center point
*/
function find_angle(p0,p1,c) {
var p0c = Math.sqrt(Math.pow(c.x-p0.x,2)+
Math.pow(c.y-p0.y,2)); // p0->c (b)
var p1c = Math.sqrt(Math.pow(c.x-p1.x,2)+
Math.pow(c.y-p1.y,2)); // p1->c (a)
var p0p1 = Math.sqrt(Math.pow(p1.x-p0.x,2)+
Math.pow(p1.y-p0.y,2)); // p0->p1 (c)
return Math.acos((p1c*p1c+p0c*p0c-p0p1*p0p1)/(2*p1c*p0c));
}
Bonus: Example with HTML5-canvas
Basically what you have is two vectors, one vector from P1 to P2 and another from P1 to P3. So all you need is an formula to calculate the angle between two vectors.
Have a look here for a good explanation and the formula.
If you are thinking of P1 as the center of a circle, you are thinking too complicated.
You have a simple triangle, so your problem is solveable with the law of cosines. No need for any polar coordinate tranformation or somesuch. Say the distances are P1-P2 = A, P2-P3 = B and P3-P1 = C:
Angle = arccos ( (B^2-A^2-C^2) / 2AC )
All you need to do is calculate the length of the distances A, B and C.
Those are easily available from the x- and y-coordinates of your points and
Pythagoras' theorem
Length = sqrt( (X2-X1)^2 + (Y2-Y1)^2 )
I ran into a similar problem recently, only I needed to differentiate between a positive and negative angles. In case this is of use to anyone, I recommend the code snippet I grabbed from this mailing list about detecting rotation over a touch event for Android:
#Override
public boolean onTouchEvent(MotionEvent e) {
float x = e.getX();
float y = e.getY();
switch (e.getAction()) {
case MotionEvent.ACTION_MOVE:
//find an approximate angle between them.
float dx = x-cx;
float dy = y-cy;
double a=Math.atan2(dy,dx);
float dpx= mPreviousX-cx;
float dpy= mPreviousY-cy;
double b=Math.atan2(dpy, dpx);
double diff = a-b;
this.bearing -= Math.toDegrees(diff);
this.invalidate();
}
mPreviousX = x;
mPreviousY = y;
return true;
}
Very Simple Geometric Solution with Explanation
Few days ago, a fell into the same problem & had to sit with the math book. I solved the problem by combining and simplifying some basic formulas.
Lets consider this figure-
We want to know ϴ, so we need to find out α and β first. Now, for any straight line-
y = m * x + c
Let- A = (ax, ay), B = (bx, by), and O = (ox, oy). So for the line OA-
oy = m1 * ox + c ⇒ c = oy - m1 * ox ...(eqn-1)
ay = m1 * ax + c ⇒ ay = m1 * ax + oy - m1 * ox [from eqn-1]
⇒ ay = m1 * ax + oy - m1 * ox
⇒ m1 = (ay - oy) / (ax - ox)
⇒ tan α = (ay - oy) / (ax - ox) [m = slope = tan ϴ] ...(eqn-2)
In the same way, for line OB-
tan β = (by - oy) / (bx - ox) ...(eqn-3)
Now, we need ϴ = β - α. In trigonometry we have a formula-
tan (β-α) = (tan β + tan α) / (1 - tan β * tan α) ...(eqn-4)
After replacing the value of tan α (from eqn-2) and tan b (from eqn-3) in eqn-4, and applying simplification we get-
tan (β-α) = ( (ax-ox)*(by-oy)+(ay-oy)*(bx-ox) ) / ( (ax-ox)*(bx-ox)-(ay-oy)*(by-oy) )
So,
ϴ = β-α = tan^(-1) ( ((ax-ox)*(by-oy)+(ay-oy)*(bx-ox)) / ((ax-ox)*(bx-ox)-(ay-oy)*(by-oy)) )
That is it!
Now, take following figure-
This C# or, Java method calculates the angle (ϴ)-
private double calculateAngle(double P1X, double P1Y, double P2X, double P2Y,
double P3X, double P3Y){
double numerator = P2Y*(P1X-P3X) + P1Y*(P3X-P2X) + P3Y*(P2X-P1X);
double denominator = (P2X-P1X)*(P1X-P3X) + (P2Y-P1Y)*(P1Y-P3Y);
double ratio = numerator/denominator;
double angleRad = Math.Atan(ratio);
double angleDeg = (angleRad*180)/Math.PI;
if(angleDeg<0){
angleDeg = 180+angleDeg;
}
return angleDeg;
}
In Objective-C you could do this by
float xpoint = (((atan2((newPoint.x - oldPoint.x) , (newPoint.y - oldPoint.y)))*180)/M_PI);
Or read more here
You mentioned a signed angle (-90). In many applications angles may have signs (positive and negative, see http://en.wikipedia.org/wiki/Angle). If the points are (say) P2(1,0), P1(0,0), P3(0,1) then the angle P3-P1-P2 is conventionally positive (PI/2) whereas the angle P2-P1-P3 is negative. Using the lengths of the sides will not distinguish between + and - so if this matters you will need to use vectors or a function such as Math.atan2(a, b).
Angles can also extend beyond 2*PI and while this is not relevant to the current question it was sufficiently important that I wrote my own Angle class (also to make sure that degrees and radians did not get mixed up). The questions as to whether angle1 is less than angle2 depends critically on how angles are defined. It may also be important to decide whether a line (-1,0)(0,0)(1,0) is represented as Math.PI or -Math.PI
Recently, I too have the same problem... In Delphi
It's very similar to Objective-C.
procedure TForm1.FormPaint(Sender: TObject);
var ARect: TRect;
AWidth, AHeight: Integer;
ABasePoint: TPoint;
AAngle: Extended;
begin
FCenter := Point(Width div 2, Height div 2);
AWidth := Width div 4;
AHeight := Height div 4;
ABasePoint := Point(FCenter.X+AWidth, FCenter.Y);
ARect := Rect(Point(FCenter.X - AWidth, FCenter.Y - AHeight),
Point(FCenter.X + AWidth, FCenter.Y + AHeight));
AAngle := ArcTan2(ClickPoint.Y-Center.Y, ClickPoint.X-Center.X) * 180 / pi;
AngleLabel.Caption := Format('Angle is %5.2f', [AAngle]);
Canvas.Ellipse(ARect);
Canvas.MoveTo(FCenter.X, FCenter.Y);
Canvas.LineTo(FClickPoint.X, FClickPoint.Y);
Canvas.MoveTo(FCenter.X, FCenter.Y);
Canvas.LineTo(ABasePoint.X, ABasePoint.Y);
end;
Here's a C# method to return the angle (0-360) anticlockwise from the horizontal for a point on a circle.
public static double GetAngle(Point centre, Point point1)
{
// Thanks to Dave Hill
// Turn into a vector (from the origin)
double x = point1.X - centre.X;
double y = point1.Y - centre.Y;
// Dot product u dot v = mag u * mag v * cos theta
// Therefore theta = cos -1 ((u dot v) / (mag u * mag v))
// Horizontal v = (1, 0)
// therefore theta = cos -1 (u.x / mag u)
// nb, there are 2 possible angles and if u.y is positive then angle is in first quadrant, negative then second quadrant
double magnitude = Math.Sqrt(x * x + y * y);
double angle = 0;
if(magnitude > 0)
angle = Math.Acos(x / magnitude);
angle = angle * 180 / Math.PI;
if (y < 0)
angle = 360 - angle;
return angle;
}
Cheers,
Paul
function p(x, y) {return {x,y}}
function normaliseToInteriorAngle(angle) {
if (angle < 0) {
angle += (2*Math.PI)
}
if (angle > Math.PI) {
angle = 2*Math.PI - angle
}
return angle
}
function angle(p1, center, p2) {
const transformedP1 = p(p1.x - center.x, p1.y - center.y)
const transformedP2 = p(p2.x - center.x, p2.y - center.y)
const angleToP1 = Math.atan2(transformedP1.y, transformedP1.x)
const angleToP2 = Math.atan2(transformedP2.y, transformedP2.x)
return normaliseToInteriorAngle(angleToP2 - angleToP1)
}
function toDegrees(radians) {
return 360 * radians / (2 * Math.PI)
}
console.log(toDegrees(angle(p(-10, 0), p(0, 0), p(0, -10))))
there IS a simple answer for this using high school math..
Let say that you have 3 points
To get angle from point A to B
angle = atan2(A.x - B.x, B.y - A.y)
To get angle from point B to C
angle2 = atan2(B.x - C.x, C.y - B.y)
Answer = 180 + angle2 - angle
If (answer < 0){
return answer + 360
}else{
return answer
}
I just used this code in the recent project that I made, change the B to P1.. you might as well remove the "180 +" if you want
well, the other answers seem to cover everything required, so I would like to just add this if you are using JMonkeyEngine:
Vector3f.angleBetween(otherVector)
as that is what I came here looking for :)
Atan2 output in degrees
PI/2 +90
| |
| |
PI ---.--- 0 +180 ---.--- 0
| |
| |
-PI/2 +270
public static double CalculateAngleFromHorizontal(double startX, double startY, double endX, double endY)
{
var atan = Math.Atan2(endY - startY, endX - startX); // Angle in radians
var angleDegrees = atan * (180 / Math.PI); // Angle in degrees (can be +/-)
if (angleDegrees < 0.0)
{
angleDegrees = 360.0 + angleDegrees;
}
return angleDegrees;
}
// Angle from point2 to point 3 counter clockwise
public static double CalculateAngle0To360(double centerX, double centerY, double x2, double y2, double x3, double y3)
{
var angle2 = CalculateAngleFromHorizontal(centerX, centerY, x2, y2);
var angle3 = CalculateAngleFromHorizontal(centerX, centerY, x3, y3);
return (360.0 + angle3 - angle2)%360;
}
// Smaller angle from point2 to point 3
public static double CalculateAngle0To180(double centerX, double centerY, double x2, double y2, double x3, double y3)
{
var angle = CalculateAngle0To360(centerX, centerY, x2, y2, x3, y3);
if (angle > 180.0)
{
angle = 360 - angle;
}
return angle;
}
}

Efficient maths algorithm to calculate intersections

For a game I am developing I need an algorithm that can calculate intersections. I have solved the problem, but the way I have done it is really nasty and I am hoping someone here might have a more elegant solution.
A pair of points represent the end points of a line drawn between them. Given two pairs of points, do the drawn lines intersect, and if so, at what point?
So for example call the lines (A.x, A.y)-(B.x, B.y) and (C.x, C.y)-(D.x, D.y)
Can anyone think of a solution? A solution in any language will do.
Edit: A point I should have made clearer, the algorithm must return false if the point of intersection is beyond the lengths of the line segments.
Most of the answers already here seem to follow the general idea that:
find the intersection of two straight lines passing the given points.
determine if the intersection belong to both line segments.
But when intersection does not occur often, a better way probably is to reverse these steps:
express the straight lines in the form of y = ax + b (line passing A,B) and y = cx + d (line passing C,D)
see if C and D are on the same side of y = ax+b
see if A and B are on the same side of y = cx+d
if the answer to the above are both no, then there is an intersection. otherwise there is no intersection.
find the intersection if there is one.
Note: to do step 2, just check if (C.y - a(C.x) - b) and (D.y - a(D.x) - b) have the same sign. Step 3 is similar. Step 5 is just standard math from the two equations.
Furthermore, if you need to compare each line segment with (n-1) other line segments, precomputing step 1 for all lines saves you time.
If you get the chance you should really check out the Collision Detection bible, "Real Time Collision Detection" if you plan on doing anything non-trivial. I'm not a professional game programmer and I understood and could apply the concepts in it with little trouble.
Amazon - Real Time Collision Detection
Basically, doing a set of line intersection tests is expensive no matter what. What you do is use things like Bounding Boxes (axis aligned or oriented) over your complex polygons. This will allow you to quickly do a worst case O(N^2) check of collision between each "object". You can then speed things up even further by using spatial trees (Binary Partitioning or QuadTrees) by only checking intersections of objects close to eachother.
This allows you to prune many, many collision tests. The best optimization is not doing something at all. Only once you have a collision between bounding boxes do you do your expensive line intersections to determine if the objects truly do intersect or not. This allows you to scale the number of objects up while still keeping the speed reasonable.
float x12 = x1 - x2;
float x34 = x3 - x4;
float y12 = y1 - y2;
float y34 = y3 - y4;
float c = x12 * y34 - y12 * x34;
if (fabs(c) < 0.01)
{
// No intersection
return false;
}
else
{
// Intersection
float a = x1 * y2 - y1 * x2;
float b = x3 * y4 - y3 * x4;
float x = (a * x34 - b * x12) / c;
float y = (a * y34 - b * y12) / c;
return true;
}
Formulas taken from:
Line-line intersection - Wikipedia
A simple optimization that may save you alot of time is to check the axis-aligned bounding boxes of the lines prior to getting into the intersection calculation.
If the bounding boxes are completely disjoint then you can be certain there is no intersection.
Of course this is dependent of the data you have. if an intersection is very likely in every check you make then you might find yourself wasting time on a check that is always true.
public struct PointD
{
public double X { get; set; }
public double Y { get; set; }
}
/// <summary>
/// Find the intersection point between two lines.
/// </summary>
/// <param name="IntersectPoint">The intersection point. A <see cref="Esteem.Geometry.PointD">PointD</see> structure.</param>
/// <param name="L1StartPoint">The starting point of first line. A PointD structure.</param>
/// <param name="L1EndPoint">The end point of first line. A PointD structure.</param>
/// <param name="L2StartPoint">The starting point of second line. A PointD structure.</param>
/// <param name="L2EndPoint">The end point of second line. A PointD structure.</param>
/// <param name="L1IntersectPos">The intersection position at first line.</param>
/// <param name="L2IntersectPos">The intersection position at second line.</param>
/// <returns>Returns a boolean. True if there is intersection, false otherwise.</returns>
/// <remarks>The formula is taken from comp.graphics.algorithms Frequently Asked Questions.</remarks>
public static bool LineIntersect(out PointD IntersectPoint, PointD L1StartPoint, PointD L1EndPoint, PointD L2StartPoint, PointD L2EndPoint, out double L1IntersectPos, out double L2IntersectPos)
{
IntersectPoint = new PointD();
double ay_cy, ax_cx, px, py;
double dx_cx = L2EndPoint.X - L2StartPoint.X,
dy_cy = L2EndPoint.Y - L2StartPoint.Y,
bx_ax = L1EndPoint.X - L1StartPoint.X,
by_ay = L1EndPoint.Y - L1StartPoint.Y;
double de = (bx_ax) * (dy_cy) - (by_ay) * (dx_cx);
//double tor = 1.0E-10; //tolerance
L1IntersectPos = 0; L2IntersectPos = 0;
if (Math.Abs(de)<0.01)
return false;
//if (de > -tor && de < tor) return false; //line is in parallel
ax_cx = L1StartPoint.X - L2StartPoint.X;
ay_cy = L1StartPoint.Y - L2StartPoint.Y;
double r = ((ay_cy) * (dx_cx) - (ax_cx) * (dy_cy)) / de;
double s = ((ay_cy) * (bx_ax) - (ax_cx) * (by_ay)) / de;
px = L1StartPoint.X + r * (bx_ax);
py = L1StartPoint.Y + r * (by_ay);
IntersectPoint.X = px; //return the intersection point
IntersectPoint.Y = py; //return the intersection position
L1IntersectPos = r; L2IntersectPos = s;
return true; //indicate there is intersection
}
To check whether the intersection point is not beyond the original length of the line, just make sure that 0<r<1 and 0<s<1
Below is my line-line intersection as described in MathWorld. For general collision detection/intersection you may want to look at the Separating Axis Theorem. I found this tutorial on SAT very informative.
/// <summary>
/// Returns the intersection point of the given lines.
/// Returns Empty if the lines do not intersect.
/// Source: http://mathworld.wolfram.com/Line-LineIntersection.html
/// </summary>
public static PointF LineIntersection(PointF v1, PointF v2, PointF v3, PointF v4)
{
float tolerance = 0.000001f;
float a = Det2(v1.X - v2.X, v1.Y - v2.Y, v3.X - v4.X, v3.Y - v4.Y);
if (Math.Abs(a) < float.Epsilon) return PointF.Empty; // Lines are parallel
float d1 = Det2(v1.X, v1.Y, v2.X, v2.Y);
float d2 = Det2(v3.X, v3.Y, v4.X, v4.Y);
float x = Det2(d1, v1.X - v2.X, d2, v3.X - v4.X) / a;
float y = Det2(d1, v1.Y - v2.Y, d2, v3.Y - v4.Y) / a;
if (x < Math.Min(v1.X, v2.X) - tolerance || x > Math.Max(v1.X, v2.X) + tolerance) return PointF.Empty;
if (y < Math.Min(v1.Y, v2.Y) - tolerance || y > Math.Max(v1.Y, v2.Y) + tolerance) return PointF.Empty;
if (x < Math.Min(v3.X, v4.X) - tolerance || x > Math.Max(v3.X, v4.X) + tolerance) return PointF.Empty;
if (y < Math.Min(v3.Y, v4.Y) - tolerance || y > Math.Max(v3.Y, v4.Y) + tolerance) return PointF.Empty;
return new PointF(x, y);
}
/// <summary>
/// Returns the determinant of the 2x2 matrix defined as
/// <list>
/// <item>| x1 x2 |</item>
/// <item>| y1 y2 |</item>
/// </list>
/// </summary>
public static float Det2(float x1, float x2, float y1, float y2)
{
return (x1 * y2 - y1 * x2);
}
(I would leave this as a comment, except I haven't yet figured out how to do so.)
I would just like to add, as an alternative/complement to a bounding box test, you could also test to see if the distance between the mid-points of the lines are greater than half of the combined length of the lines. If so, the lines can't possibly intersect.
Imagine a minimal enclosing circle for each line, then test circle intersection. This allows for pre-computation (at least for static lines, and lines that preserve their length) and an efficient way to exclude a lot of potential intersections.
Well, mathematics and scalar products can help there.
- Say you want to intersect segments [AB] and [CD]
- Suppose the line intersection of the lines is M
M is inside segment [ÅB] if and only if
Vector(AB) . Vector(AM) >= 0
and
Vector(AB) . Vector(MB) >= 0
Where the dot "." denotes a scalar product : u . v = ux * vx + uy * vy
So, your algo is :
- find M
- M is inside both segment if and only if the 4 eq below are true
Vector(AB) . Vector(AM) >= 0
Vector(AB) . Vector(MB) >= 0
Vector(CD) . Vector(CM) >= 0
Vector(CD) . Vector(MD) >= 0
Hope this helps
private function Loop(e:Event):void
{
var x12:Number = Ball1.x - Ball2.x;
var x34:Number = Ball3.x - Ball4.x;
var y12:Number = Ball1.y - Ball2.y;
var y34:Number = Ball3.y - Ball4.y;
// Det
var c:Number = x12 * y34 - y12 * x34;
if (Math.abs(c) < 0.01)
{
Circle.visible = false;
}
else
{
var a:Number = Ball1.x * Ball2.y - Ball1.y * Ball2.x;
var b:Number = Ball3.x * Ball4.y - Ball3.y * Ball4.x;
var px:Number = (a * x34 - b * x12) / c;
var py:Number = (a * y34 - b * y12) / c;
var Btwn12x:Boolean = (px >= Math.min(Ball1.x, Ball2.x)) && (px <= Math.max(Ball1.x, Ball2.x));
var Btwn12y:Boolean = (py >= Math.min(Ball1.y, Ball2.y)) && (py <= Math.max(Ball1.y, Ball2.y));
var Btwn34x:Boolean = (px >= Math.min(Ball3.x, Ball4.x)) && (px <= Math.max(Ball3.x, Ball4.x));
var Btwn34y:Boolean = (py >= Math.min(Ball3.y, Ball4.y)) && (py <= Math.max(Ball3.y, Ball4.y));
var Btwn12:Boolean = Btwn12x && Btwn12y;
var Btwn34:Boolean = Btwn34x && Btwn34y;
if(Btwn12 && Btwn34)
{
Circle.visible = true;
Circle.x = px;
Circle.y = py;
}
else
{
Circle.visible = false;
}
}
}

Resources