void TaskStatistics(NMEA_INFO *Basic, DERIVED_INFO *Calculated, const double this_maccready) { if (!ValidTaskPoint(ActiveWayPoint) || ((ActiveWayPoint>0) && !ValidTaskPoint(ActiveWayPoint-1))) { Calculated->LegSpeed = 0; Calculated->LegDistanceToGo = 0; Calculated->LegDistanceCovered = 0; Calculated->LegTimeToGo = 0; if (!AATEnabled) { Calculated->AATTimeToGo = 0; } // Calculated->TaskSpeed = 0; Calculated->TaskDistanceToGo = 0; Calculated->TaskDistanceCovered = 0; Calculated->TaskTimeToGo = 0; Calculated->LKTaskETE = 0; Calculated->TaskTimeToGoTurningNow = -1; Calculated->TaskAltitudeRequired = 0; Calculated->TaskAltitudeDifference = 0; Calculated->TaskAltitudeDifference0 = 0; Calculated->TaskAltitudeArrival = 0; Calculated->TerrainWarningLatitude = 0.0; Calculated->TerrainWarningLongitude = 0.0; Calculated->GRFinish = INVALID_GR; Calculated->FinalGlide = false; CheckGlideThroughTerrain(Basic, Calculated); // BUGFIX 091123 // no task selected, so work things out at current heading GlidePolar::MacCreadyAltitude(this_maccready, 100.0, Basic->TrackBearing, Calculated->WindSpeed, Calculated->WindBearing, &(Calculated->BestCruiseTrack), &(Calculated->VMacCready), (Calculated->FinalGlide==true), NULL, 1.0e6, CRUISE_EFFICIENCY); return; } // LockFlightData(); LockTaskData(); // Calculate Task Distances // First calculate distances for this waypoint double LegCovered, LegToGo=0, LegXTD=0, LegCurrentCourse; double LegDistance, LegBearing=0; bool calc_turning_now; double w1lat; double w1lon; double w0lat; double w0lon; if (AATEnabled && (ActiveWayPoint>0) && (ValidTaskPoint(ActiveWayPoint))) { w1lat = Task[ActiveWayPoint].AATTargetLat; w1lon = Task[ActiveWayPoint].AATTargetLon; } else { w1lat = WayPointList[TASKINDEX].Latitude; w1lon = WayPointList[TASKINDEX].Longitude; } DistanceBearing(Basic->Latitude, Basic->Longitude, w1lat, w1lon, &LegToGo, &LegBearing); if (AATEnabled && (ActiveWayPoint>0) && ValidTaskPoint(ActiveWayPoint+1) && Calculated->IsInSector && (this_maccready>0.1) ) { calc_turning_now = true; } else { calc_turning_now = false; } if (ActiveWayPoint<1) { LegCovered = 0; LegCurrentCourse=LegBearing; if (ValidTaskPoint(ActiveWayPoint+1)) { // BUGFIX 091221 LegToGo=0; } } else { if (AATEnabled) { LKASSERT((ActiveWayPoint-1)>=0); // TODO accuracy: Get best range point to here... w0lat = Task[ActiveWayPoint-1].AATTargetLat; w0lon = Task[ActiveWayPoint-1].AATTargetLon; } else { LKASSERT((ActiveWayPoint-1)>=0); LKASSERT(ValidTaskPoint(ActiveWayPoint-1)); w0lat = WayPointList[Task[ActiveWayPoint-1].Index].Latitude; w0lon = WayPointList[Task[ActiveWayPoint-1].Index].Longitude; } DistanceBearing(w1lat, w1lon, w0lat, w0lon, &LegDistance, NULL); LegCovered = ProjectedDistance(w0lon, w0lat, w1lon, w1lat, Basic->Longitude, Basic->Latitude, &LegXTD, &LegCurrentCourse); if ((StartLine==0) && (ActiveWayPoint==1)) { // Correct speed calculations for radius // JMW TODO accuracy: legcovered replace this with more accurate version // LegDistance -= StartRadius; LegCovered = max(0.0, LegCovered-StartRadius); } } Calculated->LegDistanceToGo = LegToGo; Calculated->LegDistanceCovered = LegCovered; Calculated->LegCrossTrackError = LegXTD; Calculated->LegActualTrueCourse = LegCurrentCourse; Calculated->TaskDistanceCovered = LegCovered; if (Basic->Time > Calculated->LegStartTime) { if (flightstats.LegStartTime[ActiveWayPoint]<0) { flightstats.LegStartTime[ActiveWayPoint] = Basic->Time; } Calculated->LegSpeed = Calculated->LegDistanceCovered / (Basic->Time - Calculated->LegStartTime); } // Now add distances for start to previous waypoint if (!AATEnabled) { for(int i=0;i< ActiveWayPoint-1; i++) { if (!ValidTaskPoint(i) || !ValidTaskPoint(i+1)) continue; w1lat = WayPointList[Task[i].Index].Latitude; w1lon = WayPointList[Task[i].Index].Longitude; w0lat = WayPointList[Task[i+1].Index].Latitude; w0lon = WayPointList[Task[i+1].Index].Longitude; DistanceBearing(w1lat, w1lon, w0lat, w0lon, &LegDistance, NULL); Calculated->TaskDistanceCovered += LegDistance; } } else if (ActiveWayPoint>0) { // JMW added correction for distance covered Calculated->TaskDistanceCovered = aatdistance.DistanceCovered(Basic->Longitude, Basic->Latitude, ActiveWayPoint); } CheckTransitionFinalGlide(Basic, Calculated); // accumulators double TaskAltitudeRequired = 0; double TaskAltitudeRequired0 = 0; Calculated->TaskDistanceToGo = 0; Calculated->TaskTimeToGo = 0; Calculated->LKTaskETE = 0; Calculated->TaskTimeToGoTurningNow = 0; Calculated->TaskAltitudeArrival = 0; double LegTime0; // Calculate Final Glide To Finish int FinalWayPoint = getFinalWaypoint(); double final_height = FAIFinishHeight(Basic, Calculated, -1); double total_energy_height = Calculated->NavAltitude + Calculated->EnergyHeight; double height_above_finish = total_energy_height - final_height; if (ISPARAGLIDER) { TaskAltitudeRequired = final_height; TaskAltitudeRequired0 = final_height; } // Now add it for remaining waypoints int task_index= FinalWayPoint; double StartBestCruiseTrack = -1; while ((task_index>ActiveWayPoint) && (ValidTaskPoint(task_index))) { double this_LegTimeToGo; bool this_is_final = (task_index==FinalWayPoint) || ForceFinalGlide; this_is_final = true; // JMW CHECK FGAMT if (AATEnabled) { w1lat = Task[task_index].AATTargetLat; w1lon = Task[task_index].AATTargetLon; w0lat = Task[task_index-1].AATTargetLat; w0lon = Task[task_index-1].AATTargetLon; } else { w1lat = WayPointList[Task[task_index].Index].Latitude; w1lon = WayPointList[Task[task_index].Index].Longitude; w0lat = WayPointList[Task[task_index-1].Index].Latitude; w0lon = WayPointList[Task[task_index-1].Index].Longitude; } double NextLegDistance, NextLegBearing; DistanceBearing(w0lat, w0lon, w1lat, w1lon, &NextLegDistance, &NextLegBearing); double LegAltitude = GlidePolar:: MacCreadyAltitude(this_maccready, NextLegDistance, NextLegBearing, Calculated->WindSpeed, Calculated->WindBearing, 0, 0, this_is_final, &this_LegTimeToGo, height_above_finish, CRUISE_EFFICIENCY); double LegAltitude0 = GlidePolar:: MacCreadyAltitude(0, NextLegDistance, NextLegBearing, Calculated->WindSpeed, Calculated->WindBearing, 0, 0, true, &LegTime0, 1.0e6, CRUISE_EFFICIENCY ); if (LegTime0>=0.9*ERROR_TIME) { // can't make it, so assume flying at current mc LegAltitude0 = LegAltitude; } TaskAltitudeRequired += LegAltitude; TaskAltitudeRequired0 += LegAltitude0; if(ISPARAGLIDER) { // if required altitude is less than previous turpoint altitude, // use previous turn point altitude double w0Alt = FAIFinishHeight(Basic, Calculated, task_index-1); if(TaskAltitudeRequired < w0Alt) { Calculated->TaskAltitudeArrival += w0Alt - TaskAltitudeRequired; TaskAltitudeRequired = w0Alt; } if(TaskAltitudeRequired0 < w0Alt) { TaskAltitudeRequired0 = w0Alt; } } Calculated->TaskDistanceToGo += NextLegDistance; Calculated->TaskTimeToGo += this_LegTimeToGo; if (task_index==1) { StartBestCruiseTrack = NextLegBearing; } if (calc_turning_now) { if (task_index == ActiveWayPoint+1) { double NextLegDistanceTurningNow, NextLegBearingTurningNow; double this_LegTimeToGo_turningnow=0; DistanceBearing(Basic->Latitude, Basic->Longitude, w1lat, w1lon, &NextLegDistanceTurningNow, &NextLegBearingTurningNow); GlidePolar:: MacCreadyAltitude(this_maccready, NextLegDistanceTurningNow, NextLegBearingTurningNow, Calculated->WindSpeed, Calculated->WindBearing, 0, 0, this_is_final, &this_LegTimeToGo_turningnow, height_above_finish, CRUISE_EFFICIENCY); Calculated->TaskTimeToGoTurningNow += this_LegTimeToGo_turningnow; } else { Calculated->TaskTimeToGoTurningNow += this_LegTimeToGo; } } height_above_finish-= LegAltitude; task_index--; } // current waypoint, do this last! if (AATEnabled && (ActiveWayPoint>0) && ValidTaskPoint(ActiveWayPoint+1) && Calculated->IsInSector) { if (Calculated->WaypointDistance<AATCloseDistance()*3.0) { LegBearing = AATCloseBearing(Basic, Calculated); } } #ifdef BCT_ALT_FIX // Don't calculate BCT yet. LegAltitude will be used to calculate // task altitude difference, which will then be used to calculate BCT. #endif double LegAltitude = GlidePolar::MacCreadyAltitude(this_maccready, LegToGo, LegBearing, Calculated->WindSpeed, Calculated->WindBearing, #ifdef BCT_ALT_FIX 0, #else &(Calculated->BestCruiseTrack), #endif &(Calculated->VMacCready), // (Calculated->FinalGlide==1), true, // JMW CHECK FGAMT &(Calculated->LegTimeToGo), height_above_finish, CRUISE_EFFICIENCY); double LegAltitude0 = GlidePolar::MacCreadyAltitude(0, LegToGo, LegBearing, Calculated->WindSpeed, Calculated->WindBearing, 0, 0, true, &LegTime0, 1.0e6, CRUISE_EFFICIENCY ); #ifndef BCT_ALT_FIX // fix problem of blue arrow wrong in task sector if (StartBestCruiseTrack>=0) // use it only if assigned, workaround if (Calculated->IsInSector && (ActiveWayPoint==0)) { // set best cruise track to first leg bearing when in start sector Calculated->BestCruiseTrack = StartBestCruiseTrack; } #endif // JMW TODO accuracy: Use safetymc where appropriate if (LegTime0>= 0.9*ERROR_TIME) { // can't make it, so assume flying at current mc LegAltitude0 = LegAltitude; } TaskAltitudeRequired += LegAltitude; TaskAltitudeRequired0 += LegAltitude0; Calculated->TaskDistanceToGo += LegToGo; Calculated->TaskTimeToGo += Calculated->LegTimeToGo; #ifndef BCT_ALT_FIX height_above_finish-= LegAltitude; #endif if (calc_turning_now) { Calculated->TaskTimeToGoTurningNow += Basic->Time-Calculated->TaskStartTime; } else { Calculated->TaskTimeToGoTurningNow = -1; } if (ISPARAGLIDER) { Calculated->TaskAltitudeRequired = TaskAltitudeRequired; } else { Calculated->TaskAltitudeRequired = TaskAltitudeRequired + final_height; TaskAltitudeRequired0 += final_height; } Calculated->TaskAltitudeDifference = total_energy_height - Calculated->TaskAltitudeRequired; Calculated->TaskAltitudeDifference0 = total_energy_height - TaskAltitudeRequired0; Calculated->NextAltitudeDifference0 = total_energy_height - Calculated->NextAltitudeRequired0; Calculated->TaskAltitudeArrival += Calculated->TaskAltitudeDifference; Calculated->GRFinish= CalculateGlideRatio(Calculated->TaskDistanceToGo, Calculated->NavAltitude - final_height); if (Calculated->TaskSpeedAchieved >0) Calculated->LKTaskETE = Calculated->TaskDistanceToGo/Calculated->TaskSpeedAchieved; else Calculated->LKTaskETE=0; #ifdef BCT_ALT_FIX // This MCA call's only purpose is to update BestCruiseTrack (BCT). // It must occur after TaskAltitudeDifference (TAD) is updated, // since BCT depends on TAD. GlidePolar::MacCreadyAltitude(this_maccready, LegToGo, LegBearing, Calculated->WindSpeed, Calculated->WindBearing, &(Calculated->BestCruiseTrack), 0, true, 0, height_above_finish, CRUISE_EFFICIENCY, Calculated->TaskAltitudeDifference); // fix problem of blue arrow wrong in task sector if (StartBestCruiseTrack>=0) // use it only if assigned, workaround if (Calculated->IsInSector && (ActiveWayPoint==0)) { // set best cruise track to first leg bearing when in start sector Calculated->BestCruiseTrack = StartBestCruiseTrack; } height_above_finish-= LegAltitude; #endif CheckGlideThroughTerrain(Basic, Calculated); CheckForceFinalGlide(Basic, Calculated); UnlockTaskData(); }
void DistanceToNext(NMEA_INFO *Basic, DERIVED_INFO *Calculated) { // LockFlightData(); LockTaskData(); if(ValidTaskPoint(ActiveWayPoint)) { double w1lat, w1lon; double w0lat, w0lon; if(DoOptimizeRoute()) { w0lat = Task[ActiveWayPoint].AATTargetLat; w0lon = Task[ActiveWayPoint].AATTargetLon; } else { w0lat = WayPointList[TASKINDEX].Latitude; w0lon = WayPointList[TASKINDEX].Longitude; } DistanceBearing(Basic->Latitude, Basic->Longitude, w0lat, w0lon, &Calculated->WaypointDistance, &Calculated->WaypointBearing); Calculated->ZoomDistance = Calculated->WaypointDistance; if (AATEnabled && (ActiveWayPoint>0) && ValidTaskPoint(ActiveWayPoint+1)) { w1lat = Task[ActiveWayPoint].AATTargetLat; w1lon = Task[ActiveWayPoint].AATTargetLon; DistanceBearing(Basic->Latitude, Basic->Longitude, w1lat, w1lon, &Calculated->WaypointDistance, &Calculated->WaypointBearing); if (Calculated->WaypointDistance>AATCloseDistance()*3.0) { Calculated->ZoomDistance = max(Calculated->WaypointDistance, Calculated->ZoomDistance); } else { Calculated->WaypointBearing = AATCloseBearing(Basic, Calculated); } } else if ((ActiveWayPoint==0) && (ValidTaskPoint(ActiveWayPoint+1)) && (Calculated->IsInSector) ) { // JMW set waypoint bearing to start direction if in start sector if (AATEnabled) { w1lat = Task[ActiveWayPoint+1].AATTargetLat; w1lon = Task[ActiveWayPoint+1].AATTargetLon; } else { w1lat = WayPointList[Task[ActiveWayPoint+1].Index].Latitude; w1lon = WayPointList[Task[ActiveWayPoint+1].Index].Longitude; } DistanceBearing(Basic->Latitude, Basic->Longitude, w1lat, w1lon, NULL, &Calculated->WaypointBearing); } } else { Calculated->ZoomDistance = 0; Calculated->WaypointDistance = 0; Calculated->WaypointBearing = 0; } UnlockTaskData(); // UnlockFlightData(); }