I am developing a Meter app (in android). I am calculating distance between two points by formula (in back ground)
double calculateDistancs(double lat1, double long1, double lat2,
double long2) {
double earthRadius = 6371000; // meters
double dLat = Math.toRadians(lat2 - lat1);
double dLng = Math.toRadians(long2 - long1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
+ Math.cos(Math.toRadians(lat1))
* Math.cos(Math.toRadians(lat2)) * Math.sin(dLng / 2)
* Math.sin(dLng / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
float dist = (float) (earthRadius * c);
return dist;
}
I am not getting same and accurate distance between my home to metro station .
Provide other approach if available in android.
So second option is use google api for getting rout distance bn two latlong but in this case it will hit api many times.I want t know which approach is best.
I am getting different latlong at same place, may some one please make me understand for this.
The problem most probably is not caused by the function you posted.
Probably you are summing up jumping gps locations.
Just summing up the distance from one location to the other is not sufficient, especially at low speeds, like walking speed.
However there are weak points in the formula:
float dist = (float) (earthRadius * c);
You are always using double, and then downgrade to the lower precision float, but return the double. This is makes no sense.
Fix that with:
double dist = earthRadius * c;
Related
I have a longitude and latitude stored as a geometry with SRID 4326.
I want to make a line that is exactly 1000 meters long that is 90 degrees (to the right).
I know that the conversion from a longitudal/latitudal degree to a meter varies about where you are on the globe. That is why I will pass a reference long/lat that can be taken into consideration.
I am looking for something "good enough" that assumes that the distance you want will be no greater than 100 miles.
Given a long/lat and a meter distance of 1000 meters, return to me the size of the line long/lat degrees.
This question is specific to one example but I am looking for a general solution, because I have many functions that work upon "SRID Units" and the SRID I work with is long/lat (4326) but I always want to deal with meters and not degrees.
The hope is that I can call scaler function to convert the meters I want to the 4326 units.
Some hacks I have considered for finding X meters is converting the geometry into a geography and using the STBuffer(X) to make a circle with a radius equal to that of X, then create a long line that intersects the buffer and to find the point of the intersection, which will be the long/lat of exactly X meters away. This seems very hacky and inefficient but might be the most accurate
Edit:
To find the deltaX and deltaY the function is doing the the following:
DeltaX = Cos(#AngleRads) * #DistanceInDegrees;
DeltaY = Sin(#AngleRads) * #DistanceInDegrees;
I can supply #AngleRads and #DistanceInDegrees.
The problem is that #DistanceInDegrees has to match 4326 units (degrees). Is it even possible to find a #DistanceInDegrees that will correspond to 1000 meters no matter what angle is given?
When I use the formula
#DistanceInDegrees = (#Meters / 6371008.7714) * (180 / pi()) / cos(#Lat1 * pi()/180) and a angle of 90 degrees, then the length of the line is 1002 meters, close but not identically 1000.. If I use a degree of 45 the length of the line is 1191.67 meters.
If I understand your question, this can be done with a little math.
This also assumes the mean radius of the earth to be 6,371,008.7714 meters.
Example
Declare #Lat1 float = -37.786570
Declare #Lng1 float = 145.178179
Declare #Meters float = -1000
Select Lat1 = #Lat1
,Lng1 = #Lng1
,Lat2 = #Lat1
,Lng2 = #Lng1 + (#Meters / 6371008.7714) * (180 / pi()) / cos(#Lat1 * pi()/180)
Returns
The results can be validated here
After your EDIT, It seems you are looking for DISTANCE and BEARING
Here is a Table-Valued Function which may help
Example
Select * from [dbo].[tvf-Geo-Distance-Bearing](-37.786570,145.178179,1000,-45)
Returns
RetLat RetLng
-37.7802105711301 145.170133170589
Now, when I calculate the distance, I get 999.99999448737 meters
The Table-Valued Function If Interested
CREATE Function [dbo].[tvf-Geo-Distance-Bearing] (#Lat1 float,#Lng1 float,#Dist Float,#Degr float)
Returns #LatLng Table (RetLat float,RetLng Float)
As
Begin
Declare #Lat2 float,#Lng2 float,#eRad float = 6371008.7714
Select #Lat1 = RADIANS(#Lat1)
,#Lng1 = RADIANS(#Lng1)
,#Degr = RADIANS(#Degr)
Set #Lat2 = Asin(Sin(#Lat1) * Cos(#Dist / #eRad ) + Cos(#Lat1) * Sin(#Dist / #eRad ) * Cos(#Degr ))
Set #Lng2 = #Lng1 + Atn2(Sin(#Degr) * Sin(#Dist / #eRad ) * Cos(#Lat1), Cos(#Dist / #eRad ) - Sin(#Lat1) * Sin(#Lat2))
Insert Into #LatLng
Select Degrees(#Lat2)
,Degrees(#Lng2)
Return;
End
I have 2 degree-to-radian functions pre-defined using #define:
Function 1:
#define degreesToRadians(degrees) (M_PI * degrees / 180.0)
Function 2:
#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)
Only the 2nd function returns correct answer, while the first one provides weird answer. What are the differences between them?
Non of the two "functions" mentioned above is a functions, they are macros, and the first macro is not safe, for example, expanding the macro degreesToRadians(10 + 10) gives (M_PI * 10 + 10 / 180.0), which is interpreted as ((M_PI * 10) + (10 / 180.0)) and this is clearly wrong. While expanding DEGREES_TO_RADIANS(10 + 10) gives ((10 + 10 ) / 180.0 * M_PI) which is correct.
The other difference is that M_PI * degreess might overflow the double boundaries, and thus give a wrong answer (but this requires a rather high value in degrees)
The calculations are pretty much identical, notwithstanding floating point limitations. However, you have angle surrounded with parentheses in the second macro, which is the right thing to do.
In the first macro, if you do:
x = degreesToRadians(a + 45);
then, remembering that macros are simple text substitutions, you'll end up with:
x = (M_PI * a + 45 / 180.0);
which will not end well, since it will be calculated as if you'd written:
x = (M_PI * a) + (45 / 180.0);
In other words, you simply multiply the angle by PI and add a constant 0.25.
If instead you change the first one to be:
#define degreesToRadians(degrees) (M_PI * (degrees) / 180.0)
then it should begin to behave a little better.
The other difference has to do with either large or small values of the angle. A divide-then-multiply on a small angle (and I mean really small like 10-308, approaching the IEEE754 limits) may result in a zero result while a multiply-then-divide on a large angle (like 10308) may give you overflow.
My advice would be to ensure you use "normal" angles (or normalise them before conversion). Provided you do that, the different edge conditions of each method shouldn't matter.
And, in all honesty, you probably shouldn't even be using macros for this. With insanely optimising compilers and enumerations, macros should pretty much be relegated to conditional compilation nowadays. I'd simply rewrite it as a function along the lines of:
double degreesToRadians(double d) {
return M_PI * d / 180.0;
}
Or, you could even adjust the code so as to not worry about small or large angles (if you're paranoid):
double degreesToRadians(double d) {
if ((d > -1) && (d < 1))
return (M_PI * d) / 180.0;
return (d / 180.0) * M_PI;
}
Given two gps coordinates the length difference can be calculated by using the haversine formula. But what about the other way around:
Compute the length difference in meter for a given Lat/Long double
Compute the Lat/Long double for a given length in meters
I know this is not exactly possible since it differs from the point on the earth you are, but is it possible to approximate this or something similiar? This does not have to be very precise.
If your displacements aren't too great (less than a few KM), use the quick and dirty estimate that 111,111 meters in the y direction is 1 degree (of latitude) and 111,111 * cos(latitude) meters in the x direction is 1 degree (of longitude).
Alternatively:
//Position, decimal degrees
lat = 51.0
lon = 0.0
//Earth’s radius, sphere
R=6378137
//offsets in meters
distanceNorth = 100
distanceEast = 100
//Coordinate offsets in radians
dLat = distanceNorth/R
dLon = distanceEast/(R*Cos(Pi*lat/180))
//OffsetPosition, decimal degrees
latO = lat + dLat * 180/Pi
lonO = lon + dLon * 180/Pi
This should return:
latO = 51,00089832
lonO = 0,001427437
I have a CLLocationCoordinate2D (c1) and a CLLocation (l1), so I have lat/long values for each point and I can calculate the distance in meters between them using:
[c1 distanceFromLocation:l1]
How can I find the coordinates of a point (c2) 100 meters closer to l1 than c1 (along the same bearing)?
I have calculated it using basic trig using the following:
used the difference in latitude and longitude to calculate the hypotenuse and angle
used the ratio between the distance to cl and the distance to c2 to get the hypotenuse of a triangle ending at c2
used cos and sin to calculate the longitude and latitude of c2
But this seems like a hacky way of doing it as it doesn't take into account of curvature and seems to be using latitude and longitude in a way they are not supposed to be used. It does seem to work over short distances though.
After a bit of research, I found a basic formula for calculating curved distance between two points on the earth's surface:
dlon = lon2 - lon1
dlat = lat2 - lat1
a = { sin(dlat/2) }^2 + [ cos(lat1) * cos(lat2) * { sin(dlon/2) }^2 ]
c = 2 * arcsin(min(1,sqrt(a)))
d = R * c
Although Rickay's answer was helpful, I eventually used the following excellent library which has many useful functions for Core Location calculations: https://github.com/100grams/CoreLocationUtils
I have to see if some GPS coordinates are in a circle that I create.when I say I am creating that circle I' refering to this: I have lat1, long1,
my actual location and I want to test if there is any data surrounding this location but
not far then 1km. I am trying to use circle inequation : (x2-a2)2+(y2-b2)2 <R2 where a=lat1, b=long1 and R=radius. I know that R=1km but how do I transform 1km into data that can be compared to GPS coordinates? and x, y are every value from a collection that are testet to see if they fit.
Lat/Lng coordinates don't work with the Phytagoras Formula, as Earth is a sphere, and not flat...
Take a look at this manual:
http://www.movable-type.co.uk/scripts/latlong.html
You need the distance equation, to see if the distance between the lat/lng you have and the lat/lng of the center of the circle is smaller than R.
It's not that simple. You can't generally use the euclidean distance. This is how i think you could do it:
The correct way
The correct way to do this would be to calculate the great circle distance (the shortest walking distance on the surface), which I never really understood, but it's pretty easy to google (and adamk already gave you a link to it).
The lazy way
Assume that your points are not too close to the poles and that they are close to each other. Then you can use the latitude and longitude as if they were euclidean coordinates. (this is basically some cylindrical projection). 1 degree of latitude will then be (earth_circumference / 360) long and 1 degree of longitude will be (cos(lat) * earth_circumference / 360) long.
the complete code would look something like this:
double distance_lazy(double lat1, double lon1, double lat2, double lon2){
double xDist = (lat2 - lat1) * EARTH_CIRCUMFERENCE / 360.0;
double yDist = cos(lat1) * (lon2 - lon1) * EARTH_CIRCUMFERENCE / 360.0;
return sqrt(xDist^2 + yDist^2);
}
If your distances will be only a few km from each other, this should work pretty ok for the whole europe ... something like that.
The "weird definition" way
Another thing you can say is, that "distance" is the length straight line between the points, even though it goes through the earth. Then this would become calculating the 3D coordinates of a point and then their euclidean distance
double distance_straight_line(double lat1, double lon1, double lat2, double lon2){
double x1 = cos(lat1) * cos(lon1) * EARTH_RADIUS;
double y1 = sin(lat1) * cos(lon1) * EARTH_RADIUS;
double z1 = sin(lon1) * EARTH_RADIUS;
double x2 = cos(lat2) * cos(lon2) * EARTH_RADIUS;
double y2 = sin(lat2) * cos(lon2) * EARTH_RADIUS;
double z2 = sin(lon2) * EARTH_RADIUS;
return sqrt((x2 - x1)^2 + (y2 - y1)^2 + (z2 - z1)^2);
}
Again this will work as expected for points close to each other, this time they can be anywhere in the world. If you give it points far from each other, the output will be correct, but prety useless (unless you are very good at digging).
Hope it helps.