Exemplo n.º 1
0
static bool
WaypointInTerrainRange(WAYPOINT *List, RasterTerrain &terrain)
{
  if (WaypointOutOfTerrainRangeDontAskAgain == 1){
    return(true);
  }

  if (!terrain.isTerrainLoaded()) {
    return(true);
  }

  if (terrain.WaypointIsInTerrainRange(List->Location)) {
    return true;
  } else {
    if (WaypointOutOfTerrainRangeDontAskAgain == 0){

      TCHAR sTmp[250];
      int res;

      _stprintf(sTmp, gettext(TEXT("Waypoint #%d \"%s\" \r\nout of Terrain bounds\r\n\r\nLoad anyway?")),
                List->Number, List->Name);

      res = dlgWaypointOutOfTerrain(sTmp);

      switch(res){
      case wpTerrainBoundsYes:
        return true;
      case wpTerrainBoundsNo:
        return false;
      case wpTerrainBoundsYesAll:
        WaypointOutOfTerrainRangeDontAskAgain = 1;
        WaypointsOutOfRange = 1;
        SetToRegistry(szRegistryWaypointsOutOfRange,
                      WaypointsOutOfRange);
	Profile::StoreRegistry();
        return true;
      case mrCancel:
      case wpTerrainBoundsNoAll:
        WaypointOutOfTerrainRangeDontAskAgain = 2;
        WaypointsOutOfRange = 2;
        SetToRegistry(szRegistryWaypointsOutOfRange,
                      WaypointsOutOfRange);
	Profile::StoreRegistry();
        return false;
      }

    } else {
      if (WaypointOutOfTerrainRangeDontAskAgain == 2)
        return(false);
      if (WaypointOutOfTerrainRangeDontAskAgain == 1)
        return(true);
    }
    return false;
  }
}
Exemplo n.º 2
0
void
AirspaceDatabase::UpdateAGL(const RasterTerrain &terrain)
{
  const RasterMap *map = terrain.GetMap();
  if (map == NULL)
    /* XXX: complain */
    return;

  // want most accurate rounding here
  const RasterRounding rounding(*map, 0, 0);

  for (unsigned i = 0; i < NumberOfAirspaceAreas; i++) {
    AIRSPACE_AREA &area = AirspaceArea[i];
    GEOPOINT center;

    center.Latitude = (area.maxBound.Latitude + area.minBound.Latitude) / 2;
    center.Longitude = (area.maxBound.Longitude + area.minBound.Longitude) / 2;

    ::UpdateAGL(AirspaceArea[i], center, terrain, rounding);
  }

  for (unsigned i = 0; i < NumberOfAirspaceCircles; i++) {
    AIRSPACE_CIRCLE &circle = AirspaceCircle[i];
    ::UpdateAGL(circle, circle.Location, terrain, rounding);
  }
}
Exemplo n.º 3
0
static void
GenerateBlackboard(MapWindow &map)
{
  NMEA_INFO nmea_info;
  DERIVED_INFO derived_info;
  SETTINGS_COMPUTER settings_computer;

  memset(&nmea_info, 0, sizeof(nmea_info));
  nmea_info.Connected = 2;
  nmea_info.SatellitesUsed = 4;
  nmea_info.Location.Latitude = 51.2;
  nmea_info.Location.Longitude = 7.7;
  nmea_info.TrackBearing = 90;
  nmea_info.Speed = 50;
  nmea_info.Altitude = 1500;

  memset(&derived_info, 0, sizeof(derived_info));
  derived_info.TerrainValid = true;

  memset(&settings_computer, 0, sizeof(settings_computer));

  terrain.ServiceFullReload(nmea_info.Location);

  for (unsigned i = 0; i <AIRSPACECLASSCOUNT; ++i)
    settings_computer.iAirspaceMode[i] = 3;

  map.ReadBlackboard(nmea_info, derived_info, settings_computer,
                     blackboard.SettingsMap());
  map.UpdateProjection();
}
Exemplo n.º 4
0
static void
LoadFiles()
{
  topology = new TopologyStore(NULL);
  topology->Open();

  terrain.OpenTerrain();

  ReadWayPoints(way_points, &terrain);

  TCHAR tpath[MAX_PATH];
  GetRegistryString(szRegistryAirspaceFile, tpath, MAX_PATH);
  if (tpath[0] != 0) {
    ExpandLocalPath(tpath);

    char path[MAX_PATH];
    unicode2ascii(tpath, path, sizeof(path));

    if (!ReadAirspace(airspace_database, path))
      StartupStore(TEXT("No airspace file 1\n"));
  }

  FindAirspaceAreaBounds(airspace_database);
  FindAirspaceCircleBounds(airspace_database);
}
Exemplo n.º 5
0
void
WaypointAltitudeFromTerrain(WAYPOINT* Temp, RasterTerrain &terrain)
{
  double myalt = -1;
  if (terrain.GetMap()) {
    RasterRounding rounding(*terrain.GetMap(),0,0);

    myalt =
      terrain.GetTerrainHeight(Temp->Location, rounding);
  }

  if (myalt>0) {
    Temp->Altitude = myalt;
  } else {
    // error, can't find altitude for waypoint!
  }
}
Exemplo n.º 6
0
RasterTerrain *
RasterTerrain::OpenTerrain(FileCache *cache, OperationEnvironment &operation)
try {
  const auto path = Profile::GetPath(ProfileKeys::MapFile);
  if (path.IsNull())
    return nullptr;

  RasterTerrain *rt = new RasterTerrain(ZipArchive(path));
  if (!rt->Load(path, cache, operation)) {
    delete rt;
    return nullptr;
  }

  return rt;
} catch (const std::runtime_error &e) {
  operation.SetErrorMessage(UTF8ToWideConverter(e.what()));
  return nullptr;
}
Exemplo n.º 7
0
void 
Airspaces::SetGroundLevels(const RasterTerrain &terrain)
{
  for (auto v = airspace_tree.begin(); v != airspace_tree.end(); ++v) {
    FlatGeoPoint c_flat = v->GetCenter();
    GeoPoint g = task_projection.unproject(c_flat);
    short h = terrain.GetTerrainHeight(g);
    if (!RasterBuffer::IsSpecial(h))
      v->set_ground_level((fixed)h);
  }
}
Exemplo n.º 8
0
void 
Airspaces::SetGroundLevels(const RasterTerrain &terrain)
{
  for (auto &v : airspace_tree) {
    // If we don't need the ground level we don't have to calculate it
    if (!v.NeedGroundLevel())
      continue;

    FlatGeoPoint c_flat = v.GetCenter();
    GeoPoint g = task_projection.Unproject(c_flat);
    short h = terrain.GetTerrainHeight(g);
    if (!RasterBuffer::IsSpecial(h))
      v.SetGroundLevel((fixed)h);
  }
}
Exemplo n.º 9
0
static void
UpdateAGL(AIRSPACE_ALT &altitude, const GEOPOINT &location,
          const RasterTerrain &terrain, const RasterRounding &rounding)
{
  if (altitude.Base != abAGL)
    return;

  double terrain_height = terrain.GetTerrainHeight(location, rounding);

  if (altitude.AGL>=0) {
    altitude.Altitude = altitude.AGL + terrain_height;
  } else {
    // surface, set to zero
    altitude.AGL = 0;
    altitude.Altitude = 0;
  }
}
Exemplo n.º 10
0
void XCSoarInterface::Shutdown(void) {
  CreateProgressDialog(gettext(TEXT("Shutdown, please wait...")));
  StartHourglassCursor();

  StartupStore(TEXT("Entering shutdown...\n"));
  StartupLogFreeRamAndStorage();

  // turn off all displays
  globalRunningEvent.reset();

  StartupStore(TEXT("dlgAirspaceWarningDeInit\n"));
  dlgAirspaceWarningDeInit();

  CreateProgressDialog(gettext(TEXT("Shutdown, saving logs...")));
  // stop logger
  logger.guiStopLogger(Basic(),true);

  CreateProgressDialog(gettext(TEXT("Shutdown, saving profile...")));
  // Save settings
  Profile::StoreRegistry();

  // Stop sound

  StartupStore(TEXT("SaveSoundSettings\n"));
  Profile::SaveSoundSettings();

#ifndef DISABLEAUDIOVARIO
  //  VarioSound_EnableSound(false);
  //  VarioSound_Close();
#endif

  // Stop drawing
  CreateProgressDialog(gettext(TEXT("Shutdown, please wait...")));

  StartupStore(TEXT("CloseDrawingThread\n"));
  closeTriggerEvent.trigger();

  calculation_thread->join();
  StartupStore(TEXT("- calculation thread returned\n"));

  instrument_thread->join();
  StartupStore(TEXT("- instrument thread returned\n"));

  draw_thread->join();
  StartupStore(TEXT("- draw thread returned\n"));

  delete draw_thread;

  // Clear data

  CreateProgressDialog(gettext(TEXT("Shutdown, saving task...")));
  StartupStore(TEXT("Resume abort task\n"));
  task.ResumeAbortTask(SettingsComputer(), -1); // turn off abort if it was on.
  StartupStore(TEXT("Save default task\n"));
  task.SaveDefaultTask();
  StartupStore(TEXT("Clear task data\n"));
  task.ClearTask();
  StartupStore(TEXT("Close airspace\n"));
  CloseAirspace();

  StartupStore(TEXT("Close waypoints\n"));
  way_points.clear();

  CreateProgressDialog(gettext(TEXT("Shutdown, please wait...")));

  StartupStore(TEXT("CloseTerrainTopology\n"));

  RASP.Close();
  terrain.CloseTerrain();

  delete topology;
  delete marks;

  devShutdown();

  SaveCalculationsPersist(Basic(),Calculated());
#if (EXPERIMENTAL > 0)
  //  CalibrationSave();
#endif

  #if defined(GNAV) && !defined(PCGNAV)
    StartupStore(TEXT("Altair shutdown\n"));
    Sleep(2500);
    StopHourglassCursor();
    InputEvents::eventDLLExecute(TEXT("altairplatform.dll SetShutdown 1"));
    while(1) {
      Sleep(100); // free time up for processor to perform shutdown
    }
  #endif

  CloseFLARMDetails();

  // Kill windows

  StartupStore(TEXT("Destroy Info Boxes\n"));
  InfoBoxManager::Destroy();

  StartupStore(TEXT("Destroy Button Labels\n"));
  ButtonLabel::Destroy();

  StartupStore(TEXT("Delete Objects\n"));

  // Kill graphics objects

  DeleteFonts();

  DeleteAirspace();

  StartupStore(TEXT("Close Progress Dialog\n"));

  CloseProgressDialog();

  CloseGeoid();

  StartupStore(TEXT("Close Windows - main \n"));
  main_window.reset();
  StartupStore(TEXT("Close Graphics\n"));
  MapGfx.Destroy();

#ifdef DEBUG_TRANSLATIONS
  StartupStore(TEXT("Writing missing translations\n"));
  WriteMissingTranslations();
#endif

  StartupLogFreeRamAndStorage();
  StartupStore(TEXT("Finished shutdown\n"));
  StopHourglassCursor();

}
Exemplo n.º 11
0
/**
 * "Boots" up XCSoar
 * @param hInstance Instance handle
 * @param lpCmdLine Command line string
 * @return True if bootup successful, False otherwise
 */
bool XCSoarInterface::Startup(HINSTANCE hInstance, LPTSTR lpCmdLine)
{
  // The title bar text
  TCHAR szTitle[MAX_LOADSTRING];

  // Store instance handle in our global variable
  hInst = hInstance;

  // IDS_APP_TITLE = XCSoar (see XCSoar.rc)
  LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);

  //If it is already running, then focus on the window
  if (MainWindow::find(szTitle))
    return false;

  // Send the SettingsMap to the DeviceBlackboard
  SendSettingsMap();

  // Register window classes
  PaintWindow::register_class(hInst);
  MainWindow::register_class(hInst);
  MapWindow::register_class(hInst);

  // Fill the fast(co)sine table
  InitSineTable();

  PreloadInitialisation(true);

  // Send the SettingsMap to the DeviceBlackboard
  SendSettingsMap();

  // Creates the main window
  StartupStore(TEXT("Create main window\n"));
  RECT WindowSize = SystemWindowSize();
  main_window.set(szTitle,
		  WindowSize.left, WindowSize.top,
		  WindowSize.right, WindowSize.bottom);

  if (!main_window.defined()) {
    return false;
  }
  main_window.install_timer();

  // Initialize DeviceBlackboard
  device_blackboard.Initialise();

  // Initialize Marks
  marks = new Marks("xcsoar-marks");
  topology = new TopologyStore(marks->GetTopology());

  // Show the main and map windows
  StartupStore(TEXT("Create map window\n"));
  main_window.show();
  main_window.map.show();

#ifdef HAVE_ACTIVATE_INFO
  SHSetAppKeyWndAssoc(VK_APP1, main_window);
  SHSetAppKeyWndAssoc(VK_APP2, main_window);
  SHSetAppKeyWndAssoc(VK_APP3, main_window);
  SHSetAppKeyWndAssoc(VK_APP4, main_window);
  // Typical Record Button
  //	Why you can't always get this to work
  //	http://forums.devbuzz.com/m_1185/mpage_1/key_/tm.htm
  //	To do with the fact it is a global hotkey, but you can with code above
  //	Also APPA is record key on some systems
  SHSetAppKeyWndAssoc(VK_APP5, main_window);
  SHSetAppKeyWndAssoc(VK_APP6, main_window);
#endif

  // Initialize main blackboard data
  task.ClearTask();
  glide_computer.Initialise();
  logger.LinkGRecordDLL(); // try to link DLL if it exists

  // Load the EGM96 geoid data
  OpenGeoid();

  PreloadInitialisation(false);

  Profile::LoadWindFromRegistry();

  // TODO TB: seems to be out of date?!
  CalculateNewPolarCoef();

  // Calculate polar-related data and saves it to the cache
  StartupStore(TEXT("GlidePolar::UpdatePolar\n"));
  GlidePolar::UpdatePolar(false, SettingsComputer());

  // Show startup info depending on device
  StartupInfo();

  // Read the topology file(s)
  topology->Open();

  // Read the terrain file
  terrain.OpenTerrain();

  // Read the waypoint files
  ReadWayPoints(way_points, terrain);

  // Read and parse the airfield info file
  ReadAirfieldFile();

  // Set the home waypoint
  SetHome(way_points, terrain, SetSettingsComputer(), false, true);

  // ReSynchronise the blackboards here since SetHome touches them
  ReadBlackboardBasic(device_blackboard.Basic());

  terrain.ServiceFullReload(Basic().Location);

  // Scan for weather forecast
  CreateProgressDialog(gettext(TEXT("Scanning weather forecast")));
  StartupStore(TEXT("RASP load\n"));
  RASP.ScanAll(Basic().Location);

  // Reads the airspace files
  ReadAirspace();
  // Sorts the airspaces by priority
  SortAirspace();

  // Read the FLARM details file
  OpenFLARMDetails();

#ifndef DISABLEAUDIOVARIO
  /*
  VarioSound_Init();
  VarioSound_EnableSound(EnableSoundVario);
  VarioSound_SetVdead(SoundDeadband);
  VarioSound_SetV(0);
  VarioSound_SetSoundVolume(SoundVolume);
  */
#endif

  // Start the device thread(s)
  CreateProgressDialog(gettext(TEXT("Starting devices")));
  devStartup(lpCmdLine);

  // Reset polar in case devices need the data
  StartupStore(TEXT("GlidePolar::UpdatePolar\n"));
  GlidePolar::UpdatePolar(true, SettingsComputer());

  CreateProgressDialog(gettext(TEXT("Initialising display")));

  // Finally ready to go.. all structures must be present before this.

  // Create the drawing thread
  StartupStore(TEXT("CreateDrawingThread\n"));
  draw_thread = new DrawThread(main_window.map, main_window.flarm);
  draw_thread->start();

  // Show the infoboxes
  StartupStore(TEXT("ShowInfoBoxes\n"));
  InfoBoxManager::Show();

  // Create the calculation thread
  StartupStore(TEXT("CreateCalculationThread\n"));
  CreateCalculationThread();

#ifdef NEWTASK  
  { // NEWTASK
    PeriodClock t;
    t.reset(); t.update();
    CreateProgressDialog(gettext(TEXT("Running test 0")));
    test_newtask(0);
    StartupStore(TEXT("test 0 %d\n"),t.elapsed());

    /*
    t.update();
    CreateProgressDialog(gettext(TEXT("Running test 1")));
    test_newtask(1);
    StartupStore(TEXT("test 1 %d\n"),t.elapsed());

    t.update();
    CreateProgressDialog(gettext(TEXT("Running test 2")));
    test_newtask(2);
    StartupStore(TEXT("test 2 %d\n"),t.elapsed());

    t.update();
    CreateProgressDialog(gettext(TEXT("Running test 3")));
    test_newtask(3);
    StartupStore(TEXT("test 3 %d\n"),t.elapsed());

    t.update();
    CreateProgressDialog(gettext(TEXT("Running test 4")));
    test_newtask(4);
    StartupStore(TEXT("test 4 %d\n"),t.elapsed());
    */
    CreateProgressDialog(gettext(TEXT("test complete")));
  }
#endif

  // Initialise the airspace warning dialog
  StartupStore(TEXT("dlgAirspaceWarningInit\n"));
  dlgAirspaceWarningInit();

  // Find unique ID of this PDA
  ReadAssetNumber();

  StartupStore(TEXT("ProgramStarted\n"));

  // Give focus to the map
  main_window.map.set_focus();

  // Start calculation thread
  calculation_thread->start();

  // Start instrument thread
  instrument_thread->start();

  globalRunningEvent.trigger();

  return true;
}
Exemplo n.º 12
0
void
SetHome(const WayPointList &way_points, RasterTerrain &terrain,
        SETTINGS_COMPUTER &settings,
        const bool reset, const bool set_location)
{
  StartupStore(TEXT("SetHome\n"));

  // check invalid home waypoint or forced reset due to file change
  // VENTA3
  if (reset || !way_points.verify_index(0) ||
      !way_points.verify_index(settings.HomeWaypoint)) {
    settings.HomeWaypoint = -1;
  }
  // VENTA3 -- reset Alternates
  if (reset
      || !way_points.verify_index(settings.Alternate1)
      || !way_points.verify_index(settings.Alternate2)) {
    settings.Alternate1= -1;
    settings.Alternate2= -1;
  }
  // check invalid task ref waypoint or forced reset due to file change
  if (reset || !way_points.verify_index(settings.TeamCodeRefWaypoint)) {
    settings.TeamCodeRefWaypoint = -1;
  }

  if (!way_points.verify_index(settings.HomeWaypoint)) {
    // search for home in waypoint list, if we don't have a home
    settings.HomeWaypoint = -1;
    for (unsigned i = 0; way_points.verify_index(i); ++i)
      {
        if ((way_points.get(i).Flags & HOME) == HOME)
          {
            if (settings.HomeWaypoint== -1) {
              settings.HomeWaypoint = i;
	      break; // only search for one
            }
          }
      }
  }
  // set team code reference waypoint if we don't have one
  if (settings.TeamCodeRefWaypoint== -1) {
    settings.TeamCodeRefWaypoint =
      settings.HomeWaypoint;
  }

  if (set_location) {
    if (way_points.verify_index(settings.HomeWaypoint)) {
      // OK, passed all checks now
      StartupStore(TEXT("Start at home waypoint\n"));
      const WAYPOINT &home = way_points.get(settings.HomeWaypoint);
      device_blackboard.SetStartupLocation(home.Location, home.Altitude);
    } else {

      // no home at all, so set it from center of terrain if available
      GEOPOINT loc;
      if (terrain.GetTerrainCenter(&loc)) {
	StartupStore(TEXT("Start at terrain center\n"));
	device_blackboard.SetStartupLocation(loc, 0);
      }
    }
  }

  //
  // Save the home waypoint number in the resgistry
  //
  // VENTA3> this is probably useless, since HomeWayPoint &c were currently
  //         just loaded from registry.
  SetToRegistry(szRegistryHomeWaypoint,settings.HomeWaypoint);
  SetToRegistry(szRegistryAlternate1,settings.Alternate1);
  SetToRegistry(szRegistryAlternate2,settings.Alternate2);
  SetToRegistry(szRegistryTeamcodeRefWaypoint,settings.TeamCodeRefWaypoint);
}
Exemplo n.º 13
0
double
FinalGlideThroughTerrain(const double this_bearing,
                         const NMEA_INFO &basic,
                         const DERIVED_INFO &calculated,
                         const SETTINGS_COMPUTER &settings,
                         const RasterTerrain &terrain,
                         GEOPOINT *retloc,
                         const double max_range,
                         bool *out_of_range,
                         double *TerrainBase)
{
  double mc = GlidePolar::GetMacCready();
  double irange = GlidePolar::MacCreadyAltitude(mc,
						1.0, this_bearing,
                                                calculated.WindSpeed,
                                                calculated.WindBearing,
						0, 0, true, 0);
  const GEOPOINT start_loc = basic.Location;
  if (retloc) {
    *retloc = start_loc;
  }
  *out_of_range = false;

  if (irange <= 0.0 || calculated.NavAltitude <= 0)
    // can't make progress in this direction at the current windspeed/mc
    return 0;

  const RasterMap *map = terrain.GetMap();
  if (map == NULL)
    return 0;

  const double glide_max_range = calculated.NavAltitude/irange;

  // returns distance one would arrive at altitude in straight glide
  // first estimate max range at this altitude
  GEOPOINT loc, last_loc;
  double h=0.0, dh=0.0;
  // int imax=0;
  double last_dh=0;
  double altitude;

  double retval = 0;
  int i=0;
  bool start_under = false;

  // calculate terrain rounding factor

  FindLatitudeLongitude(start_loc, 0,
                        glide_max_range/NUMFINALGLIDETERRAIN, &loc);

  double Xrounding = fabs(loc.Longitude-start_loc.Longitude)/2;
  double Yrounding = fabs(loc.Latitude-start_loc.Latitude)/2;
  const RasterRounding rounding(*map, Xrounding, Yrounding);

  loc = last_loc = start_loc;

  altitude = calculated.NavAltitude;
  h =  max(0, terrain.GetTerrainHeight(loc,rounding));
  dh = altitude - h - settings.SafetyAltitudeTerrain;
  last_dh = dh;
  if (dh<0) {
    start_under = true;
    // already below safety terrain height
    //    retval = 0;
    //    goto OnExit;
  }

  // find grid
  GEOPOINT dloc;

  FindLatitudeLongitude(loc, this_bearing, glide_max_range, &dloc);
  dloc.Latitude -= start_loc.Latitude;
  dloc.Longitude -= start_loc.Longitude;

  double f_scale = 1.0/NUMFINALGLIDETERRAIN;
  if ((max_range>0) && (max_range<glide_max_range)) {
    f_scale *= max_range/glide_max_range;
  }

  double delta_alt = -f_scale * calculated.NavAltitude;

  dloc.Latitude *= f_scale;
  dloc.Longitude *= f_scale;

  for (i=1; i<=NUMFINALGLIDETERRAIN; i++) {
    double f;
    bool solution_found = false;
    double fi = i*f_scale;
    // fraction of glide_max_range

    if ((max_range>0)&&(fi>=1.0)) {
      // early exit
      *out_of_range = true;
      return max_range;
    }

    if (start_under) {
      altitude += 2.0*delta_alt;
    } else {
      altitude += delta_alt;
    }

    // find lat, lon of point of interest

    loc.Latitude += dloc.Latitude;
    loc.Longitude += dloc.Longitude;

    // find height over terrain
    h =  max(0,terrain.GetTerrainHeight(loc, rounding));

    dh = altitude - h - settings.SafetyAltitudeTerrain;

    if (TerrainBase && (dh>0) && (h>0)) {
      *TerrainBase = min(*TerrainBase, h);
    }

    if (start_under) {
      if (dh>last_dh) {
        // better solution found, ok to continue...
        if (dh>0) {
          // we've now found a terrain point above safety altitude,
          // so consider rest of track to search for safety altitude
          start_under = false;
        }
      } else {
        f= 0.0;
        solution_found = true;
      }
    } else if (dh<=0) {
      if ((dh<last_dh) && (last_dh>0)) {
        f = max(0,min(1,(-last_dh)/(dh-last_dh)));
      } else {
        f = 0.0;
      }
      solution_found = true;
    }
    if (solution_found) {
      loc.Latitude = last_loc.Latitude*(1.0-f)+loc.Latitude*f;
      loc.Longitude = last_loc.Longitude*(1.0-f)+loc.Longitude*f;
      if (retloc) {
        *retloc = loc;
      }
      return Distance(start_loc, loc);
    }
    last_dh = dh;
    last_loc = loc;
  }

  *out_of_range = true;
  retval = glide_max_range;

  return retval;
}
Exemplo n.º 14
0
short
WayPointFile::AltitudeFromTerrain(GeoPoint &location,
                                  const RasterTerrain &terrain)
{
  return terrain.GetTerrainHeight(location);
}