I have a function which queries my database to find nearby users. However, my database stores the longitude and latitude of users, and to find the distance from the user, I need to call a function (distance) to check which users to return in the query. Is there a way to do what I have in the code (call my local distance function inside my querystring?)
exports.getNearby = function (longitude, latitude) {
var long1 = longitude;
var lat1 = latitude;
return new Promise(((resolve, reject) => {
const queryString = `SELECT ${userModel.userId}
FROM ${userModel.collectionName} where SELECT distance(${userLocationModel.latitude},
${userLocationModel.longitude}, ${lat1}, ${long1}) < 4`;
db.query(queryString, (err, res) => {
if (err) {
logger.log('error', ` getUser - ${userIdArr} - ${err}`);
reject(err);
} else {
resolve(res.rows[0]);
}
});
}));
};
function distance(lat1, lon1, lat2, lon2) { //returns in km
return 12742 * asin(sqrt(0.5 - cos((lat2 - lat1) * 0.01745329252)/2
+ cos(lat1 * 0.01745329252) * cos(lat2 * 0.01745329252) *
(1 - cos((lon2 - lon1) * 0.01745329252)) / 2));
}
Function written in Postgres (as suggested by #LaurenzAlbe)
CREATE FUNCTION distance(
lat1 double precision,
lng1 double precision,
lat2 double precision,
lng2 double precision
) RETURNS double precision AS
'SELECT 12742
* asin(
|/ (
0.5 - cos(
(lat2 - lat1) * 0.01745329252
)/2
+ cos(lat1 * 0.01745329252)
* cos(lat2 * 0.01745329252)
* (1 - cos(
(lon2 - lon1) * 0.01745329252
)) / 2
)
)'
LANGUAGE sql IMMUTABLE;
If you want to use the function in an SQL statement, you have to define it inside the database using CREATE FUNCTION.
For a function like that, I'd choose LANGUAGE sql.
Have you considered using the PostGIS extension if you want to do geographical data processing inside the database? It offers all imaginable functions out of the box.
Here is how your function could look as SQL function:
CREATE FUNCTION distance(
lat1 double precision,
lng1 double precision,
lat2 double precision,
lng2 double precision
) RETURNS double precision AS
'SELECT 12742
* asin(
|/ (
0.5 - cos(
(lat2 - lat1) * 0.01745329252
)/2
+ cos(lat1 * 0.01745329252)
* cos(lat2 * 0.01745329252)
* (1 - cos(
(lon2 - lon1) * 0.01745329252
)) / 2
)
)'
LANGUAGE sql IMMUTABLE;
Related
I am currently using powerpivot and I added a column to create a calculated field for all rows. The purpose of the function is to find the distance between two zip codes by takin their Latitude and Longitude; this function always works in excel worksheets but when I attempt to use the same function in power query, it does not work. The reason why I'm using power query for this function is because the data set is over 4,000,000 rows...
I'm using the function below and it returns as "#ERROR"
=ACOS(COS(RADIANS(90-'Origin vs Destination w PKG'[Latitude]))*COS(RADIANS(90-'Origin vs Destination w PKG'[DLatitude]))+SIN(RADIANS(90-'Origin vs Destination w PKG'[Latitude]))*SIN(RADIANS(90-'Origin vs Destination w PKG'[DLatitude]))*COS(RADIANS('Origin vs Destination w PKG'[Longitude]-'Origin vs Destination w PKG'[DLongitude])))*3958.8
Above is the function. Does anyone know how to get the distance function between two coordinates to work in PowerPivot?
Thanks a lot
Assuming Table1 has 4 columns [Latitude_1], [Longitude_1], [Latitude_2], [Longitude_2] and the coordinates are in decimal [38.892456, -74.0247852] then code below generates the distance between the locations in miles (change 3959 to 6371 for kilometers) using the formula:
=ACOS(SIN(lat1)*SIN(lat2)+COS(lat1)*COS(lat2)*COS(lon2-lon1))*3959
which in powerquery code is:
= Number.Acos(Number.Sin(([Latitude_1] / 180) * Number.PI) * Number.Sin(([Latitude_2] / 180) * Number.PI) + Number.Cos(([Latitude_1] / 180) * Number.PI) * Number.Cos(([Latitude_2] / 180) * Number.PI) * Number.Cos( ([Longitude_2] / 180) * Number.PI-([Longitude_1] / 180) * Number.PI)) * 3959)
full code sample:
let Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Added Custom" = Table.AddColumn(Source, "DistanceMiles", each Number.Acos(Number.Sin(([Latitude_1] / 180) * Number.PI) * Number.Sin(([Latitude_2] / 180) * Number.PI) + Number.Cos(([Latitude_1] / 180) * Number.PI) * Number.Cos(([Latitude_2] / 180) * Number.PI) * Number.Cos( ([Longitude_2] / 180) * Number.PI-([Longitude_1] / 180) * Number.PI)) * 3959),
in #"Added Custom"
I have a problem with this function. Excel return #name error.
=ACOS(COS(RADIANS(90-B3)) * COS(RADIANS(90-$G$3)) + SIN(RADIANS(90-B3)) * SIN(RADIANS(90-$G$3)) * COS(RADIANS(C3-$G$4))) * 6371
I have a Users table that contains latitude and longitude attribute for every user. So I need to calculate the distance between two users in AQL Query.
I have done the same in Orientdb with the below query.
var laltitude = CURRENT_USER_laltitude;
var longitude = CURRENT_USER_longitude;
var query = "select distance(latitude, longitude,"+laltitude+","+longitude+") as distance from users";
First, create a js file distance.js (or whatever you want to name it) and put below code as below.
/* distance.js */
'use strict';
function gdistance(latitude1, longitude1, latitude2, longitude2, radius) {
if (!latitude1 || !longitude1 || !latitude2 || !longitude2) {
return null;
};
var lat1 = Number(latitude1), lon1 = Number(longitude1);
var lat2 = Number(latitude2), lon2 = Number(longitude2);
radius = (radius === undefined) ? 6371e3 : Number(radius);
var R = radius;
var φ1 = (lat1 * Math.PI / 180), λ1 = (lon1 * Math.PI / 180);
var φ2 = (lat2 * Math.PI / 180), λ2 = (lon2 * Math.PI / 180);
var Δφ = φ2 - φ1;
var Δλ = λ2 - λ1;
var a = Math.sin(Δφ/2) * Math.sin(Δφ/2)
+ Math.cos(φ1) * Math.cos(φ2)
* Math.sin(Δλ/2) * Math.sin(Δλ/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c; // Meters
var d2 = d / 1000; // Meters to KM
return d2;
}
module.exports = gdistance;
Now open Arango Console with arangosh. This will open with _system database by default. So if you have other than this database like me then use db._useDatabase("myDatabase") command to change database.
Now write below commands to add custom to your desired database.
Version 2.8
db._useDatabase("myDatabase");
var aqlfunctions = require("org/arangodb/aql/functions");
var f = require("/path/to/file/distance.js");
aqlfunctions.register("geo::gdistance", f, true)
Version 3.0+
db._useDatabase("myDatabase");
var aqlfunctions = require("#arangodb/aql/functions");
var f = require("/path/to/distance.js");
i.e.
var f = require("/home/ubuntu/distance.js");
var f = require("distance.js");
# If you want to remove this group's UDFs (User defined functions)
# aqlfunctions.unregisterGroup("geo");
aqlfunctions.register("geo::gdistance", f, true);
Now use in your AQL queries as below.
LET distance = geo::gdistance(attrbute_name.latitude, attrbute_name.longitude, #your_latitude, #your_longitude)
For more references with here.
Currently ArangoDB can only give you distances when you use the Geo index to return you the distance of your search start to the point matching your condition:
FOR doc IN WITHIN(##collection, #lat, #long, #radius, #distanceAttributeName)
RETURN doc
You could however use a user defined AQL function to extend AQL. User defined functions are implemented in Javascript, which is luckily used by Chris Veness to explain howto calculate distances
With ArangoDB 3.0 we most probably will support the arithmetic operations to calculate this in AQL.
I will edit this post with more details and examples soon.
I am using the following code to get the locations for the nearest clinics in kms the code works sweet. But what I cant understand is how to get around the parse object only returning 100 objects so I guess my question should be how do i return just a subset that match the current long and lat of the clinics.
I call the below functions in my viewdIdLoadMethod
List<Clinics> _clicics;
_clicics =GetAllNearestFamousPlaces (54.269412, -0.93399086);
public List<Clinics> GetAllNearestFamousPlaces(double currentLatitude,double currentLongitude)
{
List<Clinics> Caldistance = new List<Clinics>();
var query = ParseObject.GetQuery("clinics");
query.FindAsync().ContinueWith(t =>
{
IEnumerable<ParseObject> results = t.Result;
foreach (var obj in results)
{
double distance = Distance(currentLatitude, currentLongitude, obj.Get<double>("lat"), obj.Get<double>("long"));
if (distance < 25) //nearbyplaces which are within 25 kms
{
Clinics dist = new Clinics();
dist.Name = obj.Get<string>("Name");
dist.Latitute = obj.Get<double>("lat");
dist.Longitude =obj.Get<double>("long");
Caldistance.Add(dist);
}
}
});
return Caldistance;
}
private double Distance(double lat1, double lon1, double lat2, double lon2)
{
double theta = lon1 - lon2;
double dist = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) + Math.Cos(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) * Math.Cos(deg2rad(theta));
dist = Math.Acos(dist);
dist = rad2deg(dist);
dist = (dist * 60 * 1.1515) / 0.6213711922; //miles to kms
return (dist);
}
private double deg2rad(double deg)
{
return (deg * Math.PI / 180.0);
}
private double rad2deg(double rad)
{
return (rad * 180.0 / Math.PI);
}
This may not be syntactically correct - I don't actually use Parse so I'm guessing based on their docs
// assume your point of origin is 54.269412, -0.93399086
// each degree of lat/long is **roughly** 100 km so we'll fudge and +- .5 to narrow down the
// list of clinics
double lat = 54.269412;
double lng = -0.93399086;
double minLong = lng - 0.5;
double maxLong = lng + 0.5;
double minLat = lat - 0.5;
double maxLat = lat + 0.5;
var query = from clinic in ParseObject.GetQuery("clinics")
where clinic.Get<double>("lat") >= minLat
and clinic.Get<double>("lat") <= maxLat
and clinic.Get<double>("long") >= minLat
and clinic.Get<double>("long") <= maxLat
select clinic;
// 1000 is the max we can request at a time
query = query.Limit(1000);
// now execute your query to get the results, and then use your Distance() function to calculate
// the precise distance and remove results that are to far away, etc
I know how to use the javascript to calculate the radius by using the below code
var center = new google.maps.LatLng(3.2987599, 102.6872022);
var latLng = new google.maps.LatLng(3.0987599, 101.6872022);
var distanceInMetres = google.maps.geometry.spherical.computeDistanceBetween(center, latLng);
But how to convert the google.maps.geometry.spherical.computeDistanceBetween into C# function?
Distance between 2 points: (lat1,lon1) to (lat2,lon2)
distance = acos(
cos(lat1 * (PI()/180)) *
cos(lon1 * (PI()/180)) *
cos(lat2 * (PI()/180)) *
cos(lon2 * (PI()/180))
+
cos(lat1 * (PI()/180)) *
sin(lon1 * (PI()/180)) *
cos(lat2 * (PI()/180)) *
sin(lon2 * (PI()/180))
+
sin(lat1 * (PI()/180)) *
sin(lat2 * (PI()/180))
) * 3959
3959 is the Earth radius in Miles. Replace this value with
radius in KM, (or any other unit), to get results on the same unit.
You can verify your implementation by comparing to this worked example:
i have write the C# solution to calculate the distance to convert
var distanceInMetres = google.maps.geometry.spherical.computeDistanceBetween(center, latLng);
into C#. Below is the code i have using. 6371 is the radius of the Earth.
//Calculate distance earth between 2 coordinate point
double e = lat * (Math.PI / 180);
double f = lng * (Math.PI / 180);
double g = lat2 * (Math.PI / 180);
double h = lng2 * (Math.PI / 180);
double i =
(Math.Cos(e) * Math.Cos(g) * Math.Cos(f) * Math.Cos(h)
+ Math.Cos(e) * Math.Sin(f) * Math.Cos(g) * Math.Sin(h)
+ Math.Sin(e) * Math.Sin(g));
double j = Math.Acos(i);
double k = (6371 * j); //Distance in KM
The distance between 2 lat/long points can be calculated with the haversine formula, which is described here http://en.wikipedia.org/wiki/Haversine_formula
There also is another question here at stackoverflow about more or less the same issue: Calculate distance between two latitude-longitude points? (Haversine formula)