How to find the closest country from a list - php

I have a list of ISO 3166 country codes (240) and a list of 8 countries/territories/regions (Australia, Denmark, Netherlands, Qatar, South Africa, UAE, UK & USA). I would like to go through the list of country codes and, for each one, work out which is the closest one from the list of 8. The metric (geographical distance, straight-line distance, driving time, etc.) isn't particularly important as it doesn't need to be perfect, just reasonable.
The list of 8 places is subject to regular change so it's impractical to do the task manually. I've tried using the Google Maps API but have so far been unsuccessful. The ideal solution would be in PHP and would result in an array with the country code as the index and closest country (from the list of 8) as the value. Any help appreciated!

The geonames project has public data that you can use
http://www.geonames.org/
Now you can get the distance between geographical coorindates.
function distance($lat1, $lng1, $lat2, $lng2, $miles = true)
{
$pi80 = M_PI / 180;
$lat1 *= $pi80;
$lng1 *= $pi80;
$lat2 *= $pi80;
$lng2 *= $pi80;
$r = 6372.797; // mean radius of Earth in km
$dlat = $lat2 - $lat1;
$dlng = $lng2 - $lng1;
$a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlng / 2) * sin($dlng / 2);
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
$km = $r * $c;
return ($miles ? ($km * 0.621371192) : $km);
}
For your use case you could use the capital of the countries. For big countries you should possibly add some more countries near the boarders.
That is one solution. You could also store geometric shapes that approximate the country in a database and make exact queries...
However the starting point is the data. What do you actually want? What data do you have?
If efficiency is a problem I would recommend build a graph where every country is stored and linked with its border countries. If you only look at the border countries this greatly reduces computational effort.

Related

Distance in KMs results are off - what am I doing wrong? PHP [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
So I am trying to get the distance between two point based on Latitude and Longitude calculated and printed to the screen, it 'works' but the correct answer is way off. And by way off I mean 187 kms off in my particular case. I am not sure why, and I feel as though I am doing something really silly but I can't seem to locate the problem. Here's what I have so far:
/**
* Calculates Geographical Distance from Latitude and Longitude Pairs
*
* #param array $pair1 Array of first Pair
* #param array $pair2 Array of second Pair
*
* #return string
*/
private function _calculateGeographicalDistanceFromLatLng($pair1, $pair2)
{
$pi80 = M_PI / 180;
$pair1[0] *= $pi80;
$pair1[1] *= $pi80;
$pair2[0] *= $pi80;
$pair2[1] *= $pi80;
$r = 6372.797; // radius of Earth in km
$dlat = $pair2[0] - $pair1[0];
$dlng = $pair2[1] - $pair1[1];
$a = sin($dlat / 2) * sin($dlat / 2) + cos($pair1[0]) * cos($pair2[0]) * sin($dlng / 2) * sin($dlng / 2);
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
$km = $r * $c / 1000;
if ($this->_unit == "all") {
$miles = $km * 0.621371192;
return array("KM" => round($km, 2), "Mile" => round($miles, 2));
} elseif ($this->_unit == "mile") {
$miles = $km * 0.621371192;
return round($miles, 2);
} else {
return round($km, 2);
}
}
When I try and have it echo the correct answer with different options, the answer is absolutely way off.
$df = new distanceAdvice("Geographic");
$result = $df->findDistance(array("53.219383", "6.566502"), array("52.090737", "5.121420"));
if (isset($result['error'])) {
echo $result['error']['msg'];
} else {
echo "The geographical distance between the two points based on Latitude and Longitude is: " . $result . " Kilometer.<br />";
}
According to the documentation, to calculate distance between 2 points you should use computeDistanceBetween(LatLngFrom, LatLngTo)
Google handled all those Mercator Projection stuff for you so I guess, rather than writing your own, you should use this API.
I know your pain about this. I've had to encode this great circle distance formula into Excel VBA for some NASA geolocation work I've volunteered for. There is confusing information about the proper formula to use on the web when you do a google search. There is the Haversine formula, and the Spherical Law of Cosines formula. Also, the ATAN2 formula is implemented slightly differently at times [some libraries do atan2(dy, dx) while other libraries (like Excel) do atan2(dx, dy]].
For the Haversine formula (see https://en.wikipedia.org/wiki/Haversine_formula), try changing the line below. The Haversine formula is not supposed to use ATAN2, and unfortunately some first results on Google searches provide the wrong formula:
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
with
$c = 2 * asin(sqrt($a));
That is the proper Haversine formula. There may be an edge case that needs to be accounted for ... my formula in Excel included:
$c = 2 * asin(min(1,sqrt($a)));
And a source for that came from the U.S. Census (though its link is no longer valid) so here is a posting that references it:
http://www.cs.nyu.edu/visual/home/proj/tiger/gisfaq.html
Also, different distance calculators you will find online use different Earth radius values, since the earth is actually not round; even the term "sea level" is not consistent and "round" across the entire Earth. So you may still find your distance calculation is slightly different from whatever you are using as a reference just because of different Earth radius values.

Finding the nearest neighbor Algorithm using google map coordinates

Please help me to find an algorithm that finds the nearest neighbor by its coordinates (latitude/longitude) I will implemented it using PHP
for example. we have 1 client and 2 nodes
Node 1 = 32.9697, -96.8032 and Node 2=42.9697, -97.80322
each node has their own given coordinates (place on a map).
the client will send a latitude and longitude coordinates into the system and the system will find out if the coordinates that it receives from the client is near to Node 1 or Node 2
Please excuse my grammar. Hoping for your kind response. Thank you in advance
If you have only a limited number of possible targets (as I would guess from your question) you can use the following function (copied from here) and just iterate over all your targets to find the closest one.
function distance($lat1, $lng1, $lat2, $lng2, $miles = false)
{
$pi80 = M_PI / 180;
$lat1 *= $pi80;
$lng1 *= $pi80;
$lat2 *= $pi80;
$lng2 *= $pi80;
$r = 6372.797; // mean radius of Earth in km
$dlat = $lat2 - $lat1;
$dlng = $lng2 - $lng1;
$a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlng / 2) * sin($dlng / 2);
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
$km = $r * $c;
return ($miles ? ($km * 0.621371192) : $km);
}
If you have many possible locations (>=10^4) you should organise those data points in some structure to only have to evaluate a fraction of them. I'd suggest a Quadtree for this although it will not work for the poles as well as the datum-border. I'm sure you'll find better solutions if needed for such a case (which I assume you do not require).

Use a self-defined function in select clause MySQL

I'm trying to get make a query which gives me a list of stores sorted by how far they are from the current location. I'm working in php and using MySQL for my database.
To calculate the distance between 2 stores, I use the longitudes and latitudes from the 2 stores and derive the distance from it. This is contained in a self-defined function distance($lat1, $lng1, $lat2, $lng2). The result of this function is the distance in km.
I want to use this function to create an extra column in my query result so I can sort all the stores from the one most behind my current location to the one most far from my current location. Both functions are declared in the same file, but I do not get any result. Is it possible to call a function in the SELECT clause by declaring it the way I did?
function getSortedStores($cur_lat, $cur_lng)
{
$query = "SELECT Store.ID, Store.Name, distance($cur_lat, $cur_lng, Address.Latitude, Address.Longitude) AS Distance FROM Store INNER JOIN Address ON Store.ID=Address.StoreID ORDER BY Distance";
$result = mysql_query($query);
return $result;
}
function distance($lat1, $lng1, $lat2, $lng2)
{
$toRadians = M_PI / 180;
$lat1 *= $toRadians;
$lng1 *= $toRadians;
$lat2 *= $toRadians;
$lng2 *= $toRadians;
$r = 6371; // mean radius of Earth in km
$dlat = $lat2 - $lat1;
$dlng = $lng2 - $lng1;
$a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlng / 2) * sin($dlng / 2);
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
$km = $r * $c;
$km = round($km, 1);
return $km;
}
you can't use php function in mysql. for more detail about mysql User-Defined Function
see this
http://dev.mysql.com/doc/refman/5.1/en/adding-functions.html
You can't mix PHP and mySQL in that way, you can either do the calculation in mySQL with their math functions, or select the raw data and do the calculations based on the result set in PHP. But you cannot call a PHP function inside a mySQL query.
Alternatively, and assuming that your stores are not mobile. You can create a simple table table to store the distances between all of your stores. It takes up a little extra storage, but can potentially save you a fair bit of CPU cycles in the end.
TABLE distances
store1_id INT PK
store2_id INT PK
distance FLOAT
SELECT distance
FROM distances
WHERE (store1_id = $store1 AND store2_id = $store2)
OR (store1_id = $store2 AND store1_id = $store2)
LIMIT 1

Canadian Postal Codes Radius

I am using the following scripting that I found on the net to grab all postal codes between a given set coordinates.
When using it my concern is that when some postal codes being grab are greater than the distance entered; not by much - about 20 KM off.
function GetPostalCodes($latitude, $longitude, $range) {
$radius = 3959;
$north = rad2deg(asin(sin(deg2rad($latitude)) * cos($range / $radius) + cos(deg2rad($latitude)) * sin($range / $radius) * cos(deg2rad(0))));
$south = rad2deg(asin(sin(deg2rad($latitude)) * cos($range / $radius) + cos(deg2rad($latitude)) * sin($range / $radius) * cos(deg2rad(180))));
$east = rad2deg(deg2rad($longitude) + atan2(sin(deg2rad(90)) * sin($range / $radius) * cos(deg2rad($latitude)), cos($range / $radius) - sin(deg2rad($latitude)) * sin(deg2rad($north))));
$west = rad2deg(deg2rad($longitude) + atan2(sin(deg2rad(270)) * sin($range / $radius) * cos(deg2rad($latitude)), cos($range / $radius) - sin(deg2rad($latitude)) * sin(deg2rad($north))));
$return = DBSelectAllArrays("SELECT postal FROM postalcodes WHERE (latitude <= $north AND latitude >= $south AND longitude <= $east AND longitude >= $west)");
krsort($return);
if (empty($return)) return false;
return $return;
}
Is there something I am missing to get a more accurate result?
Given your comments:
$radius = 6371.0; // mean radius of Earth in km
This is taken from wikipedia, but I've seen it within a +/- 3km tolerance from other sources.
I began to question whether you were using great circle distance calculations, but this is more important for accuracy over longer distances due to the curvature of the earths surface.
Tim, you started by using a bounding box (rectangle) and then with the Haversine formula, you'll get a radius (circle), which generally is much better if you just want people within a certain distance. You don't state your purpose, but if you're looking for people who may travel a certain distance to you, you may want to consider metropolitan areas, which vary in shape. If so, look at: Canadian Metro Areas data

Building a store locator app using distance between two coordinates

I am making a small section of an app (phone and website) that can find the nearest stores (stored in my database). I am using PHP so was going to make use of the web service idea and have AJAX requests posted to a PHP Page. I have found the following info from snipplr.com:
function distance($lat1, $lng1, $lat2, $lng2, $miles = true)
{
$pi80 = M_PI / 180;
$lat1 *= $pi80;
$lng1 *= $pi80;
$lat2 *= $pi80;
$lng2 *= $pi80;
$r = 6372.797; // mean radius of Earth in km
$dlat = $lat2 - $lat1;
$dlng = $lng2 - $lng1;
$a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlng / 2) * sin($dlng / 2);
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
$km = $r * $c;
return ($miles ? ($km * 0.621371192) : $km);
}
Which is all good, but I have a database of about 300 locations. I just need bit of help getting started with this.
My idea was to do a query to a DB and get all of the long/lats in an array and loop through the array, each time using this above function. Then sort the requests by distance and done!
But I just wondered if theres a better way? I am relatively new to PHP development, so need to get an idea about best practices etc...
Thanks for the help!
i'd actually advice you to check out the solution of google. this works pretty well:
https://developers.google.com/maps/articles/phpsqlsearch?hl=en

Categories