# Measuring the distance between two coordinates in PHP

Viewed   199 times

Hi I have the need to calculate the distance between two points having the lat and long.

I would like to avoid any call to external API.

I tried to implement the Haversine Formula in PHP:

Here is the code:

``````class CoordDistance
{
public \$lat_a = 0;
public \$lon_a = 0;
public \$lat_b = 0;
public \$lon_b = 0;

public \$measure_unit = 'kilometers';

public \$measure_state = false;

public \$measure = 0;

public \$error = '';

public function DistAB()

{
\$delta_lat = \$this->lat_b - \$this->lat_a ;
\$delta_lon = \$this->lon_b - \$this->lon_a ;

\$alpha    = \$delta_lat/2;
\$beta     = \$delta_lon/2;
\$c        = asin(min(1, sqrt(\$a)));
\$distance = round(\$distance, 4);

\$this->measure = \$distance;

}
}
``````

Testing it with some given points which have public distances I don't get a reliable result.

I don't understand if there is an error in the original formula or in my implementation

4

Not long ago I wrote an example of the haversine formula, and published it on my website:

``````/**
* Calculates the great-circle distance between two points, with
* the Haversine formula.
* @param float \$latitudeFrom Latitude of start point in [deg decimal]
* @param float \$longitudeFrom Longitude of start point in [deg decimal]
* @param float \$latitudeTo Latitude of target point in [deg decimal]
* @param float \$longitudeTo Longitude of target point in [deg decimal]
* @return float Distance between points in [m] (same as earthRadius)
*/
function haversineGreatCircleDistance(
\$latitudeFrom, \$longitudeFrom, \$latitudeTo, \$longitudeTo, \$earthRadius = 6371000)
{
// convert from degrees to radians

\$latDelta = \$latTo - \$latFrom;
\$lonDelta = \$lonTo - \$lonFrom;

\$angle = 2 * asin(sqrt(pow(sin(\$latDelta / 2), 2) +
cos(\$latFrom) * cos(\$latTo) * pow(sin(\$lonDelta / 2), 2)));
}
``````

? Note that you get the distance back in the same unit as you pass in with the parameter `\$earthRadius`. The default value is 6371000 meters so the result will be in [m] too. To get the result in miles, you could e.g. pass 3959 miles as `\$earthRadius` and the result would be in [mi]. In my opinion it is a good habit to stick with the SI units, if there is no particular reason to do otherwise.

Edit:

As TreyA correctly pointed out, the Haversine formula has weaknesses with antipodal points because of rounding errors (though it is stable for small distances). To get around them, you could use the Vincenty formula instead.

``````/**
* Calculates the great-circle distance between two points, with
* the Vincenty formula.
* @param float \$latitudeFrom Latitude of start point in [deg decimal]
* @param float \$longitudeFrom Longitude of start point in [deg decimal]
* @param float \$latitudeTo Latitude of target point in [deg decimal]
* @param float \$longitudeTo Longitude of target point in [deg decimal]
* @return float Distance between points in [m] (same as earthRadius)
*/
public static function vincentyGreatCircleDistance(
\$latitudeFrom, \$longitudeFrom, \$latitudeTo, \$longitudeTo, \$earthRadius = 6371000)
{
// convert from degrees to radians

\$lonDelta = \$lonTo - \$lonFrom;
\$a = pow(cos(\$latTo) * sin(\$lonDelta), 2) +
pow(cos(\$latFrom) * sin(\$latTo) - sin(\$latFrom) * cos(\$latTo) * cos(\$lonDelta), 2);
\$b = sin(\$latFrom) * sin(\$latTo) + cos(\$latFrom) * cos(\$latTo) * cos(\$lonDelta);

\$angle = atan2(sqrt(\$a), \$b);
}
``````
Friday, November 25, 2022
5

The formula you used, seems to be the arccosine instead of the haversine formula. The haversine formula is indeed more appropriate to calculate the distance on a sphere, because it is less prone to rounding errors.

``````/**
* Calculates the great-circle distance between two points, with
* the Haversine formula.
* @param float \$latitudeFrom Latitude of start point in [deg decimal]
* @param float \$longitudeFrom Longitude of start point in [deg decimal]
* @param float \$latitudeTo Latitude of target point in [deg decimal]
* @param float \$longitudeTo Longitude of target point in [deg decimal]
* @return float Distance between points in [m] (same as earthRadius)
*/
function haversineGreatCircleDistance(
\$latitudeFrom, \$longitudeFrom, \$latitudeTo, \$longitudeTo, \$earthRadius = 6371000)
{
// convert from degrees to radians

\$latDelta = \$latTo - \$latFrom;
\$lonDelta = \$lonTo - \$lonFrom;

\$angle = 2 * asin(sqrt(pow(sin(\$latDelta / 2), 2) +
cos(\$latFrom) * cos(\$latTo) * pow(sin(\$lonDelta / 2), 2)));
}
``````

P.S. I couldn't find an error in your code, so is it just a typo that you wrote `\$lat= 41.9133741000 \$lat= 12.5203944000` ? Maybe you just calculated with \$lat=12.5203944000 and \$long=0 because you overwrote your \$lat variable.

Edit:

Tested the code and it returned a correct result:

``````\$center_lat = 41.8350;
\$center_lng = 12.470;
\$lat = 41.9133741000;
\$lng = 12.5203944000;

// test with your arccosine formula
print(\$distance); // prints 9.662174538188

// test with my haversine formula
\$distance = haversineGreatCircleDistance(\$center_lat, \$center_lng, \$lat, \$lng, 6371);
print(\$distance); // prints 9.6621745381693
``````
Thursday, October 20, 2022
1

Assuming the coordinate is a decimal number. You can use this equation.

``````function midpoint(lat1, long1, lat2, long2, per) {
return [lat1 + (lat2 - lat1) * per, long1 + (long2 - long1) * per];
}
``````

Return a new desired coordinate of [lat, long], based on the percentage (such as per=0.2 for 20%).

Sunday, August 14, 2022
2

i found the sample code in the following link to calculate the distance going through roads.

Tuesday, September 20, 2022
5

I know this is really late, but I'm posting my solution to this in case anybody needs it.

Firstly, i declared the URL (the one that calls google maps api)

``````#define DST_API @"http://maps.googleapis.com/maps/api/distancematrix/xml?origins=%@&destinations=%@&units=%@&sensor=false"
``````

Next I created a string containing this URL:

``````NSString *URL = [NSString stringWithFormat:DST_API, source, destination, units];
``````

Where source, destination are strings containing the start point and end point. units can be @"imperial" or @"metric". Now that i had the URL, i would get back an xml string. To parse this, i used TBXML. There is always a large debate about which XML Parser to use. I used TBXML as it was easy, and is the fastest.

``````TBXML *directionsParser = [[TBXML alloc] initWithURL:[NSURL URLWithString:URL]];

// Check if the Overall status is OK
TBXMLElement *root = directionsParser.rootXMLElement;
TBXMLElement *element = [TBXML childElementNamed:@"status" parentElement:root];
NSString *value = [TBXML textForElement:element];
if ([value caseInsensitiveCompare:@"OK"] != NSOrderedSame) {
[directionsParser release];
return result;
}
``````

Once checking the root status is OK, then obtain the result for the XPath expression: //row/element/distance/value

``````element = [TBXML childElementNamed:@"row" parentElement:root];
element = [TBXML childElementNamed:@"element" parentElement:element];
element = [TBXML childElementNamed:@"status" parentElement:element];
value = [TBXML textForElement:element];

// Check if the Element status is OK
if ([value caseInsensitiveCompare:@"OK"] != NSOrderedSame) {
[directionsParser release];
return result;
}

element = element->parentElement;

element = [TBXML childElementNamed:@"distance" parentElement:element];

//Note if you want the result as text, replace 'value' with 'text'
element = [TBXML childElementNamed:@"value" parentElement:element];

NSString *result = [TBXML textForElement:element];

[directionsParser release];
//Do what ever you want with result
``````

If anyone wants to have a URL to include way points, then here it is

``````#define DIR_API @"http://maps.googleapis.com/maps/api/directions/xml?origin=%@&destination=%@&waypoints=%@&units=%@&sensor=false"
``````

But to use way points, things work a bit differently as Jano pointed out.

Tuesday, December 27, 2022