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(); const bool circling = CommonInterface::GetUIState().display_mode == DisplayMode::CIRCLING; const auto center = rc.GetCenter(); if (circling || !IsNearSelf()) visible_projection.SetScreenOrigin(center.x, center.y); else if (settings_map.cruise_orientation == MapOrientation::NORTH_UP || settings_map.cruise_orientation == MapOrientation::WIND_UP) { PixelPoint offset{0, 0}; if (settings_map.glider_screen_position != 50 && settings_map.map_shift_bias != MapShiftBias::NONE) { double x = 0, y = 0; if (settings_map.map_shift_bias == MapShiftBias::TRACK) { if (basic.track_available && basic.ground_speed_available && /* 8 m/s ~ 30 km/h */ basic.ground_speed > 8) { auto angle = basic.track.Reciprocal() - visible_projection.GetScreenAngle(); const auto sc = angle.SinCos(); x = sc.first; y = sc.second; } } else if (settings_map.map_shift_bias == MapShiftBias::TARGET) { if (calculated.task_stats.current_leg.solution_remaining.IsDefined()) { auto angle = calculated.task_stats.current_leg.solution_remaining .vector.bearing.Reciprocal() - visible_projection.GetScreenAngle(); const auto sc = angle.SinCos(); x = sc.first; y = sc.second; } } double position_factor = (50. - settings_map.glider_screen_position) / 100.; offset.x = int(x * rc.GetWidth() * position_factor); offset.y = int(-y * rc.GetHeight() * 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 (circling && calculated.thermal_locator.estimate_valid) { const auto d_t = calculated.thermal_locator.estimate_location.DistanceS(basic.location); if (d_t <= 0) { SetLocationLazy(basic.location); } else { const auto d_max = 2 * visible_projection.GetMapScale(); const auto 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); else if (!visible_projection.IsValid() && terrain != nullptr) /* if there's no GPS fix yet and no home waypoint, start at the map center, to avoid showing a fully white map, which confuses users */ SetLocation(terrain->GetTerrainCenter()); OnProjectionModified(); }
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(); const bool circling = CommonInterface::GetUIState().display_mode == DisplayMode::CIRCLING; RasterPoint center; center.x = (rc.left + rc.right) / 2; center.y = (rc.top + rc.bottom) / 2; if (circling || !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 (circling && 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(); }