3

I need find angle of vehicle turn measured in degrees.

Problem description

Location points update with equal intervals (1 sec). Therefore device makes like 4-5 points during turn. I schematically displayed that on picture.

Is it possible to calculate the angle of turn using Location? If it is possible, how?


What I tried:

  1. Create two geometric vectors from points 3, 4 and 1, 2 respectively and find angle between those vectors. Coordinates of vectors I calculated like Vector1 (lat2 - lat1; lon2 - lon2). Not sure this approach could be applied to Location coordinates.
  2. Use location1.bearingTo(location2). But this doesn't give expected results. Seems like it gives "compass" results. Perhabs I could use it somehow but not sure.
  3. Also tried few trigonometric formulas like here or here or here. They didn't give expected angle.

EDIT: Solution The accepted answer works great. But to complete the answer I have to show that method of angleDifference. This one works for me:

public int getAngleDifference(int currentAngle){
    int r = 0;
    angleList.add(currentAngle);
    if (angleList.size() == 4) {
        int d = Math.abs(angleList.get(0) - angleList.get(3)) % 360;
        r = d > 180 ? 360 - d : d;

        angleList.clear();
    }
    return r;
}

I add points to list untill there're 4 of them and then calculate angle difference between 1st and 4th points for better results.

Hope it will help for someone!

Community
  • 1
  • 1
AnZ
  • 1,040
  • 24
  • 54

2 Answers2

2
vect1 = LatLon2 - LatLon1; // vector subtraction

vect2 = LatLon4 - LatLon3;

By definition of the dot product has the property:

vect1.vect2 = ||vect1||*||vect2||*Cos(theta)

Here's a breakdown of the notation

The term vect1.vect2 is the dot product of vect1 and vect2.

The general form of a dot product can be broken down component wise let v1 = <x1,y1> and v2=<x2,y2> for two arbitrary vectors v1 and v2 the dot product would be:

v1.v2 = x1*x2 + y1*y2 

and the magnitude of some arbitrary vector v is:

||v|| = sqrt(v.v); which is a scalar.

The above is equivalent to the Euclidean distance formula with components x and y:

||v|| = sqrt(x^2 + y^2)

Getting the angle

Find a value for theta given the two vectors vect1 and vect2:

theta = Math.ArcCos(vect1.vect2/(||vect1||*||vect2||))
Felix Castor
  • 1,598
  • 1
  • 18
  • 39
  • ArcCos is numerically ill conditioned for small angles as will occure in consecutive gps fixes.(Thats the reason why the haversine formula exists, which avoid the arcocos()) Have you ever implemented a working solution for his task? – AlexWien Jun 23 '15 at 18:40
  • @AlexWien small angle being a U-Turn? The dot product gives the angle he his looking for, and yes any coordinate geometry class makes you implement this. The only thing this doesn't do is give the direction, right or left, that the person is traveling. It always gives the smallest angle between two vectors. – Felix Castor Jun 23 '15 at 18:48
  • Who is talking about a u-turn? Its simply a turn. What is the range of the result of your formula: [0 - 90) or [0 - 180) ?. Does it return 179.99 for a U-Turn? Does it return 0 when driving staright ahead without any turn? – AlexWien Jun 23 '15 at 20:33
  • The OP didn't ask for that. He has a picture drawn indicating the angle he is looking for. See [Dot Product](https://en.wikipedia.org/wiki/Dot_product)... Read under Geometric definition. I'm assuming that the coordinates can be approximated as Euclidean since the sphere is so much larger than the distance of the turn so the haversine function isn't necessary. – Felix Castor Jun 23 '15 at 21:08
  • Sorry if I didnt mention about it but yes, I'm interested in U-turns also. And angle should be 0 when I'm moving straight. The more precise angle the better solution it is. – AnZ Jun 24 '15 at 09:03
  • @FelixCastor, I want to try out your approach also. Could you please explain what stands for `vector.vector`, exactly in `sqrt(vect.vect)`? As far as I understood it should be a dot product value. I must be stupid but what's the difference between `vect1.vect2` and `vector.vector`? – AnZ Jun 24 '15 at 13:14
1

Approach 1 does not work as you described: Lat, Lon are not cartesian coordinates (One degree of longitude expressed in meters is not one degree of latitide, this is only valid at the equator). You would have first to transform to a (local) cartesian system.

An error is in the drawing: The angle marked with "?" is placed at the wrong side. You most probably want angle: 180 - ? In your example the car ist turning less than 90°, altough your angle shows more than 90°. To understand better make another drawing where the car turns left for only 10 degrees. In your drawing this would be 170°, which is wrong.

Approach 2) works better, but you need to sum up the angle differences. You have to write yourself a method

double angleDifference(double angle1, double angle2);

This look easier than it is, although the code is only a few lines long. Make sure that you have some test cases that tests the behaviour when crossing the 360° limit. Example

(turn from bearing 10 to bearing 350), should either give 20 or -20, depending if you want that the method give sthe absolut evalue or the relative angle

AlexWien
  • 28,470
  • 6
  • 53
  • 83
  • I have implemented this approach. The angle changes every time even when I'm not moving. That could be caused by scatter of location coordinates (its accuracy is like 10 meters). Anyway I will test this out and let you know about results. – AnZ Jun 24 '15 at 08:59
  • `bearingTo` works quite good and it points right direction although I don't really undestand how can I convert those (-180; 180) degrees into car turn angle. Could you please give more explanation or some example (much preferable) of `angleDifference()` method? – AnZ Jun 24 '15 at 12:59
  • 1
    You need to filter out that movements while standing. for angle difference just search the internet, and write some unit test cases. If you sum up the angle difference you get an turning angle. – AlexWien Jun 24 '15 at 13:12