static void OnMultiSelectListPaintListItem(WindowControl * Sender, LKSurface& Surface) { #define PICTO_WIDTH 50 Surface.SetTextColor(RGB_BLACK); if ((DrawListIndex < iNO_ELEMENTS) &&(DrawListIndex >= 0)) { int j; static CAirspaceBase airspace_copy; int i = DrawListIndex; LKASSERT(i < MAX_LIST_ITEMS); PixelRect rc = { 0, 0, DLGSCALE(PICTO_WIDTH), static_cast<PixelScalar>(Sender->GetHeight()) }; const CAirspace* pAS = NULL; int HorDist, Bearing, VertDist; double Distance; unsigned int idx = 0; TCHAR text1[180] = {TEXT("empty")}; TCHAR text2[180] = {TEXT("empty")}; TCHAR Comment[80] = {TEXT("")}; TCHAR Comment1[80] = {TEXT("")}; Surface.SetBkColor(LKColor(0xFF, 0xFF, 0xFF)); LKASSERT(i < MAX_LIST_ITEMS); switch (Elements[i].type) { case IM_AIRSPACE: pAS = (CAirspace*) Elements[i].ptr; if (pAS) { /*********************************************************************** * here we use a local copy of the airspace, only common property exists ***********************************************************************/ airspace_copy = CAirspaceManager::Instance().GetAirspaceCopy(pAS); // airspace type already in name? if (_tcsnicmp(airspace_copy.Name(), airspace_copy.TypeName(), _tcslen(airspace_copy.TypeName())) == 0) { _stprintf(text1, TEXT("%s"), airspace_copy.Name()); // yes, take name only } else { // fixed strings max. 20 NAME_SIZE 30 => max. 30 char _stprintf(text1, TEXT("%s %s"), airspace_copy.TypeName(), airspace_copy.Name()); } CAirspaceManager::Instance().GetSimpleAirspaceAltText(Comment, sizeof (Comment) / sizeof (Comment[0]), airspace_copy.Top()); CAirspaceManager::Instance().GetSimpleAirspaceAltText(Comment1, sizeof (Comment1) / sizeof (Comment1[0]), airspace_copy.Base()); CAirspaceManager::Instance().AirspaceCalculateDistance((CAirspace*) pAS, &HorDist, &Bearing, &VertDist); _stprintf(text2, TEXT("%3.1f%s (%s - %s)"), (double) HorDist*DISTANCEMODIFY, Units::GetDistanceName(), Comment1, Comment); //8 + 8+3 21 /**************************************************************** * for drawing the airspace pictorial, we need the original data. * copy contain only base class property, not geo data, * original data are shared ressources ! * for that we need to grant all called methods are thread safe ****************************************************************/ pAS->DrawPicto(Surface, rc); } break; case IM_TASK_PT: case IM_WAYPOINT: idx = -1; LockTaskData(); // protect from external task changes if (Elements[i].type == IM_TASK_PT) { if(ValidTaskPointFast(Elements[i].iIdx)) { idx = Task[Elements[i].iIdx].Index; } } else { if(ValidWayPointFast(Elements[i].iIdx)) { idx = Elements[i].iIdx; } } // This is not a solution. It will avoid a crash but the solution is to understand // why we are getting a wrong idx, eventually. If ever we got a wrong idx! // And then this "fix" should be changed to something more useful, instead of // adopting a totally wrong waypoint for task. assert(idx < WayPointList.size()); if(idx < WayPointList.size()) { if (WayPointList[idx].Comment != NULL) { LK_tcsncpy(Comment, WayPointList[idx].Comment, 30); } else { _tcscpy(Comment, TEXT("")); } DistanceBearing(GPS_INFO.Latitude, GPS_INFO.Longitude, WayPointList[idx].Latitude, WayPointList[idx].Longitude, &Distance, NULL); if (Elements[i].type != IM_TASK_PT) { if (WayPointCalc[idx].IsLandable) { MapWindow::DrawRunway(Surface, &WayPointList[idx], rc, nullptr, 1.5, true); if (WayPointCalc[idx].IsAirport) { // remove spaces from frequency for (j = 1; j < (CUPSIZE_FREQ); j++) if (WayPointList[idx].Freq[CUPSIZE_FREQ - j] == ' ') WayPointList[idx].Freq[CUPSIZE_FREQ - j] = '\0'; if (_tcslen(WayPointList[idx].Freq) > 2) _stprintf(text1, TEXT("%s %s MHz"), WayPointList[idx].Name, WayPointList[idx].Freq); else _stprintf(text1, TEXT("%s"), WayPointList[idx].Name); } else { if (WayPointList[idx].Comment != NULL) _stprintf(text1, TEXT("%s %s"), WayPointList[idx].Name, Comment); else _stprintf(text1, TEXT("%s"), WayPointList[idx].Name); } if ((WayPointList[idx].RunwayLen >= 10) || (WayPointList[idx].RunwayDir > 0)) { _stprintf(text2, TEXT("%3.1f%s (%i%s %02i/%02i %i%s)"), Distance * DISTANCEMODIFY, Units::GetDistanceName(), (int) (WayPointList[idx].Altitude * ALTITUDEMODIFY), Units::GetAltitudeName(), (int) (WayPointList[idx].RunwayDir / 10.0 + 0.5), (int) (AngleLimit360(WayPointList[idx].RunwayDir + 180.0) / 10.0 + 0.5), (int) ((double) WayPointList[idx].RunwayLen * ALTITUDEMODIFY), Units::GetAltitudeName()); } else { _stprintf(text2, TEXT("%3.1f%s (%i%s) "), Distance * DISTANCEMODIFY, Units::GetDistanceName(), (int) (WayPointList[idx].Altitude * ALTITUDEMODIFY), Units::GetAltitudeName()); } }// waypoint isLandable else { MapWindow::DrawWaypointPicto(Surface, rc, &WayPointList[idx]); _stprintf(text1, TEXT("%s %s"), WayPointList[idx].Name, Comment); _stprintf(text2, TEXT("%3.1f%s (%i%s)"), Distance * DISTANCEMODIFY, Units::GetDistanceName(), (int) (WayPointList[idx].Altitude * ALTITUDEMODIFY), Units::GetAltitudeName()); } }// Elements IM_TASK else { int iTaskIdx = Elements[i].iIdx; MapWindow::DrawTaskPicto(Surface, iTaskIdx, rc, 3000); int iLastTaskPoint = 0; while (ValidTaskPoint(iLastTaskPoint)) iLastTaskPoint++; iLastTaskPoint--; if (iTaskIdx == 0) { // _@M2301_ "S" # S = Start Task point _stprintf(text1, TEXT("%s: (%s)"), MsgToken(2301), WayPointList[idx].Name); _stprintf(text2, TEXT("Radius %3.1f%s (%i%s)"), StartRadius * DISTANCEMODIFY, Units::GetDistanceName(), (int) (WayPointList[idx].Altitude * ALTITUDEMODIFY), Units::GetAltitudeName()); } else { if (iTaskIdx == iLastTaskPoint) { // _@M2303_ "F" // max 30 30 => max 60 char _stprintf(text1, TEXT("%s: (%s) "), MsgToken(2303), WayPointList[idx].Name); _stprintf(text2, TEXT("Radius %3.1f%s (%i%s)"), FinishRadius * DISTANCEMODIFY, Units::GetDistanceName(), (int) (WayPointList[idx].Altitude * ALTITUDEMODIFY), Units::GetAltitudeName()); } else { // _@M2302_ "T" # F = Finish point // max 30 30 => max 60 char _stprintf(text1, TEXT("%s%i: (%s) "), MsgToken(2302), iTaskIdx, WayPointList[idx].Name); double SecRadius = 0; SecRadius = SectorRadius; if (AATEnabled) { if (Task[iTaskIdx].AATType == SECTOR) SecRadius = Task[iTaskIdx].AATSectorRadius; else SecRadius = Task[iTaskIdx].AATCircleRadius; } _stprintf(text2, TEXT("Radius %3.1f%s (%i%s)"), SecRadius * DISTANCEMODIFY, Units::GetDistanceName(), (int) (WayPointList[idx].Altitude * ALTITUDEMODIFY), Units::GetAltitudeName()); } } } } UnlockTaskData(); // protect from external task changes break; } /******************** * show text ********************/ Surface.SetBackgroundTransparent(); Surface.SetTextColor(RGB_BLACK); Surface.DrawText(rc.right + DLGSCALE(2), DLGSCALE(2), text1); int ytext2 = Surface.GetTextHeight(text1); Surface.SetTextColor(RGB_DARKBLUE); Surface.DrawText(rc.right + DLGSCALE(2), ytext2, text2); } }
static BOOL FLYSEN(PDeviceDescriptor_t d, TCHAR *String, NMEA_INFO *GPS_INFO) { TCHAR ctemp[80]; double vtas; // VOID GPS SIGNAL NMEAParser::ExtractParameter(String,ctemp,8); if (_tcscmp(ctemp,_T("V"))==0) { GPS_INFO->NAVWarning=true; GPSCONNECT=false; goto label_nogps; } // ------------------------ double tmplat; double tmplon; NMEAParser::ExtractParameter(String,ctemp,1); tmplat = MixedFormatToDegrees(StrToDouble(ctemp, NULL)); NMEAParser::ExtractParameter(String,ctemp,2); tmplat = NorthOrSouth(tmplat, ctemp[0]); NMEAParser::ExtractParameter(String,ctemp,3); tmplon = MixedFormatToDegrees(StrToDouble(ctemp, NULL)); NMEAParser::ExtractParameter(String,ctemp,4); tmplon = EastOrWest(tmplon,ctemp[0]); if (!((tmplat == 0.0) && (tmplon == 0.0))) { GPS_INFO->Latitude = tmplat; GPS_INFO->Longitude = tmplon; GPS_INFO->NAVWarning=false; GPSCONNECT=true; } // GPS SPEED NMEAParser::ExtractParameter(String,ctemp,6); GPS_INFO->Speed = StrToDouble(ctemp,NULL)/10; // TRACK BEARING if (GPS_INFO->Speed>1.0) { NMEAParser::ExtractParameter(String,ctemp,5); GPS_INFO->TrackBearing = AngleLimit360(StrToDouble(ctemp, NULL)); } // HGPS NMEAParser::ExtractParameter(String,ctemp,7); GPS_INFO->Altitude = StrToDouble(ctemp,NULL); // ------------------------ label_nogps: // SATS NMEAParser::ExtractParameter(String,ctemp,9); GPS_INFO->SatellitesUsed = (int) StrToDouble(ctemp,NULL); GPS_INFO->SatellitesUsed = 4; // TIME // ignoring 00:00.00 , but that's minor problem. We don't have the date. // And no UTC, since this is local time already. NMEAParser::ExtractParameter(String,ctemp,0); double fixTime = StrToDouble(ctemp,NULL); if (fixTime>0 && GPS_INFO->SatellitesUsed>0) { double hours, mins,secs; hours = fixTime / 10000; GPS_INFO->Hour = (int)hours; mins = fixTime / 100; mins = mins - (GPS_INFO->Hour*100); GPS_INFO->Minute = (int)mins; secs = fixTime - (GPS_INFO->Hour*10000) - (GPS_INFO->Minute*100); GPS_INFO->Second = (int)secs; } // HPA from the pressure sensor // NMEAParser::ExtractParameter(String,ctemp,10); // double ps = StrToDouble(ctemp,NULL)/100; // GPS_INFO->BaroAltitude = (1 - pow(fabs(ps / QNH), 0.190284)) * 44307.69; // HBAR 1013.25 NMEAParser::ExtractParameter(String,ctemp,11); GPS_INFO->BaroAltitude = AltitudeToQNHAltitude(StrToDouble(ctemp,NULL)); // VARIO NMEAParser::ExtractParameter(String,ctemp,12); GPS_INFO->Vario = StrToDouble(ctemp,NULL)/100; // TAS NMEAParser::ExtractParameter(String,ctemp,13); vtas=StrToDouble(ctemp,NULL)/10; GPS_INFO->IndicatedAirspeed = vtas/AirDensityRatio(GPS_INFO->BaroAltitude); GPS_INFO->TrueAirspeed = vtas; if (GPS_INFO->IndicatedAirspeed >0) GPS_INFO->AirspeedAvailable = TRUE; else GPS_INFO->AirspeedAvailable = FALSE; // ignore n.14 airspeed source // OAT NMEAParser::ExtractParameter(String,ctemp,15); GPS_INFO->OutsideAirTemperature = StrToDouble(ctemp,NULL); GPS_INFO->TemperatureAvailable=TRUE; // ignore n.16 baloon temperature // BATTERY PERCENTAGES NMEAParser::ExtractParameter(String,ctemp,17); GPS_INFO->ExtBatt1_Voltage = StrToDouble(ctemp,NULL)+1000; NMEAParser::ExtractParameter(String,ctemp,18); GPS_INFO->ExtBatt2_Voltage = StrToDouble(ctemp,NULL)+1000; GPS_INFO->BaroAltitudeAvailable = TRUE; GPS_INFO->VarioAvailable = TRUE; // currently unused in LK, but ready for next future TriggerVarioUpdate(); TriggerGPSUpdate(); return TRUE; }
int LKSurface::Segment(long x, long y, int radius, const RECT& rc, double start, double end, bool horizon) { POINT pt[66]; int i; int istart; int iend; if ((x - radius) > rc.right) return false; if ((x + radius) < rc.left) return false; if ((y - radius) > rc.bottom) return false; if ((y + radius) < rc.top) return false; // JMW added faster checking... start = AngleLimit360(start); end = AngleLimit360(end); istart = iround(start / 360.0 * 64); iend = iround(end / 360.0 * 64); int npoly = 0; if (istart > iend) { iend += 64; } istart++; iend--; if (!horizon) { pt[0].x = x; pt[0].y = y; npoly = 1; } pt[npoly].x = x + (long) (radius * fastsine(start)); pt[npoly].y = y - (long) (radius * fastcosine(start)); npoly++; for (i = 0; i < 64; i++) { if (i <= iend - istart) { pt[npoly].x = x + (long) (radius * xcoords[(i + istart) % 64]); pt[npoly].y = y - (long) (radius * ycoords[(i + istart) % 64]); npoly++; } } pt[npoly].x = x + (long) (radius * fastsine(end)); pt[npoly].y = y - (long) (radius * fastcosine(end)); npoly++; if (!horizon) { pt[npoly].x = x; pt[npoly].y = y; npoly++; } else { pt[npoly].x = pt[0].x; pt[npoly].y = pt[0].y; npoly++; } if (npoly > 2) { Polygon(pt, npoly, rc); } else if (npoly > 1) { Polyline(pt, npoly, rc); } return true; }
int MapWindow::DrawCompassArc(HDC hdc, long x, long y, int radius, RECT rc, double bearing) { const int indicatorStep = 10; // For Oren: remember to always DeleteObject you create with Create, or in 1 hour any // device will run out of GDI space, including your PC... // Meanwhile, I have created LKObjects, so anytime we should use them . No need to delete them. //HPEN hPenBlack = ::CreatePen(PS_SOLID, (5), RGB(0x00,0x0,0x0)); //HPEN hPenWhite = (HPEN)CreatePen(PS_SOLID, (2), RGB(0xff,0xff,0xff)); HPEN hPenBlack = LKPen_Black_N5; HPEN hPenWhite = LKPen_White_N2; HFONT oldfont; HPEN oldpen; oldpen=(HPEN) SelectObject(hdc, hPenBlack); DrawArc(hdc, x, y,radius, rc, 300, 60); int heading = (int)(bearing +0.5); // -----------Draw the detents around the circle----------------------------- double angleDiff = heading % indicatorStep; int screenAngle = (int)(300 - angleDiff); int curHeading = (int)(heading - 60 - angleDiff); TCHAR textBuffer[32]; POINT pt[2]; int i; oldfont=(HFONT)SelectObject(hdc, LK8MediumFont); // always remember to save object or we miss font for(i = - 60; i<= 60; i+=indicatorStep,screenAngle += indicatorStep,curHeading += indicatorStep) { if ( (screenAngle < 300) && (screenAngle > 60) ) { continue; } screenAngle = (int)AngleLimit360(screenAngle); pt[0].x = x + (long) (radius * fastsine(screenAngle) ); pt[0].y = y - (long) (radius * fastcosine(screenAngle) ); // The length of the tickmarks on the compass rose double tickLength; // Make sure the display heading is between 0 and 360 int displayHeading = (int)AngleLimit360(curHeading); // If the heading is a multiple of ten, it gets a long tick if(displayHeading%30==0) { tickLength = 15; if(displayHeading%30==0) { int drawHdg = displayHeading/10; switch ( drawHdg ) { case 0: wsprintf( textBuffer, _T("N")); break; case 9: wsprintf( textBuffer, _T("E")); break; case 18: wsprintf( textBuffer, _T("S")); break; case 27: wsprintf( textBuffer, _T("W")); break; default: wsprintf( textBuffer, _T("%d"), displayHeading/10 ); } SIZE textSize; GetTextExtentPoint(hdc, textBuffer, _tcslen(textBuffer), &textSize); int textX = x + (long) ((radius - (textSize.cy/2)-2) * fastsine(screenAngle) ) - textSize.cx/2; int textY = y - (long) ((radius - (textSize.cy/2)-2) * fastcosine(screenAngle) ); drawOutlineText(hdc,textX,textY ,textBuffer,RGB_WHITE); } } else // Otherwise it gets a short tick tickLength = 10; pt[1].x = x + (long) ((radius -tickLength) * fastsine(screenAngle) ); pt[1].y = y - (long) ((radius -tickLength) * fastcosine(screenAngle) ); SelectObject(hdc, hPenBlack); ::Polyline(hdc,pt,2); SelectObject(hdc, hPenWhite); ::Polyline(hdc,pt,2); } SelectObject(hdc, hPenWhite); DrawArc(hdc, x, y,radius, rc, 300, 60); SelectObject(hdc, oldfont); SelectObject(hdc, oldpen); return 0; }
int RenderFAISector (HDC hdc, const RECT rc , double lat1, double lon1, double lat2, double lon2, int iOpposite , COLORREF fillcolor) { float fFAI_Percentage = FAI_NORMAL_PERCENTAGE; #define N_PLOYGON (3*FAI_SECTOR_STEPS) double fDist_a, fDist_b, fDist_c, fAngle; int i; int iPolyPtr=0; double lat_d,lon_d; double alpha, fDistTri, cos_alpha=0; POINT apSectorPolygon[N_PLOYGON]; POINT Pt1; DistanceBearing(lat1, lon1, lat2, lon2, &fDist_c, &fAngle); if(fabs(fDist_c) < 1000.0) /* distance too short for a FAI sector */ return -1; LKASSERT(fFAI_Percentage>0); double fDistMax = fDist_c/fFAI_Percentage; LKASSERT(fFAI_Percentage!=0.5); double fDistMin = fDist_c/(1.0-2.0*fFAI_Percentage); double fDelta_Dist = 2.0* fDist_c*fFAI_Percentage / (double)(FAI_SECTOR_STEPS); double dir = -1.0; if(fDistMax < FAI_BIG_THRESHOLD) { fDistMax = fDist_c/FAI_NORMAL_PERCENTAGE; fDistMin = fDist_c/(1.0-2.0*FAI_NORMAL_PERCENTAGE); } if (iOpposite >0) { dir = 1.0; } /******************************************************************** * calc right leg ********************************************************************/ fDelta_Dist =(fDistMax-fDistMin)/ (double)(FAI_SECTOR_STEPS); fDistTri = fDistMin; if(fDistTri < FAI_BIG_THRESHOLD) fFAI_Percentage = FAI_NORMAL_PERCENTAGE; else fFAI_Percentage = FAI_NORMAL_PERCENTAGE; fDist_a = fDistMin * fFAI_Percentage; fDist_b = fDistMin * fFAI_Percentage; for(i =0 ;i < FAI_SECTOR_STEPS; i++) { LKASSERT(fDist_c*fDist_b!=0); cos_alpha = ( fDist_b*fDist_b + fDist_c*fDist_c - fDist_a*fDist_a )/(2.0*fDist_c*fDist_b); alpha = acos(cos_alpha)*180/PI * dir; FindLatitudeLongitude(lat1, lon1, AngleLimit360( fAngle + alpha ) , fDist_b, &lat_d, &lon_d); MapWindow::LatLon2Screen(lon_d, lat_d, Pt1); apSectorPolygon[iPolyPtr++] = Pt1; fDistTri += fDelta_Dist; if(fDistTri < FAI_BIG_THRESHOLD) fFAI_Percentage = FAI_NORMAL_PERCENTAGE; else fFAI_Percentage = FAI_NORMAL_PERCENTAGE; fDist_a = fFAI_Percentage * fDistTri; fDist_b = fDistTri - fDist_a - fDist_c; } /******************************************************************** * calc top leg ********************************************************************/ if(fDistMax < FAI_BIG_THRESHOLD) fFAI_Percentage = FAI_NORMAL_PERCENTAGE; else fFAI_Percentage = FAI_NORMAL_PERCENTAGE; fDelta_Dist = (fDistMax*(1.0-3.0*fFAI_Percentage)) / (double)(FAI_SECTOR_STEPS); fDist_a = fDist_c; fDist_b = fDistMax - fDist_a - fDist_c; for(i =0 ;i < FAI_SECTOR_STEPS; i++) { LKASSERT(fDist_c*fDist_b!=0); cos_alpha = ( fDist_b*fDist_b + fDist_c*fDist_c - fDist_a*fDist_a )/(2.0*fDist_c*fDist_b); alpha = acos(cos_alpha)*180/PI * dir; FindLatitudeLongitude(lat1, lon1, AngleLimit360( fAngle + alpha ) , fDist_b, &lat_d, &lon_d); MapWindow::LatLon2Screen(lon_d, lat_d, Pt1); apSectorPolygon[iPolyPtr++] = Pt1; fDist_a += fDelta_Dist; fDist_b = fDistMax - fDist_a - fDist_c; } /******************************************************************** * calc left leg ********************************************************************/ fDelta_Dist =(fDistMax-fDistMin)/ (double)(FAI_SECTOR_STEPS); fDistTri = fDistMax; fDist_b = fDistMax * fFAI_Percentage; fDist_a = fDistTri - fDist_b - fDist_c; for(i =0 ;i < FAI_SECTOR_STEPS; i++) { LKASSERT(fDist_c*fDist_b!=0); cos_alpha = ( fDist_b*fDist_b + fDist_c*fDist_c - fDist_a*fDist_a )/(2.0*fDist_c*fDist_b); alpha = acos(cos_alpha)*180/PI * dir; FindLatitudeLongitude(lat1, lon1, AngleLimit360( fAngle + alpha ) , fDist_b, &lat_d, &lon_d); MapWindow::LatLon2Screen(lon_d, lat_d, Pt1); apSectorPolygon[iPolyPtr++] = Pt1; fDistTri -= fDelta_Dist; if(fDistTri < FAI_BIG_THRESHOLD) fFAI_Percentage = FAI_NORMAL_PERCENTAGE; else fFAI_Percentage = FAI_NORMAL_PERCENTAGE; fDist_b = fFAI_Percentage * fDistTri; fDist_a = fDistTri - fDist_b - fDist_c; } /******************************************************************** * draw polygon ********************************************************************/ HPEN hpSectorPen = (HPEN)CreatePen(PS_SOLID, IBLSCALE(2), fillcolor ); HBRUSH hpSectorFill = NULL; HPEN hpOldPen = (HPEN) SelectObject(hdc, hpSectorPen); HBRUSH hpOldBrush; /* if (fillcolor != 0) { hpSectorFill = (HBRUSH)CreateSolidBrush(fillcolor); hpOldBrush = (HBRUSH)SelectObject(hdc, hpSectorFill); } else */ hpOldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(HOLLOW_BRUSH)); /********************************************/ // Polygon(hdc, apSectorPolygon,iPolyPtr); if (ForcedClipping || DeviceNeedClipping) ClipPolygon(hdc,apSectorPolygon,iPolyPtr,rc, true); else Polygon(hdc,apSectorPolygon,iPolyPtr); /********************************************/ SelectObject(hdc, (HPEN)hpOldPen); SelectObject(hdc, (HBRUSH)hpOldBrush); DeleteObject(hpSectorPen); if(hpSectorFill != NULL) DeleteObject(hpSectorFill); /******************************************************************** * calc round leg grid ********************************************************************/ hpSectorPen = (HPEN)CreatePen(PS_SOLID, (2), RGB_DARKGREY ); SelectObject(hdc, hpSectorPen); double fTic= 1/DISTANCEMODIFY; if(fDist_c > 5/DISTANCEMODIFY) fTic = 10/DISTANCEMODIFY; if(fDist_c > 50/DISTANCEMODIFY) fTic = 25/DISTANCEMODIFY; if(fDist_c > 100/DISTANCEMODIFY) fTic = 50/DISTANCEMODIFY; if(fDist_c > 200/DISTANCEMODIFY) fTic = 100/DISTANCEMODIFY; if(fDist_c > 500/DISTANCEMODIFY) fTic = 250/DISTANCEMODIFY; POINT line[2]; fDistTri = ((int)(fDistMin/fTic)+1) * fTic ; HFONT hfOld = (HFONT)SelectObject(hdc, LK8PanelUnitFont); int iCnt =0; SetTextColor(hdc, RGB_DARKGREY); while(fDistTri < fDistMax) { fDelta_Dist = (fDistTri-fDistMin)*(1.0-2.0*fFAI_Percentage) / (double)(FAI_SECTOR_STEPS-1); fDist_a = fDistTri*fFAI_Percentage; fDist_b = fDistTri - fDist_a - fDist_c; for(i =0 ;i < FAI_SECTOR_STEPS; i++) { LKASSERT(fDist_c*fDist_b!=0); cos_alpha = ( fDist_b*fDist_b + fDist_c*fDist_c - fDist_a*fDist_a )/(2.0*fDist_c*fDist_b); alpha = acos(cos_alpha)*180/PI * dir; FindLatitudeLongitude(lat1, lon1, AngleLimit360( fAngle + alpha ) , fDist_b, &lat_d, &lon_d); MapWindow::LatLon2Screen(lon_d, lat_d, line[0]); if(i> 0) { ForcedClipping=true; MapWindow::_DrawLine(hdc, PS_DASH, NIBLSCALE(1), line[0] , line[1] , RGB_BLACK, rc); ForcedClipping=false; } // Polyline(hdc, line, 2); line[1] = line[0]; fDist_a += fDelta_Dist; fDist_b = fDistTri - fDist_a - fDist_c; TCHAR text[180]; SIZE tsize; if(iCnt==0) _stprintf(text, TEXT("%i%s"), (int)(fDistTri*DISTANCEMODIFY), Units::GetUnitName(Units::GetUserDistanceUnit())); else _stprintf(text, TEXT("%i"), (int)(fDistTri*DISTANCEMODIFY)); GetTextExtentPoint(hdc, text, _tcslen(text), &tsize); if(i == 0) ExtTextOut(hdc, line[0].x, line[0].y, ETO_OPAQUE, NULL, text, _tcslen(text), NULL); if(iCnt > 1) if(i == FAI_SECTOR_STEPS-1) ExtTextOut(hdc, line[0].x, line[0].y, ETO_OPAQUE, NULL, text, _tcslen(text), NULL); if(iCnt > 2) if((i== (FAI_SECTOR_STEPS/2))) ExtTextOut(hdc, line[0].x, line[0].y, ETO_OPAQUE, NULL, text, _tcslen(text), NULL); } iCnt++; fDistTri+=fTic; } SelectObject(hdc, hfOld); SelectObject(hdc, (HPEN)hpOldPen); DeleteObject( hpSectorPen); return 0; }
double Reciprocal(double InBound) { return AngleLimit360(InBound+180); }
#else const double cruise_efficiency) #endif { int i; double BestSpeed, BestGlide, Glide; double BestSinkRate, TimeToDestCruise; static double HeadWind, CrossWind=0.0; static double CrossBearingLast= -1.0; static double WindSpeedLast= -1.0; double CrossBearing; double BestTime; static double HeadWindSqd, CrossWindSqd=0.0; CrossBearing = AngleLimit360(Bearing - WindBearing); if ((CrossBearing != CrossBearingLast)||(WindSpeed != WindSpeedLast)) { // saves a few floating point operations HeadWind = WindSpeed * fastcosine(CrossBearing); CrossWind = WindSpeed * fastsine(CrossBearing); HeadWindSqd = HeadWind*HeadWind; CrossWindSqd = CrossWind*CrossWind; // save old values CrossBearingLast = CrossBearing; WindSpeedLast = WindSpeed; } double sinkrate; double tc; // time spent in cruise
static BOOL FLYSEN(PDeviceDescriptor_t d, TCHAR *String, NMEA_INFO *pGPS) { TCHAR ctemp[80]; double vtas; static int offset=-1; GPSCONNECT=true; // firmware 3.31h no offset // firmware 3.32 1 offset // Determine firmware version, assuming it will not change in the session! if (offset<0) { NMEAParser::ExtractParameter(String,ctemp,8); if ( (_tcscmp(ctemp,_T("A"))==0) || (_tcscmp(ctemp,_T("V"))==0)) offset=0; else { NMEAParser::ExtractParameter(String,ctemp,9); if ( (_tcscmp(ctemp,_T("A"))==0) || (_tcscmp(ctemp,_T("V"))==0)) offset=1; else return TRUE; } } // VOID GPS SIGNAL NMEAParser::ExtractParameter(String,ctemp,8+offset); if (_tcscmp(ctemp,_T("V"))==0) { pGPS->NAVWarning=true; // GPSCONNECT=false; // 121127 NO!! goto label_nogps; } // ------------------------ double tmplat; double tmplon; NMEAParser::ExtractParameter(String,ctemp,1+offset); tmplat = MixedFormatToDegrees(StrToDouble(ctemp, NULL)); NMEAParser::ExtractParameter(String,ctemp,2+offset); tmplat = NorthOrSouth(tmplat, ctemp[0]); NMEAParser::ExtractParameter(String,ctemp,3+offset); tmplon = MixedFormatToDegrees(StrToDouble(ctemp, NULL)); NMEAParser::ExtractParameter(String,ctemp,4+offset); tmplon = EastOrWest(tmplon,ctemp[0]); if (!((tmplat == 0.0) && (tmplon == 0.0))) { pGPS->Latitude = tmplat; pGPS->Longitude = tmplon; pGPS->NAVWarning=false; } // GPS SPEED NMEAParser::ExtractParameter(String,ctemp,6+offset); pGPS->Speed = StrToDouble(ctemp,NULL)/10; // TRACK BEARING if (pGPS->Speed>1.0) { NMEAParser::ExtractParameter(String,ctemp,5+offset); pGPS->TrackBearing = AngleLimit360(StrToDouble(ctemp, NULL)); } // HGPS NMEAParser::ExtractParameter(String,ctemp,7+offset); pGPS->Altitude = StrToDouble(ctemp,NULL); // ------------------------ label_nogps: // SATS NMEAParser::ExtractParameter(String,ctemp,9+offset); pGPS->SatellitesUsed = (int) StrToDouble(ctemp,NULL); // DATE // Firmware 3.32 has got the date if (offset>0) { NMEAParser::ExtractParameter(String,ctemp,0); long gy, gm, gd; TCHAR *Stop; gy = _tcstol(&ctemp[4], &Stop, 10) + 2000; ctemp[4] = '\0'; gm = _tcstol(&ctemp[2], &Stop, 10); ctemp[2] = '\0'; gd = _tcstol(&ctemp[0], &Stop, 10); if ( ((gy > 1980) && (gy <2100) ) && (gm != 0) && (gd != 0) ) { pGPS->Year = gy; pGPS->Month = gm; pGPS->Day = gd; } } // TIME // ignoring 00:00.00 // We need to manage UTC time #ifndef OLD_TIME_MODIFY static int StartDay=-1; if (pGPS->SatellitesUsed>0) { NMEAParser::ExtractParameter(String,ctemp,0+offset); pGPS->Time = TimeModify(ctemp, pGPS, StartDay); } // TODO : check if TimeHasAdvanced check is needed (cf. Parser.cpp) #else NMEAParser::ExtractParameter(String,ctemp,0+offset); double fixTime = StrToDouble(ctemp,NULL); static int day_difference=0, previous_months_day_difference=0; static int startday=-1; if (fixTime>0 && pGPS->SatellitesUsed>0) { double hours, mins,secs; hours = fixTime / 10000; pGPS->Hour = (int)hours; mins = fixTime / 100; mins = mins - (pGPS->Hour*100); pGPS->Minute = (int)mins; secs = fixTime - (pGPS->Hour*10000) - (pGPS->Minute*100); pGPS->Second = (int)secs; fixTime = secs + (pGPS->Minute*60) + (pGPS->Hour*3600); if ((startday== -1) && (pGPS->Day != 0)) { if (offset) StartupStore(_T(". FLYSEN First GPS DATE: %d-%d-%d%s"), pGPS->Year, pGPS->Month, pGPS->Day,NEWLINE); else StartupStore(_T(". FLYSEN No Date, using PNA GPS DATE: %d-%d-%d%s"), pGPS->Year, pGPS->Month, pGPS->Day,NEWLINE); startday = pGPS->Day; day_difference=0; previous_months_day_difference=0; } if (startday != -1) { if (pGPS->Day < startday) { // detect change of month (e.g. day=1, startday=26) previous_months_day_difference=day_difference+1; day_difference=0; startday = pGPS->Day; StartupStore(_T(". FLYSEN Change GPS DATE to NEW MONTH: %d-%d-%d (%d days running)%s"), pGPS->Year, pGPS->Month, pGPS->Day,previous_months_day_difference,NEWLINE); } if ( (pGPS->Day-startday)!=day_difference) { StartupStore(_T(". FLYSEN Change GPS DATE: %d-%d-%d%s"), pGPS->Year, pGPS->Month, pGPS->Day,NEWLINE); } day_difference = pGPS->Day-startday; if ((day_difference+previous_months_day_difference)>0) { fixTime += (day_difference+previous_months_day_difference) * 86400; } } pGPS->Time = fixTime; } #endif // HPA from the pressure sensor // NMEAParser::ExtractParameter(String,ctemp,10+offset); // double ps = StrToDouble(ctemp,NULL)/100; // pGPS->BaroAltitude = (1 - pow(fabs(ps / QNH), 0.190284)) * 44307.69; // HBAR 1013.25 NMEAParser::ExtractParameter(String,ctemp,11+offset); double palt=StrToDouble(ctemp,NULL); UpdateBaroSource( pGPS, 0,d, AltitudeToQNHAltitude(palt)); // VARIO NMEAParser::ExtractParameter(String,ctemp,12+offset); pGPS->Vario = StrToDouble(ctemp,NULL)/100; // TAS NMEAParser::ExtractParameter(String,ctemp,13+offset); vtas=StrToDouble(ctemp,NULL)/10; pGPS->IndicatedAirspeed = vtas/AirDensityRatio(palt); pGPS->TrueAirspeed = vtas; if (pGPS->IndicatedAirspeed >0) pGPS->AirspeedAvailable = TRUE; else pGPS->AirspeedAvailable = FALSE; // ignore n.14 airspeed source // OAT NMEAParser::ExtractParameter(String,ctemp,15+offset); pGPS->OutsideAirTemperature = StrToDouble(ctemp,NULL); pGPS->TemperatureAvailable=TRUE; // ignore n.16 baloon temperature // BATTERY PERCENTAGES NMEAParser::ExtractParameter(String,ctemp,17+offset); pGPS->ExtBatt1_Voltage = StrToDouble(ctemp,NULL)+1000; NMEAParser::ExtractParameter(String,ctemp,18+offset); pGPS->ExtBatt2_Voltage = StrToDouble(ctemp,NULL)+1000; pGPS->VarioAvailable = TRUE; // currently unused in LK, but ready for next future TriggerVarioUpdate(); TriggerGPSUpdate(); return TRUE; }
void CalculateAATTaskSectors() { int i; int awp = ActiveTaskPoint; if(AATEnabled == FALSE || DoOptimizeRoute()) return; double latitude = GPS_INFO.Latitude; double longitude = GPS_INFO.Longitude; double altitude = GPS_INFO.Altitude; LockTaskData(); Task[0].AATTargetOffsetRadius = 0.0; Task[0].AATTargetOffsetRadial = 0.0; if (Task[0].Index>=0) { Task[0].AATTargetLat = WayPointList[Task[0].Index].Latitude; Task[0].AATTargetLon = WayPointList[Task[0].Index].Longitude; } for(i=1;i<MAXTASKPOINTS;i++) { if(ValidTaskPoint(i)) { if (!ValidTaskPoint(i+1)) { // This must be the final waypoint, so it's not an AAT OZ Task[i].AATTargetLat = WayPointList[Task[i].Index].Latitude; Task[i].AATTargetLon = WayPointList[Task[i].Index].Longitude; continue; } if(Task[i].AATType == SECTOR) { FindLatitudeLongitude (WayPointList[Task[i].Index].Latitude, WayPointList[Task[i].Index].Longitude, Task[i].AATStartRadial , Task[i].AATSectorRadius , &Task[i].AATStartLat, &Task[i].AATStartLon); FindLatitudeLongitude (WayPointList[Task[i].Index].Latitude, WayPointList[Task[i].Index].Longitude, Task[i].AATFinishRadial , Task[i].AATSectorRadius, &Task[i].AATFinishLat, &Task[i].AATFinishLon); } // JMWAAT: if locked, don't move it if (i<awp) { // only update targets for current/later waypoints continue; } Task[i].AATTargetOffsetRadius = min(1.0, max(Task[i].AATTargetOffsetRadius,-1.0)); Task[i].AATTargetOffsetRadial = min(90.0, max(-90.0, Task[i].AATTargetOffsetRadial)); double targetbearing; double targetrange; targetbearing = AngleLimit360(Task[i].Bisector+Task[i].AATTargetOffsetRadial); if(Task[i].AATType == SECTOR) { //AATStartRadial //AATFinishRadial targetrange = ((Task[i].AATTargetOffsetRadius+1.0)/2.0); double aatbisector = HalfAngle(Task[i].AATStartRadial, Task[i].AATFinishRadial); if (fabs(AngleLimit180(aatbisector-targetbearing))>90) { // bisector is going away from sector targetbearing = Reciprocal(targetbearing); targetrange = 1.0-targetrange; } if (!AngleInRange(Task[i].AATStartRadial, Task[i].AATFinishRadial, targetbearing,true)) { // Bisector is not within AAT sector, so // choose the closest radial as the target line if (fabs(AngleLimit180(Task[i].AATStartRadial-targetbearing)) <fabs(AngleLimit180(Task[i].AATFinishRadial-targetbearing))) { targetbearing = Task[i].AATStartRadial; } else { targetbearing = Task[i].AATFinishRadial; } } targetrange*= Task[i].AATSectorRadius; } else { targetrange = Task[i].AATTargetOffsetRadius *Task[i].AATCircleRadius; } // TODO accuracy: if i=awp and in sector, range parameter needs to // go from current aircraft position to projection of target // out to the edge of the sector if (InAATTurnSector(longitude, latitude, i, altitude) && (awp==i) && !Task[i].AATTargetLocked) { // special case, currently in AAT sector/cylinder double dist; double qdist; double bearing; // find bearing from last target through current aircraft position with offset DistanceBearing(Task[i-1].AATTargetLat, Task[i-1].AATTargetLon, latitude, longitude, &qdist, &bearing); bearing = AngleLimit360(bearing+Task[i].AATTargetOffsetRadial); dist = ((Task[i].AATTargetOffsetRadius+1)/2.0)* FindInsideAATSectorDistance(latitude, longitude, i, bearing); // if (dist+qdist>aatdistance.LegDistanceAchieved(awp)) { // JMW: don't prevent target from being closer to the aircraft // than the best achieved, so can properly plan arrival time FindLatitudeLongitude (latitude, longitude, bearing, dist, &Task[i].AATTargetLat, &Task[i].AATTargetLon); UpdateTargetAltitude(Task[i]); TargetModified = true; // } } else { FindLatitudeLongitude (WayPointList[Task[i].Index].Latitude, WayPointList[Task[i].Index].Longitude, targetbearing, targetrange, &Task[i].AATTargetLat, &Task[i].AATTargetLon); UpdateTargetAltitude(Task[i]); TargetModified = true; } } } CalculateAATIsoLines(); if (!TargetDialogOpen) { TargetModified = false; // allow target dialog to detect externally changed targets } UnlockTaskData(); }
BOOL NMEAParser::ParseGPS_POSITION_internal(const GPS_POSITION& loc, NMEA_INFO& GPSData) { gpsValid = !(loc.dwFlags & GPS_DATA_FLAGS_HARDWARE_OFF); if (!gpsValid) { return TRUE; } GPSCONNECT=TRUE; switch (loc.FixType) { case GPS_FIX_UNKNOWN: gpsValid = false; break; case GPS_FIX_2D: case GPS_FIX_3D: gpsValid = true; break; default: break; } if (loc.dwValidFields & GPS_VALID_SATELLITE_COUNT) { nSatellites = loc.dwSatelliteCount; } if(!activeGPS) { return TRUE; } GPSData.SatellitesUsed = nSatellites; GPSData.NAVWarning = !gpsValid; if (loc.dwValidFields & GPS_VALID_UTC_TIME) { GPSData.Hour = loc.stUTCTime.wHour; GPSData.Minute = loc.stUTCTime.wMinute; GPSData.Second = loc.stUTCTime.wSecond; GPSData.Month = loc.stUTCTime.wMonth; GPSData.Day = loc.stUTCTime.wDay; GPSData.Year = loc.stUTCTime.wYear; if(!TimeHasAdvanced(TimeModify(&GPSData, StartDay), &GPSData)) { return FALSE; } } if (loc.dwValidFields & GPS_VALID_LATITUDE) { GPSData.Latitude = loc.dblLatitude; } if (loc.dwValidFields & GPS_VALID_LONGITUDE) { GPSData.Longitude = loc.dblLongitude; } if (loc.dwValidFields & GPS_VALID_SPEED) { GPSData.Speed = KNOTSTOMETRESSECONDS * loc.flSpeed; } if (loc.dwValidFields & GPS_VALID_HEADING) { if (GPSData.Speed>trackbearingminspeed) { GPSData.TrackBearing = AngleLimit360(loc.flHeading); } } if (loc.dwValidFields & GPS_VALID_MAGNETIC_VARIATION) { } if (loc.dwValidFields & GPS_VALID_ALTITUDE_WRT_SEA_LEVEL) { GPSData.Altitude = loc.flAltitudeWRTSeaLevel; GPSData.Altitude += (GPSAltitudeOffset/1000); // BUGFIX 100429 } #if 0 if (loc.dwValidFields & GPS_VALID_ALTITUDE_WRT_ELLIPSOID) { /* MSDN says.. * "flAltitudeWRTEllipsoid : Altitude, in meters, with respect to the WGS84 ellipsoid. " * "flAltitudeWRTSeaLevel : Altitude, in meters, with respect to sea level. " * * But when I get this structure, flAltitudeWRTSeaLevel field has proper value. But, * flAltitudeWRTEllipsoid field has different meaning value. * * But flAltitudeWRTEllipsoid field contains just geodial separation. */ } #endif if (loc.dwValidFields & GPS_VALID_POSITION_DILUTION_OF_PRECISION) { } if (loc.dwValidFields & GPS_VALID_HORIZONTAL_DILUTION_OF_PRECISION) { } if (loc.dwValidFields & GPS_VALID_VERTICAL_DILUTION_OF_PRECISION) { } if (loc.dwValidFields & GPS_VALID_SATELLITES_USED_PRNS) { } if (loc.dwValidFields & GPS_VALID_SATELLITES_IN_VIEW) { } if (loc.dwValidFields & GPS_VALID_SATELLITES_IN_VIEW_PRNS) { } if (loc.dwValidFields & GPS_VALID_SATELLITES_IN_VIEW_ELEVATION) { } if (loc.dwValidFields & GPS_VALID_SATELLITES_IN_VIEW_AZIMUTH) { } if (loc.dwValidFields & GPS_VALID_SATELLITES_IN_VIEW_SIGNAL_TO_NOISE_RATIO) { } if(gpsValid && !GPSData.NAVWarning && GPSData.SatellitesUsed == 0) { GPSData.SatellitesUsed = -1; } TriggerGPSUpdate(); return TRUE; }
BOOL NMEAParser::RMC(TCHAR *String, TCHAR **params, size_t nparams, NMEA_INFO *pGPS) { TCHAR *Stop; static bool logbaddate=true; double speed=0; gpsValid = !NAVWarn(params[1][0]); GPSCONNECT = TRUE; RMCAvailable=true; // 100409 #ifdef PNA if (DeviceIsGM130) { double ps = GM130BarPressure(); RMZAltitude = (1 - pow(fabs(ps / QNH), 0.190284)) * 44307.69; // StartupStore(_T("....... Pressure=%.0f QNH=%.2f Altitude=%.1f\n"),ps,QNH,RMZAltitude); RMZAvailable = TRUE; UpdateBaroSource(pGPS, BARO__GM130, NULL, RMZAltitude); } if (DeviceIsRoyaltek3200) { if (Royaltek3200_ReadBarData()) { double ps = Royaltek3200_GetPressure(); RMZAltitude = (1 - pow(fabs(ps / QNH), 0.190284)) * 44307.69; #if 0 pGPS->TemperatureAvailable=true; pGPS->OutsideAirTemperature = Royaltek3200_GetTemperature(); #endif } RMZAvailable = TRUE; UpdateBaroSource(pGPS, BARO__ROYALTEK3200, NULL, RMZAltitude); } #endif // PNA if (!activeGPS) { // Before ignoring anything else, commit RMZ altitude otherwise it will be ignored! if(RMZAvailable) { UpdateBaroSource(pGPS, isFlarm? BARO__RMZ_FLARM:BARO__RMZ, NULL, RMZAltitude); } return TRUE; } // if no valid fix, we dont get speed either! if (gpsValid) { // speed is in knots, 2 = 3.7kmh speed = StrToDouble(params[6], NULL); } pGPS->NAVWarning = !gpsValid; // say we are updated every time we get this, // so infoboxes get refreshed if GPS connected // the RMC sentence marks the start of a new fix, so we force the old data to be saved for calculations // note that Condor sends no date.. if ((_tcslen(params[8]) <6) && !DevIsCondor) { #if TESTBENCH StartupStore(_T(".... RMC date field empty, skip sentence!\n")); #endif return TRUE; } // Even with no valid position, we let RMC set the time and date if valid long gy, gm, gd; gy = _tcstol(¶ms[8][4], &Stop, 10) + 2000; params[8][4] = '\0'; gm = _tcstol(¶ms[8][2], &Stop, 10); params[8][2] = '\0'; gd = _tcstol(¶ms[8][0], &Stop, 10); // SeeYou PC is sending NMEA sentences with RMC date 2072-02-27 if ( ((gy > 1980) && (gy <2100) ) && (gm != 0) && (gd != 0) ) { pGPS->Year = gy; pGPS->Month = gm; pGPS->Day = gd; force_advance: RMCtime = StrToDouble(params[0],NULL); #ifndef OLD_TIME_MODIFY double ThisTime = TimeModify(params[0], pGPS, StartDay); #else double ThisTime = TimeModify(RMCtime, pGPS); #endif // RMC time has priority on GGA and GLL etc. so if we have it we use it at once if (!TimeHasAdvanced(ThisTime, pGPS)) { #if DEBUGSEQ StartupStore(_T("..... RMC time not advanced, skipping \n")); // 31C #endif return FALSE; } } else { if (DevIsCondor) { #if DEBUGSEQ StartupStore(_T(".. Condor not sending valid date, using 1.1.2012%s"),NEWLINE); #endif gy=2012; gm=1; gd=1; goto force_advance; } if (gpsValid && logbaddate) { // 091115 StartupStore(_T("------ NMEAParser:RMC Receiving an invalid or null DATE from GPS%s"),NEWLINE); StartupStore(_T("------ NMEAParser: Date received is y=%ld m=%ld d=%ld%s"),gy,gm,gd,NEWLINE); // 100422 StartupStore(_T("------ This message will NOT be repeated. %s%s"),WhatTimeIsIt(),NEWLINE); DoStatusMessage(MsgToken(875)); logbaddate=false; } gy=2012; gm=2; gd=30; // an impossible date! goto force_advance; } if (gpsValid) { double tmplat; double tmplon; tmplat = MixedFormatToDegrees(StrToDouble(params[2], NULL)); tmplat = NorthOrSouth(tmplat, params[3][0]); tmplon = MixedFormatToDegrees(StrToDouble(params[4], NULL)); tmplon = EastOrWest(tmplon,params[5][0]); if (!((tmplat == 0.0) && (tmplon == 0.0))) { pGPS->Latitude = tmplat; pGPS->Longitude = tmplon; } pGPS->Speed = KNOTSTOMETRESSECONDS * speed; if (pGPS->Speed>trackbearingminspeed) { pGPS->TrackBearing = AngleLimit360(StrToDouble(params[7], NULL)); } } // gpsvalid 091108 #ifdef WIN32 // As soon as we get a fix for the first time, set the // system clock to the GPS time. static bool sysTimeInitialised = false; if (!pGPS->NAVWarning && (gpsValid)) { if (SetSystemTimeFromGPS) { if (!sysTimeInitialised) { if ( ( pGPS->Year > 1980 && pGPS->Year<2100) && ( pGPS->Month > 0) && ( pGPS->Hour > 0)) { sysTimeInitialised =true; // Attempting only once SYSTEMTIME sysTime; // ::GetSystemTime(&sysTime); int hours = (int)pGPS->Hour; int mins = (int)pGPS->Minute; int secs = (int)pGPS->Second; sysTime.wYear = (unsigned short)pGPS->Year; sysTime.wMonth = (unsigned short)pGPS->Month; sysTime.wDay = (unsigned short)pGPS->Day; sysTime.wHour = (unsigned short)hours; sysTime.wMinute = (unsigned short)mins; sysTime.wSecond = (unsigned short)secs; sysTime.wMilliseconds = 0; ::SetSystemTime(&sysTime); } } } } #else #warning "Set system clock to the GPS time not implemented." #endif if(RMZAvailable) { UpdateBaroSource(pGPS, BARO__RMZ, NULL, RMZAltitude); } if (!GGAAvailable) { // update SatInUse, some GPS receiver dont emmit GGA sentance if (!gpsValid) { pGPS->SatellitesUsed = 0; } else { pGPS->SatellitesUsed = -1; } } if ( !GGAAvailable || (GGAtime == RMCtime) ) { #if DEBUGSEQ StartupStore(_T("... RMC trigger gps, GGAtime==RMCtime\n")); // 31C #endif TriggerGPSUpdate(); } return TRUE; } // END RMC
// draw aircraft void RenderPlaneSideview(HDC hdc, double fDist, double fAltitude,double brg, DiagrammStruct* psDia ) { //BOOL bInvCol = true ; //INVERTCOLORS #define NO_AP_PTS 17 int deg = DEG_TO_INT(AngleLimit360(brg)); double fCos = COSTABLE[deg]; double fSin = SINETABLE[deg]; int TAIL = 6; int PROFIL = 1; int FINB = 3; int BODY = 2; int NOSE = 7; int WING = (int) (22.0 ); int TUBE = (int) (14.0 ) ; int FINH = 6+BODY; POINT Start; int HEAD = TUBE / 2; TUBE = 3 * TUBE/ 2; POINT AircraftSide [8] = { {(int)(fSin * (HEAD+0 ) ), -BODY-1}, // 1 {(int)(fSin * (HEAD+NOSE) ), 0}, // 2 {(int)(fSin * (HEAD+0 ) ), BODY+1}, // 3 {(int)(fSin * (-TUBE) ), BODY}, // 4 -1 {(int)(fSin * -TUBE ), -FINH}, // 5 {(int)(fSin * (-TUBE+FINB) ), -FINH}, // 6 {(int)(fSin * (-TUBE+FINB+3) ), -BODY+1}, // 7 +1 {(int)(fSin * (HEAD+0) ), -BODY-1} // 8 }; #define FACT 2 BODY = (int)((double)(BODY+1) * fCos * fCos); int DIA = (BODY + PROFIL); /* both wings */ POINT AircraftWing [13] = { {(int)(fCos * BODY ) , -DIA}, // 1 {(int)(fCos * (int)( FACT*BODY) ), -PROFIL}, // 2 {(int)(fCos * WING ) , -PROFIL}, // 3 {(int)(fCos * WING ), 0* PROFIL}, // 4 {(int)(fCos * (int)( FACT*BODY) ) , PROFIL}, // 5 {(int)(fCos * BODY ), DIA}, // 6 {(int)(fCos * -BODY ) , DIA}, // 7 {(int)(fCos * (int)( -FACT*BODY)), PROFIL}, // 8 {(int)(fCos * -WING ), 0* PROFIL }, // 9 {(int)(fCos * -WING ) , -PROFIL} , // 10 {(int)(fCos * (int)( -FACT*BODY)), -PROFIL}, // 11 {(int)(fCos * -BODY ) , -DIA}, // 12 {(int)(fCos * BODY ), -DIA} // 13 }; POINT AircraftWingL [7] = { {(int)(0 * -BODY ), DIA }, // 1 {(int)(fCos * (int)( -FACT*BODY)), PROFIL }, // 2 {(int)(fCos * -WING ), 0* PROFIL }, // 3 {(int)(fCos * -WING ), -PROFIL }, // 4 {(int)(fCos * (int)( -FACT*BODY)), -PROFIL }, // 5 {(int)(0 * -BODY ), -DIA }, // 6 {(int)(0 * -BODY ), DIA } // 7 }; POINT AircraftWingR [7] = { {(int)(0 * BODY ) , -DIA }, // 1 {(int)(fCos * (int)( FACT*BODY) ) , -PROFIL }, // 2 {(int)(fCos * WING ) , -PROFIL }, // 3 {(int)(fCos * WING ) , 0* PROFIL}, // 4 {(int)(fCos * (int)( FACT*BODY) ) , PROFIL }, // 5 {(int)(0 * BODY ) , DIA }, // 6 {(int)(0 * BODY ) , -DIA } // 7 }; POINT AircraftTail [5] = { {(int)(fCos * TAIL - fSin*TUBE), -FINH}, // 1 {(int)(fCos * TAIL - fSin*TUBE), -FINH +PROFIL}, // 2 {(int)(fCos * -TAIL - fSin*TUBE), -FINH +PROFIL}, // 3 {(int)(fCos * -TAIL - fSin*TUBE), -FINH }, // 4 {(int)(fCos * TAIL - fSin*TUBE), -FINH}, // 5 }; Start.x = CalcDistanceCoordinat(fDist, psDia); Start.y = CalcHeightCoordinat(fAltitude, psDia); HBRUSH oldBrush; HPEN oldPen; /* if(bInvCol) { oldPen = (HPEN)SelectObject(hdc, GetStockObject(WHITE_PEN)); oldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(BLACK_BRUSH)); } else */ { oldPen = (HPEN) SelectObject(hdc, GetStockObject(BLACK_PEN)); oldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(WHITE_BRUSH)); } //SelectObject(hdc, GetStockObject(BLACK_PEN)); PolygonRotateShift(AircraftWing, 13, Start.x, Start.y, 0); PolygonRotateShift(AircraftSide, 8, Start.x, Start.y, 0); PolygonRotateShift(AircraftTail, 5, Start.x, Start.y, 0); PolygonRotateShift(AircraftWingL, 7, Start.x, Start.y, 0); PolygonRotateShift(AircraftWingR, 7, Start.x, Start.y, 0); HBRUSH GreenBrush = CreateSolidBrush(COLORREF RGB_GREEN); HBRUSH RedBrush = CreateSolidBrush(COLORREF RGB_RED); if((brg < 180)) { SelectObject(hdc, RedBrush); Polygon(hdc,AircraftWingL ,7 ); SelectObject(hdc, GetStockObject(WHITE_BRUSH)); Polygon(hdc,AircraftSide ,8 ); SelectObject(hdc, GreenBrush); Polygon(hdc,AircraftWingR ,7 ); SelectObject(hdc, oldBrush); } else { SelectObject(hdc, GreenBrush); Polygon(hdc,AircraftWingR ,7 ); SelectObject(hdc, GetStockObject(WHITE_BRUSH)); Polygon(hdc,AircraftSide ,8 ); SelectObject(hdc, RedBrush); Polygon(hdc,AircraftWingL ,7 ); SelectObject(hdc, oldBrush); //Polygon(hdc,AircraftWing ,13); } if((brg < 90)|| (brg > 270)) { Polygon(hdc,AircraftTail ,5 ); } SelectObject(hdc, oldPen); SelectObject(hdc, oldBrush); DeleteObject(RedBrush); DeleteObject(GreenBrush); } //else !asp_heading_task
BOOL NMEAParser::RMC(TCHAR *String, TCHAR **params, size_t nparams, NMEA_INFO *GPS_INFO) { TCHAR *Stop; static bool logbaddate=true; double speed=0; gpsValid = !NAVWarn(params[1][0]); GPSCONNECT = TRUE; RMCAvailable=true; // 100409 if (!activeGPS) return TRUE; // 091205 BUGFIX true // if no valid fix, we dont get speed either! if (gpsValid) { speed = StrToDouble(params[6], NULL); // speed is in knots, 2 = 3.7kmh if (speed>2.0) { GPS_INFO->MovementDetected = TRUE; if (ReplayLogger::IsEnabled()) { // stop logger replay if aircraft is actually moving. ReplayLogger::Stop(); } } else { GPS_INFO->MovementDetected = FALSE; if (ReplayLogger::IsEnabled()) { // block actual GPS signal if not moving and a log is being replayed return TRUE; } } } GPS_INFO->NAVWarning = !gpsValid; // say we are updated every time we get this, // so infoboxes get refreshed if GPS connected // the RMC sentence marks the start of a new fix, so we force the old data to be saved for calculations #ifndef NEWTRIGGERGPS if (!GGAAvailable) { TriggerGPSUpdate(); } #endif // Even with no valid position, we let RMC set the time and date if valid long gy, gm, gd; gy = _tcstol(¶ms[8][4], &Stop, 10) + 2000; params[8][4] = '\0'; gm = _tcstol(¶ms[8][2], &Stop, 10); params[8][2] = '\0'; gd = _tcstol(¶ms[8][0], &Stop, 10); // SeeYou PC is sending NMEA sentences with RMC date 2072-02-27 if ( ((gy > 1980) && (gy <2100) ) && (gm != 0) && (gd != 0) ) { GPS_INFO->Year = gy; GPS_INFO->Month = gm; GPS_INFO->Day = gd; #ifdef NEWTRIGGERGPS double ThisTime = TimeConvert(StrToDouble(params[0],NULL), GPS_INFO); // 091208 #else double ThisTime = TimeModify(StrToDouble(params[0],NULL), GPS_INFO); #endif #ifndef NEWTRIGGERGPS if (!TimeHasAdvanced(ThisTime, GPS_INFO)) return FALSE; #endif #ifdef NEWTRIGGERGPS // is time advanced to a new quantum? if (ThisTime >NmeaTime) { // yes so lets trigger the gps event TriggerGPSUpdate(); // and only then advance the time in the GPSINFO Sleep(50); // 091208 NmeaTime=ThisTime; TimeSet(GPS_INFO); // 091208 TimeHasAdvanced(ThisTime, GPS_INFO); // 091208 StartupStore(_T(".............. trigger from RMC\n")); } #endif } else { if (gpsValid && logbaddate) { // 091115 StartupStore(_T("------ NMEAParser:RMC Receiving an invalid or null DATE from GPS%s"),NEWLINE); StartupStore(_T("------ NMEAParser: Date received is y=%d m=%d d=%d%s"),gy,gm,gd,NEWLINE); // 100422 StartupStore(_T("------ This message will NOT be repeated.%s"),NEWLINE); // DoStatusMessage(_T("WARNING: GPS IS SENDING INVALID DATE, AND PROBABLY WRONG TIME")); // REMOVE FIXV2 // LKTOKEN 875 WARNING: GPS IS SENDING INVALID DATE, AND PROBABLY WRONG TIME")); DoStatusMessage(gettext(TEXT("_@M875_"))); logbaddate=false; } } // } // 091108 if (gpsValid) { // 091108 BUGFIX set latlon and speed ONLY if valid gpsdata, missing check! double tmplat; double tmplon; tmplat = MixedFormatToDegrees(StrToDouble(params[2], NULL)); tmplat = NorthOrSouth(tmplat, params[3][0]); tmplon = MixedFormatToDegrees(StrToDouble(params[4], NULL)); tmplon = EastOrWest(tmplon,params[5][0]); if (!((tmplat == 0.0) && (tmplon == 0.0))) { GPS_INFO->Latitude = tmplat; GPS_INFO->Longitude = tmplon; } GPS_INFO->Speed = KNOTSTOMETRESSECONDS * speed; if (GPS_INFO->Speed>1.0) { // JMW don't update bearing unless we're moving GPS_INFO->TrackBearing = AngleLimit360(StrToDouble(params[7], NULL)); } } // gpsvalid 091108 // Altair doesn't have a battery-backed up realtime clock, // so as soon as we get a fix for the first time, set the // system clock to the GPS time. static bool sysTimeInitialised = false; if (!GPS_INFO->NAVWarning && (gpsValid)) { if (SetSystemTimeFromGPS) { if (!sysTimeInitialised) { if ( ( GPS_INFO->Year > 1980 && GPS_INFO->Year<2100) && ( GPS_INFO->Month > 0) && ( GPS_INFO->Hour > 0)) { sysTimeInitialised =true; // Attempting only once SYSTEMTIME sysTime; // ::GetSystemTime(&sysTime); int hours = (int)GPS_INFO->Hour; int mins = (int)GPS_INFO->Minute; int secs = (int)GPS_INFO->Second; sysTime.wYear = (unsigned short)GPS_INFO->Year; sysTime.wMonth = (unsigned short)GPS_INFO->Month; sysTime.wDay = (unsigned short)GPS_INFO->Day; sysTime.wHour = (unsigned short)hours; sysTime.wMinute = (unsigned short)mins; sysTime.wSecond = (unsigned short)secs; sysTime.wMilliseconds = 0; ::SetSystemTime(&sysTime); } } } } if (!ReplayLogger::IsEnabled()) { if(RMZAvailable) { // JMW changed from Altitude to BaroAltitude GPS_INFO->BaroAltitudeAvailable = true; GPS_INFO->BaroAltitude = RMZAltitude; } else if(RMAAvailable) { // JMW changed from Altitude to BaroAltitude GPS_INFO->BaroAltitudeAvailable = true; GPS_INFO->BaroAltitude = RMAAltitude; } } if (!GGAAvailable) { // update SatInUse, some GPS receiver dont emmit GGA sentance if (!gpsValid) { GPS_INFO->SatellitesUsed = 0; } else { GPS_INFO->SatellitesUsed = -1; } } return TRUE; }
int MapWindow::SharedTopView(HDC hdc, DiagrammStruct* psDia , double fAS_Bearing, double fWP_Bearing) { int iOldDisplayOrientation = DisplayOrientation; DiagrammStruct m_Dia = *psDia; RECT rct = m_Dia.rc; unsigned short getsideviewpage=GetSideviewPage(); LKASSERT(getsideviewpage<NUMBER_OF_SHARED_MULTIMAPS); LKASSERT(Current_Multimap_SizeY!=SIZE0); DisplayOrientation = GetMMNorthUp(getsideviewpage); switch(GetMMNorthUp(getsideviewpage)) { case TRACKUP: break; case NORTHUP: default: m_Dia.fXMin = -m_Dia.fXMax; break; } double fOldScale = zoom.Scale(); HFONT hfOld = (HFONT)SelectObject(hdc, LK8PanelUnitFont); if(zoom.AutoZoom()) zoom.AutoZoom(false); double fFact = 1.25 ; #ifdef INIT_CASE switch(ScreenSize) { case ss896x672: fFact=0.938; break; case ss800x480: fFact=0.750; break; case ss640x480: fFact=0.938; break; case ss480x272: fFact=0.708; break; case ss400x240: fFact=0.750; break; case ss320x240: fFact=0.938; break; case ss480x800: fFact=1.250; break; case ss480x640: fFact=1.250; break; case ss272x480: fFact=1.250; break; case ss240x400: fFact=1.250; break; case ss240x320: fFact=1.250; break; default: fFact=1.000; break; } #endif if((ScreenSizeX > 0) && (ScreenSizeY > 0)) { if(ScreenSizeX > ScreenSizeY) fFact = (double)ScreenSizeY/(double)ScreenSizeX * 1.250; } PanLatitude = DrawInfo.Latitude; PanLongitude = DrawInfo.Longitude; switch(GetMMNorthUp(getsideviewpage)) { case TRACKUP: DisplayAngle = AngleLimit360(fAS_Bearing +270.0); DisplayAircraftAngle = AngleLimit360(fWP_Bearing); break; case NORTHUP: default: DisplayAngle = 0; if( getsideviewpage == IM_HEADING || getsideviewpage==IM_VISUALGLIDE) DisplayAircraftAngle = AngleLimit360(fAS_Bearing); else DisplayAircraftAngle = AngleLimit360(DrawInfo.TrackBearing); break; } int iOldLocator = EnableThermalLocator; EnableThermalLocator =0; MapWindow::ChangeDrawRect(rct); // set new area for terrain and topology zoom.ModifyMapScale(); zoom.RequestedScale((m_Dia.fXMax -m_Dia.fXMin) * fFact * (DISTANCEMODIFY)/10.0f); POINT Orig = { CalcDistanceCoordinat(0.0, (DiagrammStruct*) &m_Dia),(rct.bottom-rct.top)/2}; POINT Orig_Aircraft= {0,0}; zoom.ModifyMapScale(); zoom.UpdateMapScale(); CalculateScreenPositions( Orig, rct, &Orig_Aircraft); CalculateScreenPositionsAirspace(rct); // // Expose variables in use for topview drawing // Current_Multimap_TopOrig=Orig_Aircraft; Current_Multimap_TopZoom=GetInvDrawScale(); Current_Multimap_TopAngle=DisplayAngle; bool terrainpainted=false; if (IsMultimapTerrain() && DerivedDrawInfo.TerrainValid && RasterTerrain::isTerrainLoaded() ) { LKTextBlack=false; BlackScreen=false; LockTerrainDataGraphics(); DrawTerrain(hdc, rct, GetAzimuth(), 40.0); UnlockTerrainDataGraphics(); terrainpainted=true; } else { // We fill up the background wity chosen empty map color // display border and fill background.. SelectObject(hdc, hInvBackgroundBrush[BgMapColor]); SelectObject(hdc, GetStockObject(WHITE_PEN)); Rectangle(hdc,rct.left,rct.top,rct.right,rct.bottom); // We force LK painting black values on screen depending on the background color in use // blackscreen would force everything to be painted white, instead LKTextBlack=BgMapColorTextBlack[BgMapColor]; if (BgMapColor>6 ) BlackScreen=true; else BlackScreen=false; } ResetLabelDeclutter(); // We reduce screen cluttering for some cases.. short olddecluttermode=DeclutterMode; if (Current_Multimap_SizeY==SIZE4) goto _nomoredeclutter; if (Current_Multimap_SizeY<SIZE3) { DeclutterMode+=2; } else { if (Current_Multimap_SizeY==SIZE3) DeclutterMode++; } if (DeclutterMode>dmVeryHigh) DeclutterMode=dmVeryHigh; _nomoredeclutter: if (IsMultimapTopology()) { // Do not print topology labels, to be used with another config later! // SaturateLabelDeclutter(); RECT rc_red = rct; rc_red.bottom -= 3; DrawTopology (hdc, rc_red); } else { // No topology is desired, but terrain requires water areas nevertheless if (terrainpainted) { RECT rc_red = rct; rc_red.bottom -= 3; DrawTopology (hdc, rc_red,true); // water only! } } if (IsMultimapAirspace()) { if ( (GetAirSpaceFillType() == asp_fill_ablend_full) || (GetAirSpaceFillType() == asp_fill_ablend_borders) ) { DrawTptAirSpace(hdc, rct); } else { if ( GetAirSpaceFillType() == asp_fill_border_only) DrawAirSpaceBorders(hdc, rct); // full screen, to hide clipping effect on low border else DrawAirSpace(hdc, rct); // full screen, to hide clipping effect on low border } // DrawAirspaceLabels( hdc, rct, Orig_Aircraft); } if (Flags_DrawTask && MapSpaceMode!=MSM_MAPASP && ValidTaskPoint(ActiveWayPoint) && ValidTaskPoint(1)) { DrawTaskAAT(hdc, DrawRect); DrawTask(hdc, DrawRect, Current_Multimap_TopOrig); } if (IsMultimapWaypoints()) { DrawWaypointsNew(hdc,DrawRect); } if (Flags_DrawFAI) DrawFAIOptimizer(hdc, DrawRect, Current_Multimap_TopOrig); DeclutterMode=olddecluttermode; // set it back correctly /* THIS STUFF DOES NOT WORK IN SHARED MAPS, YET NEED FIXING LatLon2Screen for shared maps using Sideview #ifdef GTL2 if (((FinalGlideTerrain == 2) || (FinalGlideTerrain == 4)) && DerivedDrawInfo.TerrainValid) DrawTerrainAbove(hdc, DrawRect); #endif */ // // Stuff for MAPTRK only (M1) if (MapSpaceMode==MSM_MAPTRK) { if(IsMultimapTerrain() || IsMultimapTopology() ) { if (FinalGlideTerrain && DerivedDrawInfo.TerrainValid) DrawGlideThroughTerrain(hdc, DrawRect); } if (extGPSCONNECT) DrawBearing(hdc, DrawRect); // Wind arrow if (IsMultimapOverlaysGauges()) DrawWindAtAircraft2(hdc, Current_Multimap_TopOrig, DrawRect); } if (MapSpaceMode==MSM_MAPWPT) { if (extGPSCONNECT) DrawBearing(hdc, DrawRect); } switch(GetMMNorthUp(getsideviewpage)) { case NORTHUP: default: DrawCompass( hdc, rct, 0); break; case TRACKUP: if(getsideviewpage == IM_HEADING || getsideviewpage == IM_VISUALGLIDE) DrawCompass( hdc, rct, DrawInfo.TrackBearing-90.0); else DrawCompass( hdc, rct, DisplayAngle); break; } /**************************************************************************************************** * draw vertical line ****************************************************************************************************/ POINT line[2]; line[0].x = rct.left; line[0].y = Orig_Aircraft.y-1; line[1].x = rct.right; line[1].y = line[0].y; switch(GetMMNorthUp(getsideviewpage)) { case TRACKUP: // Are we are not topview fullscreen? if (Current_Multimap_SizeY<SIZE4 && !MapSpaceMode==MSM_VISUALGLIDE) { DrawDashLine(hdc,NIBLSCALE(1), line[0], line[1], Sideview_TextColor, rct); } else { if (TrackBar) DrawHeadUpLine(hdc, Orig, rct, psDia->fXMin ,psDia->fXMax); } break; case NORTHUP: default: if (TrackBar) { DrawHeadUpLine(hdc, Orig, rct, psDia->fXMin ,psDia->fXMax); } break; } DrawAircraft(hdc, Orig_Aircraft); // M3 has sideview always on, so wont apply here, and no need to check if (Current_Multimap_SizeY==SIZE4) { DrawMapScale(hdc,rct,0); } MapWindow::zoom.RequestedScale(fOldScale); EnableThermalLocator = iOldLocator; DisplayOrientation = iOldDisplayOrientation; SelectObject(hdc, hfOld); return 0; }
void Heading(NMEA_INFO *Basic, DERIVED_INFO *Calculated) { double x0, y0, mag=0; static double LastTime = 0; static double lastHeading = 0; static double lastSpeed = 0; if (DoInit[MDI_HEADING]) { LastTime = 0; lastHeading = 0; DoInit[MDI_HEADING]=false; } if ((Basic->Speed>0)||(Calculated->WindSpeed>0)) { x0 = fastsine(Basic->TrackBearing)*Basic->Speed; y0 = fastcosine(Basic->TrackBearing)*Basic->Speed; x0 += fastsine(Calculated->WindBearing)*Calculated->WindSpeed; y0 += fastcosine(Calculated->WindBearing)*Calculated->WindSpeed; Calculated->Heading = AngleLimit360(atan2(x0,y0)*RAD_TO_DEG); if (!Calculated->Flying) { // don't take wind into account when on ground Calculated->Heading = Basic->TrackBearing; } // calculate turn rate in wind coordinates if(Basic->Time > LastTime) { double dT = Basic->Time - LastTime; LKASSERT(dT!=0); Calculated->TurnRateWind = AngleLimit180(Calculated->Heading - lastHeading)/dT; lastHeading = Calculated->Heading; } if (ISCAR) { // On ground, TAS is GS. Wind gradient irrilevant, normally. Calculated->TrueAirspeedEstimated = Basic->Speed; LKASSERT(AirDensityRatio(Calculated->NavAltitude)!=0); Calculated->IndicatedAirspeedEstimated = Basic->Speed/AirDensityRatio(Calculated->NavAltitude); } else { // calculate estimated true airspeed mag = isqrt4((unsigned long)(x0*x0*100+y0*y0*100))/10.0; Calculated->TrueAirspeedEstimated = mag; LKASSERT(AirDensityRatio(Calculated->NavAltitude)!=0); Calculated->IndicatedAirspeedEstimated = mag/AirDensityRatio(Calculated->NavAltitude); } // estimate bank angle (assuming balanced turn) double angle = atan(DEG_TO_RAD*Calculated->TurnRateWind* Calculated->TrueAirspeedEstimated/9.81); Calculated->BankAngle = RAD_TO_DEG*angle; if (ISCAR) { if(Basic->Time > LastTime) { Calculated->Gload = ((Basic->Speed - lastSpeed) / (Basic->Time-LastTime))/9.81; lastSpeed=Basic->Speed; } else { Calculated->Gload = 0; } } else { Calculated->Gload = 1.0/max(0.001,fabs(cos(angle))); } LastTime = Basic->Time; // estimate pitch angle (assuming balanced turn) /* Calculated->PitchAngle = RAD_TO_DEG* atan2(Calculated->GPSVario-Calculated->Vario, Calculated->TrueAirspeedEstimated); */ // should be used as here only when no real vario available Calculated->PitchAngle = RAD_TO_DEG* atan2(Calculated->Vario, Calculated->TrueAirspeedEstimated); // update zigzag wind if ( ((AutoWindMode==D_AUTOWIND_ZIGZAG) || (AutoWindMode==D_AUTOWIND_BOTHCIRCZAG)) && (!ReplayLogger::IsEnabled()) ) { double zz_wind_speed; double zz_wind_bearing; int quality=0; quality = WindKalmanUpdate(Basic, Calculated, &zz_wind_speed, &zz_wind_bearing); if (quality>0) { SetWindEstimate(zz_wind_speed, zz_wind_bearing); Calculated->WindSpeed = zz_wind_speed; Calculated->WindBearing = zz_wind_bearing; /* 100118 redundant!! removed. TOCHECK * Vector v_wind; v_wind.x = zz_wind_speed*cos(zz_wind_bearing*3.1415926/180.0); v_wind.y = zz_wind_speed*sin(zz_wind_bearing*3.1415926/180.0); LockFlightData(); if (windanalyser) { windanalyser->slot_newEstimate(Basic, Calculated, v_wind, quality); } UnlockFlightData(); */ } } // else basic speed is 0 and there is no wind.. } else { Calculated->Heading = Basic->TrackBearing; Calculated->TrueAirspeedEstimated = 0; // BUGFIX 100318 Calculated->IndicatedAirspeedEstimated = 0; // BUGFIX 100318 } }
void AATDistance::ShiftTargetFromBehind(double longitude, double latitude, int taskwaypoint) { // JMWAAT if being externally updated e.g. from task dialog, don't move it if (TargetDialogOpen) return; if (taskwaypoint==0) return; // best is decreasing or first entry in sector, so project // target in direction of improvement or first entry into sector double course_bearing; double course_bearing_orig; double d_total_orig; double d_total_this; d_total_this = DoubleLegDistance(taskwaypoint, longitude, latitude); d_total_orig = DoubleLegDistance(taskwaypoint, Task[taskwaypoint].AATTargetLon, Task[taskwaypoint].AATTargetLat); if (d_total_this>d_total_orig-2.0*AATCloseDistance()) { // this is better than the previous best! (or very close) ShiftTargetFromInFront(longitude, latitude, taskwaypoint); return; } // JMWAAT if locked, don't move it if (Task[taskwaypoint].AATTargetLocked) { // 20080615 JMW don't do this; locked stays locked // Task[taskwaypoint].AATTargetLocked = false; // JMWAAT JB return; } /* // check to see if deviation is big enough to adjust target along track DistanceBearing(Task[taskwaypoint-1].AATTargetLat, Task[taskwaypoint-1].AATTargetLon, latitude, longitude, NULL, &course_bearing); DistanceBearing(Task[taskwaypoint-1].AATTargetLat, Task[taskwaypoint-1].AATTargetLon, Task[taskwaypoint].AATTargetLat, Task[taskwaypoint].AATTargetLon, NULL, &course_bearing_orig); if (fabs(AngleLimit180(course_bearing-course_bearing_orig))<5.0) { // don't update it if course deviation is less than 5 degrees, // otherwise we end up wasting a lot of CPU in recalculating, and also // the target ends up drifting. return; } course_bearing = AngleLimit360(course_bearing+ Task[taskwaypoint].AATTargetOffsetRadial); //JMWAAT Task[taskwaypoint].AATTargetOffsetRadial = course_bearing; */ DistanceBearing(Task[taskwaypoint-1].AATTargetLat, Task[taskwaypoint-1].AATTargetLon, latitude, longitude, NULL, &course_bearing); course_bearing = AngleLimit360(course_bearing+ Task[taskwaypoint].AATTargetOffsetRadial); DistanceBearing(latitude, longitude, Task[taskwaypoint].AATTargetLat, Task[taskwaypoint].AATTargetLon, NULL, &course_bearing_orig); if (fabs(AngleLimit180(course_bearing-course_bearing_orig))<5.0) { // don't update it if course deviation is less than 5 degrees, // otherwise we end up wasting a lot of CPU in recalculating, and also // the target ends up drifting. return; } double max_distance = FindInsideAATSectorDistance(latitude, longitude, taskwaypoint, course_bearing, 0); // total distance of legs from previous through this to next target double delta = max_distance/2; // move target in line with previous target along track // at an offset to improve on max distance double t_distance_lower = 0; double t_distance = delta*2; int steps = 0; do { // find target position along projected line but // make sure it is in sector, and set at a distance // to preserve total task distance // we are aiming to make d_total_this = d_total_orig double t_lat, t_lon; FindLatitudeLongitude(latitude, longitude, course_bearing, t_distance, &t_lat, &t_lon); if (InAATTurnSector(t_lon, t_lat, taskwaypoint, 0)) { d_total_this = DoubleLegDistance(taskwaypoint, t_lon, t_lat); if (d_total_orig - d_total_this>0.0) { t_distance_lower = t_distance; // ok, can go further t_distance += delta; } else { t_distance -= delta; } } else { t_distance -= delta; } delta /= 2.0; } while ((delta>5.0) && (steps++<20)); // now scan to edge of sector to find approximate range % if (t_distance_lower>5.0) { FindLatitudeLongitude(latitude, longitude, course_bearing, t_distance_lower, &Task[taskwaypoint].AATTargetLat, &Task[taskwaypoint].AATTargetLon); UpdateTargetAltitude(Task[taskwaypoint]); Task[taskwaypoint].AATTargetOffsetRadius = FindInsideAATSectorRange(latitude, longitude, taskwaypoint, course_bearing, t_distance_lower); TargetModified = true; CalculateAATIsoLines(); } // if ((!t_in_sector) && (d_diff_total>1.0)) { // JMW TODO enhancement: this is too short now so need to lengthen the // next waypoint if possible // (re discussion with paul mander) // } }
void dlgWayPointDetailsShowModal(short mypage){ TCHAR sTmp[128]; double sunsettime; int sunsethours; int sunsetmins; WndProperty *wp; if (!ScreenLandscape) { TCHAR filename[MAX_PATH]; LocalPathS(filename, TEXT("dlgWayPointDetails_L.xml")); wf = dlgLoadFromXML(CallBackTable, filename, hWndMainWindow, TEXT("IDR_XML_WAYPOINTDETAILS_L")); } else { TCHAR filename[MAX_PATH]; LocalPathS(filename, TEXT("dlgWayPointDetails.xml")); wf = dlgLoadFromXML(CallBackTable, filename, hWndMainWindow, TEXT("IDR_XML_WAYPOINTDETAILS")); } nTextLines = 0; if (!wf) return; wInfo = ((WndFrame *)wf->FindByName(TEXT("frmInfos"))); wCommand = ((WndFrame *)wf->FindByName(TEXT("frmCommands"))); wSpecial = ((WndFrame *)wf->FindByName(TEXT("frmSpecial"))); wDetails = (WndListFrame*)wf->FindByName(TEXT("frmDetails")); LKASSERT(wInfo!=NULL); LKASSERT(wCommand!=NULL); LKASSERT(wSpecial!=NULL); LKASSERT(wDetails!=NULL); // Resize Frames up to real screen size on the right. wInfo->SetBorderKind(BORDERLEFT); wCommand->SetBorderKind(BORDERLEFT); wSpecial->SetBorderKind(BORDERLEFT); wDetails->SetBorderKind(BORDERLEFT); wCommand->SetVisible(false); wSpecial->SetVisible(false); // // CAPTION: top line in black // // if SeeYou waypoint if (WPLSEL.Format == LKW_CUP) { TCHAR ttmp[50]; // and it is landable if ((WPLSEL.Style>1) && (WPLSEL.Style<6) ) { _stprintf(sTmp, TEXT("%s "), WPLSEL.Name); // ICAO name probably, let's print it if ( _tcslen(WPLSEL.Code)==4 ) { _stprintf(ttmp,_T("(%s) "),WPLSEL.Code); _tcscat(sTmp, ttmp); } if ( _tcslen(WPLSEL.Freq)>0 ) { _stprintf(ttmp,_T("%s "),WPLSEL.Freq); _tcscat(sTmp, ttmp); } if ( WPLSEL.RunwayDir>=0 ) { _stprintf(ttmp,_T("RW %d "),WPLSEL.RunwayDir); _tcscat(sTmp, ttmp); } if ( WPLSEL.RunwayLen>0 ) { // we use Altitude instead of distance, to keep meters and feet _stprintf(ttmp,_T("%.0f%s"),Units::ToUserAltitude((double)WPLSEL.RunwayLen), Units::GetAltitudeName()); _tcscat(sTmp, ttmp); } wf->SetCaption(sTmp); } else { _stprintf(sTmp, TEXT("%s: "), wf->GetCaption()); _tcscat(sTmp, WayPointList[SelectedWaypoint].Name); wf->SetCaption(sTmp); } } else { _stprintf(sTmp, TEXT("%s: "), wf->GetCaption()); _tcscat(sTmp, WayPointList[SelectedWaypoint].Name); wf->SetCaption(sTmp); } // // Waypoint Comment // wp = ((WndProperty *)wf->FindByName(TEXT("prpWpComment"))); LKASSERT(wp); if (WayPointList[SelectedWaypoint].Comment==NULL) wp->SetText(_T("")); else wp->SetText(WayPointList[SelectedWaypoint].Comment); wp->SetButtonSize(16); // // Lat and Lon // Units::CoordinateToString( WayPointList[SelectedWaypoint].Longitude, WayPointList[SelectedWaypoint].Latitude, sTmp, sizeof(sTmp)-1); wp = ((WndProperty *)wf->FindByName(TEXT("prpCoordinate"))); LKASSERT(wp); wp->SetText(sTmp); // // Waypoint Altitude // Units::FormatUserAltitude(WayPointList[SelectedWaypoint].Altitude, sTmp, sizeof(sTmp)-1); wp = ((WndProperty *)wf->FindByName(TEXT("prpAltitude"))); LKASSERT(wp); wp->SetText(sTmp); // // SUNSET at waypoint // sunsettime = DoSunEphemeris(WayPointList[SelectedWaypoint].Longitude, WayPointList[SelectedWaypoint].Latitude); sunsethours = (int)sunsettime; sunsetmins = (int)((sunsettime-sunsethours)*60); _stprintf(sTmp, TEXT("%02d:%02d"), sunsethours, sunsetmins); ((WndProperty *)wf->FindByName(TEXT("prpSunset")))->SetText(sTmp); // // Distance and bearing // double distance, bearing; DistanceBearing(GPS_INFO.Latitude, GPS_INFO.Longitude, WayPointList[SelectedWaypoint].Latitude, WayPointList[SelectedWaypoint].Longitude, &distance, &bearing); TCHAR DistanceText[MAX_PATH]; if (ScreenLandscape) { Units::FormatUserDistance(distance, DistanceText, 10); if ( Units::GetUserDistanceUnit() == unNauticalMiles || Units::GetUserDistanceUnit() == unStatuteMiles ) { _stprintf(sTmp,_T(" (%.1fkm)"), distance*TOKILOMETER); } else { _stprintf(sTmp,_T(" (%.1fnm)"), distance*TONAUTICALMILES); } _tcscat(DistanceText,sTmp); } else { Units::FormatUserDistance(distance, DistanceText, 10); } ((WndProperty *)wf->FindByName(TEXT("prpDistance")))->SetText(DistanceText); if (ScreenLandscape) { _stprintf(sTmp, TEXT("%d%s (R:%d%s)"),iround(bearing), TEXT(DEG), iround(AngleLimit360(bearing+180)), TEXT(DEG)); } else { _stprintf(sTmp, TEXT("%d")TEXT(DEG), iround(bearing)); } ((WndProperty *)wf->FindByName(TEXT("prpBearing")))->SetText(sTmp); // // Altitude reqd at mc 0 // double alt=0; alt = CALCULATED_INFO.NavAltitude - GlidePolar::MacCreadyAltitude(0.0, distance, bearing, CALCULATED_INFO.WindSpeed, CALCULATED_INFO.WindBearing, 0, 0, true, 0)- WayPointList[SelectedWaypoint].Altitude; if (SafetyAltitudeMode==1 || WayPointCalc[SelectedWaypoint].IsLandable) alt-=(SAFETYALTITUDEARRIVAL/10); _stprintf(sTmp, TEXT("%.0f %s"), alt*ALTITUDEMODIFY, Units::GetAltitudeName()); wp = ((WndProperty *)wf->FindByName(TEXT("prpMc0"))); if (wp) wp->SetText(sTmp); // alt reqd at current mc alt = CALCULATED_INFO.NavAltitude - GlidePolar::MacCreadyAltitude(MACCREADY, distance, bearing, CALCULATED_INFO.WindSpeed, CALCULATED_INFO.WindBearing, 0, 0, true, 0)- WayPointList[SelectedWaypoint].Altitude; if (SafetyAltitudeMode==1 || WayPointCalc[SelectedWaypoint].IsLandable) alt-=(SAFETYALTITUDEARRIVAL/10); _stprintf(sTmp, TEXT("%.0f %s"), alt*ALTITUDEMODIFY, Units::GetAltitudeName()); wp = ((WndProperty *)wf->FindByName(TEXT("prpMc2"))); if (wp) { wp->SetText(sTmp); } wf->SetKeyDownNotify(FormKeyDown); ((WndButton *)wf->FindByName(TEXT("cmdClose")))->SetOnClickNotify(OnCloseClicked); // We DONT use PREV anymore ((WndButton *)wf->FindByName(TEXT("cmdPrev")))->SetVisible(false); // // Details (WAYNOTES) page // wDetailsEntry = (WndOwnerDrawFrame*)wf->FindByName(TEXT("frmDetailsEntry")); LKASSERT(wDetailsEntry!=NULL); wDetailsEntry->SetCanFocus(true); nTextLines = TextToLineOffsets(WayPointList[SelectedWaypoint].Details, LineOffsets, MAXLINES); // ScrollbarWidth is initialised from DrawScrollBar in WindowControls, so it might not be ready here if ( wDetails->ScrollbarWidth == -1) { #if defined (PNA) #define SHRINKSBFACTOR 1.0 // shrink width factor. Range .1 to 1 where 1 is very "fat" #else #define SHRINKSBFACTOR 0.75 // shrink width factor. Range .1 to 1 where 1 is very "fat" #endif wDetails->ScrollbarWidth = (int) (SCROLLBARWIDTH_INITIAL * ScreenDScale * SHRINKSBFACTOR); } wDetailsEntry->SetWidth(wDetails->GetWidth() - wDetails->ScrollbarWidth - 5); WndButton *wb; TCHAR captmp[200]; // Resize also buttons wb = ((WndButton *)wf->FindByName(TEXT("cmdInserInTask"))); if (wb) { wb->SetOnClickNotify(OnInserInTaskClicked); wb->SetWidth(wCommand->GetWidth()-wb->GetLeft()*2); if ((ActiveWayPoint<0) || !ValidTaskPoint(0)) { // this is going to be the first tp (ActiveWayPoint 0) _stprintf(captmp,_T("%s"),MsgToken(1824)); // insert as START } else { LKASSERT(ActiveWayPoint>=0 && ValidTaskPoint(0)); int indexInsert = max(ActiveWayPoint,0); // safe check if (indexInsert==0) { _stprintf(captmp,_T("%s"),MsgToken(1824)); // insert as START } else { LKASSERT(ValidWayPoint(Task[indexInsert].Index)); _stprintf(captmp,_T("%s <%s>"),MsgToken(1825),WayPointList[ Task[indexInsert].Index ].Name); // insert before xx } } wb->SetCaption(captmp); } wb = ((WndButton *)wf->FindByName(TEXT("cmdAppendInTask1"))); if (wb) { wb->SetOnClickNotify(OnAppendInTask1Clicked); wb->SetWidth(wCommand->GetWidth()-wb->GetLeft()*2); } wb = ((WndButton *)wf->FindByName(TEXT("cmdAppendInTask2"))); if (wb) { wb->SetOnClickNotify(OnAppendInTask2Clicked); wb->SetWidth(wCommand->GetWidth()-wb->GetLeft()*2); } wb = ((WndButton *)wf->FindByName(TEXT("cmdRemoveFromTask"))); if (wb) { wb->SetOnClickNotify(OnRemoveFromTaskClicked); wb->SetWidth(wCommand->GetWidth()-wb->GetLeft()*2); } wb = ((WndButton *)wf->FindByName(TEXT("cmdReplace"))); if (wb) { wb->SetWidth(wCommand->GetWidth()-wb->GetLeft()*2); int tmpIdx = -1; if (ValidTaskPoint(ActiveWayPoint)) tmpIdx = Task[ActiveWayPoint].Index; if( ValidTaskPoint(PanTaskEdit)) tmpIdx = RealActiveWaypoint; if(tmpIdx != -1) { wb->SetOnClickNotify(OnReplaceClicked); _stprintf(captmp,_T("%s <%s>"),MsgToken(1826),WayPointList[tmpIdx ].Name); // replace xx } else { _stprintf(captmp,_T("( %s )"),MsgToken(555)); } wb->SetCaption(captmp); } wb = ((WndButton *)wf->FindByName(TEXT("cmdNewHome"))); if (wb) { wb->SetOnClickNotify(OnNewHomeClicked); wb->SetWidth(wSpecial->GetWidth()-wb->GetLeft()*2); } wb = ((WndButton *)wf->FindByName(TEXT("cmdTeamCode"))); if (wb) { wb->SetOnClickNotify(OnTeamCodeClicked); wb->SetWidth(wSpecial->GetWidth()-wb->GetLeft()*2); } page = mypage; NextPage(0); wf->ShowModal(); delete wf; wf = NULL; }
int RenderFAISector (LKSurface& Surface, const RECT& rc , double lat1, double lon1, double lat2, double lon2, int iOpposite , const LKColor& fillcolor) { POINT Pt1; float fFAI_Percentage = FAI_NORMAL_PERCENTAGE; double fDist_a, fDist_b, fDist_c, fAngle; int i; int iPolyPtr=0; double lat_d,lon_d; double alpha, fDistTri, cos_alpha=0; POINT apSectorPolygon[MAX_FAI_SECTOR_PTS+1]; DistanceBearing(lat1, lon1, lat2, lon2, &fDist_c, &fAngle); if(fabs(fDist_c) < 1000.0) /* distance too short for a FAI sector */ return -1; double fDistMax = fDist_c/FAI_NORMAL_PERCENTAGE; double fDistMin = fDist_c/(1.0-2.0*FAI28_45Threshold); double fDelta_Dist = 2.0* fDist_c*fFAI_Percentage / (double)(FAI_SECTOR_STEPS-1); double fA, fB; double fMinLeg, fMaxLeg,fDiff=0; double dir = -1.0; BOOL bBigFAISector = false; if(fDistMax > FAI28_45Threshold) { bBigFAISector = true; fDistMax = fDist_c/FAI_BIG_PERCENTAGE; } if(fDistMin < FAI28_45Threshold) { fDistMin = fDist_c/(1.0-2.0*FAI_NORMAL_PERCENTAGE); } if (iOpposite >0) { dir = 1.0; } //#define HELP_LINES #ifdef HELP_LINES int x2,y2, style; FindLatitudeLongitude(lat1, lon1, AngleLimit360 (fAngle), fDist_c/2, &lat_d, &lon_d); x1 = (lon_d - lon_c)*fastcosine(lat_d); y1 = (lat_d - lat_c); FindLatitudeLongitude(lat_d, lon_d, AngleLimit360 (fAngle-90.0), fDist_c, &lat_d, &lon_d); x2 = (lon_d - lon_c)*fastcosine(lat_d); y2 = (lat_d - lat_c); Surface.DrawLine(rc, x1, y1, x2, y2, style); #endif /******************************************************************** * right below threshold 1 ********************************************************************/ fA = fDistMin; if(fDistMax > FAI28_45Threshold) fB = FAI28_45Threshold; else fB = fDistMax ; if(fA<fB) { fDelta_Dist =(fB-fA)/ (double)(FAI_SECTOR_STEPS-1); fDistTri = fA; for(i =0 ;i < FAI_SECTOR_STEPS; i++) { fDist_a = FAI_NORMAL_PERCENTAGE * fDistTri; fDist_b = fDistTri - fDist_a - fDist_c; LKASSERT(fDist_c*fDist_b!=0); cos_alpha = ( fDist_b*fDist_b + fDist_c*fDist_c - fDist_a*fDist_a )/(2.0*fDist_c*fDist_b); alpha = acos(cos_alpha)*180/PI * dir; FindLatitudeLongitude(lat1, lon1, AngleLimit360( fAngle + alpha ) , fDist_b, &lat_d, &lon_d); MapWindow::LatLon2Screen(lon_d, lat_d, Pt1); LKASSERT(iPolyPtr < MAX_FAI_SECTOR_PTS); apSectorPolygon[iPolyPtr++] = Pt1; fDistTri += fDelta_Dist; } } /******************************************************************** * right threshold extender 2 ********************************************************************/ if(fDistMin < FAI28_45Threshold) if(bBigFAISector && (fDistMin < FAI28_45Threshold)) { fMaxLeg = FAI28_45Threshold*FAI_BIG_MAX_PERCENTAGE; fMinLeg = FAI28_45Threshold*FAI_BIG_PERCENTAGE; fA = FAI28_45Threshold*FAI_NORMAL_PERCENTAGE; fB = FAI28_45Threshold-fMaxLeg-fDist_c; if(fB < fMinLeg) fB = fMinLeg; fDist_a = fA; fDelta_Dist = (fB-fA) / (double)(FAI_SECTOR_STEPS-1); for(i =0 ;i < FAI_SECTOR_STEPS; i++) { fDist_b = FAI28_45Threshold - fDist_a - fDist_c; LKASSERT(fDist_c*fDist_b!=0); cos_alpha = ( fDist_b*fDist_b + fDist_c*fDist_c - fDist_a*fDist_a )/(2.0*fDist_c*fDist_b); alpha = acos(cos_alpha)*180/PI * dir; FindLatitudeLongitude(lat1, lon1, AngleLimit360( fAngle + alpha ) , fDist_b, &lat_d, &lon_d); MapWindow::LatLon2Screen(lon_d, lat_d, Pt1); LKASSERT(iPolyPtr < MAX_FAI_SECTOR_PTS); apSectorPolygon[iPolyPtr++] = Pt1; fDist_a += fDelta_Dist; } } /******************************************************************** * right above threshold 3 ********************************************************************/ if(bBigFAISector) { fA = FAI28_45Threshold; if(fDistMin > fA) fA= fDistMin; fB =fDist_c/(1- FAI_BIG_PERCENTAGE-FAI_BIG_MAX_PERCENTAGE); if(fA < fB) { fDelta_Dist =(fB-fA)/ (double)(FAI_SECTOR_STEPS-1); fDistTri = fA; for(i =0 ;i < FAI_SECTOR_STEPS; i++) { fMaxLeg = fDistTri*FAI_BIG_MAX_PERCENTAGE; fMinLeg = fDistTri*FAI_BIG_PERCENTAGE; fDist_a = fDistTri-fMinLeg-fDist_c;; fDist_b = fMinLeg; if(fDist_a > fMaxLeg) { fDiff = fDist_a - fMaxLeg; fDist_b+=fDiff; fDist_a-=fDiff; } LKASSERT(fDist_c*fDist_b!=0); cos_alpha = ( fDist_a*fDist_a + fDist_c*fDist_c - fDist_b*fDist_b )/(2.0*fDist_c*fDist_a); alpha = acos(cos_alpha)*180/PI * dir; FindLatitudeLongitude(lat1, lon1, AngleLimit360( fAngle + alpha ) , fDist_a, &lat_d, &lon_d); MapWindow::LatLon2Screen(lon_d, lat_d, Pt1); LKASSERT(iPolyPtr < MAX_FAI_SECTOR_PTS); apSectorPolygon[iPolyPtr++] = Pt1; fDistTri += fDelta_Dist; } } } /******************************************************************** * TOP limited round 4 ********************************************************************/ if(fDistMax <= FAI28_45Threshold) fDist_b = fDistMax*(1.0-2*FAI_NORMAL_PERCENTAGE); else fDist_b = fDistMax*FAI_BIG_MAX_PERCENTAGE; fDist_a = fDistMax-fDist_b-fDist_c; fDelta_Dist = (fDist_a-fDist_b) / (double)(FAI_SECTOR_STEPS-1); for(i =0 ;i < FAI_SECTOR_STEPS; i++) { LKASSERT(fDist_c*fDist_b!=0); cos_alpha = ( fDist_b*fDist_b + fDist_c*fDist_c - fDist_a*fDist_a )/(2.0*fDist_c*fDist_b); alpha = acos(cos_alpha)*180/PI * dir; FindLatitudeLongitude(lat1, lon1, AngleLimit360( fAngle + alpha ) , fDist_b, &lat_d, &lon_d); MapWindow::LatLon2Screen(lon_d, lat_d, Pt1); LKASSERT(iPolyPtr < MAX_FAI_SECTOR_PTS); apSectorPolygon[iPolyPtr++] = Pt1; fDist_a -= fDelta_Dist; fDist_b += fDelta_Dist; } /******************************************************************** * calc left leg ********************************************************************/ /******************************************************************** * LEFT above threshold 5 ********************************************************************/ if(bBigFAISector) { fB = FAI28_45Threshold; if( fB < fDistMin) fB = fDistMin; fA =fDist_c/(1- FAI_BIG_PERCENTAGE-FAI_BIG_MAX_PERCENTAGE); if(fA >= fB) { fDelta_Dist =(fA-fB)/ (double)(FAI_SECTOR_STEPS-1); fDistTri = fA; for(i =0 ;i < FAI_SECTOR_STEPS; i++) { fMaxLeg = fDistTri*FAI_BIG_MAX_PERCENTAGE; fMinLeg = fDistTri*FAI_BIG_PERCENTAGE; fDist_a = fDistTri-fMinLeg-fDist_c; fDist_b = fMinLeg; if(fDist_a > fMaxLeg) { fDiff = fDist_a - fMaxLeg; fDist_b+=fDiff; fDist_a-=fDiff; } LKASSERT(fDist_c*fDist_b!=0); cos_alpha = ( fDist_b*fDist_b + fDist_c*fDist_c - fDist_a*fDist_a )/(2.0*fDist_c*fDist_b); alpha = acos(cos_alpha)*180/PI * dir; FindLatitudeLongitude(lat1, lon1, AngleLimit360( fAngle + alpha ) , fDist_b, &lat_d, &lon_d); MapWindow::LatLon2Screen(lon_d, lat_d, Pt1); LKASSERT(iPolyPtr < MAX_FAI_SECTOR_PTS); apSectorPolygon[iPolyPtr++] = Pt1; fDistTri -= fDelta_Dist; } } } /******************************************************************** * LEFT threshold extender 6 ********************************************************************/ if(fDistMin < FAI28_45Threshold) if((fDistMin < FAI28_45Threshold) && (FAI28_45Threshold < fDistMax)) { fMaxLeg = FAI28_45Threshold*FAI_BIG_MAX_PERCENTAGE; fMinLeg = FAI28_45Threshold*FAI_BIG_PERCENTAGE; fA = FAI28_45Threshold*FAI_NORMAL_PERCENTAGE; fB = FAI28_45Threshold-fMaxLeg-fDist_c; if(fB < fMinLeg) fB = fMinLeg; fDist_b = fB; fDelta_Dist = (fA-fB) / (double)(FAI_SECTOR_STEPS-1); for(i =0 ;i < FAI_SECTOR_STEPS; i++) { fDist_a = FAI28_45Threshold - fDist_b - fDist_c; LKASSERT(fDist_c*fDist_b!=0); cos_alpha = ( fDist_b*fDist_b + fDist_c*fDist_c - fDist_a*fDist_a )/(2.0*fDist_c*fDist_b); alpha = acos(cos_alpha)*180/PI * dir; FindLatitudeLongitude(lat1, lon1, AngleLimit360( fAngle + alpha ) , fDist_b, &lat_d, &lon_d); MapWindow::LatLon2Screen(lon_d, lat_d, Pt1); LKASSERT(iPolyPtr < MAX_FAI_SECTOR_PTS); apSectorPolygon[iPolyPtr++] = Pt1; fDist_b += fDelta_Dist; } } /******************************************************************** * LEFT below threshold 7 ********************************************************************/ fA = fDistMin; if(fDistMax > FAI28_45Threshold) fB = FAI28_45Threshold; else fB = fDistMax ; if(fA<fB) { fDelta_Dist =(fB-fA)/ (double)(FAI_SECTOR_STEPS-1); fDistTri = fB; for(i =0 ;i < FAI_SECTOR_STEPS; i++) { fDist_b = FAI_NORMAL_PERCENTAGE * fDistTri; fDist_a = fDistTri - fDist_b - fDist_c; LKASSERT(fDist_c*fDist_b!=0); cos_alpha = ( fDist_b*fDist_b + fDist_c*fDist_c - fDist_a*fDist_a )/(2.0*fDist_c*fDist_b); alpha = acos(cos_alpha)*180/PI * dir; FindLatitudeLongitude(lat1, lon1, AngleLimit360( fAngle + alpha ) , fDist_b, &lat_d, &lon_d); MapWindow::LatLon2Screen(lon_d, lat_d, Pt1); LKASSERT(iPolyPtr < MAX_FAI_SECTOR_PTS); apSectorPolygon[iPolyPtr++] = Pt1; fDistTri -= fDelta_Dist; } } /******************************************************************** * low open PEAK round 8 ********************************************************************/ if(fDistMin >FAI28_45Threshold) { fDist_b = fDistMin*FAI_BIG_PERCENTAGE; fDist_a = fDistMin-fDist_b-fDist_c; fDelta_Dist = (fDist_b-fDist_a) / (double)(FAI_SECTOR_STEPS-1); for(i =0 ;i < FAI_SECTOR_STEPS; i++) { LKASSERT(fDist_c*fDist_b!=0); cos_alpha = ( fDist_b*fDist_b + fDist_c*fDist_c - fDist_a*fDist_a )/(2.0*fDist_c*fDist_b); alpha = acos(cos_alpha)*180/PI * dir; FindLatitudeLongitude(lat1, lon1, AngleLimit360( fAngle + alpha ) , fDist_b, &lat_d, &lon_d); MapWindow::LatLon2Screen(lon_d, lat_d, Pt1); LKASSERT(iPolyPtr < MAX_FAI_SECTOR_PTS); apSectorPolygon[iPolyPtr++] = Pt1; fDist_a += fDelta_Dist; fDist_b -= fDelta_Dist; } } /******************************************************************** * draw polygon ********************************************************************/ LKPen hpSectorPen(PEN_SOLID, IBLSCALE(2), fillcolor ); LKPen hpOldPen = Surface.SelectObject(hpSectorPen); LKBrush hpOldBrush = Surface.SelectObject(LKBrush_Hollow); Surface.Polygon(apSectorPolygon,iPolyPtr,rc); Surface.SelectObject(hpOldPen); Surface.SelectObject(hpOldBrush); hpSectorPen.Release(); /******************************************************************** * calc round leg grid ********************************************************************/ hpSectorPen.Create(PEN_SOLID, (1), RGB_BLACK ); Surface.SelectObject(hpSectorPen); Surface.SetTextColor(RGB_BLACK); double fTic= 1/DISTANCEMODIFY; if(fDist_c > 5/DISTANCEMODIFY) fTic = 10/DISTANCEMODIFY; if(fDist_c > 50/DISTANCEMODIFY) fTic = 25/DISTANCEMODIFY; if(fDist_c > 100/DISTANCEMODIFY) fTic = 50/DISTANCEMODIFY; // if(fDist_c > 200/DISTANCEMODIFY) fTic = 100/DISTANCEMODIFY; if(fDist_c > 500/DISTANCEMODIFY) fTic = 250/DISTANCEMODIFY; POINT line[2]; BOOL bFirstUnit = true; LKASSERT(fTic!=0); fDistTri = ((int)(fDistMin/fTic)+1) * fTic ; LKFont hfOld = Surface.SelectObject(LK8PanelUnitFont); int iCnt = 0; while(fDistTri <= fDistMax) { TCHAR text[180]; SIZE tsize; if(bFirstUnit) _stprintf(text, TEXT("%i%s"), (int)(fDistTri*DISTANCEMODIFY), Units::GetUnitName(Units::GetUserDistanceUnit())); else _stprintf(text, TEXT("%i"), (int)(fDistTri*DISTANCEMODIFY)); bFirstUnit = false; Surface.GetTextSize(text, _tcslen(text), &tsize); int j=0; if(fDistTri < FAI28_45Threshold) { fDist_b = fDistTri*FAI_NORMAL_PERCENTAGE; fDist_a = fDistTri-fDist_b-fDist_c; fDelta_Dist = (fDist_a-fDist_b) / (double)(FAI_SECTOR_STEPS-1); } else { fMaxLeg = fDistTri*FAI_BIG_MAX_PERCENTAGE; fMinLeg = fDistTri*FAI_BIG_PERCENTAGE; fA = fMaxLeg; fB = fDistTri-fA-fDist_c; fDist_a = fA; fDist_b = fB; if(fB < fMinLeg) { fDiff = fMinLeg-fB; fB+=2*fDiff; fDist_b += fDiff; fDist_a -= fDiff; } if(fB > fMaxLeg) { fDiff = fB - fMaxLeg; fB+=2*fDiff; fDist_b-=fDiff; fDist_a+=fDiff; } fFAI_Percentage = FAI_BIG_PERCENTAGE; fDelta_Dist = (fA-fB) / (double)(FAI_SECTOR_STEPS-1); } for(i =0 ;i < FAI_SECTOR_STEPS; i++) { LKASSERT(fDist_c*fDist_b!=0); cos_alpha = ( fDist_b*fDist_b + fDist_c*fDist_c - fDist_a*fDist_a )/(2.0*fDist_c*fDist_b); alpha = acos(cos_alpha)*180/PI * dir; FindLatitudeLongitude(lat1, lon1, AngleLimit360( fAngle + alpha ) , fDist_b, &lat_d, &lon_d); MapWindow::LatLon2Screen(lon_d, lat_d, line[0]); if(j> 0) { ForcedClipping=true; Surface.DrawLine(PEN_DASH, NIBLSCALE(1), line[0] , line[1] , RGB_BLACK, rc); ForcedClipping=false; } if(j==0) { Surface.DrawText(line[0].x, line[0].y, text, _tcslen(text)); j=1; } // TCHAR text[180]; SIZE tsize; if(iCnt==0) _stprintf(text, TEXT("%i%s"), (int)(fDistTri*DISTANCEMODIFY), Units::GetUnitName(Units::GetUserDistanceUnit())); else _stprintf(text, TEXT("%i"), (int)(fDistTri*DISTANCEMODIFY)); Surface.GetTextSize(text, _tcslen(text), &tsize); if(i == 0) Surface.DrawText(line[0].x, line[0].y, text, _tcslen(text)); if(iCnt > 1) if(i == FAI_SECTOR_STEPS-1) Surface.DrawText(line[0].x, line[0].y, text, _tcslen(text)); if(iCnt > 2) if((i== (FAI_SECTOR_STEPS/2))) Surface.DrawText(line[0].x, line[0].y, text, _tcslen(text)); line[1] = line[0]; fDist_a -= fDelta_Dist; fDist_b += fDelta_Dist; } fDistTri+=fTic;iCnt++; // if((iCnt %2) ==0) // DrawText(hdc, line[0].x, line[0].y, ETO_OPAQUE, NULL, text, _tcslen(text), NULL); } Surface.SelectObject(hfOld); Surface.SelectObject(hpOldPen); return 0; }
double AngleDifference(double angle1, double angle0) { angle0 = AngleLimit360(angle0); angle1 = AngleLimit360(angle1); return fmod(angle1-angle0+180,360)-180; }
// draw aircraft void RenderPlaneSideview(LKSurface& Surface, double fDist, double fAltitude,double brg, DiagrammStruct* psDia ) { //BOOL bInvCol = true ; //INVERTCOLORS #define NO_AP_PTS 17 int deg = DEG_TO_INT(AngleLimit360(brg)); double fCos = COSTABLE[deg]; double fSin = SINETABLE[deg]; int TAIL = 6; int PROFIL = 1; int FINB = 3; int BODY = 2; int NOSE = 7; int WING = (int) (22.0 ); int TUBE = (int) (14.0 ) ; int FINH = 6+BODY; POINT Start; int HEAD = TUBE / 2; TUBE = 3 * TUBE/ 2; POINT AircraftSide [8] = { {(int)(fSin * (HEAD+0 ) ), -BODY-1}, // 1 {(int)(fSin * (HEAD+NOSE) ), 0}, // 2 {(int)(fSin * (HEAD+0 ) ), BODY+1}, // 3 {(int)(fSin * (-TUBE) ), BODY}, // 4 -1 {(int)(fSin * -TUBE ), -FINH}, // 5 {(int)(fSin * (-TUBE+FINB) ), -FINH}, // 6 {(int)(fSin * (-TUBE+FINB+3) ), -BODY+1}, // 7 +1 {(int)(fSin * (HEAD+0) ), -BODY-1} // 8 }; #define FACT 2 BODY = (int)((double)(BODY+1) * fCos * fCos); int DIA = (BODY + PROFIL); /* both wings */ POINT AircraftWing [13] = { {(int)(fCos * BODY ) , -DIA}, // 1 {(int)(fCos * (int)( FACT*BODY) ), -PROFIL}, // 2 {(int)(fCos * WING ) , -PROFIL}, // 3 {(int)(fCos * WING ), 0* PROFIL}, // 4 {(int)(fCos * (int)( FACT*BODY) ) , PROFIL}, // 5 {(int)(fCos * BODY ), DIA}, // 6 {(int)(fCos * -BODY ) , DIA}, // 7 {(int)(fCos * (int)( -FACT*BODY)), PROFIL}, // 8 {(int)(fCos * -WING ), 0* PROFIL }, // 9 {(int)(fCos * -WING ) , -PROFIL} , // 10 {(int)(fCos * (int)( -FACT*BODY)), -PROFIL}, // 11 {(int)(fCos * -BODY ) , -DIA}, // 12 {(int)(fCos * BODY ), -DIA} // 13 }; POINT AircraftWingL [7] = { {(int)(0 * -BODY ), DIA }, // 1 {(int)(fCos * (int)( -FACT*BODY)), PROFIL }, // 2 {(int)(fCos * -WING ), 0* PROFIL }, // 3 {(int)(fCos * -WING ), -PROFIL }, // 4 {(int)(fCos * (int)( -FACT*BODY)), -PROFIL }, // 5 {(int)(0 * -BODY ), -DIA }, // 6 {(int)(0 * -BODY ), DIA } // 7 }; POINT AircraftWingR [7] = { {(int)(0 * BODY ) , -DIA }, // 1 {(int)(fCos * (int)( FACT*BODY) ) , -PROFIL }, // 2 {(int)(fCos * WING ) , -PROFIL }, // 3 {(int)(fCos * WING ) , 0* PROFIL}, // 4 {(int)(fCos * (int)( FACT*BODY) ) , PROFIL }, // 5 {(int)(0 * BODY ) , DIA }, // 6 {(int)(0 * BODY ) , -DIA } // 7 }; POINT AircraftTail [5] = { {(int)(fCos * TAIL - fSin*TUBE), -FINH}, // 1 {(int)(fCos * TAIL - fSin*TUBE), -FINH +PROFIL}, // 2 {(int)(fCos * -TAIL - fSin*TUBE), -FINH +PROFIL}, // 3 {(int)(fCos * -TAIL - fSin*TUBE), -FINH }, // 4 {(int)(fCos * TAIL - fSin*TUBE), -FINH}, // 5 }; Start.x = CalcDistanceCoordinat(fDist, psDia); Start.y = CalcHeightCoordinat(fAltitude, psDia); const auto oldPen = Surface.SelectObject(LK_BLACK_PEN); const auto oldBrush = Surface.SelectObject(LKBrush_White); PolygonRotateShift(AircraftWing, 13, Start.x, Start.y, 0); PolygonRotateShift(AircraftSide, 8, Start.x, Start.y, 0); PolygonRotateShift(AircraftTail, 5, Start.x, Start.y, 0); PolygonRotateShift(AircraftWingL, 7, Start.x, Start.y, 0); PolygonRotateShift(AircraftWingR, 7, Start.x, Start.y, 0); #ifndef UNDITHER LKBrush GreenBrush(RGB_GREEN); LKBrush RedBrush(RGB_RED); #else LKBrush GreenBrush(RGB_WHITE); LKBrush RedBrush(RGB_BLACK); #endif if((brg < 180)) { Surface.SelectObject(RedBrush); Surface.Polygon(AircraftWingL ,7 ); Surface.SelectObject(LKBrush_White); Surface.Polygon(AircraftSide ,8 ); Surface.SelectObject(GreenBrush); Surface.Polygon(AircraftWingR ,7 ); Surface.SelectObject(oldBrush); } else { Surface.SelectObject(GreenBrush); Surface.Polygon(AircraftWingR ,7 ); Surface.SelectObject(LKBrush_White); Surface.Polygon(AircraftSide ,8 ); Surface.SelectObject(RedBrush); Surface.Polygon(AircraftWingL ,7 ); Surface.SelectObject(oldBrush); } if((brg < 90)|| (brg > 270)) { Surface.Polygon(AircraftTail ,5 ); } Surface.SelectObject(oldPen); Surface.SelectObject(oldBrush); } //else !asp_heading_task
void LKSurface::Segment(long x, long y, int radius, const RECT& rc, double start, double end) { // JMW added faster checking... if ((x - radius) > rc.right) return; if ((x + radius) < rc.left) return; if ((y - radius) > rc.bottom) return; if ((y + radius) < rc.top) return; bool EmptySector = end == start; if(EmptySector) { RasterPoint pt[2]; start = AngleLimit360(start); pt[0].x = x; pt[0].y = y; pt[1].x = x + (long) (radius * fastsine(start)); pt[1].y = y - (long) (radius * fastcosine(start)); Polyline(pt, array_size(pt), rc); } else { RasterPoint pt[68]; start = AngleLimit360(start); end = AngleLimit360(end); const int istart = std::ceil(start / 360.0 * 64); const int iend = std::floor(((end > start) ? end : end + 360) / 360 * 64); int npoly = 0; // Center point pt[npoly].x = x; pt[npoly].y = y; npoly++; // first Segment point pt[npoly].x = x + (long) (radius * fastsine(start)); pt[npoly].y = y - (long) (radius * fastcosine(start)); npoly++; for (int i = 0; i < 64; i++) { if (i <= iend - istart) { pt[npoly].x = x + (long) (radius * xcoords[(i + istart) % 64]); pt[npoly].y = y - (long) (radius * ycoords[(i + istart) % 64]); npoly++; } } // Last Segment Point pt[npoly].x = x + (long) (radius * fastsine(end)); pt[npoly].y = y - (long) (radius * fastcosine(end)); npoly++; // Close Polygon ( center point ) pt[npoly].x = x; pt[npoly].y = y; npoly++; assert(npoly <= (int)array_size(pt)); Polygon(pt, npoly, rc); } }
//#define CUPDEBUG bool ParseCUPWayPointString(TCHAR *String,WAYPOINT *Temp) { TCHAR ctemp[(COMMENT_SIZE*2)+1]; // must be bigger than COMMENT_SIZE! TCHAR *pToken; TCHAR TempString[READLINE_LENGTH+1]; TCHAR OrigString[READLINE_LENGTH+1]; TCHAR Tname[NAME_SIZE+1]; int flags=0; unsigned int i, j; bool ishome=false; // 100310 // strtok does not return empty fields. we create them here with special char #define DUMCHAR '|' Temp->Visible = true; // default all waypoints visible at start Temp->FarVisible = true; Temp->Format = LKW_CUP; Temp->Number = WayPointList.size(); Temp->FileNum = globalFileNum; #if BUGSTOP // This should never happen LKASSERT(_tcslen(String) < sizeof(OrigString)); #endif LK_tcsncpy(OrigString, String,READLINE_LENGTH); // if string is too short do nothing if (_tcslen(OrigString)<11) return false; #ifdef CUPDEBUG StartupStore(_T("OLD:<%s>%s"),OrigString,NEWLINE); #endif for (i=0,j=0; i<_tcslen(OrigString); i++) { // skip last comma, and avoid overruning the end if ( (i+1)>= _tcslen(OrigString)) break; if ( (OrigString[i] == _T(',')) && (OrigString[i+1] == _T(',')) ) { TempString[j++] = _T(','); TempString[j++] = _T(DUMCHAR); continue; } /* we need terminations for comments if ( OrigString[i] == _T('\r') ) continue; if ( OrigString[i] == _T('\n') ) continue; */ TempString[j++] = OrigString[i]; } TempString[j] = _T('\0'); #ifdef CUPDEBUG StartupStore(_T("NEW:<%s>%s"),TempString,NEWLINE); #endif // ---------------- NAME ---------------- pToken = _tcstok(TempString, TEXT(",")); if (pToken == NULL) return false; if (_tcslen(pToken)>NAME_SIZE) { pToken[NAME_SIZE-1]= _T('\0'); } _tcscpy(Temp->Name, pToken); CleanCupCode(Temp->Name); #ifdef CUPDEBUG StartupStore(_T(" CUP NAME=<%s>%s"),Temp->Name,NEWLINE); #endif // ---------------- CODE ------------------ pToken = _tcstok(NULL, TEXT(",")); if (pToken == NULL) return false; if (_tcslen(pToken)>CUPSIZE_CODE) pToken[CUPSIZE_CODE-1]= _T('\0'); _tcscpy(Temp->Code, pToken); for (i=_tcslen(Temp->Code)-1; i>1; i--) if (Temp->Code[i]==' ') Temp->Code[i]=0; else break; _tcscpy(Tname,Temp->Code); for (j=0, i=0; i<_tcslen(Tname); i++) //if (Tname[i]!='\"') Temp->Code[j++]=Tname[i]; if ( (Tname[i]!='\"') && (Tname[i]!=DUMCHAR) ) Temp->Code[j++]=Tname[i]; Temp->Code[j]= _T('\0'); if (_tcslen(Temp->Code)>5) { // 100310 if ( _tcscmp(Temp->Code,_T("LKHOME")) == 0 ) { StartupStore(_T(". Found LKHOME inside CUP waypoint <%s>%s"),Temp->Name,NEWLINE); ishome=true; } } #ifdef CUPDEBUG StartupStore(_T(" CUP CODE=<%s>%s"),Temp->Code,NEWLINE); #endif // ---------------- COUNTRY ------------------ pToken = _tcstok(NULL, TEXT(",")); if (pToken == NULL) return false; LK_tcsncpy(Temp->Country,pToken,CUPSIZE_COUNTRY); if (_tcslen(Temp->Country)>3) { Temp->Country[3]= _T('\0'); } if ((_tcslen(Temp->Country) == 1) && Temp->Country[0]==DUMCHAR) Temp->Country[0]=_T('\0'); #ifdef CUPDEBUG StartupStore(_T(" CUP COUNTRY=<%s>%s"),Temp->Country,NEWLINE); #endif // ---------------- LATITUDE ------------------ pToken = _tcstok(NULL, TEXT(",")); if (pToken == NULL) return false; Temp->Latitude = CUPToLat(pToken); if((Temp->Latitude > 90) || (Temp->Latitude < -90)) { return false; } #ifdef CUPDEBUG StartupStore(_T(" CUP LATITUDE=<%f>%s"),Temp->Latitude,NEWLINE); #endif // ---------------- LONGITUDE ------------------ pToken = _tcstok(NULL, TEXT(",")); if (pToken == NULL) return false; Temp->Longitude = CUPToLon(pToken); if((Temp->Longitude > 180) || (Temp->Longitude < -180)) { return false; } #ifdef CUPDEBUG StartupStore(_T(" CUP LONGITUDE=<%f>%s"),Temp->Longitude,NEWLINE); #endif // ---------------- ELEVATION ------------------ pToken = _tcstok(NULL, TEXT(",")); if (pToken == NULL) return false; Temp->Altitude = ReadAltitude(pToken); #ifdef CUPDEBUG StartupStore(_T(" CUP ELEVATION=<%f>%s"),Temp->Altitude,NEWLINE); #endif if (Temp->Altitude == -9999){ Temp->Altitude=0; } // ---------------- STYLE ------------------ pToken = _tcstok(NULL, TEXT(",")); if (pToken == NULL) return false; Temp->Style = (int)_tcstol(pToken,NULL,10); switch(Temp->Style) { case 2: // airfield grass case 4: // glider site case 5: // airfield solid flags = AIRPORT; flags += LANDPOINT; break; case 3: // outlanding flags = LANDPOINT; break; default: flags = TURNPOINT; break; } if (ishome) flags += HOME; Temp->Flags = flags; #ifdef CUPDEBUG StartupStore(_T(" CUP STYLE=<%d> flags=%d %s"),Temp->Style,Temp->Flags,NEWLINE); #endif // ---------------- RWY DIRECTION ------------------ pToken = _tcstok(NULL, TEXT(",")); if (pToken == NULL) return false; if ((_tcslen(pToken) == 1) && (pToken[0]==DUMCHAR)) Temp->RunwayDir=-1; else Temp->RunwayDir = (int)AngleLimit360(_tcstol(pToken, NULL, 10)); #ifdef CUPDEBUG StartupStore(_T(" CUP RUNWAY DIRECTION=<%d>%s"),Temp->RunwayDir,NEWLINE); #endif // ---------------- RWY LENGTH ------------------ pToken = _tcstok(NULL, TEXT(",")); if (pToken == NULL) return false; if ((_tcslen(pToken) == 1) && (pToken[0]==DUMCHAR)) Temp->RunwayLen = -1; else Temp->RunwayLen = (int)ReadLength(pToken); #ifdef CUPDEBUG StartupStore(_T(" CUP RUNWAY LEN=<%d>%s"),Temp->RunwayLen,NEWLINE); #endif // ---------------- AIRPORT FREQ ------------------ pToken = _tcstok(NULL, TEXT(",")); if (pToken == NULL) return false; if (_tcslen(pToken)>CUPSIZE_FREQ) pToken[CUPSIZE_FREQ-1]= _T('\0'); _tcscpy(Temp->Freq, pToken); TrimRight(Temp->Freq); _tcscpy(Tname,Temp->Freq); for (j=0, i=0; i<_tcslen(Tname); i++) if ( (Tname[i]!='\"') && (Tname[i]!=DUMCHAR) ) Temp->Freq[j++]=Tname[i]; Temp->Freq[j]= _T('\0'); #ifdef CUPDEBUG StartupStore(_T(" CUP FREQ=<%s>%s"),Temp->Freq,NEWLINE); #endif // ---------------- COMMENT ------------------ pToken = _tcstok(NULL, TEXT("\n\r")); if (pToken != NULL) { if (_tcslen(pToken)>=COMMENT_SIZE) pToken[COMMENT_SIZE-1]= _T('\0'); // remove trailing spaces and CR LF _tcscpy(ctemp, pToken); for (i=_tcslen(ctemp)-1; i>1; i--) { if ( (ctemp[i]==' ') || (ctemp[i]=='\r') || (ctemp[i]=='\n') ) ctemp[i]=0; else break; } // now remove " " (if there) for (j=0, i=0; i<_tcslen(ctemp); i++) if (ctemp[i]!='\"') ctemp[j++]=ctemp[i]; ctemp[j]= _T('\0'); if (_tcslen(ctemp) >0 ) { if (Temp->Comment) { free(Temp->Comment); } Temp->Comment = (TCHAR*)malloc((_tcslen(ctemp)+1)*sizeof(TCHAR)); if (Temp->Comment) _tcscpy(Temp->Comment, ctemp); } #ifdef CUPDEBUG StartupStore(_T(" CUP COMMENT=<%s>%s"),Temp->Comment,NEWLINE); #endif } else { Temp->Comment=NULL; // useless } if(Temp->Altitude <= 0) { WaypointAltitudeFromTerrain(Temp); } if (Temp->Details) { free(Temp->Details); } return true; }
static BOOL FLYSEN(PDeviceDescriptor_t d, TCHAR *String, NMEA_INFO *GPS_INFO) { TCHAR ctemp[80]; double vtas; static int offset=-1; // firmware 3.31h no offset // firmware 3.32 1 offset // Determine firmware version, assuming it will not change in the session! if (offset<0) { NMEAParser::ExtractParameter(String,ctemp,8); if ( (_tcscmp(ctemp,_T("A"))==0) || (_tcscmp(ctemp,_T("V"))==0)) offset=0; else { NMEAParser::ExtractParameter(String,ctemp,9); if ( (_tcscmp(ctemp,_T("A"))==0) || (_tcscmp(ctemp,_T("V"))==0)) offset=1; else return TRUE; } } // VOID GPS SIGNAL NMEAParser::ExtractParameter(String,ctemp,8+offset); if (_tcscmp(ctemp,_T("V"))==0) { GPS_INFO->NAVWarning=true; GPSCONNECT=false; goto label_nogps; } // ------------------------ double tmplat; double tmplon; NMEAParser::ExtractParameter(String,ctemp,1+offset); tmplat = MixedFormatToDegrees(StrToDouble(ctemp, NULL)); NMEAParser::ExtractParameter(String,ctemp,2+offset); tmplat = NorthOrSouth(tmplat, ctemp[0]); NMEAParser::ExtractParameter(String,ctemp,3+offset); tmplon = MixedFormatToDegrees(StrToDouble(ctemp, NULL)); NMEAParser::ExtractParameter(String,ctemp,4+offset); tmplon = EastOrWest(tmplon,ctemp[0]); if (!((tmplat == 0.0) && (tmplon == 0.0))) { GPS_INFO->Latitude = tmplat; GPS_INFO->Longitude = tmplon; GPS_INFO->NAVWarning=false; GPSCONNECT=true; } // GPS SPEED NMEAParser::ExtractParameter(String,ctemp,6+offset); GPS_INFO->Speed = StrToDouble(ctemp,NULL)/10; // TRACK BEARING if (GPS_INFO->Speed>1.0) { NMEAParser::ExtractParameter(String,ctemp,5+offset); GPS_INFO->TrackBearing = AngleLimit360(StrToDouble(ctemp, NULL)); } // HGPS NMEAParser::ExtractParameter(String,ctemp,7+offset); GPS_INFO->Altitude = StrToDouble(ctemp,NULL); // ------------------------ label_nogps: // SATS NMEAParser::ExtractParameter(String,ctemp,9+offset); GPS_INFO->SatellitesUsed = (int) StrToDouble(ctemp,NULL); // DATE // Firmware 3.32 has got the date if (offset>0) { NMEAParser::ExtractParameter(String,ctemp,0); long gy, gm, gd; TCHAR *Stop; gy = _tcstol(&ctemp[4], &Stop, 10) + 2000; ctemp[4] = '\0'; gm = _tcstol(&ctemp[2], &Stop, 10); ctemp[2] = '\0'; gd = _tcstol(&ctemp[0], &Stop, 10); if ( ((gy > 1980) && (gy <2100) ) && (gm != 0) && (gd != 0) ) { GPS_INFO->Year = gy; GPS_INFO->Month = gm; GPS_INFO->Day = gd; } } // TIME // ignoring 00:00.00 // And no UTC, since this is local time already. NMEAParser::ExtractParameter(String,ctemp,0+offset); double fixTime = StrToDouble(ctemp,NULL); if (fixTime>0 && GPS_INFO->SatellitesUsed>0) { double hours, mins,secs; hours = fixTime / 10000; GPS_INFO->Hour = (int)hours; mins = fixTime / 100; mins = mins - (GPS_INFO->Hour*100); GPS_INFO->Minute = (int)mins; secs = fixTime - (GPS_INFO->Hour*10000) - (GPS_INFO->Minute*100); GPS_INFO->Second = (int)secs; } // HPA from the pressure sensor // NMEAParser::ExtractParameter(String,ctemp,10+offset); // double ps = StrToDouble(ctemp,NULL)/100; // GPS_INFO->BaroAltitude = (1 - pow(fabs(ps / QNH), 0.190284)) * 44307.69; // HBAR 1013.25 NMEAParser::ExtractParameter(String,ctemp,11+offset); if (d == pDevPrimaryBaroSource) { GPS_INFO->BaroAltitude = AltitudeToQNHAltitude(StrToDouble(ctemp,NULL)); GPS_INFO->BaroAltitudeAvailable = TRUE; } // VARIO NMEAParser::ExtractParameter(String,ctemp,12+offset); GPS_INFO->Vario = StrToDouble(ctemp,NULL)/100; // TAS NMEAParser::ExtractParameter(String,ctemp,13+offset); vtas=StrToDouble(ctemp,NULL)/10; GPS_INFO->IndicatedAirspeed = vtas/AirDensityRatio(GPS_INFO->BaroAltitude); GPS_INFO->TrueAirspeed = vtas; if (GPS_INFO->IndicatedAirspeed >0) GPS_INFO->AirspeedAvailable = TRUE; else GPS_INFO->AirspeedAvailable = FALSE; // ignore n.14 airspeed source // OAT NMEAParser::ExtractParameter(String,ctemp,15+offset); GPS_INFO->OutsideAirTemperature = StrToDouble(ctemp,NULL); GPS_INFO->TemperatureAvailable=TRUE; // ignore n.16 baloon temperature // BATTERY PERCENTAGES NMEAParser::ExtractParameter(String,ctemp,17+offset); GPS_INFO->ExtBatt1_Voltage = StrToDouble(ctemp,NULL)+1000; NMEAParser::ExtractParameter(String,ctemp,18+offset); GPS_INFO->ExtBatt2_Voltage = StrToDouble(ctemp,NULL)+1000; GPS_INFO->VarioAvailable = TRUE; // currently unused in LK, but ready for next future TriggerVarioUpdate(); TriggerGPSUpdate(); return TRUE; }
void MapWindow::RenderNearAirspace(LKSurface& Surface, const RECT rci) { RECT rc = rci; /* rectangle for sideview */ RECT rct = rc; /* rectangle for topview */ rc.top = (int)((double)(rci.bottom-rci.top )*fSplitFact); rct.bottom = rc.top ; // Expose the topview rect size in use.. Current_Multimap_TopRect=rct; LKFont hfOldFnt = Surface.SelectObject(LK8PanelUnitFont/* Sender->GetFont()*/); int *iSplit = &Multimap_SizeY[Get_Current_Multimap_Type()]; int k; static double fHeigtScaleFact = 1.0; double GPSlat, GPSlon, GPSalt, GPSbrg; double calc_terrainalt; double calc_altitudeagl; // double alt; TCHAR text[TBSIZE+1]; TCHAR buffer[TBSIZE+1]; CAirspaceBase near_airspace; CAirspace *found = NULL; // bool bFound = false; DiagrammStruct sDia; bool bAS_Inside=false; int iAS_Bearing=0; int iAS_HorDistance=15000; int iABS_AS_HorDistance=0; int iAS_VertDistance=0; bool bValid; static bool bHeightScale = false; long wpt_brg = 0; POINT line[2]; POINT TxYPt; POINT TxXPt; SIZE tsize; LKColor GREEN_COL = RGB_GREEN; LKColor BLUE_COL = RGB_BLUE; LKColor LIGHTBLUE_COL = RGB_LIGHTBLUE; BOOL bInvCol = true; //INVERTCOLORS unsigned short getsideviewpage=GetSideviewPage(); LKASSERT(getsideviewpage<3); if(bInvCol) Sideview_TextColor = INV_GROUND_TEXT_COLOUR; else Sideview_TextColor = RGB_WHITE; switch(LKevent) { case LKEVENT_NEWRUN: // CALLED ON ENTRY: when we select this page coming from another mapspace bHeightScale = false; // fZOOMScale[getsideviewpage] = 1.0; fHeigtScaleFact = 1.0; if (IsMultimapTopology()) ForceVisibilityScan=true; break; case LKEVENT_UP: // click on upper part of screen, excluding center if(bHeightScale) fHeigtScaleFact /= ZOOMFACTOR; else fZOOMScale[getsideviewpage] /= ZOOMFACTOR; if (IsMultimapTopology()) ForceVisibilityScan=true; break; case LKEVENT_DOWN: // click on lower part of screen, excluding center if(bHeightScale) fHeigtScaleFact *= ZOOMFACTOR; else fZOOMScale[getsideviewpage] *= ZOOMFACTOR; if (IsMultimapTopology()) ForceVisibilityScan=true; break; case LKEVENT_LONGCLICK: for (k=0 ; k <= Sideview_iNoHandeldSpaces; k++) { if( Sideview_pHandeled[k].psAS != NULL) { if (PtInRect(&(Sideview_pHandeled[k].rc), startScreen)) { #if 1 // MULTISELECT dlgAddMultiSelectListItem((long*) Sideview_pHandeled[k].psAS, 0, IM_AIRSPACE, 0); #else if (EnableSoundModes)PlayResource(TEXT("IDR_WAV_BTONE4")); dlgAirspaceDetails(Sideview_pHandeled[k].psAS); // dlgA #endif LKevent=LKEVENT_NONE; } } } dlgMultiSelectListShowModal(); if ( LKevent != LKEVENT_NONE ) { if (PtInRect(&rc, startScreen)) bHeightScale = !bHeightScale; if (PtInRect(&rct, startScreen)) bHeightScale = false; } break; case LKEVENT_PAGEUP: #ifdef OFFSET_SETP if(bHeightScale) fOffset -= OFFSET_SETP; else #endif { if(*iSplit == SIZE1) *iSplit = SIZE0; if(*iSplit == SIZE2) *iSplit = SIZE1; if(*iSplit == SIZE3) *iSplit = SIZE2; } break; case LKEVENT_PAGEDOWN: #ifdef OFFSET_SETP if(bHeightScale) fOffset += OFFSET_SETP; else #endif { if(*iSplit == SIZE2) *iSplit = SIZE3; if(*iSplit == SIZE1) *iSplit = SIZE2; if(*iSplit == SIZE0) *iSplit = SIZE1; } break; } LKASSERT(((*iSplit==SIZE0)||(*iSplit==SIZE1)||(*iSplit==SIZE2)||(*iSplit==SIZE3)||(*iSplit==SIZE4))); LKevent=LKEVENT_NONE; // Current_Multimap_SizeY is global, and must be used by all multimaps! // It is defined in Multimap.cpp and as an external in Multimap.h // It is important that it is updated, because we should resize terrain // only if needed! Resizing terrain takes some cpu and some time. // So we need to know when this is not necessary, having the same size of previous // multimap, if we are switching. // The current implementation is terribly wrong by managing resizing of sideview in // each multimap: it should be done by a common layer. // CAREFUL: // If for any reason DrawTerrain() is called after resizing to 0 (full sideview) // LK WILL CRASH with no hope to recover. if(Current_Multimap_SizeY != *iSplit) { Current_Multimap_SizeY=*iSplit; SetSplitScreenSize(*iSplit); rc.top = (long)((double)(rci.bottom-rci.top )*fSplitFact); rct.bottom = rc.top ; } if(bInvCol) { GREEN_COL = GREEN_COL.ChangeBrightness(0.6); BLUE_COL = BLUE_COL.ChangeBrightness(0.6);; LIGHTBLUE_COL = LIGHTBLUE_COL.ChangeBrightness(0.4);; } GPSlat = DrawInfo.Latitude; GPSlon = DrawInfo.Longitude; GPSalt = DrawInfo.Altitude; GPSbrg = DrawInfo.TrackBearing; calc_terrainalt = DerivedDrawInfo.TerrainAlt; calc_altitudeagl = DerivedDrawInfo.AltitudeAGL; GPSalt = DerivedDrawInfo.NavAltitude; bValid = false; iAS_HorDistance = 5000; iAS_Bearing = (int)GPSbrg; iAS_VertDistance= 0; found = CAirspaceManager::Instance().GetNearestAirspaceForSideview(); if(found != NULL) { near_airspace = CAirspaceManager::Instance().GetAirspaceCopy(found); bValid = near_airspace.GetDistanceInfo(bAS_Inside, iAS_HorDistance, iAS_Bearing, iAS_VertDistance); } iABS_AS_HorDistance = abs( iAS_HorDistance); wpt_brg = (long)AngleLimit360(GPSbrg - iAS_Bearing + 90.0); // Variables from ASP system here contain the following informations: // fAS_HorDistance - always contains horizontal distance from the asp, negative if horizontally inside (This does not mean that we're inside vertically as well!) // fAS_Bearing - always contains bearing to the nearest horizontal point // bValid - true if bAS_Inside, iAS_HorDistance, iAS_Bearing, iAS_VertDistance contains valid informations // this will be true if the asp border is close enough to be tracked by the warning system // bAS_Inside - current position is inside in the asp, calculated by the warning system // iAS_HorDistance - horizontal distance to the nearest horizontal border, negative if horizontally inside, calculated by the warning system // iAS_Bearing - bearing to the nearest horizontal border, calculated by the warning system // iAS_VertDistance - vertical distance to the nearest asp border, negative if the border is above us, positive if the border below us, calculated by the warning system // near_airspace.WarningLevel(): // awNone - no warning condition exists // awYellow - current position is near to a warning position // awRed - current posisiton is forbidden by asp system, we are in a warning position /********************************************************************* * calc the horizontal zoom *********************************************************************/ sDia.fXMin = -5000.0; sDia.fXMax = 5000.0; /* even when invalid the horizontal distance is calculated correctly */ if(bValid) { double fScaleDist = iABS_AS_HorDistance; sDia.fXMin = min(-2500.0 , fScaleDist * 1.5 ); sDia.fXMax = max( 2500.0 , fScaleDist * 1.5 ); #ifdef NEAR_AS_ZOOM_1000M if(((iABS_AS_HorDistance) < 900) && (bValid)) // 1km zoom { sDia.fXMin = min(-900.0, fScaleDist * 1.5 ); sDia.fXMax = max( 900.0, fScaleDist * 1.5 ); } #endif #ifdef NEAR_AS_ZOOM_1000FT if((abs(iABS_AS_HorDistance) < 333)) // 1000ft zoom { sDia.fXMin = min(-333.0, fScaleDist * 1.5 ); sDia.fXMax = max( 333.0, fScaleDist * 1.5 ); } #endif } #define RND_FACT 10.0 if( ( sDia.fXMax *fZOOMScale[getsideviewpage]) > 100000) fZOOMScale[getsideviewpage] /= ZOOMFACTOR; if(( sDia.fXMax *fZOOMScale[getsideviewpage]) < 500) { fZOOMScale[getsideviewpage] *= ZOOMFACTOR; } double fOldZoomScale=-1; if(fZOOMScale[getsideviewpage] != fOldZoomScale) { fOldZoomScale = fZOOMScale[getsideviewpage]; sDia.fXMax = sDia.fXMax *fZOOMScale[getsideviewpage]; sDia.fXMin = -sDia.fXMax /5; } /********************************************************************* * calc the vertical zoom *********************************************************************/ sDia.fYMin = max(0.0, GPSalt-2300); sDia.fYMax = max(MAXALTTODAY, GPSalt+1000); if(bValid) { double fBottom = near_airspace.Base()->Altitude; sDia.fYMin = min(fBottom*0.8, sDia.fYMin ); sDia.fYMin = max(0.0, sDia.fYMin ); if(sDia.fYMin < 300) sDia.fYMin =0; sDia.fYMax = max((fBottom*1.2f), sDia.fYMax ); if(abs(iAS_VertDistance) < 250) { sDia.fYMax = ((int)((GPSalt+abs(iAS_VertDistance))/400) + 2) *400 ; sDia.fYMin = ((int)((GPSalt-abs(iAS_VertDistance))/400) - 1) *400 ; if(sDia.fYMin-MIN_ALTITUDE < 0) sDia.fYMin = 0; } #ifdef VERTICAL_ZOOM_50 if(abs(iAS_VertDistance) < 50) { sDia.fYMax = ((int)((GPSalt+abs(iAS_VertDistance))/100) + 2) *100 ; sDia.fYMin = ((int)((GPSalt-abs(iAS_VertDistance))/100) - 1) *100 ; if(sDia.fYMin-MIN_ALTITUDE < 0) sDia.fYMin = 0; } #endif sDia.fYMin = max((double)0.0f,(double) sDia.fYMin); #ifdef OFFSET_SETP if(( sDia.fYMax + fOffset) > MAX_ALTITUDE) fOffset -= OFFSET_SETP; if(( sDia.fYMin + fOffset) < 0.0) fOffset += OFFSET_SETP; sDia.fYMin += fOffset; sDia.fYMax += fOffset; #endif // if(fHeigtScaleFact * sDia.fYMax > MAX_ALTITUDE ) // fHeigtScaleFact /=ZOOMFACTOR; if(fHeigtScaleFact * sDia.fYMax < MIN_ALTITUDE ) fHeigtScaleFact *=ZOOMFACTOR; sDia.fYMax *= fHeigtScaleFact; } /**************************************************************************************************** * draw topview first ****************************************************************************************************/ if(fSplitFact > 0.0) { sDia.rc = rct; sDia.rc.bottom-=1; SharedTopView(Surface, &sDia, (double) iAS_Bearing, (double) wpt_brg); } /**************************************************************************************************** * draw airspace and terrain elements ****************************************************************************************************/ RECT rcc = rc; /* rc corrected */ if(sDia.fYMin < GC_SEA_LEVEL_TOLERANCE) rcc.bottom -= SV_BORDER_Y; /* scale witout sea */ sDia.rc = rcc; RenderAirspaceTerrain(Surface, GPSlat, GPSlon, iAS_Bearing, &sDia ); LKFont hfOld = Surface.SelectObject(LK8InfoNormalFont); if(bValid) { LKASSERT(_tcslen(near_airspace.Name())<TBSIZE); // Diagnostic only in 3.1j, to be REMOVED LK_tcsncpy(Sideview_szNearAS, near_airspace.Name(), TBSIZE ); } else { _stprintf(text,TEXT("%s"), MsgToken(1259)); // LKTOKEN _@M1259_ "Too far, not calculated" Surface.GetTextSize(text, _tcslen(text), &tsize); TxYPt.x = (rc.right-rc.left-tsize.cx)/2; TxYPt.y = (rc.bottom-rc.top)/2; Surface.SetBkMode(TRANSPARENT); Surface.DrawText(TxYPt.x, TxYPt.y-20, text, _tcslen(text)); _stprintf(Sideview_szNearAS,TEXT("%s"), text); } Surface.SelectObject(hfOld); /**************************************************************************************************** * draw airspace and terrain elements ****************************************************************************************************/ /**************************************************************************************************** * draw diagram ****************************************************************************************************/ double xtick = 1.0; double fRange =fabs(sDia.fXMax - sDia.fXMin) ; if (fRange>3.0*1000.0) xtick = 2.0; if (fRange>15*1000.0) xtick = 5.0; if (fRange>50.0*1000.0) xtick = 10.0; if (fRange>100.0*1000.0) xtick = 20.0; if (fRange>200.0*1000.0) xtick = 25.0; if (fRange>250.0*1000.0) xtick = 50.0; if (fRange>500.0*1000.0) xtick = 100.0; if (fRange>1000.0*1000.0) xtick = 1000.0; if(bInvCol) { Surface.SelectObject(LK_BLACK_PEN); Surface.SelectObject(LKBrush_Black); } else { Surface.SelectObject(LK_WHITE_PEN); Surface.SelectObject(LKBrush_White); } LKColor txtCol = GROUND_TEXT_COLOUR; if(bInvCol) if(sDia.fYMin > GC_SEA_LEVEL_TOLERANCE) txtCol = INV_GROUND_TEXT_COLOUR; Surface.SetBkMode(TRANSPARENT); Surface.SetTextColor(txtCol); _stprintf(text, TEXT("%s"),Units::GetUnitName(Units::GetUserDistanceUnit())); switch(GetMMNorthUp(getsideviewpage)) { case NORTHUP: default: DrawXGrid(Surface, rc , xtick/DISTANCEMODIFY, xtick, 0,TEXT_ABOVE_LEFT, RGB_BLACK, &sDia,text); break; case TRACKUP: DrawXGrid(Surface, rci, xtick/DISTANCEMODIFY, xtick, 0,TEXT_ABOVE_LEFT, RGB_BLACK, &sDia,text); break; } Surface.SetTextColor(Sideview_TextColor); double fHeight = (sDia.fYMax-sDia.fYMin); double ytick = 100.0; if (fHeight >500.0) ytick = 200.0; if (fHeight >1000.0) ytick = 500.0; if (fHeight >2000.0) ytick = 1000.0; if (fHeight >4000.0) ytick = 2000.0; if (fHeight >8000.0) ytick = 4000.0; if(Units::GetUserAltitudeUnit() == unFeet) ytick = ytick * FEET_FACTOR; _stprintf(text, TEXT("%s"),Units::GetUnitName(Units::GetUserAltitudeUnit())); if(sDia.fYMin < GC_SEA_LEVEL_TOLERANCE) rc.bottom -= SV_BORDER_Y; /* scale witout sea */ DrawYGrid(Surface, rc, ytick/ALTITUDEMODIFY,ytick, 0,TEXT_UNDER_RIGHT ,Sideview_TextColor, &sDia, text); if(!bInvCol) Surface.SetBkMode(OPAQUE); /**************************************************************************************************** * draw AGL ****************************************************************************************************/ if(calc_altitudeagl - sDia.fYMin > 500) { Surface.SetTextColor(LIGHTBLUE_COL); Units::FormatUserAltitude(calc_altitudeagl, buffer, 7); LK_tcsncpy(text, MsgToken(1742), TBSIZE-_tcslen(buffer)); // AGL: _tcscat(text,buffer); Surface.GetTextSize(text, _tcslen(text), &tsize); TxYPt.x = CalcDistanceCoordinat(0, &sDia)- tsize.cx/2; TxYPt.y = CalcHeightCoordinat( (calc_terrainalt + calc_altitudeagl )*0.8, &sDia ); if((tsize.cy) < ( CalcHeightCoordinat( calc_terrainalt, &sDia )- TxYPt.y )) { Surface.DrawText(TxYPt.x+IBLSCALE(1), TxYPt.y , text, _tcslen(text)); } } Surface.SetBkMode(TRANSPARENT); /**************************************************************************************************** * Print current Elevation ****************************************************************************************************/ Surface.SetTextColor(RGB_BLACK); int x,y; if((calc_terrainalt- sDia.fYMin) > 0) { Units::FormatUserAltitude(calc_terrainalt, buffer, 7); LK_tcsncpy(text, MsgToken(1743), TBSIZE-_tcslen(buffer)); // ELV: _tcscat(text,buffer); Surface.GetTextSize(text, _tcslen(text), &tsize); x = CalcDistanceCoordinat(0, &sDia) - tsize.cx/2; y = CalcHeightCoordinat( calc_terrainalt, &sDia ); if ((ELV_FACT*tsize.cy) < abs(rc.bottom - y)) { Surface.DrawText(x, rc.bottom -(int)(ELV_FACT * tsize.cy), text, _tcslen(text)); } } /**************************************************************************************************** * draw side elements ****************************************************************************************************/ Surface.SetTextColor(Sideview_TextColor); Surface.SetBkMode(OPAQUE); LKFont hfOld2 = Surface.SelectObject(LK8InfoNormalFont); // DrawTelescope ( hdc, iAS_Bearing-90.0, rc.right - NIBLSCALE(13), rc.top + NIBLSCALE(58)); Surface.SelectObject(hfOld2); Surface.SetBkMode(TRANSPARENT); Surface.SelectObject(hfOld); Surface.SetTextColor(GROUND_TEXT_COLOUR); if(bInvCol) if(sDia.fYMin > GC_SEA_LEVEL_TOLERANCE) Surface.SetTextColor(INV_GROUND_TEXT_COLOUR); /****************************************************************************************************/ /****************************************************************************************************/ /**************************************************************************************************** * draw distances to next airspace ****************************************************************************************************/ /****************************************************************************************************/ /****************************************************************************************************/ if (bValid) { /**************************************************************************************************** * draw horizontal distance to next airspace ****************************************************************************************************/ Surface.SetTextColor(Sideview_TextColor); Surface.SetBkMode(OPAQUE); LKFont hfOldU = Surface.SelectObject(LK8InfoNormalFont); // horizontal distance line[0].x = CalcDistanceCoordinat(0, &sDia); line[0].y = CalcHeightCoordinat( GPSalt, &sDia ); line[1].x = CalcDistanceCoordinat(iABS_AS_HorDistance, &sDia); line[1].y = line[0].y; Surface.DrawDashLine(THICK_LINE, line[0], line[1], Sideview_TextColor, rc); if(iAS_HorDistance < 0) { line[0].y = CalcHeightCoordinat( GPSalt - (double)iAS_VertDistance, &sDia ); line[1].y = line[0].y; Surface.DrawDashLine(THICK_LINE, line[0], line[1], Sideview_TextColor, rc); } bool bLeft = false; if( line[0].x < line[1].x) bLeft = false; else bLeft = true; Units::FormatUserDistance(iABS_AS_HorDistance, buffer, 7); _stprintf(text,_T(" %s"),buffer); Surface.GetTextSize(text, _tcslen(text), &tsize); if((GPSalt- sDia.fYMin /*-calc_terrainalt */) < 300) TxXPt.y = CalcHeightCoordinat( GPSalt, &sDia ) - tsize.cy; else TxXPt.y = CalcHeightCoordinat( GPSalt, &sDia ) + NIBLSCALE(3); if(tsize.cx > (line[1].x - line[0].x) ) TxXPt.x = CalcDistanceCoordinat( iABS_AS_HorDistance ,&sDia) -tsize.cx- NIBLSCALE(3); else TxXPt.x = CalcDistanceCoordinat( iABS_AS_HorDistance / 2.0, &sDia) -tsize.cx/2; Surface.DrawText(TxXPt.x, TxXPt.y, text, _tcslen(text)); /**************************************************************************************************** * draw vertical distance to next airspace ****************************************************************************************************/ line[0].x = CalcDistanceCoordinat( iABS_AS_HorDistance , &sDia); line[0].y = CalcHeightCoordinat( GPSalt, &sDia ); line[1].x = line[0].x; line[1].y = CalcHeightCoordinat( GPSalt - (double)iAS_VertDistance, &sDia ); Surface.DrawDashLine(THICK_LINE, line[0], line[1], Sideview_TextColor, rc); Units::FormatUserAltitude( (double)abs(iAS_VertDistance), buffer, 7); _stprintf(text,_T(" %s"),buffer); Surface.GetTextSize(text, _tcslen(text), &tsize); if ( bLeft ) TxYPt.x = CalcDistanceCoordinat(iABS_AS_HorDistance, &sDia)- tsize.cx - NIBLSCALE(3); else TxYPt.x = CalcDistanceCoordinat(iABS_AS_HorDistance, &sDia)+ NIBLSCALE(5); if( abs( line[0].y - line[1].y) > tsize.cy) TxYPt.y = CalcHeightCoordinat( GPSalt - (double)iAS_VertDistance/2.0, &sDia) -tsize.cy/2 ; else TxYPt.y = min( line[0].y , line[1].y) - tsize.cy ; Surface.DrawText(TxYPt.x, TxYPt.y , text, _tcslen(text)); Surface.SelectObject(hfOldU); } /**************************************************************************************************** * draw plane sideview at least ****************************************************************************************************/ RenderPlaneSideview(Surface, 0.0 , GPSalt,wpt_brg, &sDia ); hfOldFnt = Surface.SelectObject(LK8InfoNormalFont/* Sender->GetFont()*/); DrawMultimap_SideTopSeparator(Surface,rct); /**************************************************************************************************** * draw selection frame ****************************************************************************************************/ if(bHeightScale) DrawSelectionFrame(Surface, rc); #ifdef TOP_SELECTION_FRAME else DrawSelectionFrame(hdc, rci); #endif Surface.SelectObject(hfOldFnt/* Sender->GetFont()*/); Surface.SetBkMode(TRANSPARENT); Surface.SelectObject(hfOldFnt/* Sender->GetFont()*/); }
void DistanceBearing(double lat1, double lon1, double lat2, double lon2, double *Distance, double *Bearing) { // incomplete, test does not show benefits, low hits #if (LK_CACHECALC && LK_CACHECALC_DBE) #define CASIZE_DBE 50 static bool doinit=true; static int cacheIndex; static double cur_checksum; static double cur_lat1, cur_lat2, cur_lon1, cur_lon2; bool cacheFound; int i; static double cache_checksum[CASIZE_DBE]; static double cache_lat1[CASIZE_DBE]; static double cache_lat2[CASIZE_DBE]; static double cache_lon1[CASIZE_DBE]; static double cache_lon2[CASIZE_DBE]; static double cache_Distance[CASIZE_DBE]; static double cache_Bearing[CASIZE_DBE]; if (doinit) { cacheIndex=0; for (i=0; i<CASIZE_DBE; i++) { cache_checksum[i]=0; cache_lat1[i]=0; cache_lat2[i]=0; cache_lon1[i]=0; cache_lon2[i]=0; cache_Distance[i]=0; cache_Bearing[i]=0; } doinit=false; } Cache_Calls_DBE++; cur_checksum=lat1+lat2+lon1+lon2; cacheFound=false; for (i=0; i<CASIZE_DBE; i++) { if ( cache_checksum[i] != cur_checksum ) continue; if ( cache_lat1[i] != lat1 ) { Cache_False_DBE++; continue; } if ( cache_lat2[i] != lat2 ) { Cache_False_DBE++; continue; } if ( cache_lon1[i] != lon1 ) { Cache_False_DBE++; continue; } if ( cache_lon2[i] != lon2 ) { Cache_False_DBE++; continue; } cacheFound=true; break; } if (cacheFound) { Cache_Hits_DBE++; } else { cur_lat1=lat1; cur_lat2=lat2; cur_lon1=lon1; cur_lon2=lon2; } #endif lat1 *= DEG_TO_RAD; lat2 *= DEG_TO_RAD; lon1 *= DEG_TO_RAD; lon2 *= DEG_TO_RAD; double clat1 = cos(lat1); double clat2 = cos(lat2); double dlon = lon2-lon1; if (Distance) { double s1 = sin((lat2-lat1)/2); double s2 = sin(dlon/2); double a= max(0.0,min(1.0,s1*s1+clat1*clat2*s2*s2)); *Distance = 6371000.0*2.0*atan2(sqrt(a),sqrt(1.0-a)); } if (Bearing) { double y = sin(dlon)*clat2; double x = clat1*sin(lat2)-sin(lat1)*clat2*cos(dlon); *Bearing = (x==0 && y==0) ? 0:AngleLimit360(atan2(y,x)*RAD_TO_DEG); } #if (LK_CACHECALC && LK_CACHECALC_DBE) if (!cacheFound) { if (++cacheIndex==CASIZE_DBE) cacheIndex=0; cache_checksum[cacheIndex]=cur_checksum; cache_lat1[cacheIndex]=cur_lat1; cache_lat2[cacheIndex]=cur_lat2; cache_lon1[cacheIndex]=cur_lon1; cache_lon2[cacheIndex]=cur_lon2; } #endif }
void MapWindow::DrawWindAtAircraft2(LKSurface& Surface, const POINT& Orig, const RECT& rc) { int i; POINT Start; TCHAR sTmp[12]; static SIZE tsize = {0,0}; if (DerivedDrawInfo.WindSpeed<1) { return; // JMW don't bother drawing it if not significant } if (tsize.cx == 0){ const auto oldFont = Surface.SelectObject(MapWindowBoldFont); Surface.GetTextSize(TEXT("99"), 2, &tsize); Surface.SelectObject(oldFont); tsize.cx = tsize.cx/2; } int wmag = iround(4.0*DerivedDrawInfo.WindSpeed); Start.y = Orig.y; Start.x = Orig.x; int kx = tsize.cx/ScreenScale/2; POINT Arrow[7] = { {0,-20}, {-6,-26}, {0,-20}, {6,-26}, {0,-20}, {8+kx, -24}, {-8-kx, -24}}; for (i=1;i<4;i++) Arrow[i].y -= wmag; PolygonRotateShift(Arrow, 7, Start.x, Start.y, DerivedDrawInfo.WindBearing-DisplayAngle); // // Draw Wind Arrow // POINT Tail[2] = {{0,-20}, {0,-26-min(20,wmag)*3}}; double angle = AngleLimit360(DerivedDrawInfo.WindBearing-DisplayAngle); for(i=0; i<2; i++) { if (ScreenScale>1) { Tail[i].x *= ScreenScale; Tail[i].y *= ScreenScale; } protateshift(Tail[i], angle, Start.x, Start.y); } // optionally draw dashed line for wind arrow Surface.DrawLine(PEN_DASH, 1, Tail[0], Tail[1], LKColor(0,0,0), rc); // Paint wind value only while circling if ( (mode.Is(Mode::MODE_CIRCLING)) ) { _stprintf(sTmp, _T("%d"), iround(DerivedDrawInfo.WindSpeed * SPEEDMODIFY)); TextInBoxMode_t TextInBoxMode = {0}; TextInBoxMode.AlligneCenter = true; // { 16 | 32 }; // JMW test {2 | 16}; TextInBoxMode.WhiteBorder = true; if (Arrow[5].y>=Arrow[6].y) { TextInBox(Surface, &rc, sTmp, Arrow[5].x-kx, Arrow[5].y, 0, &TextInBoxMode); } else { TextInBox(Surface, &rc, sTmp, Arrow[6].x-kx, Arrow[6].y, 0, &TextInBoxMode); } } const auto hpOld = Surface.SelectObject(LKPen_Black_N2); const auto hbOld = Surface.SelectObject(LKBrush_Grey); Surface.Polygon(Arrow,5); Surface.SelectObject(hbOld); Surface.SelectObject(hpOld); }