You are here

function ip_geoloc_center_of_locations in IP Geolocation Views & Maps 7

Same name and namespace in other branches
  1. 8 ip_geoloc_api.inc \ip_geoloc_center_of_locations()

Calculate the center of the supplied locations using one of two algorithms.

The first algorithm returns the center of the rectangle whose horizontal sides pass through the top and bottom locations in the set, while its vertical sides pass through the left-most and right-most locations.

The second algorithm returns the center of gravity of all supplied locations. The second algorithn is therefore sensitive to location clusters. This may be what you want, or it may be what you want to avoid.

Parameters

array $locations: array of location objects each with latitude and longitude

bool $center_of_gravity: if TRUE use the center of gravity algorithm

Return value

array containing latitude and longitude of the center

3 calls to ip_geoloc_center_of_locations()
ip_geoloc_plugin_style_leaflet::render in views/ip_geoloc_plugin_style_leaflet.inc
Transform the View result in a list of marker locations and render on map.
ip_geoloc_plugin_style_map::render in views/ip_geoloc_plugin_style_map.inc
Transform the View result in a list of markers and render these on a map.
ip_geoloc_plugin_style_openlayers::render in views/ip_geoloc_plugin_style_openlayers.inc
Transform the View result in a list of markers and render these on a map.

File

./ip_geoloc_api.inc, line 592
API functions of IP geolocation module

Code

function ip_geoloc_center_of_locations($locations, $center_of_gravity = FALSE) {
  if (empty($locations)) {
    return array(
      NULL,
      NULL,
    );
  }
  if ($center_of_gravity) {

    // Because longitude turns back on itself, cannot simply average coords.
    $count = 0;
    $x = $y = $z = 0.0;
    foreach ($locations as $location) {
      if (isset($location->lon)) {
        $lng = $location->lon;
        $lat = $location->lat;
      }
      elseif (isset($location->longitude)) {
        $lng = $location->longitude;
        $lat = $location->latitude;
      }
      else {
        continue;
      }
      $lng = deg2rad($lng);
      $lat = deg2rad($lat);

      // Convert to Cartesian coords and total the 3 dimensions independently.
      $x += cos($lat) * cos($lng);
      $y += cos($lat) * sin($lng);
      $z += sin($lat);
      $count++;
    }
    $x /= $count;
    $y /= $count;
    $z /= $count;
    $center_lat = atan2($z, sqrt($x * $x + $y * $y));
    $center_lng = atan2($y, $x);
    return array(
      rad2deg($center_lat),
      rad2deg($center_lng),
    );
  }

  // Alternative method based on top & bottom lat and left & right lon.
  $top = $bottom = $left = $right = NULL;
  foreach ($locations as $location) {
    if (isset($location->lon)) {
      $lng = $location->lon;
      $lat = $location->lat;
    }
    elseif (isset($location->longitude)) {
      $lng = $location->longitude;
      $lat = $location->latitude;
    }
    else {
      continue;
    }
    if (!isset($top) || $lat > $top) {
      $top = $lat;
    }
    if (!isset($bottom) || $lat < $bottom) {
      $bottom = $lat;
    }
    if (!isset($left) || $lng < $left) {
      $left = $lng;
    }
    if (!isset($right) || $lng > $right) {
      $right = $lng;
    }
  }
  if (!isset($top) || !isset($left)) {
    return array(
      NULL,
      NULL,
    );
  }
  $center_lat = 0.5 * ($top + $bottom);
  $center_lng = 0.5 * ($left + $right);
  if ($right - $left > 180) {

    // If the angle between right and left is greater than 180, then averaging
    // is still ok, provided we flip over to the opposite end of the world.
    $center_lng = $center_lng > 0.0 ? $center_lng - 180.0 : $center_lng + 180.0;
  }
  return array(
    $center_lat,
    $center_lng,
  );
}