Created
December 5, 2011 10:45
-
-
Save OmarIthawi/1433194 to your computer and use it in GitHub Desktop.
Haversine Java Implementation in Solr, vs PHP implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[ | |
{ | |
"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 | |
} | |
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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"; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[{ | |
"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 | |
}] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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