bool AbstractTask::UpdateIdle(const AircraftState &state, const GlidePolar &glide_polar) { if (stats.start.task_started && task_behaviour.calc_cruise_efficiency && glide_polar.IsValid()) { fixed val = fixed(1); if (CalcCruiseEfficiency(state, glide_polar, val)) stats.cruise_efficiency = std::max(ce_lpf.Update(val), fixed(0)); } else { stats.cruise_efficiency = ce_lpf.Reset(fixed(1)); } if (stats.start.task_started && task_behaviour.calc_effective_mc && glide_polar.IsValid()) { fixed val = glide_polar.GetMC(); if (CalcEffectiveMC(state, glide_polar, val)) stats.effective_mc = std::max(em_lpf.Update(val), fixed(0)); } else { stats.effective_mc = em_lpf.Reset(glide_polar.GetMC()); } if (task_behaviour.calc_glide_required && glide_polar.IsValid()) UpdateStatsGlide(state, glide_polar); else stats.glide_required = fixed(0); // error return false; }
bool AirspaceWarningManager::UpdateTask(const AircraftState &state, const GlidePolar &glide_polar, const TaskStats &task_stats) { if (!glide_polar.IsValid()) return false; const ElementStat ¤t_leg = task_stats.current_leg; if (!task_stats.task_valid || !current_leg.location_remaining.IsValid()) return false; const GlideResult &solution = current_leg.solution_remaining; if (!solution.IsOk() || !solution.IsAchievable()) /* glide solver failed, cannot continue */ return false; const AirspaceAircraftPerformance perf_task(glide_polar, current_leg.solution_remaining); GeoPoint location_tp = current_leg.location_remaining; const fixed time_remaining = solution.time_elapsed; const GeoVector vector(state.location, location_tp); fixed max_distance = config.warning_time * glide_polar.GetVMax(); if (vector.distance > max_distance) /* limit the distance to what our glider can actually fly within the configured warning time */ location_tp = state.location.IntermediatePoint(location_tp, max_distance); return UpdatePredicted(state, location_tp, perf_task, AirspaceWarning::WARNING_TASK, time_remaining); }
/** * Specialisation based on simplified theoretical MC cross-country * speeds. Assumes cruise at best LD (ignoring wind) for current MC * setting, climb rate at MC setting, with direct descent possible * at sink rate of cruise. */ explicit AirspaceAircraftPerformance(const GlidePolar &polar) :vertical_tolerance(0), cruise_speed(polar.GetVBestLD()), cruise_descent(polar.GetSBestLD()), descent_rate(polar.GetSMax()), climb_rate(polar.GetMC()), max_speed(polar.GetVMax()) { assert(polar.IsValid()); }
void RenderMacCready(Canvas &canvas, const PixelRect rc, const ChartLook &chart_look, const GlidePolar &glide_polar) { ChartRenderer chart(chart_look, canvas, rc); if (!glide_polar.IsValid()) { chart.DrawNoData(); return; } chart.ScaleXFromValue(0); chart.ScaleXFromValue(MAX_MACCREADY); chart.ScaleYFromValue(0); chart.ScaleYFromValue(glide_polar.GetVMax()); chart.DrawXGrid(Units::ToSysVSpeed(1), 1, ChartRenderer::UnitFormat::NUMERIC); chart.DrawYGrid(Units::ToSysSpeed(10), 10, ChartRenderer::UnitFormat::NUMERIC); GlidePolar gp = glide_polar; double m = 0; double m_last; gp.SetMC(m); double v_last = gp.GetVBestLD(); double vav_last = 0; do { m_last = m; m+= MAX_MACCREADY/STEPS_MACCREADY; gp.SetMC(m); const double v = gp.GetVBestLD(); const double vav = gp.GetAverageSpeed(); chart.DrawLine(m_last, v_last, m, v, ChartLook::STYLE_BLACK); chart.DrawLine(m_last, vav_last, m, vav, ChartLook::STYLE_BLUETHINDASH); v_last = v; vav_last = vav; } while (m<MAX_MACCREADY); // draw current MC setting chart.DrawLine(glide_polar.GetMC(), 0, glide_polar.GetMC(), glide_polar.GetVMax(), ChartLook::STYLE_REDTHICKDASH); // draw labels and other overlays gp.SetMC(0.9*MAX_MACCREADY); chart.DrawLabel(_T("Vopt"), 0.9*MAX_MACCREADY, gp.GetVBestLD()); gp.SetMC(0.9*MAX_MACCREADY); chart.DrawLabel(_T("Vave"), 0.9*MAX_MACCREADY, gp.GetAverageSpeed()); chart.DrawYLabel(_T("V"), Units::GetSpeedName()); chart.DrawXLabel(_T("MC"), Units::GetVerticalSpeedName()); RenderGlidePolarInfo(canvas, rc, chart_look, glide_polar); }
bool AirspaceWarningManager::UpdateGlide(const AircraftState &state, const GlidePolar &glide_polar) { if (!glide_polar.IsValid()) return false; const GeoPoint location_predicted = state.GetPredictedState(prediction_time_glide).location; const AirspaceAircraftPerformance perf_glide(glide_polar); return UpdatePredicted(state, location_predicted, perf_glide, AirspaceWarning::WARNING_GLIDE, prediction_time_glide); }
inline void GlideComputerAirData::FlightState(const NMEAInfo &basic, const DerivedInfo &calculated, FlyingState &flying, const GlidePolar &glide_polar) { fixed v_takeoff = glide_polar.IsValid() ? glide_polar.GetVTakeoff() /* if there's no valid polar, assume 10 m/s (36 km/h); that's an arbitrary value, but better than nothing */ : fixed(10); flying_computer.Compute(v_takeoff, basic, calculated, flying); }
void MacCreadyCaption(TCHAR *sTmp, const GlidePolar &glide_polar) { if (!glide_polar.IsValid()) { *sTmp = _T('\0'); return; } _stprintf(sTmp, _T("%s: %d %s\r\n%s: %d %s"), _("Vopt"), (int)Units::ToUserSpeed(glide_polar.GetVBestLD()), Units::GetSpeedName(), _("Vave"), (int)Units::ToUserTaskSpeed(glide_polar.GetAverageSpeed()), Units::GetTaskSpeedName()); }
/** * Specialisation of AirspaceAircraftPerformance for tasks where * part of the path is in cruise, part in final glide. This is * intended to be used temporarily only. * * This simplifies the path by assuming flight is constant altitude * or descent to the task point elevation. */ AirspaceAircraftPerformance(const GlidePolar &polar, const GlideResult &solution) :vertical_tolerance(0.001), cruise_speed(positive(solution.time_elapsed) ? solution.vector.distance / solution.time_elapsed : fixed(1)), cruise_descent(positive(solution.time_elapsed) ? (positive(solution.height_climb) ? -solution.height_climb : solution.height_glide) / solution.time_elapsed : fixed(0)), descent_rate(polar.GetSBestLD()), climb_rate(positive(solution.time_elapsed) && positive(solution.height_climb) ? polar.GetMC() : fixed(0)), max_speed(cruise_speed) { assert(polar.IsValid()); assert(solution.IsOk()); assert(solution.IsAchievable()); }
bool AirspaceWarningManager::UpdateInside(const AircraftState& state, const GlidePolar &glide_polar) { if (!glide_polar.IsValid()) return false; bool found = false; AirspacePredicateAircraftInside condition(state); Airspaces::AirspaceVector results = airspaces.FindInside(state, condition); for (const auto &i : results) { const AbstractAirspace &airspace = i.GetAirspace(); if (!airspace.IsActive()) continue; // ignore inactive airspaces if (!config.IsClassEnabled(airspace.GetType())) continue; AirspaceWarning *warning = GetWarningPtr(airspace); if (warning == nullptr || warning->IsStateAccepted(AirspaceWarning::WARNING_INSIDE)) { GeoPoint c = airspace.ClosestPoint(state.location, GetProjection()); const AirspaceAircraftPerformance perf_glide(glide_polar); AirspaceInterceptSolution solution; airspace.Intercept(state, c, GetProjection(), perf_glide, solution); if (warning == nullptr) warning = GetNewWarningPtr(airspace); warning->UpdateSolution(AirspaceWarning::WARNING_INSIDE, solution); found = true; } } return found; }
bool AbortTask::UpdateSample(const AircraftState &state, const GlidePolar &glide_polar, bool full_update) { assert(state.location.IsValid()); Clear(); unsigned active_waypoint_on_entry; if (is_active) active_waypoint_on_entry = active_waypoint; else { active_waypoint = 0; active_waypoint_on_entry = (unsigned) -1 ; } active_task_point = 0; // default to best result if can't find user-set one if (!glide_polar.IsValid()) /* can't work without a polar */ return false; AlternateList approx_waypoints; approx_waypoints.reserve(128); WaypointVisitorVector wvv(approx_waypoints); waypoints.VisitWithinRange(state.location, GetAbortRange(state, glide_polar), wvv); if (approx_waypoints.empty()) { /** @todo increase range */ return false; } // sort by arrival time // first try with final glide only reachable_landable |= FillReachable(state, approx_waypoints, glide_polar, true, true, true); reachable_landable |= FillReachable(state, approx_waypoints, glide_polar, false, true, true); // inform clients that the landable reachable scan has been performed ClientUpdate(state, true); // now try without final glide constraint and not preferring airports FillReachable(state, approx_waypoints, glide_polar, false, false, false); // inform clients that the landable unreachable scan has been performed ClientUpdate(state, false); if (task_points.size()) { const TaskWaypoint &task_point = task_points[active_task_point].point; active_waypoint = task_point.GetWaypoint().id; if (is_active && (active_waypoint_on_entry != active_waypoint)) { stats.start.Reset(); force_full_update = true; return true; } } return false; // nothing to do }