I have a latitude and longitude of some point I used the following function to fin distance between points. Then I used the next function to convert latitude and longitude to cartesian coordinates. when I use the following formula to find distance of point with cartesian coordinates, the result is different than the first method. why?
(x^2+y^2+z^2)^0.5
def distance(lat2,lat1,lon2,lon1):
distance=[]
speed=[]
accelerate=[]
radius = 6371 # km
dlat = math.radians(lat2-lat1)
dlon = math.radians(lon2-lon1)
a = math.sin(dlat/2) * math.sin(dlat/2) + math.cos(math.radians(lat1)) \
* math.cos(math.radians(lat2)) * math.sin(dlon/2) * math.sin(dlon/2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
d = radius * c
distance.append(d)
for i in range(len(distance)-1):
speed.append((distance[i])/0.25)
for i in range(len(speed)-1):
accelerate.append((speed[i+1]-speed[i])/0.25)
return distance,speed,accelerate
def X_Y_Z(latitude,longitude):
R=6371
X=[]
Y=[]
Z=[]
for lat,lon in zip(latitude,longitude):
x = R * math.cos(lat) * math.cos(lon)
y = R * math.cos(lat) * math.sin(lon)
z = R *math.sin(lat)
X.append(x)
Y.append(y)
Z.append(z)
return X,Y,Z
for example the distance between (40.714531 ,-73.725607) and (40.714527 , -73.725591) is 0.001377. But cartesian coordinates give me different distance:
(642.430295 , -6287.620268 , 801.720448) and (642.527042 -6287.607109 801.746119)
Related
I am requesting data from backend (laravel) based on a set distance between 2 points latitude and longitude eg. Lat= 78.3232 and Long = 65.3234 and distance = 30 miles/kilometers , get the rows within the 30 miles.
The problem I'm having is with distance.
I am using react-native-maps and the zoom in/out is based on the latitudeDelta and longitudeDelta and I don't know how to calculate the radius/distance of them when the user zooms in/out to be sent to the backend and get data based on the points and radius/distance
at the moment, I have this function on the client-side. to determine when to fetch new data when user changes the region. but it has a problem of hard-coded distance (5.0 KM)
const _onRegionChangeComplete = (onCompletedregion: Region) => {
if (initialRegion) {
const KMDistance = helper.distance(
initialRegion?.latitude,
initialRegion?.longitude,
onCompletedregion.latitude,
onCompletedregion.longitude,
"K"
);
if (KMDistance > 5.0) {
props.getNearByReports({ // request backend if distance difference more than 5 kilometers
latitude: onCompletedregion.latitude,
longitude: onCompletedregion.longitude
});
}
}
};
helper.distance // get the difference in distance between the initial points and after the user done changing the region
function distance(
lat1: number,
lon1: number,
lat2: number,
lon2: number,
unit: string
) {
var radlat1 = (Math.PI * lat1) / 180;
var radlat2 = (Math.PI * lat2) / 180;
var theta = lon1 - lon2;
var radtheta = (Math.PI * theta) / 180;
var dist =
Math.sin(radlat1) * Math.sin(radlat2) +
Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
dist = Math.acos(dist);
dist = (dist * 180) / Math.PI;
dist = dist * 60 * 1.1515;
if (unit == "K") {
dist = dist * 1.609344;
}
if (unit == "M") {
dist = dist * 0.8684;
}
return dist;
}
The distance value is hard coded in the backend and frontend (which shouldn't be) cuz when the user zooms in/out , the radius/distance should change too. I am unable to calculate the distance from latitudeDelta and longitudeDelta
// Backend query code (simplified)
SELECT
id, (
6371 * acos (
cos ( radians(78.3232) )
* cos( radians( lat ) )
* cos( radians( lng ) - radians(65.3234) )
+ sin ( radians(78.3232) )
* sin( radians( lat ) )
)
) AS distance
FROM markers
HAVING distance < 5 // hard-coded distance
ORDER BY distance
LIMIT 0 , 20;
latitudeDelta is the amount of degrees that are visible on the screen. 1 degree is always equal to approx. 69 miles, so you can calculate the diameter of the currently visible area in miles with this diameter = latitudeDelta * 69. This is assuming the screen is in portrait mode and, therefore, latitudeDelta is the larger value. If not, use longitudeDelta instead. I hope I understood your question correctly and this is helpful.
I found this formula and it works, however what i trying to do is to give ability to filter by distance from his ZIP code.
I found formula that calculates distance between two latitude and longitude coordinates.
(3956 * ACOS(COS(RADIANS(start_lat)) * COS(RADIANS(end_lat)) * COS(RADIANS(end_lon) - RADIANS(start_lon)) + SIN(RADIANS(start_lat)) * SIN(RADIANS(end_lat))))
I have filter on page that sends following info
$_POST["start_latitude"] = 34.023179;
$_POST["start_longitude"] = -118.303965;
$_POST["max_distance"] = 50;
If i do
SELECT (3956 * ACOS(COS(RADIANS({$_POST["start_latitude"]})) * COS(RADIANS(34.018626))
* COS(RADIANS(-118.249978) - RADIANS({$_POST["start_longitude"]}))
+ SIN(RADIANS({$_POST["start_latitude"]})) * SIN(RADIANS(34.018626))))
Will output distance as number of miles 4 miles in this case.
How can i convert this formula for my goal to find places no longer than say 50 miles from coordinates entered? I know all need to be done is change of places in formula, but i am not good with school math.
SELECT place_name FROM places
WHERE place_latitude = ? AND place_longitude = ?
EDIT:
I have places table where i got 1000 records in format
id place_name latitude longitude
1 xxx 432423 -43432
2 yyy 523452 -54353
3 zzz 553453 -53422
etc.
So the formula has to do something like
SELECT place_name FROM places
(CALCULATE each place distance from
$_POST["start_latitude"] and $_POST["start_longitude"]
and select only ones that) < 50
Put the distance formula into the WHERE clause:
SELECT place_name
FROM places
WHERE (3956 * ACOS(COS(RADIANS(:start_latitude)) * COS(RADIANS(latitude)) * COS(RADIANS(-longitude) - RADIANS(:start_longitude)) + SIN(RADIANS(:start_latitude)) * SIN(RADIANS(latitude))))
< :max_distance
This resouce and web service usefull, check it:
http://www.codebump.com/services/PlaceLookup.asmx
function calc_distance($point1, $point2)
{
$radius = 3958; // Earth's radius (miles)
$deg_per_rad = 57.29578; // Number of degrees/radian (for conversion)
$distance = ($radius * pi() * sqrt(
($point1['lat'] - $point2['lat'])
* ($point1['lat'] - $point2['lat'])
+ cos($point1['lat'] / $deg_per_rad) // Convert these to
* cos($point2['lat'] / $deg_per_rad) // radians for cos()
* ($point1['long'] - $point2['long'])
* ($point1['long'] - $point2['long'])
) / 180);
return $distance; // Returned using the units used for $radius.
}
EDIT
Check the page :
http://www.mssqltips.com/sqlservertip/2690/calculate-the-geographical-distance-between-two-cities-in-sql-server/
--
DECLARE #98001 GEOGRAPHY;
DECLARE #Patzip GEOGRAPHY;
SELECT #98001 = Coordinates FROM ZipCodeLKUP INNER JOIN
Facility ON ZipCodeLKUP.ZipCode = Facility.ZipCode
Where Facility.ZipCode=98001
SELECT #Patzip = Coordinates FROM ZipCodeLKUP INNER JOIN
HIDIMV_year ON ZipCodeLKUP.ZipCode = HIDIMV_year .Patzip
where PATZIP in ('98001', '98466','97202')
SELECT #98001.STDistance(#Patzip)/1000 AS [Distance in KM]
I'm currently using this query to get a town inside my DB by giving a coordinate :
SELECT *
FROM citiesTable
WHERE latitude >= ? AND latitude <= ?
AND longitude >= ? AND longitude <= ?;
This code works well and do I want but sometimes the query doesn't match anything...
So, in this case, I would put a bird distance to this query in order to get adjacent town.
Any suggestion on how can I do that ?
Searching for "distance from longitude and latitude" gave a link to http://www.movable-type.co.uk/scripts/latlong.html which specifies this code for calculating the distance:
var R = 6371; // km
var dLat = (lat2-lat1).toRad();
var dLon = (lon2-lon1).toRad();
var lat1 = lat1.toRad();
var lat2 = lat2.toRad();
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
A couple more minutes of searching led to http://www.movable-type.co.uk/scripts/latlong-db.html
That page is chock-full of information. Here's a simple (but inefficient) solution, assuming your town is at $lon,$lat and $R is 6371 (which is km), and finally that you want the cities to be within $rad of your town:
Select ID, Postcode, Lat, Lon,
acos(sin($lat)*sin(radians(Lat)) + cos($lat)*cos(radians(Lat))*cos(radians(Lon)-$lon))*$R As D
From MyTable
Where acos(sin($lat)*sin(radians(Lat)) + cos($lat)*cos(radians(Lat))*cos(radians(Lon)-$lon))*$R < $rad
SELECT postcode, lat, lng,
truncate(
(degrees(acos
(sin(radians(lat))
*
sin( radians('.$latitude.'))
+
cos(radians(lat))
*
cos( radians('.$latitude.'))
*
cos( radians(lng - ('.$longitude.')))
)
)
* 69.172), 2)
as distance
FROM myData
This query calculates distance (in miles). But when I check distance for same lat and longitude at google maps my result doesnt match. If the distance is around 10 miles then my result is a bit accurate, but over that it gets wrong (for example, my result showed 13 miles and google showed 22 miles for same post code values)
I got this query from http://forums.mysql.com/read.php?23,3868,3868#msg-3868
How can I get it accurate. Any ideas?
Thanks for help.
UPDATE
I tried #Blixt code in PHP. Picked up 2 sample postcodes and their lats longs
//B28 9ET
$lat1 = 52.418819;
$long1 = -1.8481053;
//CV5 8BX
$lat2 = 52.4125573;
$long2 = -1.5407743;
$dtr = M_PI / 180;
$latA = $lat1 * $dtr;
$lonA = $long1 * $dtr;
$latB = $lat2 * $dtr;
$lonB = $long2 * $dtr;
$EarthRadius = 3958.76; //miles
echo $distance = $EarthRadius * acos(cos($latA) * cos($latB) * cos($lonB - $lonA) + sin($latA) * sin($latB));
Results:
My app - 12.95 miles
Google - 17.8 miles
Any ideas how to get it right?
Have a look at this source code. When I tested it against various other measurement services it seemed to get the same results. It's C# but the math should be easy enough to convert.
Here are the relevant pieces:
public const double EarthRadius = 6371.0072; // Kilometers
//public const double EarthRadius = 3958.76; // Miles
/* ... */
const double dtr = Math.PI / 180;
double latA = this.Latitude * dtr;
double lonA = this.Longitude * dtr;
double latB = other.Latitude * dtr;
double lonB = other.Longitude * dtr;
return GpsLocation.EarthRadius * Math.Acos(Math.Cos(latA) * Math.Cos(latB) * Math.Cos(lonB - lonA) + Math.Sin(latA) * Math.Sin(latB));
Note: The Earth is not perfectly spherical, so the constants used may differ. There is no easy way to make the measurements truly exact. See Wikipedia.
I'm using a lat/long SRID in my PostGIS database (-4326). I would like to find the nearest points to a given point in an efficient manner. I tried doing an
ORDER BY ST_Distance(point, ST_GeomFromText(?,-4326))
which gives me ok results in the lower 48 states, but up in Alaska it gives me garbage. Is there a way to do real distance calculations in PostGIS, or am I going to have to give a reasonable sized buffer and then calculate the great circle distances and sort the results in the code afterwards?
You are looking for ST_distance_sphere(point,point) or st_distance_spheroid(point,point).
See:
http://postgis.refractions.net/documentation/manual-1.3/ch06.html#distance_sphere
http://postgis.refractions.net/documentation/manual-1.3/ch06.html#distance_spheroid
This is normally referred to a geodesic or geodetic distance... while the two terms have slightly different meanings, they tend to be used interchangably.
Alternatively, you can project the data and use the standard st_distance function... this is only practical over short distances (using UTM or state plane) or if all distances are relative to a one or two points (equidistant projections).
PostGIS 1.5 handles true globe distances using lat longs and meters. It is aware that lat/long is angular in nature and has a 360 degree line
This is from SQL Server, and I use Haversine for a ridiculously fast distance that may suffer from your Alaska issue (can be off by a mile):
ALTER function [dbo].[getCoordinateDistance]
(
#Latitude1 decimal(16,12),
#Longitude1 decimal(16,12),
#Latitude2 decimal(16,12),
#Longitude2 decimal(16,12)
)
returns decimal(16,12)
as
/*
fUNCTION: getCoordinateDistance
Computes the Great Circle distance in kilometers
between two points on the Earth using the
Haversine formula distance calculation.
Input Parameters:
#Longitude1 - Longitude in degrees of point 1
#Latitude1 - Latitude in degrees of point 1
#Longitude2 - Longitude in degrees of point 2
#Latitude2 - Latitude in degrees of point 2
*/
begin
declare #radius decimal(16,12)
declare #lon1 decimal(16,12)
declare #lon2 decimal(16,12)
declare #lat1 decimal(16,12)
declare #lat2 decimal(16,12)
declare #a decimal(16,12)
declare #distance decimal(16,12)
-- Sets average radius of Earth in Kilometers
set #radius = 6366.70701949371
-- Convert degrees to radians
set #lon1 = radians( #Longitude1 )
set #lon2 = radians( #Longitude2 )
set #lat1 = radians( #Latitude1 )
set #lat2 = radians( #Latitude2 )
set #a = sqrt(square(sin((#lat2-#lat1)/2.0E)) +
(cos(#lat1) * cos(#lat2) * square(sin((#lon2-#lon1)/2.0E))) )
set #distance =
#radius * ( 2.0E *asin(case when 1.0E < #a then 1.0E else #a end ) )
return #distance
end
Vicenty is slow, but accurate to within 1 mm (and I only found a javascript imp of it):
/*
* Calculate geodesic distance (in m) between two points specified by latitude/longitude (in numeric degrees)
* using Vincenty inverse formula for ellipsoids
*/
function distVincenty(lat1, lon1, lat2, lon2) {
var a = 6378137, b = 6356752.3142, f = 1/298.257223563; // WGS-84 ellipsiod
var L = (lon2-lon1).toRad();
var U1 = Math.atan((1-f) * Math.tan(lat1.toRad()));
var U2 = Math.atan((1-f) * Math.tan(lat2.toRad()));
var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1);
var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2);
var lambda = L, lambdaP = 2*Math.PI;
var iterLimit = 20;
while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0) {
var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda);
var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) +
(cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda));
if (sinSigma==0) return 0; // co-incident points
var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda;
var sigma = Math.atan2(sinSigma, cosSigma);
var sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
var cosSqAlpha = 1 - sinAlpha*sinAlpha;
var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha;
if (isNaN(cos2SigmaM)) cos2SigmaM = 0; // equatorial line: cosSqAlpha=0 (ยง6)
var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
lambdaP = lambda;
lambda = L + (1-C) * f * sinAlpha *
(sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
}
if (iterLimit==0) return NaN // formula failed to converge
var uSq = cosSqAlpha * (a*a - b*b) / (b*b);
var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
var s = b*A*(sigma-deltaSigma);
s = s.toFixed(3); // round to 1mm precision
return s;
}