bool GlueMapWindow::ShowMapItems(const GeoPoint &location, bool show_empty_message) const { fixed range = visible_projection.DistancePixelsToMeters(Layout::GetHitRadius()); MapItemList list; MapItemListBuilder builder(list, location, range); builder.AddLocation(Basic(), terrain); if (route_planner) builder.AddArrivalAltitudes(*route_planner, terrain, GetComputerSettings().task.safety_height_arrival); if (Basic().location_available) builder.AddSelfIfNear(Basic().location, Calculated().heading); if (task) builder.AddTaskOZs(*task); const Airspaces *airspace_database = airspace_renderer.GetAirspaces(); if (airspace_database) builder.AddVisibleAirspace(*airspace_database, airspace_renderer.GetWarningManager(), GetComputerSettings().airspace, GetMapSettings().airspace, Basic(), Calculated()); if (marks && render_projection.GetMapScale() <= fixed_int_constant(30000)) builder.AddMarkers(*marks); if (render_projection.GetMapScale() <= fixed_int_constant(4000)) builder.AddThermals(Calculated().thermal_locator, Basic(), Calculated()); if (waypoints) builder.AddWaypoints(*waypoints); if (Basic().flarm.available) builder.AddTraffic(Basic().flarm); // Sort the list of map items list.Sort(); // Show the list dialog if (list.empty()) { if (show_empty_message) ShowMessageBox(_("There is nothing interesting near this location."), _("Map elements at this location"), MB_OK | MB_ICONINFORMATION); return false; } ShowMapItemListDialog(UIGlobals::GetMainWindow(), list, UIGlobals::GetDialogLook(), look, traffic_look, final_glide_bar_renderer.GetLook(), GetMapSettings(), glide_computer != NULL ? &glide_computer->GetAirspaceWarnings() : NULL); return true; }
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 (GetDisplayMode() == DM_CIRCLING && settings.circle_zoom_enabled) return; if (!IsNearSelf()) return; fixed wpd = calculated.auto_zoom_distance; if (settings.auto_zoom_enabled && positive(wpd)) { // Calculate distance percentage between plane symbol and map edge // 50: centered 100: at edge of map int AutoZoomFactor = (GetDisplayMode() == DM_CIRCLING) ? 50 : 100 - settings.glider_screen_position; // Leave 5% of full distance for target display AutoZoomFactor -= 5; // Adjust to account for map scale units AutoZoomFactor *= 8; wpd = wpd / ((fixed) AutoZoomFactor / fixed_int_constant(100)); // Clip map auto zoom range to reasonable values wpd = max(fixed_int_constant(525), min(settings.max_auto_zoom_distance / fixed_int_constant(10), wpd)); visible_projection.SetFreeMapScale(wpd); } }
void InputEvents::sub_SetZoom(fixed value) { MapSettings &settings_map = CommonInterface::SetMapSettings(); GlueMapWindow *map_window = CommonInterface::main_window.ActivateMap(); if (map_window == NULL) return; DisplayMode displayMode = XCSoarInterface::main_window.GetDisplayMode(); if (settings_map.auto_zoom_enabled && !(displayMode == DisplayMode::CIRCLING && settings_map.circle_zoom_enabled) && !CommonInterface::IsPanning()) { settings_map.auto_zoom_enabled = false; // disable autozoom if user manually changes zoom Profile::Set(szProfileAutoZoom, false); Message::AddMessage(_("Auto. zoom off")); } fixed vmin = CommonInterface::GetComputerSettings().polar.glide_polar_task.GetVMin(); fixed scale_2min_distance = vmin * fixed_int_constant(12); const fixed scale_500m = fixed_int_constant(50); const fixed scale_1600km = fixed_int_constant(1600*100); fixed minreasonable = (displayMode == DisplayMode::CIRCLING) ? scale_500m : max(scale_500m, scale_2min_distance); value = max(minreasonable, min(scale_1600km, value)); map_window->SetMapScale(value); map_window->QuickRedraw(); }
void TrackLineRenderer::Draw(Canvas &canvas, const Angle screen_angle, const Angle track_angle, const RasterPoint pos) { const auto sc = (track_angle - screen_angle).SinCos(); const fixed x = sc.first, y = sc.second; RasterPoint end; end.x = pos.x + iround(x * fixed_int_constant(400)); end.y = pos.y - iround(y * fixed_int_constant(400)); canvas.Select(look.track_line_pen); canvas.DrawLine(pos, end); }
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); } }
bool OLCTriangle::path_closed() const { // RESERVED FOR FUTURE USE: DO NOT DELETE // note this may fail if resolution of sampled trace is too low assert(n_points > 0); const ScanTaskPoint end(0, n_points-1); fixed d_min(-1); ScanTaskPoint start(0, 0); assert(first_tp < n_points); for (start.point_index = 0; start.point_index <= first_tp; ++start.point_index) { const fixed d_this = GetPointFast(start).get_location().distance( GetPointFast(end).get_location()); if (!positive(d_min) || (d_this < d_min)) { d_min = d_this; } if (d_this<= fixed_int_constant(1000)) { return true; } } return false; }
bool OLCTriangle::IsPathClosed() const { // RESERVED FOR FUTURE USE: DO NOT DELETE // note this may fail if resolution of sampled trace is too low assert(n_points > 0); const GeoPoint end_location = GetPoint(n_points - 1).GetLocation(); fixed d_min(-1); assert(first_tp < n_points); for (unsigned start_index = 0; start_index <= first_tp; ++start_index) { const fixed d_this = GetPoint(start_index).GetLocation().Distance(end_location); if (!positive(d_min) || d_this < d_min) d_min = d_this; if (d_this<= fixed_int_constant(1000)) return true; } return false; }
void MapWindow::RenderMarks(Canvas &canvas) { if (marks != NULL && render_projection.GetMapScale() <= fixed_int_constant(30000)) marks->Draw(canvas, render_projection); }
void AircraftStateFilter::update(const AIRCRAFT_STATE& state) { fixed dt = state.Time- m_state_last.Time; if (negative(dt)) { reset(state); return; } if (!positive(dt)) return; GeoVector vec(m_state_last.Location, state.Location); const fixed MACH_1 = fixed_int_constant(343); if (vec.Distance / dt > MACH_1) { reset(state); return; } m_x+= vec.Bearing.sin()*vec.Distance; m_y+= vec.Bearing.cos()*vec.Distance; m_vx = m_lpf_x.update(m_df_x.update(m_x)); m_vy = m_lpf_y.update(m_df_y.update(m_y)); m_vz = m_lpf_alt.update(m_df_alt.update(state.NavAltitude)); m_state_last = state; }
fixed GlideResult::DestinationAngleGround() const { if (positive(vector.distance)) return (altitude_difference + pure_glide_height) / vector.distance; return fixed_int_constant(1000); }
fixed GlideResult::GlideAngleGround() const { if (positive(vector.distance)) return pure_glide_height / vector.distance; return fixed_int_constant(1000); }
void TargetMapWindow::set(ContainerWindow &parent, int left, int top, unsigned width, unsigned height, WindowStyle style) { projection.SetFreeMapScale(fixed_int_constant(5000)); BufferWindow::set(parent, left, top, width, height, style); }
fixed GlideResult::destination_angle_ground() const { if (positive(Vector.Distance)) return (AltitudeDifference+HeightGlide) / Vector.Distance; return fixed_int_constant(1000); }
fixed GlideResult::glide_angle_ground() const { if (positive(Vector.Distance)) return HeightGlide / Vector.Distance; return fixed_int_constant(1000); }
void TargetMapWindow::set(ContainerWindow &parent, PixelScalar left, PixelScalar top, UPixelScalar width, UPixelScalar height, WindowStyle style) { projection.SetFreeMapScale(fixed_int_constant(5000)); BufferWindow::set(parent, left, top, width, height, style); }
void MapWindow::set(ContainerWindow &parent, const PixelRect &rc) { WindowStyle style; style.enable_double_clicks(); DoubleBufferWindow::set(parent, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, style); // initialize other systems visible_projection.SetMapScale(fixed_int_constant(5000)); visible_projection.SetScreenOrigin((rc.left + rc.right) / 2, (rc.bottom + rc.top) / 2); visible_projection.UpdateScreenBounds(); #ifndef ENABLE_OPENGL buffer_projection = visible_projection; #endif }
/** * Draws the FLARM traffic icons onto the given canvas * @param canvas Canvas for drawing */ void MapWindow::DrawFLARMTraffic(Canvas &canvas, const RasterPoint aircraft_pos) const { // Return if FLARM icons on moving map are disabled if (!GetMapSettings().show_flarm_on_map) return; // Return if FLARM data is not available const FlarmState &flarm = Basic().flarm; if (!flarm.available) return; const WindowProjection &projection = render_projection; // if zoomed in too far out, dont draw traffic since it will be too close to // the glider and so will be meaningless (serves only to clutter, cant help // the pilot) if (projection.GetMapScale() > fixed_int_constant(7300)) return; // Circle through the FLARM targets for (auto it = flarm.traffic.begin(), end = flarm.traffic.end(); it != end; ++it) { const FlarmTraffic &traffic = *it; if (!traffic.location_available) continue; // Save the location of the FLARM target GeoPoint target_loc = traffic.location; // Points for the screen coordinates for the icon, name and average climb RasterPoint sc, sc_name, sc_av; // If FLARM target not on the screen, move to the next one if (!projection.GeoToScreenIfVisible(target_loc, sc)) continue; // Draw the name 16 points below the icon sc_name = sc; sc_name.y -= Layout::Scale(20); // Draw the average climb value above the icon sc_av = sc; sc_av.y += Layout::Scale(5); TextInBoxMode mode; mode.mode = RM_OUTLINED; // JMW TODO enhancement: decluttering of FLARM altitudes (sort by max lift) int dx = sc_av.x - aircraft_pos.x; int dy = sc_av.y - aircraft_pos.y; // only draw labels if not close to aircraft if (dx * dx + dy * dy > Layout::Scale(30 * 30)) { // If FLARM callsign/name available draw it to the canvas if (traffic.HasName() && !StringIsEmpty(traffic.name)) TextInBox(canvas, traffic.name, sc_name.x, sc_name.y, mode, get_client_rect()); if (traffic.climb_rate_avg30s >= fixed(0.1)) { // If average climb data available draw it to the canvas TCHAR label_avg[100]; Units::FormatUserVerticalSpeed(traffic.climb_rate_avg30s, label_avg, false); TextInBox(canvas, label_avg, sc_av.x, sc_av.y, mode, get_client_rect()); } } TrafficRenderer::Draw(canvas, traffic_look, traffic, traffic.track - projection.GetScreenAngle(), sc); } }
bool GlueMapWindow::ShowMapItems(const GeoPoint &location, bool show_empty_message) const { /* not using MapWindowBlackboard here because this method is called by the main thread */ const ComputerSettings &computer_settings = CommonInterface::GetComputerSettings(); const MapSettings &settings = CommonInterface::GetMapSettings(); const MoreData &basic = CommonInterface::Basic(); const DerivedInfo &calculated = CommonInterface::Calculated(); fixed range = visible_projection.DistancePixelsToMeters(Layout::GetHitRadius()); MapItemList list; MapItemListBuilder builder(list, location, range); if (settings.item_list.add_location) builder.AddLocation(basic, terrain); if (settings.item_list.add_arrival_altitude && route_planner) builder.AddArrivalAltitudes(*route_planner, terrain, computer_settings.task.safety_height_arrival); if (basic.location_available) builder.AddSelfIfNear(basic.location, basic.attitude.heading); if (task) builder.AddTaskOZs(*task); const Airspaces *airspace_database = airspace_renderer.GetAirspaces(); if (airspace_database) builder.AddVisibleAirspace(*airspace_database, airspace_renderer.GetWarningManager(), computer_settings.airspace, settings.airspace, basic, calculated); if (marks && visible_projection.GetMapScale() <= fixed_int_constant(30000)) builder.AddMarkers(*marks); if (visible_projection.GetMapScale() <= fixed_int_constant(4000)) builder.AddThermals(calculated.thermal_locator, basic, calculated); if (waypoints) builder.AddWaypoints(*waypoints); #ifdef HAVE_NOAA if (noaa_store) builder.AddWeatherStations(*noaa_store); #endif builder.AddTraffic(basic.flarm.traffic, computer_settings.team_code); // Sort the list of map items list.Sort(); // Show the list dialog if (list.empty()) { if (show_empty_message) ShowMessageBox(_("There is nothing interesting near this location."), _("Map elements at this location"), MB_OK | MB_ICONINFORMATION); return false; } ShowMapItemListDialog(UIGlobals::GetMainWindow(), list, UIGlobals::GetDialogLook(), look, traffic_look, final_glide_bar_renderer.GetLook(), settings, glide_computer != NULL ? &glide_computer->GetAirspaceWarnings() : NULL); return true; }
void WaypointIconRenderer::DrawLandable(const Waypoint &waypoint, const RasterPoint &point, Reachability reachable) { if (!settings.vector_landable_rendering) { const MaskedIcon *icon; if (reachable == ReachableTerrain) icon = waypoint.IsAirport() ? &look.airport_reachable_icon : &look.field_reachable_icon; else if (reachable == ReachableStraight) icon = waypoint.IsAirport() ? &look.airport_marginal_icon : &look.field_marginal_icon; else icon = waypoint.IsAirport() ? &look.airport_unreachable_icon : &look.field_unreachable_icon; icon->draw(canvas, point); return; } // SW rendering of landables fixed scale = fixed(Layout::SmallScale(settings.landable_rendering_scale)) / fixed_int_constant(150); fixed radius = fixed_int_constant(10) * scale; canvas.black_pen(); if (settings.landable_style == wpLandableWinPilot) { // Render landable with reachable state if (reachable != Unreachable) { canvas.select(reachable == ReachableTerrain ? look.reachable_brush : look.terrain_unreachable_brush); DrawLandableBase(canvas, point, waypoint.IsAirport(), radius + radius / fixed_two); } canvas.select(look.magenta_brush); } else if (settings.landable_style == wpLandableAltB) { if (reachable != Unreachable) canvas.select(reachable == ReachableTerrain ? look.reachable_brush : look.orange_brush); else canvas.select(look.unreachable_brush); } else { if (reachable != Unreachable) canvas.select(reachable == ReachableTerrain ? look.reachable_brush : look.terrain_unreachable_brush); else if (waypoint.IsAirport()) canvas.select(look.white_brush); else canvas.select(look.light_gray_brush); } DrawLandableBase(canvas, point, waypoint.IsAirport(), radius); // Render runway indication const Runway &runway = waypoint.runway; if (runway.IsDirectionDefined()) { fixed len; if (settings.scale_runway_length && runway.IsLengthDefined()) len = (radius / fixed_two) + (((int) runway.GetLength() - 500) / 500) * (radius / fixed_four); else len = radius; len += fixed_two * scale; Angle runwayDrawingAngle = runway.GetDirection() - screen_rotation; canvas.select(look.white_brush); DrawLandableRunway(canvas, point, runwayDrawingAngle, len, fixed_int_constant(5) * scale); } }
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(); }
bool MapWindowProjection::WaypointInScaleFilter(const Waypoint &way_point) const { return (GetMapScale() <= (way_point.is_landable() ? fixed_int_constant(20000) : fixed_int_constant(10000))); }