Find nearest latitude and longitude points - geolocation

An question on latitude and longitude...Probably a silly one.
I have a set of latitude and longitudes for various locations.And, I have the latitude and longitude of the location in which I am in.
Now,I have to find the nearest places from my locations from the set of latitudes and longitudes I have. Is thee any special way of calculating it or it is just mere subtraction and checking the difference?
Could you please throw some light on this?
Thanks,
J

It depends on how the points are placed.
For example - if most of the points are in a parking lot, then Euclidean Distance should work well.
In other cases - Geodesic Distance needs to be computed. This link should help you with more information.
Here is the conversion from Decimal format to Degree-Minute-Second format and vice versa.
cheers

You can use this SQL. it will select then nearest Lat, Lng from your DB entries.
SELECT id,lat,lng, ((ACOS(SIN(your_lat * PI() / 180) * SIN(lat * PI()
/ 180) + COS(your_lat * PI() / 180) * COS(lat * PI() / 180) *
COS((your_long - lng) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS
distance FROM your_table_name HAVING distance <='10'
ORDER BY distance ASC LIMIT 0,10
Hope this will help.

Related

Quaternion to Yaw to Heading

I have quaternion values q available.
These are correct, because they align the object correctly in the ROS RVIZ tool.
I now want to get a heading value from these values.
My idea was to calculate the Yaw value first and then do a Radian to Degree conversion to get the heading.
However, this works only conditionally, as soon as the object moves in the direction of NE everything is correct and the correct heading value is output. The same applies for the direction SW. However, when the object moves in the NW direction, I get a heading value of 135 degrees, exactly the opposite direction. Exactly the same applies to the direction SE.
My conversions look as follows:
double heading = atan2(2.0*(q.y*q.z + q.w*q.x), -1.0 +2.0 * (q.w*q.w + q.x*q.x)) * 180 / M_PI;
if(heading < 0){
heading +=360;
}
I got the formula from:
https://math.stackexchange.com/questions/3496329/map-quaternion-to-heading-pitch-roll-using-different-axis
My Question is:
What I'm doing wrong.. Why are NW and SE swapped?
Really don't know ROS RVIZ.
But for Bullet3d I use:
siny = +2.0 * (q.w * q.z + q.y * q.x);
cosy = +1.0 - 2.0 * (q.x * q.x + q.z * q.z);
heading = atan2(siny, cosy); // in radians
Since this is inside ROS it would typically be recommended to use the tf library that already exists which includes a getRPY() function for quaternions. Take the following example:
tf2::Quaternion tf_quat;
tf2::fromMsg(quat_msg, tf_quat); //Assume quat_msg is a quaternion ros msg
tf2::Matrix3x3 m(tf_quat);
double roll, pitch, yaw;
m.getRPY(roll, pitch, yaw);
My Problem was, that the Yaw value was reflected and rotated by 90 Degrees.
My RVIZ tool does not use N E S W System, so in this case it was displayed correct.
The solution was:
double heading = (atan2(2.0*(q.y*q.z + q.w*q.x), -1.0 +2.0 * (q.w*q.w + q.x*q.x)) * 180 / M_PI) - 90;
if(heading < 0){
heading +=360;
}
heading = -heading + 360
Thanks, your solutions are also correct, if the value is not rotated.

is there anyway to calculate miles or meters to pixel on google map for calculating zoom level?

I have been searching on this thing from long time.
Is there any math formula to convert miles or meters to pixel for zoom level in google map? Any kind of help is appreciated. I am currently working for iOS.
I found a solution from here https://gist.github.com/ryanhanwu/4dbcdbdf384f5a3cca1f
I re-wrote it for Swift 4 as below
let topLeft: CLLocationCoordinate2D = mapView.projection.visibleRegion().farLeft
let bottomLeft: CLLocationCoordinate2D = mapView.projection.visibleRegion().nearLeft
let zoom = mapView.camera.zoom
let lat = Double(fabs(Float(topLeft.latitude - bottomLeft.latitude)))
let metersPerPixel: Double = Double((cos(lat * .pi / 180) * 2 * .pi) * 6378137 / Double((256 * pow(2, zoom))))

SQLite query with location fields inside of region

I have a database with two columns, latitude and longitude.
I wonder if it's possible in the Transact-SQL command to retrieve only the records in a defined region of the location passed as a parameter;
For example let's say you have the following records, which is all from the same location, but we're using them for testing purposes.
Now I have the SQL query:
[self.fmQueue inDatabase:^(FMDatabase *db)
{
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(latitude, longitude);
CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:center radius:400.0f identifier:#"identifier"];
NSString* queryCommand = [NSString stringWithFormat:#"SELECT * FROM %# WHERE ?EXPRESSION_ABOUT_REGION?", readingsTable];
FMResultSet* result = [db executeQuery:queryCommand];
if (completionblock)
{
completionblock([self readingsArrayFromResultSet:result]);
}
}];
I could just retrieve records and then compare for every each one with a constructed CLLocationCoordinate2D, [region containsCoordinate:CLLocationCoordinate2D], but that feels so bad performant.
I'm looking for the most performant and appropriate solution to retrieve the desired region related location records in the T-SQL query.
Issues with the Previous Approximation
The previous answer here models the Earth as a Cartesian plane, with latitude and longitude as x and y, and then draws either a circle or a rectangle around the points---the actual shape does not matter, both methods have the same properties.
This can be fine if your constraints are really loose, and they may be here in your particular instance. For the sake of making this answer more useful to everybody I've answered the problem assuming your constraints are not quite as loose. For mobile geolocation apps in general this approximation causes problems. Maybe you've seen an app that's got it wrong. The resulting distances don't make any sense. There are several flaws with the previous approach:
Bad approximation: The scale of the Earth is big so simple approximations can be off by a scale of miles. This is bad if the user is in a car and really bad if the user is on foot. Simple tricks with degrees are not an improvement over circles or squares: latitude and longitude are not evenly distributed, and you need a full approximation like Haversine to get accurate data.
Excludes good points: Unless you severely expand the shape, your sample will exclude valid points.
Includes bad points: And the more you expand the shape to capture excluded valid points, the more you capture invalid points.
Broken sort order: Without the real calculation, you won't be able to correctly sort the output by distance. This means any ordered list you produce will be way off. Usually you want the points in order of closeness.
Two calculations: If you go back and fix it, you're doing two computations.
Single-point Haversine in C/Objective-C
The selection code is already in the other answer. This is the recomputation you referenced that you'll have to perform for each point after in Objective-C or C:
/////////////////////////////////////
//Fill these in or turn them into function arguments
float lat1=center_point.latitude;
float lon1=center_point.longitude;
float lat2=argument_point.latitude;
float lon2=argument_point.longitude;
/////////////////////////////////////
//Conversion factor, degrees to radians
float PI=3.14159265358979;
float f=PI/180;
lat1*=f; lon1*=f; lat2*=f; lon2*=f;
//Haversine Formula (from R.W. Sinnott, "Virtues of the Haversine", Sky and Telescope, vol. 68, no. 2, 1984, p. 159):
float dlon = lon2 - lon1;
float dlat = lat2 - lat1;
float a = pow((sin(dlat/2)),2) + cos(lat1) * cos(lat2) * pow((sin(dlon/2)),2);
float c = 2 * asin(MIN(1,sqrt(a)));
float R = 6378.137;//km Radius of Earth
float d = R * c;
d *= 0.621371192; //optional: km to miles [statute] conversion factor
//NSString conversion?
//if (d >= .23) return [NSString stringWithFormat:#"%0.1f m",d]; //.23m ~ 400 yds
//d *= 5280; //miles to feet conversion factor
//d /= 3; //feet to yards
//int y=(int)d;
//return [NSString stringWithFormat:#"%d yds",y];
return d;
That should be all the tools you need to complete your task as discussed.
Haversine in SQLite
I would like to show you a direct SQLite-only solution, but I was never able to get Haversine to run satisfactorily directly inside of SQLite. You don't get a square root in SQLite. You don't get a pow() function, though you can repeat an argument times itself. You don't get sin, cos, or sinh. There are extensions that add some of these features. I don't know how well-supported they are compared to the base SQLite. Even with them it's going to be too slow.
People seem to recommend updating the columns with pre-computed sines. That's fine as long as you don't need to take the sine of a difference over a whole column, in which case you're writing a new column to the table every time you need to make a new calculation, which is terrible. At any rate, I'd like to show you a comparison of how slow SQLite is on computing the Haversine, but I can't get it to compute it at all. (I think my memory of SQLite being slow on this is actually a memory of MySQL on the server being slow.)
All-points Solution in Kerf
The preceding discussion I hope is a close-to-exhaustive look at what you can do with the standard tools.
The good news is if you do it right this calculation is fast on the phone. I built a thing for you that I think solves your problem in a better way. If you are willing to use another tool, in Kerf this problem is easy. I went back and committed to the repo vectorized operations for trigonometric functions so that the calculations would be fast. My iPhone 5 will do 10,000 points in 20 milliseconds, and 100,000 points in 150 milliseconds. You can do a million points in 1.5 seconds, but at that point you'd need a throbber. Disclosure as per the rules: I built it.
From the Kerf REPL:
//ARTIFICIAL POINT GENERATION ///////////////////
n: 10**4
point_lat: 80 + rand(40.0)
point_lon: 80 + rand(40.0)
mytable: {{lats: 60 + rand(n, 60.0), lons: 60 + rand(n, 60.0)}}
lats : mytable.lats
lons : mytable.lons
/////////////////////////////////////
//COMPUTATION////////////////////////
dlon: lons - point_lon
dlat: lats - point_lat
distances_km: (6378.137 * 2) * asin(mins(1,sqrt(pow(sin(dlat/2),2) + cos(point_lat) * cos(lats) * pow(sin(dlon/2) ,2))))
//distances_miles: 0.621371192 * distances_km //km to miles [statute] conversion
//sort_order: ascend distances_km
Or via the Kerf iOS SDK. Removing the semicolon at the end of a statement will allow you to log it as JSON to the terminal.
KSKerfSDK *kerf = [KSKerfSDK new];
kerf.showTimingEnabled = YES;
//Sample Data Generation
[kerf jsonObjectFromCall:#"n: 10**4;"];
[kerf jsonObjectFromCall:#"point_lat: 80 + rand(40.0);"];
[kerf jsonObjectFromCall:#"point_lon: 80 + rand(40.0);"];
[kerf jsonObjectFromCall:#"mytable: {{lats: 60 + rand(n, 60.0), lons: 60 + rand(n, 60.0)}};"];
[kerf jsonObjectFromCall:#"lats : mytable.lats;"];
[kerf jsonObjectFromCall:#"lons : mytable.lons;"];
//Computation
[kerf jsonObjectFromCall:#"dlon: lons - point_lon;"];
[kerf jsonObjectFromCall:#"dlat: lats - point_lat;"];
NSLog(#"%#", [kerf jsonObjectFromCall:#"distances_km: (6378.137 * 2) * asin(mins(1,sqrt(pow(sin(dlat/2),2) + cos(point_lat) * cos(lats) * pow(sin(dlon/2) ,2)))); "]);
To test whether points (x,y) are inside a circle with center (cx,cy) and radius r, use the equation (x-cx)² + (y-cy)² <= r².
This does not correspond to circle because longitude and latitude values do not have the same length in the earth's surface, but it's near enough.
In SQL:
... WHERE (longitude - :lon) * (longitude - :lon) +
(latitude - :lat) * (latitude - :lat) <= :r * :r
If you use a rectangle instead, you can use simpler expressions that have a chance of being optimized with an index:
... WHERE longitude BETWEEN :XMin AND :XMax
AND latitude BETWEEN :YMin AND :YMax

iOS comparing geographical locations

I wonder how I calculate the distance between the iPhone user position and a given coordinates stored in a plist for example?
You can use the CLLocation method distanceFromLocation: to calculate between two CLLocation objects. You can use CLLocationManager to get user's current location and you can create a CLLocation instance for the coordinates using initWithLatitude:longitude: initializer.
distanceFromLocation: returns the distance in meters.
This is the general formula to calculate the instance between to points, in kilometers.
acos(sin(lat1rad) * sin(lat2rad) + cos(lat1rad) * cos(lat2rad) * cos(lon2rad - lon1rad))) * 6378.1
6378.1 is the approx. radius of the Earth in kilometers. Make sure you express de values in radians and not in degrees. Just in case, the easiest way to convert degrees to radians is:
radians = (degrees * 0.01745329) // degrees * pi over 180
EDIT: fixed the formula to convert between degrees and radians. Thank you Ozzah!

geo-indexing: efficiently calculating proximity based on latitude/longitude

My simple web app (WSGI, Python) supports text queries to find items in the database.
Now I'd like to extend this to allow for queries like "find all items within 1 mile of {lat,long}".
Of course that's a complex job if efficiency is a concern, so I'm thinking of a dedicated external module that does indexing for geo-coordinates - sort of like Lucene would for text.
I assume a generic component like this already exists, but haven't been able to find anything so far. Any help would be greatly appreciated.
Have you checked out mongo db, they have a geo indexing feature. http://www.mongodb.org/display/DOCS/Geospatial+Indexing
I could only think of a semi-brute-force attack if you plan to implement it directly with Python, which I already did with similar purposes:
#!/usr/bin/python
from math import *
def distance(p1,p2): # uses the haversine function and an ellipsoid model
lat1, long1 = p1; lat2, long2 = p2
lat1=radians(lat1); long1=radians(long1); lat2=radians(lat2); long2=radians(long2)
maior=6378.137; menor=6356.7523142
R=(maior*menor)/sqrt((maior*cos(lat1))**2 + (menor*sin(lat1))**2)
d_lat = lat2 - lat1; d_long = long2 - long1
a = sin(d_lat/2)**2 + cos(lat1) * cos(lat2) * sin(d_long/2)**2
c = 2 * atan2(sqrt(a), sqrt(1-a))
length = R * c
x = sin(d_long) * cos(lat2)
y = cos(lat2) * sin(lat1) - sin(lat2) * cos (lat1) * cos(d_long)
bearing = 90-(degrees(atan2(y, -x)))
return length, bearing
For the screening of points for distance, you can first find candidate points whose "x" and "y" coordinates are inside a square centered on your testing position (much faster) and just then test for actual geodesic distance.
Hope it helps!

Resources