I am working on an AS3 AIR for Android application. "my problem is this: given a GPS location, I want to retrieve the direction of movement (North, NW, West, SW, South, SE, East, NE)"
I would like the code for how to use 2 different GPS readings to deduce the direction of travel. I would then like to use that data for 360 degrees.
I think I understand how I can get general direction like North, South, East, and West. I would get 2 separate GPS readings and compare something like so...
See if X is greater in the 1st or 2nd GPS reading. See if Y is greater in the 1st or 2nd GPS reading. From this I should be able to see the general direction. Compare the differences of X1 and X2 with the difference of Y1 and Y2. then you can see what direction the user was headed in the most. Then display the direction.
Im not sure on how to take the data and use it for a 360 interpretation like a compass... can anyone help?
WORKING CODE-------------------------------------------------------------------------------
package
{
import flash.display.Sprite;
// Geolocation sensor stuff
import flash.sensors.Geolocation;
import flash.events.GeolocationEvent;
//Timer setup stuff for setting frequesncy of GPS Update
import flash.utils.Timer;
import flash.events.TimerEvent;
// Sprite and Textfield display
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
public class FlashTest extends Sprite
{
//Variable to check if current or prior Geolocation Event fired
private var gpsCheck:int = 1;
public var dLon:Number
//latitude and longitude in degrees (RAW info from Geolocation)
public var gpsLat1:Number
public var gpsLon1:Number
private var gpsLat2:Number
private var gpsLon2:Number
public var bearing:Number
// Latitude and longitude in radians converted from Degrees
public var gpsLat1R:Number
public var gpsLon1R:Number
private var gpsLat2R:Number
private var gpsLon2R:Number
private var yy:Number
private var xx:Number
public function FlashTest()
{
// Text box for displaying results
var my_txt:TextField = new TextField();
my_txt.wordWrap=true;
my_txt.width = 300;
my_txt.height = 300;
addChild(my_txt);
/*
//If GPS is on device create Geolocation object named "my_geo"
//Request updates from my_geo every 2000 milliseconds. Run onGeoUpdate function
//when Event is triggered. After that create the text box for displaying data.
if (Geolocation.isSupported)
{
var my_geo:Geolocation = new Geolocation();
my_geo.setRequestedUpdateInterval(2000);
my_geo.addEventListener(GeolocationEvent.UPDATE, onGeoUpdate);
var my_txt:TextField = new TextField();
my_txt.wordWrap=true;
my_txt.width = 300;
my_txt.height = 300;
addChild(my_txt);
}
// If GPS is not supported on device display "No GPS Signal"
else
{
addChild(my_txt);
my_txt.wordWrap=true;
my_txt.width = 300;
my_txt.height = 300;
addChild(my_txt);
my_txt.text = "No GPS Signal ";
}
*/
// False GPS reading being passed for testing
//COMMENT THESE LINES OUT STARTING HERE---
gpsLat1 = 42.1234584;
gpsLon1 = -83.1234577;
gpsLat2 = 42.1234583;
gpsLon2 = -83.1234577;
// END OF WHAT SHOULD BE COMMENTED OUT---
// Equations to convert all RAW Geolocation information over to radians
gpsLat1R = gpsLat1 * Math.PI / 180;
gpsLon1R = gpsLon1 * Math.PI / 180;
gpsLat2R = gpsLat2 * Math.PI / 180;
gpsLon2R = gpsLon2 * Math.PI / 180;
// The rest of the math
dLon = gpsLon1 - gpsLon2;
yy = Math.sin(dLon) * Math.cos(gpsLat2R);
xx = Math.cos(gpsLat1R) * Math.sin(gpsLat2R) - Math.sin(gpsLat1R) * Math.cos(gpsLat2R) * Math.cos(dLon);
bearing = Math.atan2(yy, xx) * 180 / Math.PI;
// Run The Geoupdate function
onGeoUpdate();
// onGeoUpdate basically displays the information that was collected and converted.
// This is where you will put what you want the code to do with the results
function onGeoUpdate():void
{
my_txt.text = "My Latitude is "+gpsLat1+ " and my Longitude is "+gpsLon1+
"My 2nd Latitude is "+gpsLat2+" and my 2nd Longitude is "+gpsLon2+
" Bearing is " +bearing;
}
}
}
}
The formula you need (for lon1
, lon2
longitudes, and lat1
, lat2
latitudes of the two points) is given in many places - for example, at http://www.movable-type.co.uk/scripts/latlong.html . The math goes like this (convert it to your favorite language...):
dLon = lon2 - lon1;
y = sin(dLon) * cos(lat2);
x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) *cos(dLon);
bearing = atan2(y, x) * 180 / Pi;
Note: atan2
reduces the result to a value between [-pi, pi]. After multiplying by 180/pi
the number will be between [-180,180]. In order to get a value between 0 and 360 you could do, for example:
if (bearing < 0) bearing += 360;
I hope you can fill in any other details you need to make this work for you.
EDIT I have used the numbers your gave to write a little bit of code: this is Matlab, but it should be pretty readable:
% bearings
lat1 = 42.1234584;
lat2 = 42.1234583;
lon1 = -83.1234577;
lon2 = -83.1234510;
% convert to radians:
g2r = pi/180;
lat1r = lat1 * g2r;
lat2r = lat2 * g2r;
lon1r = lon1 * g2r;
lon2r = lon2 * g2r;
dlonr = lon2r - lon1r;
y = sin(dlonr) * cos(lat2r);
x = cos(lat1r)*sin(lat2r) - sin(lat1r) * cos(lat2r)*cos(dlonr);
% compute bearning and convert back to degrees:
bearing = atan2(y, x) / g2r;
fprintf(1,'x: %+.3e\ny: %+.3e\nbearing: %.3f\n', x, y, bearing);
This results in the output:
x: -1.745e-09
y: +8.673e-08
bearing: 91.153
As you can see, x
and y
are tiny - they represent the "fraction of the circumference of the earth" that you moved (about 3.5 meters due East, it would seem...). You should be able to debug your implementation with these numbers.
Notice by the way that GPS can have a poor "absolute" accuracy (in your case, uncertainty of > 100 m), yet still be good with "relative" accuracy (it measures the difference between two positions much better than 100 m).