AirspaceInterceptSolution AbstractAirspace::Intercept(const AircraftState &state, const AirspaceAircraftPerformance &perf, const GeoPoint &loc_start, const GeoPoint &loc_end) const { const bool only_vertical = (loc_start == loc_end) && (loc_start == state.location); const auto distance_start = only_vertical ? double(0) : state.location.Distance(loc_start); const auto distance_end = loc_start == loc_end ? distance_start : (only_vertical ? double(0) : state.location.Distance(loc_end)); AirspaceInterceptSolution solution = AirspaceInterceptSolution::Invalid(); // need to scan at least three sides, top, far, bottom (if not terrain) AirspaceInterceptSolution solution_candidate = AirspaceInterceptSolution::Invalid(); if (!only_vertical) { solution_candidate = InterceptVertical(state, perf, distance_start); // search near wall if (solution_candidate.IsEarlierThan(solution)) solution = solution_candidate; if (distance_end != distance_start) { // need to search far wall also solution_candidate = InterceptVertical(state, perf, distance_end); if (solution_candidate.IsEarlierThan(solution)) solution = solution_candidate; } } solution_candidate = InterceptHorizontal(state, perf, distance_start, distance_end, false); // search top wall if (solution_candidate.IsEarlierThan(solution)) solution = solution_candidate; // search bottom wall if (!altitude_base.IsTerrain()) { solution_candidate = InterceptHorizontal(state, perf, distance_start, distance_end, true); if (solution_candidate.IsEarlierThan(solution)) solution = solution_candidate; } if (solution.IsValid()) { if (solution.distance == distance_start) solution.location = loc_start; else if (solution.distance == distance_end) solution.location = loc_end; else if (distance_end > 0) solution.location = state.location.Interpolate(loc_end, solution.distance / distance_end); else solution.location = loc_start; assert(solution.distance >= 0); } return solution; }
bool AbstractAirspace::Intercept(const AircraftState &state, const AirspaceAircraftPerformance &perf, AirspaceInterceptSolution &solution, const GeoPoint &loc_start, const GeoPoint &loc_end) const { const bool only_vertical = (loc_start == loc_end) && (loc_start == state.location); const auto distance_start = only_vertical ? fixed(0) : state.location.Distance(loc_start); const auto distance_end = loc_start == loc_end ? distance_start : (only_vertical ? fixed(0) : state.location.Distance(loc_end)); AirspaceInterceptSolution solution_this = AirspaceInterceptSolution::Invalid(); // need to scan at least three sides, top, far, bottom (if not terrain) AirspaceInterceptSolution solution_candidate = AirspaceInterceptSolution::Invalid(); if (!only_vertical) { solution_candidate = InterceptVertical(state, perf, distance_start); // search near wall if (solution_candidate.IsValid() && ((solution_candidate.elapsed_time < solution_this.elapsed_time) || negative(solution_this.elapsed_time))) solution_this = solution_candidate; if (distance_end != distance_start) { // need to search far wall also solution_candidate = InterceptVertical(state, perf, distance_end); if (solution_candidate.IsValid() && ((solution_candidate.elapsed_time < solution_this.elapsed_time) || negative(solution_this.elapsed_time))) solution_this = solution_candidate; } } solution_candidate = InterceptHorizontal(state, perf, distance_start, distance_end, false); // search top wall if (solution_candidate.IsValid() && ((solution_candidate.elapsed_time < solution_this.elapsed_time) || negative(solution_this.elapsed_time))) solution_this = solution_candidate; // search bottom wall if (!altitude_base.IsTerrain()) { solution_candidate = InterceptHorizontal(state, perf, distance_start, distance_end, true); if (solution_candidate.IsValid() && ((solution_candidate.elapsed_time < solution_this.elapsed_time) || negative(solution_this.elapsed_time))) solution_this = solution_candidate; } if (solution_this.IsValid()) { solution = solution_this; if (solution.distance == distance_start) solution.location = loc_start; else if (solution.distance == distance_end) solution.location = loc_end; else if (positive(distance_end)) solution.location = state.location.Interpolate(loc_end, solution.distance / distance_end); else solution.location = loc_start; assert(!negative(solution.distance)); return true; } else solution = AirspaceInterceptSolution::Invalid(); return false; }