PHP Function to Calculate Distance (Example)

jaimzj8 years ago

Dear All,

Sharing a function I found handy in calculating distance between two co-ordiantes in PHP.

class test {

public function GetDistance($lat1, $lng1, $lat2, $lng2) {
        $radLat1 = $lat1*3.1415926535898/180.0;
        $radLat2 = $lat2*3.1415926535898/180.0;
        $a = $radLat1 - $radLat2;
        $b = ($lng1*3.1415926535898/180.0) - ($lng2*3.1415926535898/180.0);
        $s = 2 * asin(sqrt(pow(sin($a / 2), 2) + cos($radLat1) * cos($radLat2) * pow(sin($b / 2), 2)));
        $s = $s * 6378.137; // EARTH_RADIUS;
        $s = round($s * 1000,3); 
        return $s;
    }		
}

usage example

$obj=new test();
$dis=$obj->GetDistance($lat1,$lon1,$lat2,$lon2);

returned value will be in meters.

bruno8 years ago

great code! I have a small question if you don't mind, how would you use this if you wanted to calculate distance of multiple points. Example: if i want to calculate distance travelled for the past hour, I will have a lot of co-ordinate points. How can I run this function over a bunch of points?

jaimzj8 years ago

This is how I have achieved it, please change the mysql query as per your need, but I think the code below should give you a fair idea of how you can calculate distance between multiple points.

I have not added comment's due to lack of time.


$j=0;
$sql=mysql_query("SELECT * FROM position WHERE deviceId='xxx' AND fixTime>='xxx' AND fixTime <='xxxx' AND speed >'1' ORDER BY id ASC "); 
while($row=mysql_fetch_array($sql))
{
    if($j==0)
    {
        $lat1=$row1['latitude'];
        $lon1=$row1['longitude'];
    }
    if($j>=1)
    {
        $lat2=$row1['latitude'];
        $lon2=$row1['longitude'];	
    
        $obj=new test();
        $distance=$obj->GetDistance($lat1,$lon1,$lat2,$lon2);
        
        if($distance>180) $distance=0;
        $TotalDis+=$distance;

        $lat1=$lat2;
        $lon1=$lon2;
        
    }		
$j++;
}

if($TotalDis>1000) 
$countDis = number_format(round($TotalDis/1000,1),1)." km"; else
$countDis = number_format(round($TotalDis,3),3)." m";
dimonchik8 years ago

Excuse me.
Rewritten in C #, the value differs from the value in the report :-(
Help please, that all is not so.
Those. in report 17.91 km, and I get in C# 18.2km, but it is provided if you remove the condition:


/*if( distance > 180 ) {
    distance = 0;
}else{*/
   maxDistance += distance;
//}

If you leave it turns out: 8km

Please help me!!!

Anton Tananaev8 years ago

There must be some difference in calculation algorithm.

dimonchik8 years ago

My SQL query:

String query = "SELECT * FROM `positions` WHERE `device id` =" + device_id + "AND `time` > = ' "+ date_starts +"' AND `time` <= '" + date_stop + "' AND speed > 0 ORDER BY `time` ASC";
dimonchik8 years ago

I'm in stupor... :-(

Anton Tananaev8 years ago

It's a really bad idea to use string concatenation for SQL queries.

dimonchik8 years ago

Yes, I know.
In this case, I'm just testing a work request.
Thank you! :-)

dimonchik8 years ago

C# code getDistance:


...........
String getDistance(String device_id, String date_starts, String date_stop){  // Возвращает пройденное расстояние определенного автомобиля в км или м за промежуток времени / Returns the distance traveled a specific vehicle in kilometers or meters in a time interval 
            if(date_starts != "" && date_stop != ""){
                
                _db = DBInstance.Instance;
                const String query = "SELECT * FROM <code>positions</code> WHERE <code>device_id</code> = @Device_id AND <code>time</code> >= @Date_starts AND <code>time</code> <= @Date_stop AND speed > 0 ORDER BY <code>time</code> ASC";
                _db.Open();
                MySqlCommand command = new MySqlCommand();
                command.Connection = _db;
                command.CommandText = query;
                command.Prepare();
                command.Parameters.AddWithValue("@Device_id", device_id);
                command.Parameters.AddWithValue("@Date_starts", date_starts);
                command.Parameters.AddWithValue("@Date_stop", date_stop);
                
                MySqlDataReader reader = command.ExecuteReader();
                    int i = 0;
                    double maxDistance = 0;
                    double distance = 0;
                    float lat1 = 0, lon1 = 0, lat2, lon2;
                    while(reader.Read()){
                        
                        if(i == 0){
                            lat1 = float.Parse(reader.GetString(4));
                            lon1 = float.Parse(reader.GetString(5));
                            
                        }
                        
                        if(i >= 1){
                            lat2 = float.Parse(reader.GetString(4));
                            lon2 = float.Parse(reader.GetString(5));
                            
                            
                            distance = CalcDistance.getDistance(lat1, lon1, lat2, lon2);
                            /*if( distance > 180 ) {
                                distance = 0;
                            }else{*/
                                maxDistance += distance;
                            //}
                            
                            lat1 = lat2;
                            lon1 = lon2;	
                        }
                        
                        i++;
                    }
                    
                    if(maxDistance > 1000){
                        MessageBox.Show((Math.Round(maxDistance / 1000, 1) + " Km"));
                    }else{
                        MessageBox.Show((Math.Round(maxDistance, 3)+" m"));
                    }
                    
                _db.Close();
                return maxDistance.ToString();
                
            }else{
                return "ERROR. NOT ";
            }
        }
......

public class CalcDistance
    {
.......		
        const double EARTH_RADIUS = 6378.137;
        
        public static double getDistance(float lat1, float lng1, float lat2, float lng2) {
            double radLat1 = lat1 * Math.PI / 180.0;
            double radLat2 = lat2 * Math.PI / 180.0;
            double a = radLat1 - radLat2;
            double b = (lng1 * Math.PI / 180.0) - (lng2 * Math.PI / 180.0);
            double s = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / 2), 2) + Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin(b / 2), 2)));
            s = s * EARTH_RADIUS; // EARTH_RADIUS;
            s = Math.Round(s * 1000,3); 
            return s;
        }		
    }
...........
Anton Tananaev8 years ago

Just try to calculate distance manually and compare with your result.