Skip to content

Instantly share code, notes, and snippets.

@OmarIthawi
Created December 5, 2011 10:45
Show Gist options
  • Save OmarIthawi/1433194 to your computer and use it in GitHub Desktop.
Save OmarIthawi/1433194 to your computer and use it in GitHub Desktop.
Haversine Java Implementation in Solr, vs PHP implementation
Check this question: http://stackoverflow.com/q/8384415/161278
How to run:
Compile Java:
$ javac Distance.java
Run test:
$ php DistanceTest.php
The test will print good result, except that TheProblem.json is the data that Solr actually return and it's inconsistent.
Thanks alot!
[
{
"latitude": 31.9481,
"longitude": 35.9314
}, {
"latitude": 31.9494,
"longitude": 35.923
}, {
"latitude": 31.9491,
"longitude": 35.9298
}, {
"latitude": 31.9496,
"longitude": 35.9264
}, {
"latitude": 31.9495,
"longitude": 35.9308
}, {
"latitude": 31.9516,
"longitude": 35.9346
}, {
"latitude": 31.9532,
"longitude": 35.9135
}, {
"latitude": 31.9531,
"longitude": 35.9116
}, {
"latitude": 31.953,
"longitude": 35.91
}, {
"latitude": 31.9395,
"longitude": 35.8762
}, {
"latitude": 31.9573,
"longitude": 35.9101
}, {
"latitude": 31.9484,
"longitude": 35.8793
}, {
"latitude": 31.9494,
"longitude": 35.8726
}, {
"latitude": 31.9499,
"longitude": 35.8717
}, {
"latitude": 31.9694,
"longitude": 35.8995
}, {
"latitude": 31.9607,
"longitude": 35.8765
}, {
"latitude": 31.9565,
"longitude": 35.8677
}, {
"latitude": 31.9584,
"longitude": 35.8659
}, {
"latitude": 31.9753,
"longitude": 35.8628
}, {
"latitude": 31.98,
"longitude": 35.8368
}
]
import java.util.Scanner;
public class Distance {
private double latCenterRad;
private double lonCenterRad;
private double latCenterRad_cos;
public Distance(double latCenter, double lonCenter) {
this.latCenterRad = latCenter * DistanceUtils.DEGREES_TO_RADIANS;
this.lonCenterRad = lonCenter * DistanceUtils.DEGREES_TO_RADIANS;
latCenterRad_cos = Math.cos(latCenterRad);
}
public double calculate(double lat, double lon) {
double latRad = lat * DistanceUtils.DEGREES_TO_RADIANS;
double lonRad = lon * DistanceUtils.DEGREES_TO_RADIANS;
double diffX = latCenterRad - latRad;
double diffY = lonCenterRad - lonRad;
double hsinX = Math.sin(diffX * 0.5);
double hsinY = Math.sin(diffY * 0.5);
double h = hsinX * hsinX
+ (latCenterRad_cos * Math.cos(latRad) * hsinY * hsinY);
return (DistanceUtils.EARTH_MEAN_DIAMETER * Math.atan2(Math.sqrt(h), Math.sqrt(1 - h)));
}
public double calculate2(double lat, double lon) {
double latRad = lat * DistanceUtils.DEGREES_TO_RADIANS;
double lonRad = lon * DistanceUtils.DEGREES_TO_RADIANS;
double planetRadius = DistanceUtils.EARTH_MEAN_RADIUS_KM * DistanceUtils.KM_TO_MILES;
// haversine, specialized to avoid a cos() call on latCenterRad
double diffX = latCenterRad - latRad;
double diffY = lonCenterRad - lonRad;
double hsinX = Math.sin(diffX * 0.5);
double hsinY = Math.sin(diffY * 0.5);
double h = hsinX * hsinX
+ (latCenterRad_cos * Math.cos(latRad) * hsinY * hsinY);
double result = (planetRadius * 2 * Math.atan2(Math.sqrt(h), Math.sqrt(1 - h)));
// save the results of this calculation
// lastDistDoc = doc;
// lastDist = result;
return result;
}
public static void main(String[] args) {
Scanner s = new Scanner(join(args, " "));
Distance d = new Distance(s.nextDouble(), s.nextDouble());
System.out.println(d.calculate(s.nextDouble(), s.nextDouble()));
}
private static String join(String[] input, String delimiter) {
StringBuilder sb = new StringBuilder();
for (String value : input) {
sb.append(value);
sb.append(delimiter);
}
int length = sb.length();
if (length > 0) {
// Remove the extra delimiter
sb.setLength(length - delimiter.length());
}
return sb.toString();
}
}
class DistanceUtils {
public static final double DEGREES_TO_RADIANS = Math.PI / 180.0;
public static final double EARTH_MEAN_RADIUS_KM = 6371.009;
public static final double MILES_TO_KM = 1.609344;
public static final double KM_TO_MILES = 0.621371192;
public static final double EARTH_MEAN_DIAMETER = DistanceUtils.EARTH_MEAN_RADIUS_KM * 2 * KM_TO_MILES;
}
<?php
require_once '../include.php'; // Just for autoload Zend stuff, you can ignore this and load Zend_Json manually
$center = array(
'latitude' => 31.909310,
'longitude' => 35.921612
);
$data = Zend_Json::decode(file_get_contents('data.json'));
echo trim("
Comparing haversine distance algorithms, in PHP vs Java.
Center:
latitude={$center['latitude']}
longitude={$center['longitude']}
== Data =="), "\n";
echo join("\t", array(
'latitude',
'longitude',
"php", "\t",
"java", "\t",
)), "\n";
foreach ($data as $tip) {
$php = ZendX_Misc::distance($tip['latitude'], $tip['longitude'], $center['latitude'], $center['longitude'], 'M');
$java = +trim(`java Distance {$tip['latitude']} {$tip['longitude']} {$center['latitude']} {$center['longitude']}`);
echo join("\t\t", array(
$tip['latitude'],
$tip['longitude'],
$php,
$java,
)), "\n";
}
[{
"latitude": 31.94,
"longitude": 35.8847,
"haversinDistance": 83.2840804548,
"solrDistance": 83.2840804548
}, {
"latitude": 31.9803,
"longitude": 35.8376,
"haversinDistance": 83.8028698367,
"solrDistance": 83.8028698367
}, {
"latitude": 31.9951,
"longitude": 35.8135,
"haversinDistance": 83.8093195134,
"solrDistance": 83.8093195134
}, {
"latitude": 31.9494,
"longitude": 35.9183,
"haversinDistance": 85.0358851572,
"solrDistance": 85.0358851572
}, {
"latitude": 31.9493,
"longitude": 35.923,
"haversinDistance": 85.2070886462,
"solrDistance": 85.2070886462
}, {
"latitude": 31.9686,
"longitude": 35.8993,
"haversinDistance": 85.3604644706,
"solrDistance": 85.3604644706
}]
<?php
/**
* Class that contains miscellaneous functions
* All functions were removed except for distance()
*/
class ZendX_Misc {
public static function distance($latPoint, $lonPoint, $latCenter, $lonCenter, $units = 'M') {
// $EARTH_MEAN_RADIUS_KM = 6371.009;
$planetRadius = 6371.009; // KiloMeters
$latRad = deg2rad($latPoint);
$lonRad = deg2rad($lonPoint);
$latCenterRad = deg2rad($latCenter);
$lonCenterRad = deg2rad($lonCenter);
// haversine, specialized to avoid a cos() call on latCenterRad
$diffX = $latCenterRad - $latRad;
$diffY = $lonCenterRad - $lonRad;
$hsinX = sin($diffX * 0.5);
$hsinY = sin($diffY * 0.5);
$h = ($hsinX * $hsinX) + (cos($latCenterRad) * cos($latRad) * $hsinY * $hsinY);
$distanceKM = ($planetRadius * 2 * atan2(sqrt($h), sqrt(1 - $h)));
switch (strtoupper($units)) {
case 'M':
$planetRadius = $planetRadius * 0.621371192 /* 1 km = 0.621371192 mile */;
break;
}
switch (strtoupper($units)) {
case 'M':
return $distanceKM * 0.621371192 /* 1 km = 0.621371192 mile */;
break;
case 'N':
return $distanceKM / 1.852;
break;
default:
return $distanceKM;
break;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment