CRM-13904 - Improve proximity query accuracy
authorDonald A. Lobo <lobo@civicrm.org>
Wed, 4 Dec 2013 14:29:55 +0000 (06:29 -0800)
committerDonald A. Lobo <lobo@civicrm.org>
Thu, 5 Dec 2013 05:50:14 +0000 (21:50 -0800)
http://issues.civicrm.org/jira/browse/CRM-13904

CRM/Contact/BAO/ProximityQuery.php

index 87b14ab59174c5dd415ca7b334f9e969fa4ef07b..8f1295ff1de222f7d2608ad5c3ec883e68db9e89 100644 (file)
@@ -116,24 +116,6 @@ class CRM_Contact_BAO_ProximityQuery {
     return deg2rad($angle) * self::earthRadius($latitude);
   }
 
-  /**
-   * Estimate the earth-surface distance between two locations.
-   */
-  static function earthDistance($longitudeSrc, $latitudeSrc,
-    $longitudeDst, $latitudeDst
-  ) {
-
-    $longSrc = deg2rad($longitudeSrc);
-    $latSrc  = deg2rad($latitudeSrc);
-    $longDst = deg2rad($longitudeDst);
-    $latDst  = deg2rad($latitudeDst);
-
-    $radius = self::earthRadius(($latitudeSrc + $latitudeDst) / 2);
-
-    $cosAngle = cos($latSrc) * cos($latDst) * (cos($longSrc) * cos($longDst) + sin($longSrc) * sin($longDst)) + sin($latSrc) * sin($latDst);
-    return acos($cosAngle) * $radius;
-  }
-
   /**
    * Estimate the min and max longitudes within $distance of a given location.
    */
@@ -198,55 +180,36 @@ class CRM_Contact_BAO_ProximityQuery {
     );
   }
 
-  /*
-     * Returns the SQL fragment needed to add a column called 'distance'
-     * to a query that includes the location table
-     *
-     * @param $longitude
-     * @param $latitude
-     */
-
-  static function earthDistanceSQL($longitude, $latitude) {
-    $long   = deg2rad($longitude);
-    $lat    = deg2rad($latitude);
-    $radius = self::earthRadius($latitude);
-
-    $cosLong = cos($long);
-    $cosLat  = cos($lat);
-    $sinLong = sin($long);
-    $sinLat  = sin($lat);
-
-    return "
-IFNULL( ACOS( $cosLat * COS( RADIANS( $latitude ) ) *
-              ( $cosLong * COS( RADIANS( $longitude ) ) +
-                $sinLong * SIN( RADIANS( $longitude ) ) ) +
-              $sinLat  * SIN( RADIANS( $latitude  ) ) ), 0.00000 ) * $radius
-";
-  }
-
   static function where($latitude, $longitude, $distance, $tablePrefix = 'civicrm_address') {
     self::initialize();
 
     $params = array();
     $clause = array();
 
-    list($minLongitude, $maxLongitude) = self::earthLongitudeRange($longitude,
-      $latitude,
-      $distance
-    );
-    list($minLatitude, $maxLatitude) = self::earthLatitudeRange($longitude,
-      $latitude,
-      $distance
-    );
-
-    $earthDistanceSQL = self::earthDistanceSQL($longitude, $latitude);
+    list($minLongitude, $maxLongitude) =
+      self::earthLongitudeRange($longitude,
+        $latitude,
+        $distance
+      );
+    list($minLatitude, $maxLatitude) =
+      self::earthLatitudeRange(
+        $longitude,
+        $latitude,
+        $distance
+      );
 
     $where = "
 {$tablePrefix}.geo_code_1  >= $minLatitude  AND
 {$tablePrefix}.geo_code_1  <= $maxLatitude  AND
 {$tablePrefix}.geo_code_2 >= $minLongitude AND
 {$tablePrefix}.geo_code_2 <= $maxLongitude AND
-$earthDistanceSQL  <= $distance
+ACOS(
+    COS(RADIANS({$tablePrefix}.geo_code_1)) *
+    COS(RADIANS($latitude)) *
+    COS(RADIANS({$tablePrefix}.geo_code_2) - RADIANS($longitude)) +
+    SIN(RADIANS({$tablePrefix}.geo_code_1)) *
+    SIN(RADIANS($latitude))
+  ) * 6378137  <= $distance
 ";
 
     return $where;