Calculate heading for kml in php/mysql - php

I have a table in mysql with 4 columns:
Latitude_1
Longitude_1
Latitude_2
Longitude_2
Now I want to calculate the heading for all rows to be used in a kml file.
I found this function:
// Takes two sets of geographic coordinates in decimal degrees and produces bearing (azimuth) from the first set of coordinates to the second set.//
public static function bearing($lat1, $lon1, $lat2, $lon2) {
$lat1 = deg2rad($lat1);
$lon1 = deg2rad($lon1);
$lat2 = deg2rad($lat2);
$lon2 = deg2rad($lon2);
$lonDelta = $lon2 - $lon1;
$y = sin($lonDelta) * cos($lat2);
$x = cos($lat1) * sin($lat2) - sin($lat1) * cos($lat2) * cos($lonDelta);
$brng = atan2($y, $x);
$brng = $brng * (180 / pi());
if ( $brng < 0 ) { $brng += 360; }
return $brng;
}
Now I hope that someone shows me a query that echoes all headings (bearings) of the table based on the above mentioned function

To combine an expression expr, take a look to the mysql math functions and find proper equivalents for php ones - https://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html
Simplify your expr if possible
Use your result expression expr in following query SELECT expr FROM your_table
Profit

Related

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).

How to find intersection points between two circles?

We have two points (centers of two circles) and their radius in meters, those radius make the circle. We need to find intersection points. For example we have lat1 = 55.685025, lng1 = 21.118995, r1 = 150 and lat2 = 55.682393, lng2 = 21.121387, r2 = 250. Below you can find our current formula:
// Find a and h.
$a = ($circle_1_r * $circle_1_r - $circle_2_r * $circle_2_r + $distance * $distance) / (2 * $distance);
$h = sqrt($circle_1_r * $circle_1_r - $a * $a);
// Find P2.
$circle_3_x = $circle_1_x + $a * ($circle_2_x - $circle_1_x) / $distance;
$circle_3_y = $circle_1_y + $a * ($circle_2_y - $circle_1_y) / $distance;
// Get the points P3.
$intersection_1 = $this->newLatLngPoint(
($circle_3_x + $h * ($circle_2_y - $circle_1_y) / $distance),
($circle_3_y - $h * ($circle_2_x - $circle_1_x) / $distance)
);
$intersection_2 = $this->newLatLngPoint(
($circle_3_x - $h * ($circle_2_y - $circle_1_y) / $distance),
($circle_3_y + $h * ($circle_2_x - $circle_1_x) / $distance)
);
We find such intersection points (yellow markers), however those locations doesn't match in real world.
Someone, can help to find where the problem is and how to sort it ?
P.S.
Does the altitude (Height above mean sea level) affect the final result? I don't use it but may be should?

Calculate all coordinates to x decimal places between two Lat/Long coordinates

How can I calculate every Lat/Long coordinates between two Lat/Long coordinates in PHP?
Lets say I have coordinates A:
(39.126331, -84.113288)
and coordinates B:
(39.526331, -84.213288)
How would I calculate every possible coordinates between those two Lat/Long coordinates (in a direct line) up to five decimal places (e.g. 39.12633, -84.11328) and get list of coordinates between the two?
In addition, I have another set of coordinates (Coordinates C) that are slightly off and not on the track of coordinates between A and B.
How could I calculate the distance between coordinates C and the closest coordinates between A and B?
You can compute a voronoi diagram from all the lat lon pairs and then look for adjacent cell. Also note that lat lon are angles and not world coordinate or cartesian coordinates. You can download my PHP class voronoi diagram # phpclasses.org.
Here is what solved this for me,
function point_to_line_segment_distance($startX,$startY, $endX,$endY, $pointX,$pointY)
{
$r_numerator = ($pointX - $startX) * ($endX - $startX) + ($pointY - $startY) * ($endY - $startY);
$r_denominator = ($endX - $startX) * ($endX - $startX) + ($endY - $startY) * ($endY - $startY);
$r = $r_numerator / $r_denominator;
$px = $startX + $r * ($endX - $startX);
$py = $startY + $r * ($endY - $startY);
$closest_point_on_segment_X = $px;
$closest_point_on_segment_Y = $py;
$distance = user_bomb_distance_calc($closest_point_on_segment_X, $closest_point_on_segment_Y, $pointX, $pointY);
return array($distance, $closest_point_on_segment_X, $closest_point_on_segment_Y);
}
function user_bomb_distance_calc($uLat , $uLong , $bLat , $bLong)
{
$earthRadius = 6371; #km
$dLat = deg2rad((double)$bLat - (double) $uLat);
$dlong = deg2rad((double)$bLong - (double) $uLong);
$a = sin($dLat / 2 ) * sin($dLat / 2 ) + cos(deg2rad((double)$uLat)) * cos(deg2rad((double)$bLat)) * sin($dlong / 2) * sin($dlong / 2);
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
$distance = $earthRadius * $c;
$meter = 1000; //convert to meter 1KM = 1000M
return intval( $distance * $meter ) ;
}

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

PHP returning NaN

I have a function that calculates the distance between two GPS coordinates. I then get all the coordinates from the database and loop through them all to get the distance between the current one and the previous one, then add that to an array for the specific GPS device. For some reason it is return NaN. I have tried casting it as a double, an int, and rounding the number.
Here is my PHP code:
function distance($lat1, $lon1, $lat2, $lon2) {
$lat1 = round($lat1, 3);
$lon1 = round($lon1, 3);
$lat2 = round($lat2, 3);
$lon2 = round($lon2, 3);
$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;
if($miles < 0) $miles = $miles * -1;
return ($miles * 1.609344);
}
$this->db->query("SELECT * FROM `gps_loc` WHERE `imeiN`='" . $sql . "' AND `updatetime`>=$timeLimit ORDER BY `_id` DESC");
$dist = array();
$dist2 = array();
while($row = $this->db->getResults()) {
$dist2[$row['imeiN']] = 0;
$dist[$row['imeiN']][]["lat"] = $row['lat'];
$dist[$row['imeiN']][count($dist[$row['imeiN']]) - 1]["lng"] = $row['lon'];
}
foreach($dist as $key=>$d) {
$a = 0;
$b = 0;
foreach($dist[$key] as $n) {
if($a > 0) {
$dist2[$key] += $this->distance($n['lat'], $n['lng'], $dist[$key][$a - 1]['lat'], $dist[$key][$a - 1]['lng']);
}
$a++;
}
}
echo json_encode($dist2);
The range of sin() and cos() is between -1 and 1. Therefore in your first calculation of $dist the result range is -2 to 2. You then pass this to acos(), whose argument must be between -1 and 1. Thus acos(2) for example gives NaN. Everything else from there gives NaN as well.
I'm not sure what the formula should be exactly, but that's where your NaN is coming from. Double-check your trigonometry.
The algo will produce NaN if points are too close to each other. In that case $dist gets value 1. acos(1) is NaN. All subsequent calculations produce NaN too.
You round coordinates as the first step, so it makes more probable that the values become equal after rounding, and produce NaN.
The values you are pulling from the database may be strings, which would cause this issue.
You may also want to check the issues that Kolink raised in his post.
Is that the spherical law of cosines you're using? I'd switch to the Haversine formula:
function distance($lat1, $lon1, $lat2, $lon2)
{
$radius = 3959; //approximate mean radius of the earth in miles, can change to any unit of measurement, will get results back in that unit
$delta_Rad_Lat = deg2rad($lat2 - $lat1); //Latitude delta in radians
$delta_Rad_Lon = deg2rad($lon2 - $lon1); //Longitude delta in radians
$rad_Lat1 = deg2rad($lat1); //Latitude 1 in radians
$rad_Lat2 = deg2rad($lat2); //Latitude 2 in radians
$sq_Half_Chord = sin($delta_Rad_Lat / 2) * sin($delta_Rad_Lat / 2) + cos($rad_Lat1) * cos($rad_Lat2) * sin($delta_Rad_Lon / 2) * sin($delta_Rad_Lon / 2); //Square of half the chord length
$ang_Dist_Rad = 2 * asin(sqrt($sq_Half_Chord)); //Angular distance in radians
$distance = $radius * $ang_Dist_Rad;
return $distance;
}
You should be able to change the earth's radius to any form of measurement from radius in light years to radius in nanometers and get the proper number back out for the unit used.
Thanks for all the responses here - as a result I made a function which combines to computations and tests for NaN in each, if both are not NaN - it averages the calculation, if one is NaN and the other is not - it uses the one that's valid and gives error report for the coordinates that failed one of the calculation:
function distance_slc($lat1, $lon1, $lat2, $lon2) {
$earth_radius = 3960.00; # in miles
$distance = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($lon2-$lon1)) ;
$distance = acos($distance);
$distance = rad2deg($distance);
$distance = $distance * 60 * 1.1515;
$distance1 = round($distance, 4);
// use a second method as well and average
$radius = 3959; //approximate mean radius of the earth in miles, can change to any unit of measurement, will get results back in that unit
$delta_Rad_Lat = deg2rad($lat2 - $lat1); //Latitude delta in radians
$delta_Rad_Lon = deg2rad($lon2 - $lon1); //Longitude delta in radians
$rad_Lat1 = deg2rad($lat1); //Latitude 1 in radians
$rad_Lat2 = deg2rad($lat2); //Latitude 2 in radians
$sq_Half_Chord = sin($delta_Rad_Lat / 2) * sin($delta_Rad_Lat / 2) + cos($rad_Lat1) * cos($rad_Lat2) * sin($delta_Rad_Lon / 2) * sin($delta_Rad_Lon / 2); //Square of half the chord length
$ang_Dist_Rad = 2 * asin(sqrt($sq_Half_Chord)); //Angular distance in radians
$distance2 = $radius * $ang_Dist_Rad;
//echo "distance=$distance and distance2=$distance2\n";
$avg_distance=-1;
$distance1=acos(2);
if((!is_nan($distance1)) && (!is_nan($distance2))){
$avg_distance=($distance1+$distance2)/2;
} else {
if(!is_nan($distance1)){
$avg_distance=$distance1;
try{
throw new Exception("distance1=NAN with lat1=$lat1 lat2=$lat2 lon1=$lon1 lon2=$lon2");
} catch(Exception $e){
trigger_error($e->getMessage());
trigger_error($e->getTraceAsString());
}
}
if(!is_nan($distance2)){
$avg_distance=$distance2;
try{
throw new Exception("distance1=NAN with lat1=$lat1 lat2=$lat2 lon1=$lon1 lon2=$lon2");
} catch(Exception $e){
trigger_error($e->getMessage());
trigger_error($e->getTraceAsString());
}
}
}
return $avg_distance;
}
HTH someone in the future as well.

Categories