void GlueMapWindow::UpdateMapScale() { /* not using MapWindowBlackboard here because these methods are called by the main thread */ const DerivedInfo &calculated = CommonInterface::Calculated(); const MapSettings &settings = CommonInterface::GetMapSettings(); if (InCirclingMode() && settings.circle_zoom_enabled) return; if (!IsNearSelf()) return; fixed distance = calculated.auto_zoom_distance; if (settings.auto_zoom_enabled && positive(distance)) { // Calculate distance percentage between plane symbol and map edge // 50: centered 100: at edge of map int auto_zoom_factor = InCirclingMode() ? 50 : 100 - settings.glider_screen_position; // Leave 5% of full distance for target display auto_zoom_factor -= 5; // Adjust to account for map scale units auto_zoom_factor *= 8; distance /= fixed(auto_zoom_factor) / 100; // Clip map auto zoom range to reasonable values distance = max(fixed_int_constant(525), min(settings.max_auto_zoom_distance / 10, distance)); visible_projection.SetFreeMapScale(distance); } }
void GlueMapWindow::UpdateScreenAngle() { /* not using MapWindowBlackboard here because these methods are called by the main thread */ const NMEAInfo &basic = CommonInterface::Basic(); const DerivedInfo &calculated = CommonInterface::Calculated(); const MapSettings &settings = CommonInterface::GetMapSettings(); DisplayOrientation orientation = InCirclingMode() ? settings.circling_orientation : settings.cruise_orientation; if (orientation == TARGETUP && calculated.task_stats.current_leg.vector_remaining.IsValid()) visible_projection.SetScreenAngle(calculated.task_stats.current_leg. vector_remaining.bearing); else if (orientation == NORTHUP || !basic.track_available) visible_projection.SetScreenAngle(Angle::Zero()); else // normal, glider forward visible_projection.SetScreenAngle(basic.track); compass_visible = orientation != NORTHUP; }
void GlueMapWindow::SwitchZoomClimb() { const MapSettings &settings = CommonInterface::GetMapSettings(); if (!settings.circle_zoom_enabled) return; if (InCirclingMode()) visible_projection.SetScale(settings.circling_scale); else visible_projection.SetScale(settings.cruise_scale); }
void GlueMapWindow::SetMapScale(fixed scale) { MapWindow::SetMapScale(scale); MapSettings &settings = CommonInterface::SetMapSettings(); if (InCirclingMode() && settings.circle_zoom_enabled) // save cruise scale settings.circling_scale = visible_projection.GetScale(); else settings.cruise_scale = visible_projection.GetScale(); SaveDisplayModeScales(); }
void GlueMapWindow::DrawThermalEstimate(Canvas &canvas) const { if (InCirclingMode() && IsNearSelf()) { // in circling mode, draw thermal at actual estimated location const MapWindowProjection &projection = render_projection; const ThermalLocatorInfo &thermal_locator = Calculated().thermal_locator; if (thermal_locator.estimate_valid) { RasterPoint sc; if (projection.GeoToScreenIfVisible(thermal_locator.estimate_location, sc)) { look.thermal_source_icon.Draw(canvas, sc); } } } else { MapWindow::DrawThermalEstimate(canvas); } }
void GlueMapWindow::RenderTrail(Canvas &canvas, const RasterPoint aircraft_pos) { unsigned min_time; switch(GetMapSettings().trail.length) { case TrailSettings::Length::OFF: return; case TrailSettings::Length::LONG: min_time = max(0, (int)Basic().time - 3600); break; case TrailSettings::Length::SHORT: min_time = max(0, (int)Basic().time - 600); break; case TrailSettings::Length::FULL: min_time = 0; // full break; } DrawTrail(canvas, aircraft_pos, min_time, GetMapSettings().trail.wind_drift_enabled && InCirclingMode()); }
void GlueMapWindow::UpdateProjection() { const PixelRect rc = GetClientRect(); /* not using MapWindowBlackboard here because these methods are called by the main thread */ const NMEAInfo &basic = CommonInterface::Basic(); const DerivedInfo &calculated = CommonInterface::Calculated(); const MapSettings &settings_map = CommonInterface::GetMapSettings(); RasterPoint center; center.x = (rc.left + rc.right) / 2; center.y = (rc.top + rc.bottom) / 2; if (InCirclingMode() || !IsNearSelf()) visible_projection.SetScreenOrigin(center.x, center.y); else if (settings_map.cruise_orientation == NORTHUP) { RasterPoint offset{0, 0}; if (settings_map.glider_screen_position != 50 && settings_map.map_shift_bias != MAP_SHIFT_BIAS_NONE) { fixed x = fixed_zero; fixed y = fixed_zero; if (settings_map.map_shift_bias == MAP_SHIFT_BIAS_TRACK) { if (basic.track_available && basic.ground_speed_available && /* 8 m/s ~ 30 km/h */ basic.ground_speed > fixed_int_constant(8)) { const auto sc = basic.track.Reciprocal().SinCos(); x = sc.first; y = sc.second; } } else if (settings_map.map_shift_bias == MAP_SHIFT_BIAS_TARGET) { if (calculated.task_stats.current_leg.solution_remaining.IsDefined()) { const auto sc =calculated.task_stats.current_leg.solution_remaining .vector.bearing.Reciprocal().SinCos(); x = sc.first; y = sc.second; } } fixed position_factor = fixed(50 - settings_map.glider_screen_position) / 100; offset.x = PixelScalar(x * (rc.right - rc.left) * position_factor); offset.y = PixelScalar(y * (rc.top - rc.bottom) * position_factor); offset_history.Add(offset); offset = offset_history.GetAverage(); } visible_projection.SetScreenOrigin(center.x + offset.x, center.y + offset.y); } else visible_projection.SetScreenOrigin(center.x, ((rc.top - rc.bottom) * settings_map.glider_screen_position / 100) + rc.bottom); if (!IsNearSelf()) { /* no-op - the Projection's location is updated manually */ } else if (InCirclingMode() && calculated.thermal_locator.estimate_valid) { const fixed d_t = calculated.thermal_locator.estimate_location.Distance(basic.location); if (!positive(d_t)) { SetLocationLazy(basic.location); } else { const fixed d_max = Double(visible_projection.GetMapScale()); const fixed t = std::min(d_t, d_max)/d_t; SetLocation(basic.location.Interpolate(calculated.thermal_locator.estimate_location, t)); } } else if (basic.location_available) // Pan is off SetLocationLazy(basic.location); visible_projection.UpdateScreenBounds(); }
void GlueMapWindow::RenderTrackBearing(Canvas &canvas, const RasterPoint aircraft_pos) { DrawTrackBearing(canvas, aircraft_pos, InCirclingMode()); }