001/* 002 * Copyright 2006 Marc Wick, geonames.org 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 */ 017package org.geonames.utils; 018 019/** 020 * Distance calculations. 021 * 022 * @author marc@geonames 023 * 024 */ 025public class Distance { 026 027 /** 028 * mean radius = 6372.0 029 * 030 * The Earth's equatorial radius = 6335.437 km. 031 * 032 * The Earth's polar radius = 6399.592 km. 033 * 034 * 035 */ 036 public static final double EARTH_RADIUS_KM = 6372.0; 037 038 /** 039 * statute miles 040 */ 041 public static final double EARTH_RADIUS_MILES = 3963.0; 042 043 /** 044 * http://mathworld.wolfram.com/GreatCircle.html 045 * 046 * and 047 * 048 * http://www.mathforum.com/library/drmath/view/51711.html 049 * 050 * @return 051 */ 052 public static double distance(double lat1, double lng1, double lat2, 053 double lng2, char unit, int numberOfDigits) { 054 double a1 = Math.toRadians(lat1); 055 double b1 = Math.toRadians(lng1); 056 double a2 = Math.toRadians(lat2); 057 double b2 = Math.toRadians(lng2); 058 double d = Math.acos(Math.cos(a1) * Math.cos(b1) * Math.cos(a2) 059 * Math.cos(b2) + Math.cos(a1) * Math.sin(b1) * Math.cos(a2) 060 * Math.sin(b2) + Math.sin(a1) * Math.sin(a2)); 061 062 double dist = 0; 063 if (unit == 'M') { 064 dist = d * EARTH_RADIUS_MILES; 065 } else { 066 dist = d * EARTH_RADIUS_KM; 067 } 068 069 if (Double.isNaN(dist)) { 070 // use pytagoras for very small distances, 071 dist = Math.sqrt(Math.pow(Math.abs(lat1 - lat2), 2) 072 + Math.pow(Math.abs(lng1 - lng2), 2)); 073 // as rule of thumb multiply with 110km =1 degree 074 if (unit == 'M') { 075 dist *= 69; 076 } else { 077 dist *= 110; 078 } 079 } 080 081 if (numberOfDigits == 0) { 082 dist = (int) dist; 083 } else if (numberOfDigits > 0) { 084 double factor = Math.pow(10, numberOfDigits); 085 dist = Math.floor(dist * factor) / factor; 086 } 087 return dist; 088 } 089 090 public static double distanceKM(double lat1, double lng1, double lat2, 091 double lng2) { 092 return distance(lat1, lng1, lat2, lng2, 'K', 3); 093 } 094 095 public static double distanceMiles(double lat1, double lng1, double lat2, 096 double lng2) { 097 return distance(lat1, lng1, lat2, lng2, 'M', 3); 098 } 099}