bool DevLX16xx::PutGPRMB(PDeviceDescriptor_t d) { //RMB - The recommended minimum navigation sentence is sent whenever a route or a goto is active. // On some systems it is sent all of the time with null data. // The Arrival alarm flag is similar to the arrival alarm inside the unit and can be decoded to // drive an external alarm. // Note: the use of leading zeros in this message to preserve the character spacing. // This is done, I believe, because some autopilots may depend on exact character spacing. // // $GPRMB,A,0.66,L,003,004,4917.24,N,12309.57,W,001.3,052.5,000.5,V*20 //where: // RMB Recommended minimum navigation information // A Data status A = OK, V = Void (warning) // 0.66,L Cross-track error (nautical miles, 9.99 max), // steer Left to correct (or R = right) // 003 Origin waypoint ID // 004 Destination waypoint ID // 4917.24,N Destination waypoint latitude 49 deg. 17.24 min. N // 12309.57,W Destination waypoint longitude 123 deg. 09.57 min. W // 001.3 Range to destination, nautical miles (999.9 max) // 052.5 True bearing to destination // 000.5 Velocity towards destination, knots // V Arrival alarm A = arrived, V = not arrived // *20 checksum TCHAR szTmp[256]; /* extern START_POINT StartPoints[]; extern TASK_POINT Task[]; extern TASKSTATS_POINT TaskStats[]; extern WAYPOINT *WayPointList; extern WPCALC *WayPointCalc; */ //WayPointCalc-> int overindex = GetOvertargetIndex(); if (!ValidWayPoint(overindex)) return TRUE; _stprintf( szTmp, TEXT("$GPRMB,A,0.66,L,EDLG,%6s,%010.5f,N,%010.5f,E,%05.1f,%05.1f,%05.1f,V"), WayPointList[overindex].Name, WayPointList[overindex].Latitude * 100, WayPointList[overindex].Longitude * 100, WayPointCalc[0].Distance * 1000 * TONAUTICALMILES, WayPointCalc[0].Bearing, WayPointCalc[0].VGR * TOKNOTS); // _stprintf(szTmp, TEXT("$GPRMB,A,0.00,L,KLE,UWOE,4917.24,N,12309.57,E,011.3,052.5,000.5,V")); LX16xxNMEAddCheckSumStrg(szTmp); d->Com->WriteString(szTmp); return(true); }
// return current overtarget waypoint name with leading identifier, even if empty // exception for TEAM MATE: always report OWN CODE if available void GetOvertargetName(TCHAR *overtargetname) { int index; if (OvertargetMode == OVT_MATE) { if (ValidWayPoint(TeamCodeRefWaypoint)) { if (TeammateCodeValid) _stprintf(overtargetname,_T("%s> %s"), GetOvertargetHeader(),CALCULATED_INFO.OwnTeamCode); else _stprintf(overtargetname,_T("%s: %s"), GetOvertargetHeader(),CALCULATED_INFO.OwnTeamCode); } else _stprintf(overtargetname,_T("%s ---"),GetOvertargetHeader()); return; } index=GetOvertargetIndex(); if (index<0) _stprintf(overtargetname,_T("%s ---"),GetOvertargetHeader()); else _stprintf(overtargetname,_T("%s%s"), GetOvertargetHeader(),WayPointList[index].Name); }
void MapWindow::DrawBearing(HDC hdc, const RECT rc) { int overindex=GetOvertargetIndex(); if (overindex<0) return; double startLat = DrawInfo.Latitude; double startLon = DrawInfo.Longitude; double targetLat; double targetLon; if (OvertargetMode>OVT_TASK) { LockTaskData(); targetLat = WayPointList[overindex].Latitude; targetLon = WayPointList[overindex].Longitude; UnlockTaskData(); DrawGreatCircle(hdc, startLon, startLat, targetLon, targetLat, rc); } else { if (!ValidTaskPoint(ActiveWayPoint)) { return; } LockTaskData(); if (AATEnabled && ( DoOptimizeRoute() || ((ActiveWayPoint>0) && ValidTaskPoint(ActiveWayPoint+1))) ) { targetLat = Task[ActiveWayPoint].AATTargetLat; targetLon = Task[ActiveWayPoint].AATTargetLon; } else { targetLat = WayPointList[Task[ActiveWayPoint].Index].Latitude; targetLon = WayPointList[Task[ActiveWayPoint].Index].Longitude; } UnlockTaskData(); DrawGreatCircle(hdc, startLon, startLat, targetLon, targetLat, rc); if (mode.Is(Mode::MODE_TARGET_PAN)) { // Draw all of task if in target pan mode startLat = targetLat; startLon = targetLon; LockTaskData(); for (int i=ActiveWayPoint+1; i<MAXTASKPOINTS; i++) { if (ValidTaskPoint(i)) { if (AATEnabled && ValidTaskPoint(i+1)) { targetLat = Task[i].AATTargetLat; targetLon = Task[i].AATTargetLon; } else { targetLat = WayPointList[Task[i].Index].Latitude; targetLon = WayPointList[Task[i].Index].Longitude; } DrawGreatCircle(hdc, startLon, startLat, targetLon, targetLat, rc); startLat = targetLat; startLon = targetLon; } } UnlockTaskData(); } } if (AATEnabled) { // draw symbol at target, makes it easier to see LockTaskData(); if(mode.Is(Mode::MODE_TARGET_PAN)) { for(int i=ActiveWayPoint+1; i<MAXTASKPOINTS; i++) { if(ValidTaskPoint(i) && ValidTaskPoint(i+1)) { if(i>= ActiveWayPoint) { POINT sct; LatLon2Screen(Task[i].AATTargetLon, Task[i].AATTargetLat, sct); DrawBitmapIn(hdc, sct, hBmpTarget,true); } } } } if(ValidTaskPoint(ActiveWayPoint+1) && (DoOptimizeRoute() || (ActiveWayPoint>0)) ) { POINT sct; LatLon2Screen(Task[ActiveWayPoint].AATTargetLon, Task[ActiveWayPoint].AATTargetLat, sct); DrawBitmapIn(hdc, sct, hBmpTarget,true); } UnlockTaskData(); } }
bool DevLXV7_EXP::PutGPRMB(PDeviceDescriptor_t d) { //RMB - The recommended minimum navigation sentence is sent whenever a route or a goto is active. // On some systems it is sent all of the time with null data. // The Arrival alarm flag is similar to the arrival alarm inside the unit and can be decoded to // drive an external alarm. // Note: the use of leading zeros in this message to preserve the character spacing. // This is done, I believe, because some autopilots may depend on exact character spacing. // // $GPRMB,A,0.66,L,003,004,4917.24,N,12309.57,W,001.3,052.5,000.5,V*20 //where: // RMB Recommended minimum navigation information // A Data status A = OK, V = Void (warning) // 0.66,L Cross-track error (nautical miles, 9.99 max), // steer Left to correct (or R = right) // 003 Origin waypoint ID // 004 Destination waypoint ID // 4917.24,N Destination waypoint latitude 49 deg. 17.24 min. N // 12309.57,W Destination waypoint longitude 123 deg. 09.57 min. W // 001.3 Range to destination, nautical miles (999.9 max) // 052.5 True bearing to destination // 000.5 Velocity towards destination, knots // V Arrival alarm A = arrived, V = not arrived // *20 checksum static int old_overindex = -99; static int old_overmode = -99; int overindex = GetOvertargetIndex(); int overmode = OvertargetMode; bool bTaskpresent = false; //ValidTaskPoint(0); if(bTaskpresent) if(ValidTaskPoint(ActiveWayPoint)) overindex = Task[ActiveWayPoint].Index; #define SEND_ON_CHANGE_ONLY #ifdef SEND_ON_CHANGE_ONLY if(overindex < 0) /* vaslid waypoint */ return -1; if(overindex == old_overindex) /* same as before */ if(overmode == old_overmode) /* and same mode */ return 0; #endif old_overindex = overindex; old_overmode = overmode; TCHAR szTmp[512]; int DegLat, DegLon; double MinLat, MinLon; char NoS, EoW; if (!ValidWayPoint(overindex)) return TRUE; DegLat = (int)WayPointList[overindex].Latitude; MinLat = WayPointList[overindex].Latitude - DegLat; NoS = 'N'; if((MinLat<0) || ((MinLat-DegLat==0) && (DegLat<0))) { NoS = 'S'; DegLat *= -1; MinLat *= -1; } MinLat *= 60; DegLon = (int)WayPointList[overindex].Longitude ; MinLon = WayPointList[overindex].Longitude - DegLon; EoW = 'E'; if((MinLon<0) || ((MinLon-DegLon==0) && (DegLon<0))) { EoW = 'W'; DegLon *= -1; MinLon *= -1; } MinLon *=60; #define SET_VALUES_BY_RMB #ifdef SET_VALUES_BY_RMB if(bTaskpresent) { #ifdef NO_RMB_BUT_PLXVTARG // $GPRMB,A,0.66,L,003,004 ,4917.24 ,N ,12309.57 ,W ,01.3,52.5,00.5,V*20 _stprintf( szTmp, TEXT("$GPRMB,A,0.00,R,XXX,%s%s,%02d%05.2f,%c,%03d%05.2f,%c,%.1f,%.1f,%.1f,V"), gettext(TEXT("_@M1323_")), // LKTOKEN _@M1323_ "T>" WayPointList[overindex].Name, DegLat, MinLat, NoS, DegLon, MinLon, EoW, WayPointCalc[overindex].Distance * TONAUTICALMILES, WayPointCalc[overindex].Bearing, WayPointCalc[overindex].VGR * TOKNOTS ); LXV7_EXPNMEAddCheckSumStrg(szTmp); d->Com->WriteString(szTmp); #if TESTBENCH StartupStore(TEXT("V7: %s"),szTmp); #endif #else _stprintf( szTmp, TEXT("$PLXVTARG,%s%s,%02d%05.2f,%c,%03d%05.2f,%c,%i "), gettext(TEXT("_@M1323_")), // LKTOKEN _@M1323_ "T>" WayPointList[overindex].Name, DegLat, MinLat, NoS, DegLon, MinLon, EoW, (int) (WayPointList[overindex].Altitude +0.5) ); LXV7_EXPNMEAddCheckSumStrg(szTmp); d->Com->WriteString(szTmp); #endif #if TESTBENCH StartupStore(TEXT("V7: %s"),szTmp); #endif } else { // $GPRMB,A,0.66,L,003,004 ,4917.24 ,N ,12309.57 ,W ,01.3,52.5,00.5,V*20 #ifdef NO_RMB_BUT_PLXVTARG _stprintf( szTmp, TEXT("$GPRMB,A,0.00,R,XXX,%s%s,%02d%05.2f,%c,%03d%05.2f,%c,%.1f,%.1f,%.1f,V"), GetOvertargetHeader(), WayPointList[overindex].Name, DegLat, MinLat, NoS, DegLon, MinLon, EoW, WayPointCalc[overindex].Distance * TONAUTICALMILES, WayPointCalc[overindex].Bearing, WayPointCalc[overindex].VGR * TOKNOTS ); LXV7_EXPNMEAddCheckSumStrg(szTmp); d->Com->WriteString(szTmp); #if TESTBENCH StartupStore(TEXT("V7: %s"),szTmp); #endif #else _stprintf( szTmp, TEXT("$PLXVTARG,%s%s,%02d%05.2f,%c,%03d%05.2f,%c,%i "), GetOvertargetHeader(), WayPointList[overindex].Name, DegLat, MinLat, NoS, DegLon, MinLon, EoW, (int)(WayPointList[overindex].Altitude +0.5) ); LXV7_EXPNMEAddCheckSumStrg(szTmp); d->Com->WriteString(szTmp); #endif #if TESTBENCH StartupStore(TEXT("V7: %s"),szTmp); #endif } #else /**************** * SYm style ****************/ _stprintf( szTmp, TEXT("$PFLX4,,,,%.f,%.f,,,,0,"), WayPointCalc[overindex].Distance, -WayPointCalc[overindex].AltReqd[AltArrivMode]*TOFEET ); LXV7_EXPNMEAddCheckSumStrg(szTmp); d->Com->WriteString(szTmp); #if TESTBENCH StartupStore(TEXT("V7: %s"),szTmp); #endif #endif return(true); }
void MapWindow::LKCalculateWaypointReachable(const bool forced) { #if USEONEHZLIMITER if (!forced) ONEHZLIMITER; #endif static short multicalc_slot=0; // -1 (which becomes immediately 0) will force full loading on startup, but this is not good // because currently we are not waiting for ProgramStarted=3 // and the first scan is made while still initializing other things short numslots=1; // TODO assign numslots with a function, based also on available CPU time if (NumberOfWayPoints>200) { numslots=NumberOfWayPoints/400; // keep numslots optimal if (numslots<MULTICALC_MINROBIN) numslots=MULTICALC_MINROBIN; // seconds for full scan, as this is executed at 1Hz if (numslots>MULTICALC_MAXROBIN) numslots=MULTICALC_MAXROBIN; // When waypointnumber has changed, we wont be using an exceeded multicalc_slot, which would crash the sw // In this case, we shall probably continue for the first round to calculate without going from the beginning // but this is not a problem, we are round-robin all the time here. if (++multicalc_slot>numslots) multicalc_slot=1; } else { multicalc_slot=0; // forcing full scan } unsigned int i; double waypointDistance, waypointBearing,altitudeRequired,altitudeDifference; // LandableReachable is used only by the thermal bar indicator in MapWindow2, after here // apparently, is used to tell you if you are below final glide but in range for a landable wp // Since nov 2011 we dont user LandableReachable in FinalGlide anymore. // However it is still to be understood what drawbacks we might have by changing calculations here. LandableReachable = false; if (!WayPointList) return; unsigned int scanstart; unsigned int scanend; #if DEBUGCW unsigned int numwpscanned=0; #endif LockTaskData(); if (multicalc_slot==0) { scanstart=0; // including this scanend=NumberOfWayPoints; // will be used -1, so up to this excluded value #if DEBUGCW StartupStore(_T("... wps=%d multicalc_slot=0 ignored numslot=%d, full scan %d < %d%s"),NumberOfWayPoints, numslots,scanstart,scanend,NEWLINE); #endif } else { scanstart=(NumberOfWayPoints/numslots)*(multicalc_slot-1); if (multicalc_slot==numslots) scanend=NumberOfWayPoints; else scanend=scanstart+(NumberOfWayPoints/numslots); #if DEBUGCW StartupStore(_T("... wps=%d multicalc_slot=%d of %d, scan %d < %d%s"),NumberOfWayPoints, multicalc_slot, numslots,scanstart,scanend,NEWLINE); #endif } int overtarg=GetOvertargetIndex(); if (overtarg<0) overtarg=999999; for(i=scanstart;i<scanend;i++) { // signed Overtgarget -1 becomes a very high number, casted unsigned if ( ( ((WayPointCalc[i].AltArriv[AltArrivMode] >=0)||(WayPointList[i].Visible)) && (WayPointCalc[i].IsLandable || (WayPointList[i].Style==STYLE_THERMAL))) || WaypointInTask(i) || (i==(unsigned int)overtarg) ) { DistanceBearing(DrawInfo.Latitude, DrawInfo.Longitude, WayPointList[i].Latitude, WayPointList[i].Longitude, &waypointDistance, &waypointBearing); WayPointCalc[i].Distance=waypointDistance; WayPointCalc[i].Bearing=waypointBearing; CalculateGlideRatio(waypointDistance, DerivedDrawInfo.NavAltitude - WayPointList[i].Altitude - GetSafetyAltitude(i)); altitudeRequired = GlidePolar::MacCreadyAltitude (GetMacCready(i,0), waypointDistance, waypointBearing, DerivedDrawInfo.WindSpeed, DerivedDrawInfo.WindBearing, 0,0,true,0) + WayPointList[i].Altitude + GetSafetyAltitude(i) - DerivedDrawInfo.EnergyHeight; WayPointCalc[i].AltReqd[AltArrivMode] = altitudeRequired; WayPointList[i].AltArivalAGL = DerivedDrawInfo.NavAltitude - altitudeRequired; if(WayPointList[i].AltArivalAGL >=0){ WayPointList[i].Reachable = TRUE; if (CheckLandableReachableTerrainNew(&DrawInfo, &DerivedDrawInfo, waypointDistance, waypointBearing)) { if ((signed)i!=TASKINDEX) { LandableReachable = true; } } else { WayPointList[i].Reachable = FALSE; } } else { WayPointList[i].Reachable = FALSE; } #if DEBUGCW numwpscanned++; #endif } // if landable or in task } // for all waypoints // This is wrong, because multicalc will not necessarily find the LandableReachable at each pass // As of nov 2011 it is better not to change it, and let further investigation after 3.0 if (!LandableReachable) // indentation wrong here for(i=scanstart;i<scanend;i++) { if(!WayPointList[i].Visible && WayPointList[i].FarVisible) { // visible but only at a distance (limit this to 100km radius) if( WayPointCalc[i].IsLandable ) { #if DEBUGCW numwpscanned++; #endif DistanceBearing(DrawInfo.Latitude, DrawInfo.Longitude, WayPointList[i].Latitude, WayPointList[i].Longitude, &waypointDistance, &waypointBearing); WayPointCalc[i].Distance=waypointDistance; // VENTA6 WayPointCalc[i].Bearing=waypointBearing; if (waypointDistance<100000.0) { altitudeRequired = GlidePolar::MacCreadyAltitude (GetMacCready(i,0), waypointDistance, waypointBearing, // 091221 DerivedDrawInfo.WindSpeed, DerivedDrawInfo.WindBearing, 0,0,true,0) + WayPointList[i].Altitude + GetSafetyAltitude(i); altitudeDifference = DerivedDrawInfo.NavAltitude + DerivedDrawInfo.EnergyHeight - altitudeRequired; WayPointList[i].AltArivalAGL = altitudeDifference; WayPointCalc[i].AltReqd[AltArrivMode] = altitudeRequired; if(altitudeDifference >=0){ WayPointList[i].Reachable = TRUE; if (CheckLandableReachableTerrainNew(&DrawInfo, &DerivedDrawInfo, waypointDistance, waypointBearing)) { LandableReachable = true; } else WayPointList[i].Reachable = FALSE; } else { WayPointList[i].Reachable = FALSE; } } else { WayPointList[i].Reachable = FALSE; } // <100000 } // landable wp } // visible or far visible } // for all waypoint UnlockTaskData(); #if DEBUGCW StartupStore(_T("...... processed wps: %d\n"),numwpscanned); #endif }
// // Called by LKDrawLook8000, this is what happens when we change mapspace mode, advancing through types. // We paint infopages, nearest, tri, etc.etc. // Normally there is plenty of cpu available because the map is not even calculated. // This is why we bring to the Draw thread, in the nearest pages case, also calculations. // void MapWindow::DrawMapSpace(HDC hdc, RECT rc ) { HFONT oldfont; HBRUSH hB; TextInBoxMode_t TextDisplayMode = {0}; TCHAR Buffer[LKSIZEBUFFERLARGE*2]; #ifdef DRAWLKSTATUS bool dodrawlkstatus=false; #endif static POINT p[10]; if (MapSpaceMode==MSM_WELCOME) { if (INVERTCOLORS) hB=LKBrush_Petrol; else hB=LKBrush_Mlight; } else { if (INVERTCOLORS) hB=LKBrush_Mdark; else hB=LKBrush_Mlight; } oldfont = (HFONT)SelectObject(hdc, LKINFOFONT); // save font if (MapSpaceMode!=MSM_WELCOME) FillRect(hdc,&rc, hB); if (DoInit[MDI_DRAWMAPSPACE]) { p[0].x=0; p[0].y=rc.bottom-BottomSize-NIBLSCALE(2); p[1].x=rc.right-1; p[1].y=p[0].y; p[2].x=0; p[2].y=0; p[3].x=rc.right-1; p[3].y=0; // 091230 right-1 p[4].x=0; p[4].y=0; p[5].x=0; p[5].y=rc.bottom-BottomSize-NIBLSCALE(2); p[6].x=rc.right-1; p[6].y=0; p[7].x=rc.right-1; p[7].y=rc.bottom-BottomSize-NIBLSCALE(2); // 091230 right-1 // p[8].x=0; p[8].y=rc.bottom-BottomSize-NIBLSCALE(2); p[9].x=rc.right; p[9].y=p[8].y; /* StartupStore(_T("DOINIT DRAWMAPSPACE 21=%d=%d 22=%d=%d 23=%d=%d 24=%d=%d 31=%d=%d 32=%d=%d\n"), ConfIP[LKMODE_WP][0],ConfIP21, ConfIP[LKMODE_WP][1],ConfIP22, ConfIP[LKMODE_WP][2],ConfIP23, ConfIP[LKMODE_WP][3],ConfIP24, ConfIP[LKMODE_NAV][0],ConfIP31, ConfIP[LKMODE_NAV][1],ConfIP32); */ if (MapSpaceMode==MSM_WELCOME) LoadSplash(hdc,_T("LKPROFILE")); DoInit[MDI_DRAWMAPSPACE]=false; } // Paint borders in green, but only in nearest pages and welcome if (MapSpaceMode==MSM_WELCOME || (!IsMultiMap() && MapSpaceMode!=MSM_MAP) ) { if (INVERTCOLORS) { _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[2], p[3], RGB_GREEN, rc); _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[4], p[5], RGB_GREEN, rc); _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[6], p[7], RGB_GREEN, rc); _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[0], p[1], RGB_GREEN, rc); } else { _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[2], p[3], RGB_DARKGREEN, rc); _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[4], p[5], RGB_DARKGREEN, rc); _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[6], p[7], RGB_DARKGREEN, rc); _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[0], p[1], RGB_DARKGREEN, rc); } } #ifdef DRAWLKSTATUS if (LKevent==LKEVENT_NEWRUN) dodrawlkstatus=true; #endif // We are entering mapspacemodes with no initial check on configured subpages. // Thus we need to ensure that the page is really available, or find the first valid. // However, this will prevent direct customkey access to pages! // Instead, we do it when we call next page from InfoPageChange // if (!ConfIP[ModeIndex][CURTYPE]) NextModeType(); switch (MapSpaceMode) { case MSM_WELCOME: #if (1) if (!DrawInfo.NAVWarning) { static double firsttime=DrawInfo.Time; // delayed automatic exit from welcome mode if ( DrawInfo.Time > (firsttime+1.0) ) { SetModeType(LKMODE_MAP,MP_MOVING); LKevent=LKEVENT_NONE; if (EnableSoundModes) LKSound(_T("LK_BEEP1.WAV")); RefreshMap(); break; } } #endif if(GlobalModelType==MODELTYPE_PNA_MINIMAP) { SetModeType(LKMODE_MAP,MP_MOVING); LKevent=LKEVENT_NONE; break; } DrawWelcome8000(hdc, rc); break; case MSM_MAPTRK: SetSideviewPage(IM_HEADING); LKDrawMultimap_Asp(hdc,rc); break; case MSM_MAPWPT: #if 0 // If there is no destination, force jump to the map if (GetOvertargetIndex()<0) { SetModeType(LKMODE_MAP,MP_MOVING); LKevent=LKEVENT_NONE; break; } #endif SetSideviewPage(IM_NEXT_WP); LKDrawMultimap_Asp(hdc,rc); break; case MSM_MAPASP: SetSideviewPage(IM_NEAR_AS); LKDrawMultimap_Asp(hdc,rc); break; case MSM_MAPRADAR: LKDrawMultimap_Radar(hdc,rc); break; case MSM_VISUALGLIDE: SetSideviewPage(IM_VISUALGLIDE); LKDrawMultimap_Asp(hdc,rc); break; case MSM_MAPTEST: LKDrawMultimap_Test(hdc,rc); break; case MSM_LANDABLE: case MSM_NEARTPS: case MSM_AIRPORTS: DrawNearest(hdc, rc); break; case MSM_AIRSPACES: DrawAspNearest(hdc, rc); break; case MSM_COMMON: case MSM_RECENT: DrawCommon(hdc, rc); break; case MSM_MAP: break; case MSM_INFO_THERMAL: case MSM_INFO_CRUISE: case MSM_INFO_TASK: case MSM_INFO_AUX: case MSM_INFO_TRI: case MSM_INFO_HSI: case MSM_INFO_TRF: case MSM_INFO_TARGET: case MSM_INFO_CONTEST: DrawInfoPage(hdc,rc, false); break; case MSM_TRAFFIC: DrawTraffic(hdc,rc); break; case MSM_THERMALS: DrawThermalHistory(hdc,rc); break; default: memset((void*)&TextDisplayMode, 0, sizeof(TextDisplayMode)); TextDisplayMode.Color = RGB_WHITE; TextDisplayMode.NoSetFont = 1; TextDisplayMode.AlligneCenter = 1; SelectObject(hdc, LK8TargetFont); _stprintf(Buffer,TEXT("MapSpaceMode=%d"),MapSpaceMode); TextInBox(hdc, &rc, Buffer, (rc.right-rc.left)/2, NIBLSCALE(50) , 0, &TextDisplayMode, false); break; } #ifdef DRAWLKSTATUS // no need to clear dodrawlkstatus, it is already reset at each run if (dodrawlkstatus) DrawLKStatus(hdc, rc); #endif SelectObject(hdc, oldfont); }
// // Final Glide Bar, revised for variometer gauge // void MapWindow::DrawFinalGlide(HDC hDC, const RECT rc) { SIZE TextSize; if ((GlideBarMode == (GlideBarMode_t)gbDisabled)) { GlideBarOffset=0; return; } POINT GlideBar[6] = { {0,0},{9,-9},{18,0},{18,0},{9,0},{0,0} }; POINT GlideBar0[6] = { {0,0},{9,-9},{18,0},{18,0},{9,0},{0,0} }; HPEN hpOld; HBRUSH hbOld; TCHAR Value[10]; int Offset; int Offset0; int i; int lkVarioOffset=0, minBar, maxBar; if (LKVarioBar) lkVarioOffset=LKVarioSize+NIBLSCALE(2); //@ 091114 // 091114 switch(ScreenSize) { case (ScreenSize_t)ss480x234: case (ScreenSize_t)ss480x272: case (ScreenSize_t)ss720x408: minBar=-40; maxBar=40; break; case (ScreenSize_t)ss800x480: case (ScreenSize_t)ss400x240: minBar=-45; maxBar=45; break; default: minBar=-50; // was 60 maxBar=50; break; } LockTaskData(); // protect from external task changes bool invalidbar=false; #if 101004 int barindex; barindex=GetOvertargetIndex(); if (barindex>=0) { #else if (ValidTaskPoint(ActiveWayPoint)) { #endif const int y0 = ( (rc.bottom - rc.top )/2)+rc.top; #if 110609 if ( ValidTaskPoint(1) && OvertargetMode == OVT_TASK && GlideBarMode == (GlideBarMode_t)gbFinish ) { // Before the start, there is no task altitude available! if (DerivedDrawInfo.ValidStart) { Offset = ((int)DerivedDrawInfo.TaskAltitudeDifference)/8; Offset0 = ((int)DerivedDrawInfo.TaskAltitudeDifference0)/8; } else { // In this case, print an invalid bar invalidbar=true; Offset=0; Offset0=0; } } else { Offset=(int)WayPointCalc[barindex].AltArriv[AltArrivMode]; Offset0=Offset; } #else // This is wrong, we are painting values relative to MC and ignoring safetyMC if (OvertargetMode != OVT_TASK) { //@ 101004 Offset=(int)WayPointCalc[barindex].AltArriv[AltArrivMode]; Offset0=Offset; } else { // 60 units is size, div by 8 means 60*8 = 480 meters. if ( (GlideBarMode == (GlideBarMode_t)gbFinish)) { Offset = ((int)DerivedDrawInfo.TaskAltitudeDifference)/8; Offset0 = ((int)DerivedDrawInfo.TaskAltitudeDifference0)/8; } else { Offset = ((int)DerivedDrawInfo.NextAltitudeDifference)/8; Offset0 = ((int)DerivedDrawInfo.NextAltitudeDifference0)/8; } } #endif // TODO feature: should be an angle if in final glide mode if(Offset > maxBar) Offset = maxBar; if(Offset < minBar) Offset = minBar; Offset = IBLSCALE(Offset); if(Offset<0) { GlideBar[1].y = NIBLSCALE(9); } if(Offset0 > maxBar) Offset0 = maxBar; if(Offset0 < minBar) Offset0 = minBar; Offset0 = IBLSCALE(Offset0); if(Offset0<0) { GlideBar0[1].y = NIBLSCALE(9); } for(i=0; i<6; i++) { GlideBar[i].y += y0; // if vario activated GlideBar[i].x = IBLSCALE(GlideBar[i].x)+rc.left+lkVarioOffset; //@ 091114 } GlideBar[0].y -= Offset; GlideBar[1].y -= Offset; GlideBar[2].y -= Offset; for(i=0; i<6; i++) { GlideBar0[i].y += y0; GlideBar0[i].x = IBLSCALE(GlideBar0[i].x)+rc.left+lkVarioOffset; //@ 091114 } GlideBar0[0].y -= Offset0; GlideBar0[1].y -= Offset0; GlideBar0[2].y -= Offset0; if ((Offset<0)&&(Offset0<0)) { // both below if (Offset0!= Offset) { int dy = (GlideBar0[0].y-GlideBar[0].y) +(GlideBar0[0].y-GlideBar0[3].y); dy = max(NIBLSCALE(3), dy); GlideBar[3].y = GlideBar0[0].y-dy; GlideBar[4].y = GlideBar0[1].y-dy; GlideBar[5].y = GlideBar0[2].y-dy; GlideBar0[0].y = GlideBar[3].y; GlideBar0[1].y = GlideBar[4].y; GlideBar0[2].y = GlideBar[5].y; } else { Offset0 = 0; } } else if ((Offset>0)&&(Offset0>0)) { // both above GlideBar0[3].y = GlideBar[0].y; GlideBar0[4].y = GlideBar[1].y; GlideBar0[5].y = GlideBar[2].y; if (abs(Offset0-Offset)<NIBLSCALE(4)) { Offset= Offset0; } } // draw actual glide bar if (Offset<=0) { hpOld = (HPEN)SelectObject(hDC, hpFinalGlideBelow); hbOld = (HBRUSH)SelectObject(hDC, LKBrush_Red); } else { hpOld = (HPEN)SelectObject(hDC, hpFinalGlideAbove); hbOld = (HBRUSH)SelectObject(hDC, LKBrush_Green); } Polygon(hDC,GlideBar,6); // in case of invalid bar because finish mode with real task but no valid start, we skip if (invalidbar) { _tcscpy(Value,_T("---")); goto _skipout; } // draw glide bar at mc 0 and X only for OVT_TASK 101004 // we dont have mc0 calc ready for other overtargets, not granted at least if (OvertargetMode == OVT_TASK) { if (Offset0<=0) { SelectObject(hDC, hpFinalGlideBelow); SelectObject(hDC, GetStockObject(HOLLOW_BRUSH)); } else { SelectObject(hDC, hpFinalGlideAbove); SelectObject(hDC, GetStockObject(HOLLOW_BRUSH)); } if (Offset!=Offset0) { Polygon(hDC,GlideBar0,6); } // Draw an X on final glide bar if unreachable at current Mc if ( (GlideBarMode == (GlideBarMode_t)gbFinish) ) { if ((DerivedDrawInfo.TaskTimeToGo>0.9*ERROR_TIME) || ((MACCREADY<0.01) && (DerivedDrawInfo.TaskAltitudeDifference<0))) { SelectObject(hDC, LKPen_White_N2); POINT Cross[4] = { {-5, -5}, { 5, 5}, {-5, 5}, { 5, -5} }; for (i=0; i<4; i++) { Cross[i].x = IBLSCALE(Cross[i].x+9)+lkVarioOffset; //@ 091114 Cross[i].y = IBLSCALE(Cross[i].y+9)+y0; } Polygon(hDC,Cross,2); Polygon(hDC,&Cross[2],2); } } else { if ((MACCREADY<0.01) && (DerivedDrawInfo.NextAltitudeDifference<0)) { SelectObject(hDC, LKPen_White_N2); POINT Cross[4] = { {-5, -5}, { 5, 5}, {-5, 5}, { 5, -5} }; for (i=0; i<4; i++) { Cross[i].x = IBLSCALE(Cross[i].x+9)+lkVarioOffset; Cross[i].y = IBLSCALE(Cross[i].y+9)+y0; } Polygon(hDC,Cross,2); Polygon(hDC,&Cross[2],2); } } } // draw boxed value in the center if (OvertargetMode == OVT_TASK ) { //@ 101004 // A task is made of at least 2 tps, otherwise its a goto if (( (GlideBarMode == (GlideBarMode_t)gbFinish) && ValidTaskPoint(1)) ) { if(ISPARAGLIDER && DerivedDrawInfo.TaskAltitudeDifference > 0.0) { if ( (ALTITUDEMODIFY*DerivedDrawInfo.TaskAltitudeArrival) <ALTDIFFLIMIT) //@ 091114 _stprintf(Value,TEXT(" --- ")); else _stprintf(Value,TEXT("%1.0f "), ALTITUDEMODIFY*DerivedDrawInfo.TaskAltitudeArrival); } else { if ( (ALTITUDEMODIFY*DerivedDrawInfo.TaskAltitudeDifference) <ALTDIFFLIMIT) //@ 091114 _stprintf(Value,TEXT(" --- ")); else _stprintf(Value,TEXT("%1.0f "), ALTITUDEMODIFY*DerivedDrawInfo.TaskAltitudeDifference); } } else { if ( (ALTITUDEMODIFY*WayPointCalc[barindex].AltArriv[AltArrivMode]) < ALTDIFFLIMIT) _stprintf(Value,TEXT(" --- ")); else _stprintf(Value,TEXT("%1.0f "), ALTITUDEMODIFY*WayPointCalc[barindex].AltArriv[AltArrivMode]); /* * Well this was the reason why the glidebar value was out of sync with overlays if ( (ALTITUDEMODIFY*DerivedDrawInfo.NextAltitudeDifference) < ALTDIFFLIMIT) //@ 091114 _stprintf(Value,TEXT(" --- ")); else _stprintf(Value,TEXT("%1.0f "), ALTITUDEMODIFY*DerivedDrawInfo.NextAltitudeDifference); */ } } else { if ( (ALTITUDEMODIFY*WayPointCalc[barindex].AltArriv[AltArrivMode]) < ALTDIFFLIMIT) _stprintf(Value,TEXT(" --- ")); else _stprintf(Value,TEXT("%1.0f "), ALTITUDEMODIFY*WayPointCalc[barindex].AltArriv[AltArrivMode]); } _skipout: // in case of invalidbar we get here with Offset 0 if (Offset>=0) { Offset = GlideBar[2].y+Offset+NIBLSCALE(5); } else { if (Offset0>0) { Offset = GlideBar0[1].y-NIBLSCALE(15); } else { Offset = GlideBar[2].y+Offset-NIBLSCALE(15); } } // VENTA10 GetTextExtentPoint(hDC, Value, _tcslen(Value), &TextSize); GlideBarOffset=max(NIBLSCALE(11),(int)TextSize.cx) - NIBLSCALE(2); TextInBoxMode_t TextInBoxMode = {0}; TextInBoxMode.Border = true; //={1|8}; TextInBoxMode.Reachable = true; // boxed numbers are a bit too much on the left, so increase the offset TextInBox(hDC, &rc,Value, lkVarioOffset+NIBLSCALE(1), (int)Offset, 0, &TextInBoxMode); //@ 091114 SelectObject(hDC, hbOld); SelectObject(hDC, hpOld); } else GlideBarOffset=0; // 091125 BUGFIX glidebaroffset is zero when no task point { UnlockTaskData(); } }
// // Called by LKDrawLook8000, this is what happens when we change mapspace mode, advancing through types. // We paint infopages, nearest, tri, etc.etc. // Normally there is plenty of cpu available because the map is not even calculated. // This is why we bring to the Draw thread, in the nearest pages case, also calculations. // void MapWindow::DrawMapSpace(LKSurface& Surface, const RECT& rc) { BrushReference hB; TextInBoxMode_t TextDisplayMode = {0}; TCHAR Buffer[LKSIZEBUFFERLARGE*2]; #ifdef DRAWLKSTATUS bool dodrawlkstatus=false; #endif #ifndef DITHER if (MapSpaceMode==MSM_WELCOME) { if (INVERTCOLORS) hB=LKBrush_Petrol; else hB=LKBrush_Mlight; } else { if (INVERTCOLORS) hB=LKBrush_Mdark; else hB=LKBrush_Mlight; } #else if (INVERTCOLORS) hB=LKBrush_Black; else hB=LKBrush_White; #endif const auto oldfont = Surface.SelectObject(LKINFOFONT); // save font if (MapSpaceMode==MSM_WELCOME) { LKBitmap WelcomeBitmap = LoadSplash(_T("LKPROFILE")); if(WelcomeBitmap) { DrawSplash(Surface, WelcomeBitmap); } } else { Surface.FillRect(&rc, hB); } // Paint borders in green, but only in nearest pages and welcome, and not in DITHER mode // In case we want it in dithered mode, some changes are ready to be used. #ifndef DITHER if (MapSpaceMode==MSM_WELCOME || (!IsMultiMap() && MapSpaceMode!=MSM_MAP) ) { #ifdef DITHER LKPen BorderPen(PEN_SOLID, ScreenThinSize, INVERTCOLORS?RGB_WHITE:RGB_BLACK); #else LKPen BorderPen(PEN_SOLID, ScreenThinSize, INVERTCOLORS?RGB_GREEN:RGB_DARKGREEN); #endif auto OldPen = Surface.SelectObject(BorderPen); auto OldBrush = Surface.SelectObject(LK_HOLLOW_BRUSH); Surface.Rectangle(rc.left, rc.top, rc.right, rc.bottom - BottomSize); Surface.SelectObject(OldPen); Surface.SelectObject(OldBrush); } #endif #ifdef DRAWLKSTATUS if (LKevent==LKEVENT_NEWRUN) dodrawlkstatus=true; #endif // We are entering mapspacemodes with no initial check on configured subpages. // Thus we need to ensure that the page is really available, or find the first valid. // However, this will prevent direct customkey access to pages! // Instead, we do it when we call next page from InfoPageChange // if (!ConfIP[ModeIndex][CURTYPE]) NextModeType(); switch (MapSpaceMode) { case MSM_WELCOME: #if 0 SetModeType(LKMODE_MAP,MP_MOVING); RefreshMap(); break; #endif #if (1) if (!DrawInfo.NAVWarning) { static double firsttime=DrawInfo.Time; // delayed automatic exit from welcome mode if ( DrawInfo.Time > (firsttime+3.0) ) { SetModeType(LKMODE_MAP,MP_MOVING); LKevent=LKEVENT_NONE; LKSound(_T("LK_BEEP1.WAV")); RefreshMap(); break; } } #endif if(GlobalModelType==MODELTYPE_PNA_MINIMAP) { SetModeType(LKMODE_MAP,MP_MOVING); LKevent=LKEVENT_NONE; break; } DrawWelcome8000(Surface, rc); break; case MSM_MAPTRK: SetSideviewPage(IM_HEADING); LKDrawMultimap_Asp(Surface,rc); break; case MSM_MAPWPT: #if 0 // If there is no destination, force jump to the map if (GetOvertargetIndex()<0) { SetModeType(LKMODE_MAP,MP_MOVING); LKevent=LKEVENT_NONE; break; } #endif SetSideviewPage(IM_NEXT_WP); LKDrawMultimap_Asp(Surface,rc); break; case MSM_MAPASP: SetSideviewPage(IM_NEAR_AS); LKDrawMultimap_Asp(Surface,rc); break; case MSM_MAPRADAR: LKDrawMultimap_Radar(Surface,rc); break; case MSM_VISUALGLIDE: SetSideviewPage(IM_VISUALGLIDE); LKDrawMultimap_Asp(Surface,rc); break; case MSM_MAPTEST: LKDrawMultimap_Test(Surface,rc); break; case MSM_LANDABLE: case MSM_NEARTPS: case MSM_AIRPORTS: case MSM_COMMON: case MSM_RECENT: case MSM_AIRSPACES: case MSM_THERMALS: case MSM_TRAFFIC: DrawNearest(Surface, rc); break; case MSM_MAP: break; case MSM_INFO_THERMAL: case MSM_INFO_CRUISE: case MSM_INFO_TASK: case MSM_INFO_AUX: case MSM_INFO_TRI: case MSM_INFO_HSI: case MSM_INFO_TRF: case MSM_INFO_TARGET: case MSM_INFO_CONTEST: DrawInfoPage(Surface,rc, false); break; default: memset((void*)&TextDisplayMode, 0, sizeof(TextDisplayMode)); TextDisplayMode.Color = RGB_WHITE; TextDisplayMode.NoSetFont = 1; TextDisplayMode.AlligneCenter = 1; Surface.SelectObject(LK8TargetFont); _stprintf(Buffer,TEXT("MapSpaceMode=%d"),MapSpaceMode); TextInBox(Surface, &rc, Buffer, (rc.right+rc.left)/2, NIBLSCALE(50) , &TextDisplayMode, false); break; } #ifdef DRAWLKSTATUS // no need to clear dodrawlkstatus, it is already reset at each run if (dodrawlkstatus) DrawLKStatus(hdc, rc); #endif Surface.SelectObject(oldfont); }