void
GlueMapWindow::DrawThermalBand(Canvas &canvas, const PixelRect &rc) const
{
  if (Calculated().task_stats.total.solution_remaining.IsOk() &&
      Calculated().task_stats.total.solution_remaining.altitude_difference > 50
      && GetDisplayMode() == DisplayMode::FINAL_GLIDE)
    return;

  PixelRect tb_rect;
  tb_rect.left = rc.left;
  tb_rect.right = rc.left+Layout::Scale(20);
  tb_rect.top = Layout::Scale(2);
  tb_rect.bottom = (rc.bottom-rc.top)/5 - Layout::Scale(2);

  const ThermalBandRenderer &renderer = thermal_band_renderer;
  if (task != nullptr) {
    ProtectedTaskManager::Lease task_manager(*task);
    renderer.DrawThermalBand(Basic(),
                             Calculated(),
                             GetComputerSettings(),
                             canvas,
                             tb_rect,
                             GetComputerSettings().task,
                             true,
                             &task_manager->GetOrderedTask().GetOrderedTaskSettings());
  } else {
    renderer.DrawThermalBand(Basic(),
                             Calculated(),
                             GetComputerSettings(),
                             canvas,
                             tb_rect,
                             GetComputerSettings().task,
                             true);
  }
}
Exemple #2
0
/**
 * Searches the FLARM_Traffic array for the TeamMate and updates TeamMate
 * position and TeamCode if found.
 */
void
GlideComputer::FLARM_ScanTraffic()
{
  // If (not FLARM available) cancel
  if (!Basic().flarm.FLARM_Available || !SettingsComputer().TeamFlarmTracking)
    return;

  if (SettingsComputer().TeamCodeRefWaypoint < 0)
    return;

  // Get bearing and distance to the reference waypoint
  const Waypoint *wp =
      way_points.lookup_id(SettingsComputer().TeamCodeRefWaypoint);

  if (!wp)
    return;

  const FLARM_TRAFFIC *traffic =
      Basic().flarm.FindTraffic(SettingsComputer().TeamFlarmIdTarget);

  if (!traffic)
    return;

  // Set Teammate location to FLARM contact location
  SetCalculated().TeammateLocation = traffic->Location;

  // Calculate distance and bearing from teammate to reference waypoint

  Angle bearing = wp->Location.bearing(traffic->Location);
  fixed distance = wp->Location.distance(traffic->Location);

  // Calculate TeamCode and save it in Calculated
  XCSoarInterface::SetSettingsComputer().TeammateCode.Update(bearing, distance);
  XCSoarInterface::SetSettingsComputer().TeammateCodeValid = true;
}
Exemple #3
0
/*
 * Do not disturb too much. Play alert sound only once every x minutes, not more.
 */
void GlideComputerTask::AlertBestAlternate(short soundmode) {
  static double LastAlertTime = 0;

  if (Basic().Time > LastAlertTime + 180.0) {
    if (SettingsComputer().EnableSoundModes) {
      LastAlertTime = Basic().Time;
      switch (soundmode) {
      case 0:
        break;
      case 1:
        PlayResource(TEXT("IDR_WAV_GREEN"));
        break;
      case 2:
        PlayResource(TEXT("IDR_WAV_RED"));
        break;
      case 11:
        PlayResource(TEXT("IDR_WAV_GREEN"));
        PlayResource(TEXT("IDR_WAV_GREEN"));
        break;
      default:
        break;
      }
    }
  }
}
Exemple #4
0
void
MapWindow::DrawTask(Canvas &canvas)
{
  if (task == NULL)
    return;

  ProtectedTaskManager::Lease task_manager(*task);
  const AbstractTask *task = task_manager->get_active_task();
  if (task == NULL || !task->check_task())
    return;

  /* RLD bearing is invalid if GPS not connected and in non-sim mode,
   but we can still draw targets */
  const bool draw_bearing = Basic().gps.Connected;

  RenderObservationZone ozv;
  RenderTaskPointMap tpv(canvas,
#ifdef ENABLE_OPENGL
                         /* OpenGL doesn't have the BufferCanvas
                            class */
                         NULL,
#else
                         &buffer_canvas,
#endif
                         render_projection,
                         SettingsMap(),
                         /* we're accessing the OrderedTask here,
                            which may be invalid at this point, but it
                            will be used only if active, so it's ok */
                         task_manager->get_ordered_task().get_task_projection(),
                         ozv, draw_bearing,
                         Basic().Location);
  RenderTask dv(tpv, render_projection.GetScreenBounds());
  ((TaskVisitor &)dv).Visit(*task);
}
Exemple #5
0
/**
 * Is called by the CalculationThread and processes the received GPS data in Basic()
 */
bool
GlideComputer::ProcessGPS(bool force)
{
  const MoreData &basic = Basic();
  DerivedInfo &calculated = SetCalculated();
  const ComputerSettings &settings = GetComputerSettings();

  const bool last_flying = calculated.flight.flying;

  calculated.date_time_local = basic.date_time_utc + settings.utc_offset;

  calculated.Expire(basic.clock);

  // Process basic information
  air_data_computer.ProcessBasic(Basic(), SetCalculated(),
                                 GetComputerSettings());

  // Process basic task information
  task_computer.ProcessBasicTask(basic, LastBasic(),
                                 calculated,
                                 GetComputerSettings(),
                                 force);
  task_computer.ProcessMoreTask(basic, calculated, GetComputerSettings());

  // Check if everything is okay with the gps time and process it
  if (!air_data_computer.FlightTimes(Basic(), LastBasic(), SetCalculated(),
                                     GetComputerSettings()))
    return false;

  TakeoffLanding(last_flying);

  if (!time_retreated())
    task_computer.ProcessAutoTask(basic, calculated);

  // Process extended information
  air_data_computer.ProcessVertical(Basic(), LastBasic(),
                                    SetCalculated(),
                                    GetComputerSettings());

  if (!time_retreated())
    stats_computer.ProcessClimbEvents(calculated);

  // Calculate the team code
  CalculateOwnTeamCode();

  // Calculate the bearing and range of the teammate
  CalculateTeammateBearingRange();

  vegavoice.Update(basic, Calculated(), GetComputerSettings().voice);

  // update basic trace history
  if (time_advanced())
    calculated.trace_history.append(basic);

  // Update the ConditionMonitors
  ConditionMonitorsUpdate(Basic(), Calculated(), settings);

  return idle_clock.CheckUpdate(500);
}
Exemple #6
0
void 
GlideComputer::OnStartTask()
{
  GlideComputerBlackboard::StartTask();
  air_data_computer.ResetStats();
  stats_computer.StartTask(Basic());
  log_computer.StartTask(Basic());
}
void
GlueMapWindow::DrawFlightMode(Canvas &canvas, const PixelRect &rc) const
{
  PixelScalar offset = 0;

  // draw logger status
  if (logger != nullptr && logger->IsLoggerActive()) {
    bool flip = (Basic().date_time_utc.second % 2) == 0;
    const MaskedIcon &icon = flip ? look.logger_on_icon : look.logger_off_icon;
    offset = icon.GetSize().cx;
    icon.Draw(canvas, rc.right - offset, rc.bottom - icon.GetSize().cy);
  }

  // draw flight mode
  const MaskedIcon *bmp;

  if (Calculated().common_stats.task_type == TaskType::ABORT)
    bmp = &look.abort_mode_icon;
  else if (GetDisplayMode() == DisplayMode::CIRCLING)
    bmp = &look.climb_mode_icon;
  else if (GetDisplayMode() == DisplayMode::FINAL_GLIDE)
    bmp = &look.final_glide_mode_icon;
  else
    bmp = &look.cruise_mode_icon;

  offset += bmp->GetSize().cx + Layout::Scale(6);

  bmp->Draw(canvas, rc.right - offset,
            rc.bottom - bmp->GetSize().cy - Layout::Scale(4));

  // draw flarm status
  if (!GetMapSettings().show_flarm_alarm_level)
    // Don't show indicator when the gauge is indicating the traffic anyway
    return;

  const FlarmStatus &flarm = Basic().flarm.status;
  if (!flarm.available)
    return;

  switch (flarm.alarm_level) {
  case FlarmTraffic::AlarmType::NONE:
    bmp = &look.traffic_safe_icon;
    break;
  case FlarmTraffic::AlarmType::LOW:
  case FlarmTraffic::AlarmType::INFO_ALERT:
    bmp = &look.traffic_warning_icon;
    break;
  case FlarmTraffic::AlarmType::IMPORTANT:
  case FlarmTraffic::AlarmType::URGENT:
    bmp = &look.traffic_alarm_icon;
    break;
  };

  offset += bmp->GetSize().cx + Layout::Scale(6);

  bmp->Draw(canvas, rc.right - offset,
            rc.bottom - bmp->GetSize().cy - Layout::Scale(2));
}
Exemple #8
0
void
MapWindow::DrawProjectedTrack(Canvas &canvas)
{
  if (task == NULL || !task->Valid() || !task->getSettings().AATEnabled ||
      task->getActiveIndex() ==0)
    return;

  if (Calculated().Circling || task->TaskIsTemporary()) {
    // don't display in various modes
    return;
  }

  // TODO feature: maybe have this work even if no task?
  // TODO feature: draw this also when in target pan mode

  GEOPOINT start = Basic().Location;
  GEOPOINT previous_loc = task->getTargetLocation(task->getActiveIndex() - 1);

  double distance_from_previous, bearing;
  DistanceBearing(previous_loc, start,
		  &distance_from_previous,
		  &bearing);

  if (distance_from_previous < 100.0) {
    bearing = Basic().TrackBearing;
    // too short to have valid data
  }
  POINT pt[2] = {{0,-75},{0,-400}};
  if (SettingsMap().TargetPan) {
    double screen_range = GetScreenDistanceMeters();
    double f_low = 0.4;
    double f_high = 1.5;
    screen_range = max(screen_range, Calculated().WaypointDistance);

    GEOPOINT p1, p2;
    FindLatitudeLongitude(start,
			  bearing, f_low*screen_range,
			  &p1);
    FindLatitudeLongitude(start,
			  bearing, f_high*screen_range,
			  &p2);
    LonLat2Screen(p1, pt[0]);
    LonLat2Screen(p2, pt[1]);
  } else if (fabs(bearing-Calculated().WaypointBearing)<10) {
    // too small an error to bother
    return;
  } else {
    pt[1].y = (long)(-max(MapRectBig.right-MapRectBig.left,
			  MapRectBig.bottom-MapRectBig.top)*1.2);
    PolygonRotateShift(pt, 2, Orig_Aircraft.x, Orig_Aircraft.y,
		       bearing-DisplayAngle);
  }

  Pen dash_pen(Pen::DASH, IBLSCALE(2), Color(0, 0, 0));
  canvas.select(dash_pen);
  canvas.line(pt[0], pt[1]);
}
void
GlueMapWindow::DrawFlightMode(Canvas &canvas, const PixelRect &rc) const
{
  int offset = 0;

  // draw logger status
  if (logger != NULL && logger->isLoggerActive()) {
    bool flip = (Basic().date_time_utc.second % 2) == 0;
    MaskedIcon &icon = flip ? Graphics::hLogger : Graphics::hLoggerOff;
    offset = icon.get_size().cx;
    icon.draw(canvas, rc.right - offset, rc.bottom - icon.get_size().cy);
  }

  // draw flight mode
  MaskedIcon *bmp;

  if (task != NULL && (task->get_mode() == TaskManager::MODE_ABORT))
    bmp = &Graphics::hAbort;
  else if (GetDisplayMode() == DM_CIRCLING)
    bmp = &Graphics::hClimb;
  else if (GetDisplayMode() == DM_FINAL_GLIDE)
    bmp = &Graphics::hFinalGlide;
  else
    bmp = &Graphics::hCruise;

  offset += bmp->get_size().cx + Layout::Scale(6);

  bmp->draw(canvas, rc.right - offset,
            rc.bottom - bmp->get_size().cy - Layout::Scale(4));

  // draw flarm status
  if (CommonInterface::GetUISettings().enable_flarm_gauge)
    // Don't show indicator when the gauge is indicating the traffic anyway
    return;

  const FLARM_STATE &flarm = Basic().flarm;
  if (!flarm.available || flarm.GetActiveTrafficCount() == 0)
    return;

  switch (flarm.alarm_level) {
  case 0:
    bmp = &Graphics::hBmpTrafficSafe;
    break;
  case 1:
    bmp = &Graphics::hBmpTrafficWarning;
    break;
  case 2:
  case 3:
    bmp = &Graphics::hBmpTrafficAlarm;
    break;
  };

  offset += bmp->get_size().cx + Layout::Scale(6);

  bmp->draw(canvas, rc.right - offset,
            rc.bottom - bmp->get_size().cy - Layout::Scale(2));
}
void
GlueMapWindow::DrawStallRatio(Canvas &canvas, const PixelRect &rc) const
{
  if (Basic().stall_ratio_available) {
    // JMW experimental, display stall sensor
    auto s = Clamp(Basic().stall_ratio, 0., 1.);
    int m = rc.GetHeight() * s * s;

    canvas.SelectBlackPen();
    canvas.DrawLine(rc.right - 1, rc.bottom - m, rc.right - 11, rc.bottom - m);
  }
}
void
GlueMapWindow::DrawStallRatio(Canvas &canvas, const PixelRect &rc) const
{
  if (Basic().stall_ratio_available) {
    // JMW experimental, display stall sensor
    fixed s = Clamp(Basic().stall_ratio, fixed(0), fixed(1));
    PixelScalar m((rc.bottom - rc.top) * s * s);

    canvas.SelectBlackPen();
    canvas.DrawLine(rc.right - 1, rc.bottom - m, rc.right - 11, rc.bottom - m);
  }
}
void
GlueMapWindow::DrawStallRatio(Canvas &canvas, const PixelRect &rc) const
{
  if (Basic().stall_ratio_available) {
    // JMW experimental, display stall sensor
    fixed s = max(fixed_zero, min(fixed_one, Basic().stall_ratio));
    long m = (long)((rc.bottom - rc.top) * s * s);

    canvas.black_pen();
    canvas.line(rc.right - 1, rc.bottom - m, rc.right - 11, rc.bottom - m);
  }
}
Exemple #13
0
void
MapWindow::DrawTrackBearing(Canvas &canvas, const RasterPoint aircraft_pos, bool circling) const
{
  if (!Basic().location_available)
    return;

  bool wind_relative = GetMapSettings().trail.wind_drift_enabled && circling;

  TrackLineRenderer track_line_renderer(look);
  track_line_renderer.Draw(canvas, render_projection,
                           aircraft_pos, Basic(), Calculated(), GetMapSettings(),
                           wind_relative);
}
Exemple #14
0
bool
DeviceBlackboard::expire_wall_clock()
{
  ScopeLock protect(mutexBlackboard);
  if (!Basic().Connected)
    return false;

  for (unsigned i = 0; i < NUMDEV; ++i)
    per_device_data[i].expire_wall_clock();

  Merge();
  return !Basic().Connected;
}
Exemple #15
0
void
DeviceBlackboard::tick()
{
  SetBasic().expire();

  // calculate fast data to complete aircraft state

  computer.Compute(SetBasic(), LastBasic(),
                   Calculated(), SettingsComputer());

  if (Basic().Time!= LastBasic().Time) {
    state_last = Basic();
  }
}
Exemple #16
0
/**
 * Process slow calculations. Called by the CalculationThread.
 */
void
GlideComputer::ProcessIdle(bool exhaustive)
{
  // Log GPS fixes for internal usage
  // (snail trail, stats, olc, ...)
  stats_computer.DoLogging(Basic(), Calculated());
  log_computer.Run(Basic(), Calculated(), GetComputerSettings().logger);

  task_computer.ProcessIdle(Basic(), SetCalculated(), GetComputerSettings(),
                            exhaustive);

  if (time_advanced())
    warning_computer.Update(GetComputerSettings(), Basic(), LastBasic(),
                            Calculated(), SetCalculated().airspace_warnings);
}
Exemple #17
0
/**
 * Calls the SearchBestAlternate() method if a certain time has passed since the last call
 * @author Paolo Ventafridda
 */
void GlideComputerTask::DoBestAlternateSlow() {
  static double LastSearchBestTime = 0; // VENTA3

  // VENTA3 best landing slow calculation
#ifdef WINDOWSPC
  if ( (SettingsComputer().EnableBestAlternate) && (Basic().Time > LastSearchBestTime+10.0) ) // VENTA3
#else
  if ((SettingsComputer().EnableBestAlternate) && (Basic().Time
      > LastSearchBestTime + BESTALTERNATEINTERVAL)) // VENTA3
#endif
  {
    LastSearchBestTime = Basic().Time;
    SearchBestAlternate();
  }
}
Exemple #18
0
void
MapWindow::DrawThermalEstimate(Canvas &canvas) const
{
  const MoreData &basic = Basic();
  const DerivedInfo &calculated = Calculated();
  const ThermalLocatorInfo &thermal_locator = calculated.thermal_locator;

  if (render_projection.GetMapScale() > 4000)
    return;

  // draw only at close map scales in non-circling mode

  DrawThermalSources(canvas, look.thermal_source_icon, render_projection,
                     thermal_locator.sources, basic.nav_altitude,
                     calculated.wind_available
                     ? calculated.wind : SpeedVector::Zero());

  const auto &cloud_settings = ComputerSettings().tracking.skylines.cloud;
  if (cloud_settings.show_thermals && skylines_data != nullptr) {
    ScopeLock protect(skylines_data->mutex);
    for (auto &i : skylines_data->thermals) {
      // TODO: apply wind drift
      PixelPoint pt;
      if (render_projection.GeoToScreenIfVisible(i.bottom_location, pt))
        look.thermal_source_icon.Draw(canvas, pt);
    }
  }
}
Exemple #19
0
void
GlideComputer::CalculateTeammateBearingRange()
{
  const TeamCodeSettings &settings = GetComputerSettings().team_code;
  const NMEAInfo &basic = Basic();
  TeamInfo &teamcode_info = SetCalculated();

  // No reference waypoint for teamcode calculation chosen -> cancel
  if (!DetermineTeamCodeRefLocation())
    return;

  if (settings.team_flarm_tracking) {
    ComputeFlarmTeam(basic.location, team_code_ref_location,
                     basic.flarm.traffic, settings.team_flarm_id,
                     teamcode_info);
  } else if (settings.team_code_valid) {
    teamcode_info.flarm_teammate_code_available = false;

    ComputeTeamCode(basic.location, team_code_ref_location,
                    settings.team_code,
                    teamcode_info);
  } else {
    teamcode_info.teammate_available = false;
    teamcode_info.flarm_teammate_code_available = false;
  }
}
Exemple #20
0
void
TargetMapWindow::DrawTask(Canvas &canvas)
{
  if (task == NULL)
    return;

  ProtectedTaskManager::Lease task_manager(*task);
  const AbstractTask *task = task_manager->GetActiveTask();
  if (task && task->CheckTask()) {

    OZRenderer ozv(task_look, airspace_renderer.GetLook(),
                              GetMapSettings().airspace);
    RenderTaskPoint tpv(canvas,
                        projection,
                        task_look,
                        /* we're accessing the OrderedTask here,
                           which may be invalid at this point, but it
                           will be used only if active, so it's ok */
                        task_manager->GetOrderedTask().GetTaskProjection(),
                        ozv, false, RenderTaskPoint::ALL,
                        Basic().location);
    TaskRenderer dv(tpv, projection.GetScreenBounds());
    dv.Draw(*task);
  }
}
Exemple #21
0
void
TargetMapWindow::RenderTerrain(Canvas &canvas)
{
  background.SetSunAngle(projection, GetMapSettings().terrain,
                         Basic(), Calculated());
  background.Draw(canvas, projection, GetMapSettings().terrain);
}
Exemple #22
0
void
GlideComputer::CalculateWorkingBand()
{
    const MoreData &basic = Basic();
    DerivedInfo &calculated = SetCalculated();
    const ComputerSettings &settings = GetComputerSettings();

    calculated.common_stats.height_min_working = stats_computer.GetFlightStats().GetMinWorkingHeight();
    if (calculated.terrain_base_valid) {
        calculated.common_stats.height_min_working = std::max(calculated.common_stats.height_min_working,
                calculated.GetTerrainBaseFallback()+settings.task.safety_height_arrival);
    }
    calculated.common_stats.height_max_working = std::max(calculated.common_stats.height_min_working,
            stats_computer.GetFlightStats().GetMaxWorkingHeight());

    calculated.common_stats.height_fraction_working = 1; // fallback;

    if (basic.NavAltitudeAvailable()) {
        calculated.common_stats.height_max_working = std::max(calculated.common_stats.height_max_working,
                basic.nav_altitude);
        calculated.common_stats.height_fraction_working =
            calculated.CalculateWorkingFraction(basic.nav_altitude,
                                                settings.task.safety_height_arrival);
    }
}
Exemple #23
0
void 
GlideComputer::OnStartTask()
{
  GlideComputerBlackboard::StartTask();
  GlideComputerStats::StartTask();
  logger.LogStartEvent(Basic());
}
Exemple #24
0
void
DeviceBlackboard::SetMC(fixed mc)
{
  AllDevicesPutMacCready(mc);
  if (!Basic().LocationAvailable)
    TriggerGPSUpdate();
}
void
MapWindow::DrawGlideThroughTerrain(Canvas &canvas) const
{
  if (SettingsComputer().FinalGlideTerrain) {
    canvas.hollow_brush();

#ifndef ENABLE_OPENGL
    canvas.select(Graphics::hpTerrainLineBg);
    canvas.polygon(Groundline, TERRAIN_ALT_INFO::NUMTERRAINSWEEPS);
#endif

    canvas.select(Graphics::hpTerrainLine);
    canvas.polygon(Groundline, TERRAIN_ALT_INFO::NUMTERRAINSWEEPS);
  }

  if (!Basic().flight.Flying)
    return;

  if (!Calculated().TerrainWarningLocation.is_null()) {
    RasterPoint sc;
    if (render_projection.GeoToScreenIfVisible(Calculated().TerrainWarningLocation,
                                                 sc))
      Graphics::hTerrainWarning.draw(canvas, sc.x, sc.y);
  }
}
Exemple #26
0
/**
 * Determine whether vario gauge, FLARM radar and infoboxes should be drawn
 */
void
ActionInterface::DisplayModes()
{
  // Determine whether the vario gauge should be drawn
  SetSettingsMap().EnableVarioGauge =
    vario_visible() && !SettingsMap().FullScreen;

  if (main_window.vario) {
    if (!SettingsMap().ScreenBlanked && SettingsMap().EnableVarioGauge) {
      main_window.vario->show();
    } else {
      main_window.vario->hide();
    }
  }

  if (Basic().NewTraffic) {
    // TODO bug: JMW: broken, currently won't work very well, needs to be reworked
    GaugeFLARM *gauge_flarm = main_window.flarm;
    if (gauge_flarm != NULL)
      gauge_flarm->Suppress = false;
  }

  if (SettingsMap().FullScreen) {
    InfoBoxManager::Hide();
  } else {
    InfoBoxManager::Show();
  }
}
Exemple #27
0
void
TargetMapWindow::DrawTask(Canvas &canvas)
{
  if (task == NULL)
    return;

  ProtectedTaskManager::Lease task_manager(*task);
  const AbstractTask *task = task_manager->get_active_task();
  if (task && task->check_task()) {

    RenderObservationZone ozv(task_look, airspace_renderer.GetLook());
    RenderTaskPointMap tpv(canvas,
#ifdef ENABLE_OPENGL
                           /* OpenGL doesn't have the BufferCanvas
                              class */
                           NULL,
#else
                           &buffer_canvas,
#endif
                           projection,
                           SettingsMap(),
                           task_look,
                           /* we're accessing the OrderedTask here,
                              which may be invalid at this point, but it
                              will be used only if active, so it's ok */
                           task_manager->get_ordered_task().get_task_projection(),
                           ozv, false, true,
                           Basic().location);
    RenderTask dv(tpv, projection.GetScreenBounds());
    ((TaskVisitor &)dv).Visit(*task);
  }
}
Exemple #28
0
void
MapWindow::DrawBestCruiseTrack(Canvas &canvas, const RasterPoint aircraft_pos) const
{
  if (Basic().location_available)
    BestCruiseArrowRenderer::Draw(canvas, look.task,
                                  render_projection.GetScreenAngle(),
                                  aircraft_pos, Calculated());
}
Exemple #29
0
void
MapWindow::DrawTrail(Canvas &canvas, const RasterPoint aircraft_pos,
                     unsigned min_time, bool enable_traildrift) const
{
  if (glide_computer)
    TrailRenderer::Draw(canvas, *glide_computer, render_projection, min_time,
                        enable_traildrift, aircraft_pos, Basic(), Calculated(), SettingsMap());
}
Exemple #30
0
void
GlideComputer::CalculateTeammateBearingRange()
{
  static bool InTeamSector = false;

  // No reference waypoint for teamcode calculation chosen -> cancel
  if (SettingsComputer().TeamCodeRefWaypoint < 0)
    return;

  // Get bearing and distance to the reference waypoint
  const Waypoint *wp =
      way_points.lookup_id(SettingsComputer().TeamCodeRefWaypoint);

  if (!wp)
    return;

  Angle ownBearing = wp->Location.bearing(Basic().Location);

  // If (TeamCode exists and is valid)
  if (SettingsComputer().TeammateCodeValid) {
    // Calculate bearing and distance to teammate
    SetCalculated().TeammateLocation =
        SettingsComputer().TeammateCode.GetLocation(wp->Location);

    GeoVector team_vector(Basic().Location, Calculated().TeammateLocation);

    // Save bearing and distance to teammate in Calculated
    SetCalculated().TeammateBearing = team_vector.Bearing;
    SetCalculated().TeammateRange = team_vector.Distance;

    // Hysteresis for GlideComputerEvent
    // If (closer than 100m to the teammates last position and "event" not reset)
    if (Calculated().TeammateRange < fixed(100) && InTeamSector == false) {
      InTeamSector = true;
      // Raise GCE_TEAM_POS_REACHED event
      InputEvents::processGlideComputer(GCE_TEAM_POS_REACHED);
    } else if (Calculated().TeammateRange > fixed(300)) {
      // Reset "event" when distance is greater than 300m again
      InTeamSector = false;
    }
  } else {
    SetCalculated().TeammateBearing = Angle::degrees(fixed_zero);
    SetCalculated().TeammateRange = fixed_zero;
  }
}