How to calc distance between two postcodes without API - PHP preferred - php

I've been making search functionality that takes in two fields, Start Postcode and End Postcode. The search is supposed to query the database and collect any records that fall into the radius for both postcodes. I can retrieve the records but after, I need to get the distance between the postcodes. I know how to use the GMaps API to do this but I need to do it locally with PHP for performance reasons (Looping over multiple records etc). It would be very bad for performance to do this with an API. Any suggestions?
Just to be clear: I need a code solution to calculate distance between two postcodes without API use. Is this possible and if so how?
PHP is preferred but even just the logical idea represented in any language is okay for me.

If you have latitude and longtitude you can calculate the distance between two points without api just using this code:
function distance($lat1, $lon1, $lat2, $lon2, $unit) {
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
$unit = strtoupper($unit);
if ($unit == "K") {
return ($miles * 1.609344);
} else if ($unit == "N") {
return ($miles * 0.8684);
} else {
return $miles;
}
}
echo distance(32.9697, -96.80322, 29.46786, -98.53506, "M") . " Miles<br>";
echo distance(32.9697, -96.80322, 29.46786, -98.53506, "K") . " Kilometers<br>";
echo distance(32.9697, -96.80322, 29.46786, -98.53506, "N") . " Nautical Miles<br>";

Store the Lat Lon when you save the record and then work it out from that. It does mean a call to Google Maps API on save though.

I know this is a bit late, but it may help other people in future.
First, you can get Postcode -> Lat/long databases for free.
Here's a useful site which has plenty of geo mapping data like that:
https://www.freemaptools.com/download-uk-postcode-lat-lng.htm
Before you use such calculations though, you should think about what you want - straight-line 'As the crow flies' distances or driving distances. They are not the same!
To make a point, have a look at the Google Map: https://www.google.co.uk/maps/#51.4226247,-3.8874075,8.88z
The straight-line distance (calculated using Lat/Long) between, for example, Ilfracombe and Swansea is going to bear not relationship to the driving distance where you hav eto go up to the Severn bridge.
Calculating straight line distances - cheap and quick but inaccurate.
Calculating driving distances - accurate but very difficult to do yourself - an API, and its costs are necessary if you need this

Related

Getting longitude east or west direction on route

I am trying to find the actual longitude direction on a route.
For example the route could be:
37.635118, -75.058594 (US EAST COAST) to 38.740377, -123.222656 (US WEST COAST)
In this case, the direction would be WEST, as EAST would be across the world.
Using the following distance calculator i would like to return the actual direction as well, but i am uncertain as to how i can do that.
function getdistance($lat1, $lon1, $lat2, $lon2) {
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
$res = round(($miles * 1.609344));
return $res;
}
Does anyone know how i would go about getting the W/E direction from the coordinates above?
Thank you
So i realized it was alot simpler than i thought.
$lon1-$lon2 will return either a positive or negative, and from that, its easy to find that any positive number is east, and negative is west.

PHP calculate lan/lon distance performance

I have serious performance issues with a distance calculation script.
I have approximately 3000 locations (and this will eventually be doubled) in a database. The database structure is quite complex (categories, subcategories) but with time(); I saw that these query's didn't took much time.
I have a $_GET of latitude and longitude of the user and I use this calculation to determine if the location is within a certain radius:
function distance($lat1, $lon1, $lat2, $lon2, $unit) {
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
$unit = strtoupper($unit);
if ($unit == "K") {
return ($miles * 1.609344);
} else if ($unit == "N") {
return ($miles * 0.8684);
} else {
return $miles;
}
}
// some sql queries to get the lat/lon from the locations
if ((distance($_GET["lat"], $_GET["long"], $row3["content"], $row4["content"], "K") . "") < 10) {
//push to multidimensional array
}
$row3["content"] and $row4["content"] are the latitude and longitude values. For 3000 locations, this calculation takes up to 13 seconds!
I read this:
Fastest Way to Find Distance Between Two Lat/Long Points
I think the option to draw a box, based on the $_GET of latitude and longitude could perhaps already remove the current calculation. In the sql queries I can already filter out the locations outside the 10 km range.
But I have 2 questions:
If I change the SQL to something like this: ... WHERE LAT >= x1 AND <= x2, does this affect the time of the query?
In the explanation the writer talks about "units". I've been playing around with the lat/lon values, but how do I actually calculate x1, x2, y1, y2 where the $_GET value is a point in the center with a distance of 10 km?
Thank you.
I was able to reduce the calculation time from 13 seconds to 1 second!
I did this by filtering out with mysql the locations that were not within a 10 km bounding box of my lat/long coordinates.
I used this code:
$rad = 10; // radius of bounding circle in kilometers
$R = 6371; // earth's mean radius, km
// first-cut bounding box (in degrees)
$maxLat = $_GET['lat'] + rad2deg($rad/$R);
$minLat = $_GET['lat'] - rad2deg($rad/$R);
// compensate for degrees longitude getting smaller with increasing latitude
$maxLon = $_GET['long'] + rad2deg($rad/$R/cos(deg2rad($_GET['lat'])));
$minLon = $_GET['long'] - rad2deg($rad/$R/cos(deg2rad($_GET['lat'])));
and I changed my mysql to this:
$sql2 = "SELECT ....WHERE LAT BETWEEN '".$minLat."' AND '".$maxLat."'";
$sql3 = "SELECT ....WHERE LON BETWEEN '".$minLon."' AND '".$maxLon."'";
The rest of my code and calculation is exact the same, but instead of doing 3000 calculations, mysql sweeps out the majority.
I don't know if this approach is 100% mathematically correct, but as far as I see it works very fast with minor changes to my initial coding so for my project it's great.
And of course, the source: http://www.movable-type.co.uk/scripts/latlong-db.html

Distance calculation which is faster mongodb or mysql

I am little bit confused about following problem & their solutions:
i have 2 tables users & userfriends having following structure
users
userid lat long
userfriends
userid friendid
so in users table i have lat & long of all the users & in userfriends i have list of friends for each user.
Now i want to calculate nearby users (distance) so my friend told me to use mongodb which have fast performance.
But i found another function which i can use in stored procedure in mysql
function distance($lat1, $lon1, $lat2, $lon2, $unit) {
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
$unit = strtoupper($unit);
if ($unit == "K") {
return ($miles * 1.609344);
} else if ($unit == "N") {
return ($miles * 0.8684);
} else {
return $miles;
}
}
So basically i want my distance calculation faster & quick.
So can somebody tell me am i correct in my way or i need to send needed data (lat & long of users friends) to mongodb & calculate & mongodb will return results to my database (MySQL)?
Both MySQL and MongoDB support geospatial indexing. IME, NoSQL databases have huge performance advantages when dealing with selecting individual records, but offer less of a performance benefit (still usually faster) compared with a relational database when dealing with range queries - YMMV.
There are other very fundamental differences - which are well covered elsewhere.
You really want to spend a lot of time reading the linked documents - the method you describe will be phenomonally innefficient.

Latitude/longitude vector to distance, strange problem with output

I have this code to find the distance between two sets of GPS coordinates, I got the code from elsewhere on the net.
function distance($lat1, $lon1, $lat2, $lon2, $unit) {
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
$unit = strtoupper($unit);
if ($unit == "K") {
return ($miles * 1.609344);
} else if ($unit == "N") {
return ($miles * 0.8684);
} else {
return $miles;
}
}
The ouput returned looks like this: 25.44049 but if I do
$distance_output = distance(-50.12345, 100.1235,-60.12345,120.12345,'km');
echo $distance_output . '<br />;
echo $distance_output - 15.12345;
it outputs like this:
15.12345
1.23639038e10
These are just made up numbers, but you can see the output of distance() looks like a number but then when I subtract the same number from it, it spits out a wierd exponential number. Any ideas?
Thanks a lot
Why is PHP printing my number in scientific notation, when I specified it as .000021?
Use number_format()
I tried your code (you just missed a simple quote), and the output is 1042.1216629565 and 1026.9982129565, seems ok to me.
If I substract 1042.1216629565 to 1042.1216629565, the output becomes 3.092281986028E-11 : note the minus character after the e.
This number is equal to 0.00000000003092281986028, not zero. This difference is common with floating point computation. It can be explained by rounding errors in value binary coding.
See wikipedia : http://en.wikipedia.org/wiki/Floating_point and particularly section about rounding.
If you want to display the result, use number_format()
If you want to compare two floating point values, you'll have to do use something like that :
$epsilon = 1e-6;
if (abs($value1-$value2) <= $epsilon){
}

PHP MySql and geolocation

I am writing a site that basically looks for places within a 25 mile radius of a lat and long using php and mysql.
I am wondering how something like this would work?
I would pass a lat and long to the scrip and have it pull out only locations that are within 25 miles of the lat and long from my Database of locations.
What is the best way to do this?
EDIT:
I found this code for calculating the distance between 2 points.
function distance($lat1, $lon1, $lat2, $lon2, $unit) {
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
$unit = strtoupper($unit);
if ($unit == "K") {
return ($miles * 1.609344);
} else if ($unit == "N") {
return ($miles * 0.8684);
} else {
return $miles;
}
}
Is ther a way to do this calc in the MYSQL look up so I can only return if miles =< 25?
Calculating the distance using that function there is pretty computationally expensive, because it involves a whole bunch of transcendental functions. This is going to be problematic when you have a large number of rows to filter on.
Here's an alternative, an approximation that's way less computationally expensive:
Approximate distance in miles:
sqrt(x * x + y * y)
where x = 69.1 * (lat2 - lat1)
and y = 53.0 * (lon2 - lon1)
You can improve the accuracy of this approximate distance calculation by adding the cosine math function:
Improved approximate distance in miles:
sqrt(x * x + y * y)
where x = 69.1 * (lat2 - lat1)
and y = 69.1 * (lon2 - lon1) * cos(lat1/57.3)
Source: http://www.meridianworlddata.com/Distance-Calculation.asp
I ran a bunch of tests with randomly generated datasets.
The difference in accuracy for the 3 algorithms is minimal, especially at short distances
The slowest algorithm is, of course, the one with the trig functions (the one on your question). It is 4x slower than the other two.
Definitely not worth it. Just go with an approximation.
Code is here: http://pastebin.org/424186
To use this on MySQL, create a stored procedure that takes coordinate arguments and returns the distance, then you can do something like:
SELECT columns
FROM table
WHERE DISTANCE(col_x, col_y, target_x, target_y) < 25
You may want to take a look at this solution - a somewhat brilliat workaround.
You can do it easily in two steps:
Find all locations within 25 miles in each direction of the point. This will look like: WHERE lat BETWEEN $lat1 AND $lat2 AND lng BETWEEN $lng1 AND $lng2
Then loop through each result and check to see if it really is within 25 miles using your code. (i.e., Filter out those locations that are in the corners of the square.)
For the first part, here's some code I have laying around (don't remember the source):
$lat_range = $radius / ((6076 / 5280) * 60);
$lng_range = $radius / (((cos(($city['lat'] * 3.141592653589 / 180)) * 6076) / 5280) * 60);
Basically just use ($lat - $lat_range, $lat + $lat_range) and ($lng - $lng_range, $lng + $lng_range) Radius is in miles.
Obviously you can clean up the math a bit.
Edit: I forgot to mention that you would need to tweak it a bit if you need to support locations near the equator, international date line, etc. Obviously for North America, it would be fine as-is.

Categories