Raw File
Geo.cc
/*
  This file is part of the FRED system.

  Copyright (c) 2010-2015, University of Pittsburgh, John Grefenstette,
  Shawn Brown, Roni Rosenfield, Alona Fyshe, David Galloway, Nathan
  Stone, Jay DePasse, Anuroop Sriram, and Donald Burke.

  Licensed under the BSD 3-Clause license.  See the file "LICENSE" for
  more information.
*/

//
//
// File: Geo.cc
//

#include "Geo.h"

const double Geo::DEG_TO_RAD = 0.017453292519943295769236907684886; // PI/180

// see http://andrew.hedges.name/experiments/haversine/
const double Geo::EARTH_RADIUS = 6373.0; // earth's radius in kilometers
const double Geo::KM_PER_DEG_LAT = 111.325; // assuming spherical earth

// US Mean latitude-longitude (http://www.travelmath.com/country/United+States)
const double MEAN_US_LON = -97.0; // near Wichita, KS
const double MEAN_US_LAT = 38.0; // near Wichita, KS

// from http://www.ariesmar.com/degree-latitude.php
const double Geo::MEAN_US_KM_PER_DEG_LON = 87.832; // at 38 deg N
const double Geo::MEAN_US_KM_PER_DEG_LAT = 110.996; // 

double Geo::km_per_deg_longitude = Geo::MEAN_US_KM_PER_DEG_LON;
double Geo::km_per_deg_latitude = Geo::MEAN_US_KM_PER_DEG_LAT;

void Geo::set_km_per_degree(fred::geo lat) {
  lat *= Geo::DEG_TO_RAD;
  double cosine = cos(lat);
  Geo::km_per_deg_longitude = cosine * Geo::KM_PER_DEG_LAT;
  Geo::km_per_deg_latitude = Geo::KM_PER_DEG_LAT;
  // printf("lat %.8f cosine %.8f km_per_deg_lat %.8f\n", lat, cosine, Geo::km_per_deg_longitude);
}

double Geo::haversine_distance (fred::geo lon1, fred::geo lat1, fred::geo lon2, fred::geo lat2) {
  // convert to radians
  lat1 *= DEG_TO_RAD;
  lon1 *= DEG_TO_RAD;
  lat2 *= DEG_TO_RAD;
  lon2 *= DEG_TO_RAD;
  fred::geo latH = sin(0.5 * (lat2 - lat1));
  latH *= latH;
  fred::geo lonH = sin(0.5 * (lon2 - lon1));
  lonH *= lonH;
  double a = latH + cos(lat1) * cos(lat2) * lonH;
  double c = 2 * atan2( sqrt(a), sqrt(1 - a));
  double dist = EARTH_RADIUS * c;
  return dist;
}

double Geo::spherical_cosine_distance (fred::geo lon1, fred::geo lat1, fred::geo lon2, fred::geo lat2) {
  // convert to radians
  lat1 *= DEG_TO_RAD;
  lon1 *= DEG_TO_RAD;
  lat2 *= DEG_TO_RAD;
  lon2 *= DEG_TO_RAD;
  return acos(sin(lat1)*sin(lat2)+cos(lat1)*cos(lat2)*cos(lon2-lon1))*EARTH_RADIUS;
}

double Geo::spherical_projection_distance (fred::geo lon1, fred::geo lat1, fred::geo lon2, fred::geo lat2) {
  // convert to radians
  lat1 *= DEG_TO_RAD;
  lon1 *= DEG_TO_RAD;
  lat2 *= DEG_TO_RAD;
  lon2 *= DEG_TO_RAD;
  double dlat = (lat2-lat1);
  dlat *= dlat;
  double dlon = (lon2-lon1);
  double tmp = cos(0.5*(lat1+lat2))*dlon;
  tmp *= tmp;
  return EARTH_RADIUS*sqrt(dlat+tmp);
}

/*

  int main () {
  fred::geo lon1 = -79;
  fred::geo lat1 = 40;
  int N = 0;
  for (fred::geo lon = -80.0; lon <= -79.0; lon += 0.01) {
  for (fred::geo lat = 40; lat < 40.1; lat += 0.01 ) {
  double d1 = haversine_distance(lon1,lat1,lon,lat);
  double d2 = spherical_cosine_distance(lon1,lat1,lon,lat);
  double d3 = spherical_projection_distance(lon1,lat1,lon,lat);
  N++;
  printf("%6.3f %5.2f %8.3f %8.3f %f\n", lon, lat, d1, d3, d1-d3);
  }
  }
  printf("N = %d\n", N);
  }

*/

back to top