/* * VENTA3 This is a modified Segment() */ int DrawArc(HDC hdc, long x, long y, int radius, RECT rc, double start, double end) { POINT pt[66]; int i; int istart; int iend; rectObj rect; rect.minx = x-radius; rect.maxx = x+radius; rect.miny = y-radius; rect.maxy = y+radius; rectObj rcrect; rcrect.minx = rc.left; rcrect.maxx = rc.right; rcrect.miny = rc.top; rcrect.maxy = rc.bottom; if (msRectOverlap(&rect, &rcrect)!=MS_TRUE) { 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--; 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 (npoly) { Polyline(hdc,pt,npoly); // TODO check ClipPolygon for HP31X } return TRUE; }
// HeadWind error will be shown as -999 // These values are all in m/s // We can have a serious problem when the headwind is so strong that the // aircraft is actually flying backwards. // In such case, the heading will show correctly and the pilot should see // that there is a problem. // // A positive value indicates a headwind, and a negative value indicates a tailwind. // void CalculateHeadWind(NMEA_INFO *Basic, DERIVED_INFO *Calculated) { static double CrossBearingLast= -1.0; static double WindSpeedLast= -1.0; if (Basic->NAVWarning) { Calculated->HeadWind = -999; return; } double CrossBearing; CrossBearing = AngleLimit360(Calculated->Heading - Calculated->WindBearing); #if 1 // vector wind if ((CrossBearing != CrossBearingLast)||(Calculated->WindSpeed != WindSpeedLast)) { Calculated->HeadWind = Calculated->WindSpeed * fastcosine(CrossBearing); // CrossWind = WindSpeed * fastsine(CrossBearing); UNUSED CrossBearingLast = CrossBearing; WindSpeedLast = Calculated->WindSpeed; } #else if (Basic->AirspeedAvailable) { Calculated->HeadWind = Basic->TrueAirspeed - Basic->Speed; } else { // for estimated IAS, this is also vector wind Calculated->HeadWind = Calculated->TrueAirspeedEstimated - Basic->Speed; } #endif //StartupStore(_T("..... CrossBearing=%f hdwind=%f windspeed=%f\n"),CrossBearing,Calculated->HeadWind, Calculated->WindSpeed); }
// // The heading track line, like on Garmin units // void MapWindow::DrawHeading(HDC hdc, POINT Orig, RECT rc ) { if (DrawInfo.NAVWarning) return; // 100214 if ( mode.Is(MapWindow::Mode::MODE_CIRCLING)) return; POINT p2; double tmp = 200000*zoom.ResScaleOverDistanceModify(); if ( !( DisplayOrientation == TRACKUP || DisplayOrientation == NORTHCIRCLE || DisplayOrientation == TRACKCIRCLE )) { double trackbearing = DrawInfo.TrackBearing; p2.y= Orig.y - (int)(tmp*fastcosine(trackbearing)); p2.x= Orig.x + (int)(tmp*fastsine(trackbearing)); } else { p2.x=Orig.x; p2.y=Orig.y-(int)tmp; } // Reduce the rectangle for a better effect rc.top+=NIBLSCALE(5); rc.right-=NIBLSCALE(5); rc.bottom-=NIBLSCALE(5); rc.left+=NIBLSCALE(5); ForcedClipping=true; if (BlackScreen) _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), Orig, p2, RGB_INVDRAW, rc); // 091109 else _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), Orig, p2, RGB_BLACK, rc); ForcedClipping=false; }
void MapWindow::CalculateOrigin(const RECT rc, POINT *Orig) { if (mode.Is(Mode::MODE_PAN)) { // North up DisplayAngle = 0.0; DisplayAircraftAngle = DrawInfo.TrackBearing; GliderCenter = true; } else { if (mode.Is(Mode::MODE_TARGET_PAN)) { CalculateOrientationTargetPan(); } else { CalculateOrientationNormal(); } } if(mode.Is(Mode::MODE_TARGET_PAN)) { if (ScreenLandscape) { Orig->x = (rc.left + rc.right - targetPanSize)/2; Orig->y = (rc.bottom + rc.top)/2; } else { Orig->x = (rc.left + rc.right)/2; Orig->y = (rc.bottom + rc.top + targetPanSize)/2; } } else if(mode.Is(Mode::MODE_PAN) || mode.Is(Mode::MODE_CIRCLING)) { Orig->x = (rc.left + rc.right)/2; Orig->y = (rc.bottom + rc.top)/2; } else { // automagic northup smart if (DisplayOrientation == NORTHSMART) { double trackbearing = DrawInfo.TrackBearing; int middleXY,spanxy; if (ScreenLandscape) { middleXY=((rc.bottom-BottomSize)+rc.top)/2; spanxy=NIBLSCALE(50); Orig->y= middleXY + (int)(spanxy*fastcosine(trackbearing)); // This was moving too much the map! // spanx=NIBLSCALE(40); // Orig->x= middleX - (int)(spanx*fastsine(trackbearing)); Orig->x = (rc.left + rc.right)/2; } else { middleXY=(rc.left+rc.right)/2; spanxy=NIBLSCALE(50); Orig->x= middleXY - (int)(spanxy*fastsine(trackbearing)); Orig->y = ((rc.bottom-BottomSize) + rc.top)/2; } } else { // 100924 if we are in north up autorient, position the glider in middle screen if ((zoom.Scale()*1.4) >= AutoOrientScale) { Orig->x = (rc.left + rc.right)/2; Orig->y=((rc.bottom-BottomSize)+rc.top)/2; } else { // else do it normally using configuration Orig->x = ((rc.right - rc.left )*GliderScreenPositionX/100)+rc.left; Orig->y = ((rc.top - rc.bottom )*GliderScreenPositionY/100)+rc.bottom; } } } }
// // Since many functions call LatLon2screen, and only a few need multimap checks for display angle, // we separate functions to avoid slow downs. First used by CalculateScreenPositionsGroundline // void MapWindow::LatLon2ScreenMultimap(pointObj *ptin, POINT *ptout, const int n, const int skip) { static double lastangle = -1; static int cost=1024, sint=0; LKASSERT(Current_Multimap_TopZoom!=0); const double mDisplayAngle = Current_Multimap_TopAngle; if(mDisplayAngle != lastangle) { lastangle = mDisplayAngle; int deg = DEG_TO_INT(AngleLimit360(mDisplayAngle)); cost = ICOSTABLE[deg]; sint = ISINETABLE[deg]; } const int xxs = Current_Multimap_TopOrig.x*1024-512; const int yys = Current_Multimap_TopOrig.y*1024+512; const double mDrawScale = Current_Multimap_TopZoom; const double mPanLongitude = PanLongitude; const double mPanLatitude = PanLatitude; pointObj* p = ptin; const pointObj* ptend = ptin+n; while (p<ptend) { int Y = Real2Int((mPanLatitude-p->y)/mDrawScale); int X = Real2Int((mPanLongitude-p->x)*fastcosine(p->y)/mDrawScale); ptout->x = (xxs-X*cost + Y*sint)/1024; ptout->y = (Y*cost + X*sint + yys)/1024; ptout++; p+= skip; } }
void MapWindow::DrawHeadUpLine(HDC hdc, POINT Orig, RECT rc, double fMin, double fMax ) { COLORREF rgbCol = RGB_BLACK; POINT p1, p2; double tmp = fMax*zoom.ResScaleOverDistanceModify(); double trackbearing = DisplayAircraftAngle+ (DerivedDrawInfo.Heading-DrawInfo.TrackBearing); p2.y= Orig.y - (int)(tmp*fastcosine(trackbearing)); p2.x= Orig.x + (int)(tmp*fastsine(trackbearing)); p1.y= Orig.y; p1.x= Orig.x; if (BlackScreen) rgbCol = RGB_INVDRAW; ForcedClipping=true; // Reduce the rectangle for a better effect rc.top+=NIBLSCALE(5); rc.right-=NIBLSCALE(5); rc.bottom-=NIBLSCALE(5); rc.left+=NIBLSCALE(5); _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p1, p2, rgbCol, rc); ForcedClipping=false; }
/* * VENTA3 This is a modified Segment() */ int LKSurface::DrawArc(long x, long y, int radius, const RECT& rc, double start, double end) { 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--; 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++; Polyline(pt, npoly, rc); return true; }
void MapWindow::LatLon2Screen(const double &lon, const double &lat, POINT &sc) { int Y = Real2Int((PanLatitude-lat)*zoom.DrawScale()); int X = Real2Int((PanLongitude-lon)*fastcosine(lat)*zoom.DrawScale()); irotate(X, Y, DisplayAngle); sc.x = Orig_Screen.x - X; sc.y = Orig_Screen.y + Y; }
void MapWindow::DrawFuturePos(LKSurface& Surface, const POINT& Orig, const RECT& rc, bool headUpLine) { if(DrawInfo.Speed < 13.88) return; //Don't continue if ground speed < 50 Km/h const double trackBearing = headUpLine ? DisplayAircraftAngle+(DerivedDrawInfo.Heading-DrawInfo.TrackBearing) : DrawInfo.TrackBearing; const double dist2min=120*DrawInfo.Speed*zoom.ResScaleOverDistanceModify(); // 2 min if(dist2min>=NIBLSCALE(3)) { //proceed only if the distance is not too small on the map const double dist5min=300*DrawInfo.Speed*zoom.ResScaleOverDistanceModify(); // 5 min const double dist10min=600*DrawInfo.Speed*zoom.ResScaleOverDistanceModify(); //10 min // Reduce the rectangle for a better effect const RECT ClipRect = (RECT){rc.left+NIBLSCALE(5), rc.top+NIBLSCALE(5), rc.right-NIBLSCALE(5), rc.bottom-NIBLSCALE(5) }; POINT p1,p2; if( !MapWindow::mode.autoNorthUP() && !headUpLine && (DisplayOrientation==TRACKUP || DisplayOrientation==NORTHCIRCLE || DisplayOrientation==TARGETCIRCLE || DisplayOrientation==TARGETUP)) { //Track up map view p1.x=Orig.x-NIBLSCALE(4); p2.x=Orig.x+NIBLSCALE(4); p1.y=p2.y=Orig.y-(int)round(dist2min); Surface.DrawLine(PEN_SOLID,NIBLSCALE(1),p1,p2,BlackScreen?RGB_INVDRAW:RGB_BLACK,ClipRect); p1.y=p2.y=Orig.y-(int)round(dist5min); Surface.DrawLine(PEN_SOLID,NIBLSCALE(1),p1,p2,BlackScreen?RGB_INVDRAW:RGB_BLACK,ClipRect); p1.y=p2.y=Orig.y-(int)round(dist10min); Surface.DrawLine(PEN_SOLID,NIBLSCALE(1),p1,p2,BlackScreen?RGB_INVDRAW:RGB_BLACK,ClipRect); } else { //North up map view const double sin=fastsine(trackBearing); const double cos=fastcosine(trackBearing); double distXsin=dist2min*sin; double distXcos=dist2min*cos; const double tickXsin=NIBLSCALE(4)*sin; const double tickXcos=NIBLSCALE(4)*cos; p1.x=Orig.x+(int)round(distXsin-tickXcos); p1.y=Orig.y-(int)round(distXcos+tickXsin); p2.x=Orig.x+(int)round(distXsin+tickXcos); p2.y=Orig.y-(int)round(distXcos-tickXsin); Surface.DrawLine(PEN_SOLID,NIBLSCALE(1),p1,p2,BlackScreen?RGB_INVDRAW:RGB_BLACK,ClipRect); distXsin=dist5min*sin; distXcos=dist5min*cos; p1.x=Orig.x+(int)round(distXsin-tickXcos); p1.y=Orig.y-(int)round(distXcos+tickXsin); p2.x=Orig.x+(int)round(distXsin+tickXcos); p2.y=Orig.y-(int)round(distXcos-tickXsin); Surface.DrawLine(PEN_SOLID,NIBLSCALE(1),p1,p2,BlackScreen?RGB_INVDRAW:RGB_BLACK,ClipRect); distXsin=dist10min*sin; distXcos=dist10min*cos; p1.x=Orig.x+(int)round(distXsin-tickXcos); p1.y=Orig.y-(int)round(distXcos+tickXsin); p2.x=Orig.x+(int)round(distXsin+tickXcos); p2.y=Orig.y-(int)round(distXcos-tickXsin); Surface.DrawLine(PEN_SOLID,NIBLSCALE(1),p1,p2,BlackScreen?RGB_INVDRAW:RGB_BLACK,ClipRect); } } }
void frotate(float &xin, float &yin, const float &angle) { float x= xin; float y= yin; static float lastangle = 0; static float cost=1,sint=0; if(angle != lastangle) { lastangle = angle; cost = (float)fastcosine(angle); sint = (float)fastsine(angle); } xin = x*cost - y*sint; yin = y*cost + x*sint; }
void rotate(double &xin, double &yin, const double &angle) { double x= xin; double y= yin; static double lastangle = 0; static double cost=1,sint=0; if(angle != lastangle) { lastangle = angle; cost = (double)fastcosine(angle); sint = (double)fastsine(angle); } xin = x*cost - y*sint; yin = y*cost + x*sint; }
void frotatescale(float &xin, float &yin, const float &angle, const float &scale) { float x= xin; float y= yin; static float lastangle = 0; static float lastscale = 0; static float cost=1,sint=0; if((angle != lastangle)||(scale != lastscale)) { lastangle = angle; lastscale = scale; cost = (float)fastcosine(angle)*scale; sint = (float)fastsine(angle)*scale; } xin = x*cost - y*sint; yin = y*cost + x*sint; }
void rotatescale(double &xin, double &yin, const double &angle, const double &scale) { double x= xin; double y= yin; static double lastangle = 0; static double lastscale = 0; static double cost=1,sint=0; if((angle != lastangle)||(scale != lastscale)) { lastangle = angle; lastscale = scale; cost = (double)fastcosine(angle)*scale; sint = (double)fastsine(angle)*scale; } xin = x*cost - y*sint; yin = y*cost + x*sint; }
// // The heading track line, like on Garmin units // void MapWindow::DrawHeading(HDC hdc, POINT Orig, RECT rc ) { if (GPS_INFO.NAVWarning) return; // 100214 if (zoom.RealScale()>5 || mode.Is(MapWindow::Mode::MODE_CIRCLING)) return; POINT p2; double tmp = 12000*zoom.ResScaleOverDistanceModify(); if ( !( DisplayOrientation == TRACKUP || DisplayOrientation == NORTHCIRCLE || DisplayOrientation == TRACKCIRCLE )) { double trackbearing = DrawInfo.TrackBearing; p2.y= Orig.y - (int)(tmp*fastcosine(trackbearing)); p2.x= Orig.x + (int)(tmp*fastsine(trackbearing)); } else { p2.x=Orig.x; p2.y=Orig.y-(int)tmp; } if (BlackScreen) _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), Orig, p2, RGB_INVDRAW, rc); // 091109 else _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), Orig, p2, RGB_BLACK, rc); }
void Statistics::RenderTask(LKSurface& Surface, const RECT& rc, const bool olcmode) { int i, j; unsigned int ui; double fXY_Scale = 1.5; double lat1 = 0; double lon1 = 0; double lat2 = 0; double lon2 = 0; double x1, y1, x2=0, y2=0; double lat_c, lon_c; double aatradius[MAXTASKPOINTS]; // find center ResetScale(); if ( (!ValidTaskPoint(0) || !ValidTaskPoint(1)) && !olcmode) { DrawNoData(Surface,rc); return; } for (i=0; i<MAXTASKPOINTS; i++) { aatradius[i]=0; } bool nowaypoints = true; for (i=0; i<MAXTASKPOINTS; i++) { if (ValidTaskPoint(i)) { lat1 = WayPointList[Task[i].Index].Latitude; lon1 = WayPointList[Task[i].Index].Longitude; ScaleYFromValue(rc, lat1); ScaleXFromValue(rc, lon1); nowaypoints = false; } } if (nowaypoints ) { DrawNoData(Surface, rc); return; } CPointGPSArray trace; CContestMgr::Instance().Trace(trace); for(ui=0; ui<trace.size(); ui++) { lat1 = trace[ui].Latitude(); lon1 = trace[ui].Longitude(); ScaleYFromValue(rc, lat1); ScaleXFromValue(rc, lon1); } const auto hfOldU = Surface.SelectObject(LK8InfoNormalFont); lat_c = (y_max+y_min)/2; lon_c = (x_max+x_min)/2; int nwps = 0; // find scale ResetScale(); lat1 = GPS_INFO.Latitude; lon1 = GPS_INFO.Longitude; x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); ScaleXFromValue(rc, x1*fXY_Scale); ScaleYFromValue(rc, y1*fXY_Scale); for (i=0; i<MAXTASKPOINTS; i++) { if (ValidTaskPoint(i)) { nwps++; lat1 = WayPointList[Task[i].Index].Latitude; lon1 = WayPointList[Task[i].Index].Longitude; x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); ScaleXFromValue(rc, x1*fXY_Scale); ScaleYFromValue(rc, y1*fXY_Scale); if (AATEnabled) { double aatlat; double aatlon; double bearing; double radius; if (ValidTaskPoint(i+1)) { if (Task[i].AATType == SECTOR) radius = Task[i].AATSectorRadius; else radius = Task[i].AATCircleRadius; for (j=0; j<4; j++) { bearing = j*360.0/4; FindLatitudeLongitude(WayPointList[Task[i].Index].Latitude, WayPointList[Task[i].Index].Longitude, bearing, radius, &aatlat, &aatlon); x1 = (aatlon-lon_c)*fastcosine(aatlat); y1 = (aatlat-lat_c); ScaleXFromValue(rc, x1); ScaleYFromValue(rc, y1); if (j==0) { aatradius[i] = fabs(aatlat-WayPointList[Task[i].Index].Latitude); } } } else { aatradius[i] = 0; } } } } for(ui=0; ui<trace.size(); ui++) { lat1 = trace[ui].Latitude(); lon1 = trace[ui].Longitude(); x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); ScaleXFromValue(rc, x1*fXY_Scale); ScaleYFromValue(rc, y1*fXY_Scale); } ScaleMakeSquare(rc); // draw aat areas if (AATEnabled) { for (i=MAXTASKPOINTS-1; i>0; i--) { if (ValidTaskPoint(i)) { lat1 = WayPointList[Task[i-1].Index].Latitude; lon1 = WayPointList[Task[i-1].Index].Longitude; lat2 = WayPointList[Task[i].Index].Latitude; lon2 = WayPointList[Task[i].Index].Longitude; x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); x2 = (lon2-lon_c)*fastcosine(lat2); y2 = (lat2-lat_c); #ifdef HAVE_HATCHED_BRUSH Surface.SelectObject(MapWindow::GetAirspaceBrushByClass(AATASK)); #else Surface.SelectObject(LKBrush_Yellow); #endif Surface.SelectObject(LK_WHITE_PEN); if (Task[i].AATType == SECTOR) { Surface.Segment((long)((x2-x_min)*xscale+rc.left+BORDER_X),(long)((y_max-y2)*yscale+rc.top),(long)(aatradius[i]*yscale),rc, Task[i].AATStartRadial, Task[i].AATFinishRadial); } else { Surface.DrawCircle((long)((x2-x_min)*xscale+rc.left+BORDER_X), (long)((y_max-y2)*yscale+rc.top), (long)(aatradius[i]*yscale), true); } } } } if (!AATEnabled) { for (i=MAXTASKPOINTS-1; i>0; i--) { if (ValidTaskPoint(i) && ValidTaskPoint(i-1)) { lat1 = WayPointList[Task[i-1].Index].Latitude; lon1 = WayPointList[Task[i-1].Index].Longitude; if (!ValidTaskPoint(1) ) { lat2 = GPS_INFO.Latitude; lon2 = GPS_INFO.Longitude; } else { lat2 = WayPointList[Task[i].Index].Latitude; lon2 = WayPointList[Task[i].Index].Longitude; } x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); x2 = (lon2-lon_c)*fastcosine(lat2); y2 = (lat2-lat_c); // DrawLine(hdc, rc, x1, y1, x2, y2, STYLE_DASHGREEN); if( ValidTaskPoint(4) && i <2) goto skip_FAI; #ifndef UNDITHER RenderFAISector ( Surface, rc, lat1, lon1, lat2, lon2, lat_c, lon_c,1, RGB_LIGHTYELLOW ); RenderFAISector ( Surface, rc, lat1, lon1, lat2, lon2, lat_c, lon_c,0, RGB_LIGHTCYAN ); #else RenderFAISector ( Surface, rc, lat1, lon1, lat2, lon2, lat_c, lon_c,1, RGB_LIGHTGREY ); RenderFAISector ( Surface, rc, lat1, lon1, lat2, lon2, lat_c, lon_c,0, RGB_GREY ); #endif skip_FAI: DrawLine(Surface, rc, x1, y1, x2, y2, STYLE_DASHGREEN); Surface.Segment((long)((x2-x_min)*xscale+rc.left+BORDER_X),(long)((y_max-y2)*yscale+rc.top),(long)(aatradius[i]*yscale),rc, Task[i].AATStartRadial, Task[i].AATFinishRadial); } } if( ValidTaskPoint(1) && ValidTaskPoint(3)) { lat1 = WayPointList[Task[3].Index].Latitude; lon1 = WayPointList[Task[3].Index].Longitude; lat2 = WayPointList[Task[1].Index].Latitude; lon2 = WayPointList[Task[1].Index].Longitude; #ifndef UNDITHER RenderFAISector ( Surface, rc, lat1, lon1, lat2, lon2, lat_c, lon_c,1, RGB_LIGHTYELLOW ); RenderFAISector ( Surface, rc, lat1, lon1, lat2, lon2, lat_c, lon_c,0, RGB_LIGHTCYAN ); #else RenderFAISector ( Surface, rc, lat1, lon1, lat2, lon2, lat_c, lon_c,1, RGB_LIGHTGREY ); RenderFAISector ( Surface, rc, lat1, lon1, lat2, lon2, lat_c, lon_c,0, RGB_GREY ); #endif } } // draw task lines and label for (i=MAXTASKPOINTS-1; i>0; i--) { if (ValidTaskPoint(i) && ValidTaskPoint(i-1)) { lat1 = WayPointList[Task[i-1].Index].Latitude; lon1 = WayPointList[Task[i-1].Index].Longitude; if (!ValidTaskPoint(1) ) { lat2 = GPS_INFO.Latitude; lon2 = GPS_INFO.Longitude; } else { lat2 = WayPointList[Task[i].Index].Latitude; lon2 = WayPointList[Task[i].Index].Longitude; } x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); x2 = (lon2-lon_c)*fastcosine(lat2); y2 = (lat2-lat_c); DrawLine(Surface, rc, x1, y1, x2, y2, STYLE_BLUETHIN); #if (WINDOWSPC>0) Surface.SetBackgroundOpaque(); #endif TCHAR text[100]; Surface.SetTextColor(RGB_BLUE); /* if ((i==nwps-1) && (Task[i].Index == Task[0].Index)) { _stprintf(text,TEXT("%0d"),1); DrawLabel(hdc, rc, text, x1+(x2-x1)/2, y1+(y2-y1)/2); } else */ { _stprintf(text,TEXT("%0d"),i); DrawLabel(Surface, rc, text, x1+(x2-x1)/2, y1+(y2-y1)/2); } if ((i==ActiveTaskPoint)&&(!AATEnabled)) { lat1 = GPS_INFO.Latitude; lon1 = GPS_INFO.Longitude; x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); DrawLine(Surface, rc, x1, y1, x2, y2, STYLE_REDTHICK); } } } // draw aat task line if (AATEnabled) { for (i=MAXTASKPOINTS-1; i>0; i--) { if (ValidTaskPoint(i) && ValidTaskPoint(i-1)) { if (i==1) { lat1 = WayPointList[Task[i-1].Index].Latitude; lon1 = WayPointList[Task[i-1].Index].Longitude; } else { lat1 = Task[i-1].AATTargetLat; lon1 = Task[i-1].AATTargetLon; } lat2 = Task[i].AATTargetLat; lon2 = Task[i].AATTargetLon; x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); x2 = (lon2-lon_c)*fastcosine(lat2); y2 = (lat2-lat_c); DrawLine(Surface, rc, x1, y1, x2, y2, STYLE_REDTHICK); } } } DrawXGrid(Surface, rc, 1.0, 0, STYLE_THINDASHPAPER, 1.0, false); DrawYGrid(Surface, rc, 1.0, 0, STYLE_THINDASHPAPER, 1.0, false); Surface.SelectObject(hfOldU); // Draw aircraft on top lat1 = GPS_INFO.Latitude; lon1 = GPS_INFO.Longitude; x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); Surface.SetBackgroundTransparent(); DrawLabel(Surface, rc, TEXT("+"), x1, y1); }
void MapWindow::DrawHeadUpLine(LKSurface& Surface, const POINT& Orig, const RECT& rc, double fMin, double fMax ) { const double tmp = fMax*zoom.ResScaleOverDistanceModify(); const double trackbearing = DisplayAircraftAngle+ (DerivedDrawInfo.Heading-DrawInfo.TrackBearing); const POINT p2 = { Orig.x + (int)(tmp*fastsine(trackbearing)), Orig.y - (int)(tmp*fastcosine(trackbearing)) }; const LKColor rgbCol = BlackScreen?RGB_INVDRAW:RGB_BLACK; // Reduce the rectangle for a better effect const RECT ClipRect = {rc.left+NIBLSCALE(5), rc.top+NIBLSCALE(5), rc.right-NIBLSCALE(5), rc.bottom-NIBLSCALE(5) }; Surface.DrawLine(PEN_SOLID, NIBLSCALE(1), Orig, p2, rgbCol, ClipRect); }
rectObj MapWindow::CalculateScreenBounds(double scale, const RECT& rc) { // compute lat lon extents of visible screen rectObj sb; if (scale>= 1.0) { POINT screen_center; LatLon2Screen(PanLongitude, PanLatitude, screen_center); sb.minx = sb.maxx = PanLongitude; sb.miny = sb.maxy = PanLatitude; unsigned int dx, dy; unsigned int maxsc=0; dx = screen_center.x-rc.right; dy = screen_center.y-rc.top; maxsc = max(maxsc, dx*dx+dy*dy); dx = screen_center.x-rc.left; dy = screen_center.y-rc.top; maxsc = max(maxsc, dx*dx+dy*dy); dx = screen_center.x-rc.left; dy = screen_center.y-rc.bottom; maxsc = max(maxsc, dx*dx+dy*dy); dx = screen_center.x-rc.right; dy = screen_center.y-rc.bottom; maxsc = max(maxsc, dx*dx+dy*dy); maxsc = isqrt4(maxsc); for (int i=0; i<10; i++) { double ang = i*360.0/10; POINT p; double X, Y; p.x = screen_center.x + iround(fastcosine(ang)*maxsc*scale); p.y = screen_center.y + iround(fastsine(ang)*maxsc*scale); Screen2LatLon(p.x, p.y, X, Y); sb.minx = min(X, sb.minx); sb.miny = min(Y, sb.miny); sb.maxx = max(X, sb.maxx); sb.maxy = max(Y, sb.maxy); } } else { double xmin, xmax, ymin, ymax; int x, y; double X, Y; x = rc.left; y = rc.top; Screen2LatLon(x, y, X, Y); xmin = X; xmax = X; ymin = Y; ymax = Y; x = rc.right; y = rc.top; Screen2LatLon(x, y, X, Y); xmin = min(xmin, X); xmax = max(xmax, X); ymin = min(ymin, Y); ymax = max(ymax, Y); x = rc.right; y = rc.bottom; Screen2LatLon(x, y, X, Y); xmin = min(xmin, X); xmax = max(xmax, X); ymin = min(ymin, Y); ymax = max(ymax, Y); x = rc.left; y = rc.bottom; Screen2LatLon(x, y, X, Y); xmin = min(xmin, X); xmax = max(xmax, X); ymin = min(ymin, Y); ymax = max(ymax, Y); sb.minx = xmin; sb.maxx = xmax; sb.miny = ymin; sb.maxy = ymax; } return sb; }
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; }
int 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; }
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 MapWindow::DrawTRI(HDC hDC, const RECT rc) { POINT Start; static short top=(((rc.bottom-BottomSize-(rc.top+TOPLIMITER)-BOTTOMLIMITER)/PANELROWS)+rc.top+TOPLIMITER)- (rc.top+TOPLIMITER); Start.y = ((rc.bottom-BottomSize-top)/2)+top-NIBLSCALE(10); Start.x = (rc.right - rc.left)/2; HPEN hpBlack; HBRUSH hbBlack; HPEN hpWhite; HBRUSH hbWhite; HPEN hpBorder; HBRUSH hbBorder; HPEN hpOld; HBRUSH hbOld; // gauge size radius static int radius = NIBLSCALE(65); static int planesize = radius-NIBLSCALE(10); // planebody static int planeradius = NIBLSCALE(6); static int tailsize = planesize/4+NIBLSCALE(2); static int innerradius = radius - NIBLSCALE(8); static POINT d00[2][2],d15[2][4],d30[2][4], d45[2][4], d60[2][4]; TCHAR Buffer[LKSIZEBUFFERVALUE]; double beta=0.0; bool disabled=false; if (DoInit[MDI_DRAWTRI]) { top=(((rc.bottom-BottomSize-(rc.top+TOPLIMITER)-BOTTOMLIMITER)/PANELROWS)+rc.top+TOPLIMITER)- (rc.top+TOPLIMITER); radius = NIBLSCALE(65); planesize = radius-NIBLSCALE(10); planeradius = NIBLSCALE(6); tailsize = planesize/4+NIBLSCALE(2); innerradius = radius - NIBLSCALE(8); // [a][b] a=0 external circle a=1 inner circle b=1-4 d00[0][0].x= Start.x - radius; d00[0][0].y= Start.y; d00[1][0].x= Start.x - innerradius; d00[1][0].y= Start.y; d00[0][1].x= Start.x + radius; d00[0][1].y= Start.y; d00[1][1].x= Start.x + innerradius; d00[1][1].y= Start.y; d15[0][0].x= Start.x - (long) (radius*fastcosine(15.0)); d15[0][0].y= Start.y + (long) (radius*fastsine(15.0)); d15[1][0].x= Start.x - (long) (innerradius*fastcosine(15.0)); d15[1][0].y= Start.y + (long) (innerradius*fastsine(15.0)); d15[0][1].x= Start.x - (long) (radius*fastcosine(15.0)); d15[0][1].y= Start.y - (long) (radius*fastsine(15.0)); d15[1][1].x= Start.x - (long) (innerradius*fastcosine(15.0)); d15[1][1].y= Start.y - (long) (innerradius*fastsine(15.0)); d15[0][2].x= Start.x + (long) (radius*fastcosine(15.0)); d15[0][2].y= Start.y + (long) (radius*fastsine(15.0)); d15[1][2].x= Start.x + (long) (innerradius*fastcosine(15.0)); d15[1][2].y= Start.y + (long) (innerradius*fastsine(15.0)); d15[0][3].x= Start.x + (long) (radius*fastcosine(15.0)); d15[0][3].y= Start.y - (long) (radius*fastsine(15.0)); d15[1][3].x= Start.x + (long) (innerradius*fastcosine(15.0)); d15[1][3].y= Start.y - (long) (innerradius*fastsine(15.0)); d30[0][0].x= Start.x - (long) (radius*fastcosine(30.0)); d30[0][0].y= Start.y + (long) (radius*fastsine(30.0)); d30[1][0].x= Start.x - (long) (innerradius*fastcosine(30.0)); d30[1][0].y= Start.y + (long) (innerradius*fastsine(30.0)); d30[0][1].x= Start.x - (long) (radius*fastcosine(30.0)); d30[0][1].y= Start.y - (long) (radius*fastsine(30.0)); d30[1][1].x= Start.x - (long) (innerradius*fastcosine(30.0)); d30[1][1].y= Start.y - (long) (innerradius*fastsine(30.0)); d30[0][2].x= Start.x + (long) (radius*fastcosine(30.0)); d30[0][2].y= Start.y + (long) (radius*fastsine(30.0)); d30[1][2].x= Start.x + (long) (innerradius*fastcosine(30.0)); d30[1][2].y= Start.y + (long) (innerradius*fastsine(30.0)); d30[0][3].x= Start.x + (long) (radius*fastcosine(30.0)); d30[0][3].y= Start.y - (long) (radius*fastsine(30.0)); d30[1][3].x= Start.x + (long) (innerradius*fastcosine(30.0)); d30[1][3].y= Start.y - (long) (innerradius*fastsine(30.0)); d45[0][0].x= Start.x - (long) (radius*fastcosine(45.0)); d45[0][0].y= Start.y + (long) (radius*fastsine(45.0)); d45[1][0].x= Start.x - (long) (innerradius*fastcosine(45.0)); d45[1][0].y= Start.y + (long) (innerradius*fastsine(45.0)); d45[0][1].x= Start.x - (long) (radius*fastcosine(45.0)); d45[0][1].y= Start.y - (long) (radius*fastsine(45.0)); d45[1][1].x= Start.x - (long) (innerradius*fastcosine(45.0)); d45[1][1].y= Start.y - (long) (innerradius*fastsine(45.0)); d45[0][2].x= Start.x + (long) (radius*fastcosine(45.0)); d45[0][2].y= Start.y + (long) (radius*fastsine(45.0)); d45[1][2].x= Start.x + (long) (innerradius*fastcosine(45.0)); d45[1][2].y= Start.y + (long) (innerradius*fastsine(45.0)); d45[0][3].x= Start.x + (long) (radius*fastcosine(45.0)); d45[0][3].y= Start.y - (long) (radius*fastsine(45.0)); d45[1][3].x= Start.x + (long) (innerradius*fastcosine(45.0)); d45[1][3].y= Start.y - (long) (innerradius*fastsine(45.0)); d60[0][0].x= Start.x - (long) (radius*fastcosine(60.0)); d60[0][0].y= Start.y + (long) (radius*fastsine(60.0)); d60[1][0].x= Start.x - (long) (innerradius*fastcosine(60.0)); d60[1][0].y= Start.y + (long) (innerradius*fastsine(60.0)); d60[0][1].x= Start.x - (long) (radius*fastcosine(60.0)); d60[0][1].y= Start.y - (long) (radius*fastsine(60.0)); d60[1][1].x= Start.x - (long) (innerradius*fastcosine(60.0)); d60[1][1].y= Start.y - (long) (innerradius*fastsine(60.0)); d60[0][2].x= Start.x + (long) (radius*fastcosine(60.0)); d60[0][2].y= Start.y + (long) (radius*fastsine(60.0)); d60[1][2].x= Start.x + (long) (innerradius*fastcosine(60.0)); d60[1][2].y= Start.y + (long) (innerradius*fastsine(60.0)); d60[0][3].x= Start.x + (long) (radius*fastcosine(60.0)); d60[0][3].y= Start.y - (long) (radius*fastsine(60.0)); d60[1][3].x= Start.x + (long) (innerradius*fastcosine(60.0)); d60[1][3].y= Start.y - (long) (innerradius*fastsine(60.0)); DoInit[MDI_DRAWTRI]=false; } // end dirty hack doinit //if (!CALCULATED_INFO.Flying) { // speed is in m/s if(DrawInfo.Speed <5.5 && !DrawInfo.GyroscopeAvailable) disabled=true; if (disabled) { hpBlack = LKPen_Grey_N1; hbBlack = LKBrush_Grey; } else { hpBlack = LKPen_Black_N1; hbBlack = LKBrush_Black; beta = DrawInfo.GyroscopeAvailable ? DrawInfo.Roll : DerivedDrawInfo.BankAngle; } hpWhite = LKPen_White_N1; hbWhite = LKBrush_White; hpBorder = LKPen_Grey_N2; hbBorder = LKBrush_Grey; hpOld = (HPEN)SelectObject(hDC, hpWhite); hbOld = (HBRUSH)SelectObject(hDC, hbWhite); Circle(hDC, Start.x, Start.y, radius, rc, false, true ); if(DrawInfo.AccelerationAvailable) DrawAcceleration(hDC, rc); SelectObject(hDC, hpBorder); SelectObject(hDC, hbBorder); Circle(hDC, Start.x, Start.y, radius+NIBLSCALE(2), rc, false, false ); SelectObject(hDC, hpBlack); SelectObject(hDC, hbBlack); Circle(hDC, Start.x, Start.y, planeradius, rc, false, true ); _DrawLine(hDC, PS_SOLID, NIBLSCALE(1), d00[0][0], d00[1][0], RGB_BLUE,rc); _DrawLine(hDC, PS_SOLID, NIBLSCALE(1), d00[0][1], d00[1][1], RGB_BLUE,rc); _DrawLine(hDC, PS_SOLID, NIBLSCALE(1), d15[0][0], d15[1][0], RGB_BLUE,rc); _DrawLine(hDC, PS_SOLID, NIBLSCALE(1), d15[0][1], d15[1][1], RGB_BLUE,rc); _DrawLine(hDC, PS_SOLID, NIBLSCALE(1), d15[0][2], d15[1][2], RGB_BLUE,rc); _DrawLine(hDC, PS_SOLID, NIBLSCALE(1), d15[0][3], d15[1][3], RGB_BLUE,rc); _DrawLine(hDC, PS_SOLID, NIBLSCALE(1), d30[0][0], d30[1][0], RGB_BLUE,rc); _DrawLine(hDC, PS_SOLID, NIBLSCALE(1), d30[0][1], d30[1][1], RGB_BLUE,rc); _DrawLine(hDC, PS_SOLID, NIBLSCALE(1), d30[0][2], d30[1][2], RGB_BLUE,rc); _DrawLine(hDC, PS_SOLID, NIBLSCALE(1), d30[0][3], d30[1][3], RGB_BLUE,rc); _DrawLine(hDC, PS_SOLID, NIBLSCALE(1), d45[0][0], d45[1][0], RGB_BLUE,rc); _DrawLine(hDC, PS_SOLID, NIBLSCALE(1), d45[0][1], d45[1][1], RGB_BLUE,rc); _DrawLine(hDC, PS_SOLID, NIBLSCALE(1), d45[0][2], d45[1][2], RGB_BLUE,rc); _DrawLine(hDC, PS_SOLID, NIBLSCALE(1), d45[0][3], d45[1][3], RGB_BLUE,rc); _DrawLine(hDC, PS_SOLID, NIBLSCALE(1), d60[0][0], d60[1][0], RGB_BLUE,rc); _DrawLine(hDC, PS_SOLID, NIBLSCALE(1), d60[0][1], d60[1][1], RGB_BLUE,rc); _DrawLine(hDC, PS_SOLID, NIBLSCALE(1), d60[0][2], d60[1][2], RGB_BLUE,rc); _DrawLine(hDC, PS_SOLID, NIBLSCALE(1), d60[0][3], d60[1][3], RGB_BLUE,rc); POINT a1, a2; const double beta_sine = fastsine(beta); const double beta_cosine = fastcosine(beta); a1.x = Start.x - (long)(planesize * beta_cosine); a1.y = Start.y - (long)(planesize * beta_sine); a2.x = Start.x + (long)(planesize * beta_cosine); a2.y = Start.y + (long)(planesize * beta_sine); if (disabled) _DrawLine(hDC, PS_SOLID, NIBLSCALE(4), a1, a2, RGB_GREY,rc); else _DrawLine(hDC, PS_SOLID, NIBLSCALE(4), a1, a2, RGB_BLACK,rc); a1.x = Start.x; a1.y = Start.y; a2.x = Start.x + (long)(tailsize * beta_sine); a2.y = Start.y - (long)(tailsize * beta_cosine); if (disabled) _DrawLine(hDC, PS_SOLID, NIBLSCALE(4), a1, a2, RGB_GREY,rc); else _DrawLine(hDC, PS_SOLID, NIBLSCALE(4), a1, a2, RGB_BLACK,rc); SelectObject(hDC, LK8TitleFont); int bankindy=Start.y-radius/2; #ifndef __MINGW32__ if (beta > 1) _stprintf(Buffer, TEXT("%2.0f\xB0"), beta); else if (beta < -1) _stprintf(Buffer, TEXT("%2.0f\xB0"), -beta); else _tcscpy(Buffer, TEXT("--")); #else if (beta > 1) _stprintf(Buffer, TEXT("%2.0f°"), beta); else if (beta < -1) _stprintf(Buffer, TEXT("%2.0f°"), -beta); else _tcscpy(Buffer, TEXT("--")); #endif LKWriteText(hDC, Buffer, Start.x , bankindy, 0, WTMODE_NORMAL, WTALIGN_CENTER, RGB_BLUE, false); // MapDirty = true; // if (!disabled) MapWindow::RefreshMap(); SelectObject(hDC, hbOld); SelectObject(hDC, hpOld); }
/***************************************************************** * Alpha Lima splitted RenderContest from Render Task for CC * adding FAI Sector display ****************************************************************/ void Statistics::RenderContest(LKSurface& Surface, const RECT& rc) { if(contestType == CContestMgr::TYPE_FAI_TRIANGLE) RenderFAIOptimizer(Surface, rc); else { unsigned int ui; double fXY_Scale = 1.0; double lat1 = 0; double lon1 = 0; double lat2 = 0; double lon2 = 0; double x1, y1, x2=0, y2=0; double lat_c, lon_c; ResetScale(); CContestMgr::CResult result = CContestMgr::Instance().Result(contestType, true); const CPointGPSArray &points = result.PointArray(); // find center CPointGPSArray trace; CContestMgr::Instance().Trace(trace); for(ui=0; ui<trace.size(); ui++) { lat1 = trace[ui].Latitude(); lon1 = trace[ui].Longitude(); ScaleYFromValue(rc, lat1); ScaleXFromValue(rc, lon1); } const auto hfOldU = Surface.SelectObject(LK8PanelUnitFont); lat_c = (y_max+y_min)/2; lon_c = (x_max+x_min)/2; // find scale ResetScale(); lat1 = GPS_INFO.Latitude; lon1 = GPS_INFO.Longitude; x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); ScaleXFromValue(rc, x1*fXY_Scale); ScaleYFromValue(rc, y1*fXY_Scale); for(ui=0; ui<trace.size(); ui++) { lat1 = trace[ui].Latitude(); lon1 = trace[ui].Longitude(); x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); ScaleXFromValue(rc, x1*fXY_Scale); ScaleYFromValue(rc, y1*fXY_Scale); } ScaleMakeSquare(rc); // draw track for(ui=0; trace.size() && ui<trace.size()-1; ui++) { lat1 = trace[ui].Latitude(); lon1 = trace[ui].Longitude(); lat2 = trace[ui+1].Latitude(); lon2 = trace[ui+1].Longitude(); x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); x2 = (lon2-lon_c)*fastcosine(lat2); y2 = (lat2-lat_c); DrawLine(Surface, rc, x1, y1, x2, y2, STYLE_MEDIUMBLACK); } // Draw aircraft on top double lat_p = GPS_INFO.Latitude; double lon_p = GPS_INFO.Longitude; double xp = (lon_p-lon_c)*fastcosine(lat_p); double yp = (lat_p-lat_c); if(result.Type() == contestType) { for(ui=0; ui<points.size()-1; ui++) { lat1 = points[ui].Latitude(); lon1 = points[ui].Longitude(); lat2 = points[ui+1].Latitude(); lon2 = points[ui+1].Longitude(); x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); x2 = (lon2-lon_c)*fastcosine(lat2); y2 = (lat2-lat_c); int style = STYLE_REDTHICK; if((result.Type() == CContestMgr::TYPE_OLC_FAI || result.Type() == CContestMgr::TYPE_OLC_FAI_PREDICTED) && (ui==0 || ui==3)) { // triangle start and finish style = STYLE_DASHGREEN; } else if(result.Predicted() && (result.Type() == CContestMgr::TYPE_OLC_FAI_PREDICTED || ui == points.size() - 2)) { // predicted edge style = STYLE_BLUETHIN; } if((result.Type() == CContestMgr::TYPE_FAI_3_TPS) ||// TYPE_FAI_3_TPS_PREDICTED (result.Type() == CContestMgr::TYPE_FAI_3_TPS_PREDICTED) ) { } if((contestType != CContestMgr::TYPE_FAI_TRIANGLE) ) DrawLine(Surface, rc, x1, y1, x2, y2, style); } if(result.Type() == CContestMgr::TYPE_OLC_FAI || result.Type() == CContestMgr::TYPE_OLC_FAI_PREDICTED) { // draw the last edge of a triangle lat1 = points[1].Latitude(); lon1 = points[1].Longitude(); lat2 = points[3].Latitude(); lon2 = points[3].Longitude(); x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); x2 = (lon2-lon_c)*fastcosine(lat2); y2 = (lat2-lat_c); DrawLine(Surface, rc, x1, y1, x2, y2, result.Predicted() ? STYLE_BLUETHIN : STYLE_REDTHICK); } DrawXGrid(Surface, rc, 1.0, 0, STYLE_THINDASHPAPER, 1.0, false); DrawYGrid(Surface, rc, 1.0, 0, STYLE_THINDASHPAPER, 1.0, false); Surface.SelectObject(hfOldU); #ifndef UNDITHER Surface.SetTextColor(RGB_MAGENTA); #else Surface.SetTextColor(RGB_BLACK); #endif Surface.SetBackgroundTransparent(); DrawLabel(Surface, rc, TEXT("O"), xp, yp); } } }
bool DoTarget(NMEA_INFO *Basic, DERIVED_INFO *Calculated) { double x0, y0, etas, ttgo=0; double bearing, distance; if (LKTargetIndex<0 || LKTargetIndex>=MAXTRAFFIC) return false; // DoTarget is called from MapWindow, in real time. We have enough CPU power there now #if 0 if ( LastDoTarget > Basic->Time ) LastDoTarget=Basic->Time; // We calculate in real time, because PFLAA sentences are calculated too in real time if ( Basic->Time < (LastDoTarget+3.0) ) { return false; } LastDoTarget=Basic->Time; #endif #ifdef DEBUG_LKT StartupStore(_T("... DoTarget Copy LKTraffic\n")); #endif //LockFlightData(); memcpy(LKTraffic, Basic->FLARM_Traffic, sizeof(LKTraffic)); //UnlockFlightData(); if (LKTARG.ID <=0) return false; DistanceBearing(Basic->Latitude, Basic->Longitude, LKTARG.Latitude, LKTARG.Longitude, &distance, &bearing); LKTARG.Distance=distance; LKTARG.Bearing=bearing; if (LKTARG.Speed>1) { x0 = fastsine(LKTARG.TrackBearing)*LKTARG.Speed; y0 = fastcosine(LKTARG.TrackBearing)*LKTARG.Speed; x0 += fastsine(Calculated->WindBearing)*Calculated->WindSpeed; y0 += fastcosine(Calculated->WindBearing)*Calculated->WindSpeed; // LKTARG.Heading = AngleLimit360(atan2(x0,y0)*RAD_TLK_DEG); // 101210 check etas = isqrt4((unsigned long)(x0*x0*100+y0*y0*100))/10.0; LKASSERT(AirDensityRatio(LKTARG.Altitude)!=0); LKTARG.EIAS = etas/AirDensityRatio(LKTARG.Altitude); } else { LKTARG.EIAS=0; } //double height_above_target = Calculated->NavAltitude - LKTARG.Altitude; // We DONT use EnergyHeight here because we are not considering the Target's TE either LKTARG.AltArriv = Calculated->NavAltitude - GlidePolar::MacCreadyAltitude(MACCREADY, distance, bearing, Calculated->WindSpeed, Calculated->WindBearing, 0, 0, // final glide, use wind true, &ttgo) - LKTARG.Altitude; // We CANNOT use RelativeAltitude because when ghost or zombie, it wont be updated in real time in respect // to OUR real position!! Lets use the last target altitude known. double relalt=Calculated->NavAltitude - LKTARG.Altitude; if (relalt==0) LKTARG.GR=999; else { // we need thus to invert the relative altitude LKTARG.GR=distance/(relalt); } return true; }
/***************************************************************** * Alpha Lima splitted RenderContest from Render Task for CC * adding FAI Sector display ****************************************************************/ void Statistics::RenderFAIOptimizer(LKSurface& Surface, const RECT& rc) { unsigned int ui; double fXY_Scale = 1.0; double lat0 = 0; double lon0 = 0; double lat1 = 0; double lon1 = 0; double lat2 = 0; double lon2 = 0; double x0, y0, x1, y1, x2=0, y2=0; double lat_c, lon_c; double lat_p = GPS_INFO.Latitude; double lon_p = GPS_INFO.Longitude; BOOL bFlat = false; #define DRAWPERCENT #ifdef DRAWPERCENT double fTotalPercent = 1.0; #endif ResetScale(); CContestMgr::CResult result = CContestMgr::Instance().Result(contestType, true); const CPointGPSArray &points = result.PointArray(); if(contestType == CContestMgr::TYPE_FAI_TRIANGLE) fXY_Scale = 1.5; // find center double fTotalDistance = result.Distance(); if (fTotalDistance < 1) fTotalDistance =1; CPointGPSArray trace; CContestMgr::Instance().Trace(trace); for(ui=0; ui<trace.size(); ui++) { lat1 = trace[ui].Latitude(); lon1 = trace[ui].Longitude(); ScaleYFromValue(rc, lat1); ScaleXFromValue(rc, lon1); } const auto hfOldU = Surface.SelectObject(LK8PanelUnitFont); BOOL bFAITri = CContestMgr::Instance().FAI(); double fDist, fAngle; lat_c = (y_max+y_min)/2; lon_c = (x_max+x_min)/2; double xp = (lon_p-lon_c)*fastcosine(lat_p); double yp = (lat_p-lat_c); // find scale ResetScale(); lat1 = GPS_INFO.Latitude; lon1 = GPS_INFO.Longitude; x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); ScaleXFromValue(rc, x1*fXY_Scale); ScaleYFromValue(rc, y1*fXY_Scale); for(ui=0; ui<trace.size(); ui++) { lat1 = trace[ui].Latitude(); lon1 = trace[ui].Longitude(); x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); ScaleXFromValue(rc, x1*fXY_Scale); ScaleYFromValue(rc, y1*fXY_Scale); } ScaleMakeSquare(rc); if(result.Type() == contestType) { for(ui=0; ui<points.size()-1; ui++) { lat1 = points[ui].Latitude(); lon1 = points[ui].Longitude(); lat2 = points[ui+1].Latitude(); lon2 = points[ui+1].Longitude(); x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); x2 = (lon2-lon_c)*fastcosine(lat2); y2 = (lat2-lat_c); DistanceBearing(lat1, lon1, lat2, lon2, &fDist, &fAngle); if( (ui <points.size()-2) && !bFlat && ((fDist / fTotalDistance ) > 0.05) ) { if(fDist > 5000) { #ifndef UNDITHER LKColor rgbCol = RGB_BLUE; switch(ui) { case 0: rgbCol = RGB_LIGHTYELLOW; break; case 1: rgbCol = RGB_LIGHTCYAN ; break; case 2: rgbCol = RGB_LIGHTGREEN ; break; default: break; } #else LKColor rgbCol = RGB_DARKBLUE; switch(ui) { case 0: rgbCol = RGB_LIGHTGREY; break; case 1: rgbCol = RGB_GREY ; break; case 2: rgbCol = RGB_MIDDLEGREY ; break; default: break; } #endif RenderFAISector ( Surface, rc, lat1, lon1, lat2, lon2, lat_c, lon_c,1, rgbCol ); RenderFAISector ( Surface, rc, lat1, lon1, lat2, lon2, lat_c, lon_c,0, rgbCol ); } } if((fDist / fTotalDistance ) > 0.45) /* prevent drawing almost same sectors */ bFlat = true; } // draw track for(ui=0; trace.size() && ui<trace.size()-1; ui++) { lat1 = trace[ui].Latitude(); lon1 = trace[ui].Longitude(); lat2 = trace[ui+1].Latitude(); lon2 = trace[ui+1].Longitude(); x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); x2 = (lon2-lon_c)*fastcosine(lat2); y2 = (lat2-lat_c); DrawLine(Surface, rc, x1, y1, x2, y2, STYLE_MEDIUMBLACK); } for(ui=0; ui<points.size()-1; ui++) { lat1 = points[ui].Latitude(); lon1 = points[ui].Longitude(); lat2 = points[ui+1].Latitude(); lon2 = points[ui+1].Longitude(); x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); x2 = (lon2-lon_c)*fastcosine(lat2); y2 = (lat2-lat_c); int style = STYLE_REDTHICK; if((ui > 0) && (ui < 3)) { style = STYLE_BLUETHIN; DistanceBearing(lat1, lon1, lat2, lon2, &fDist, &fAngle); #ifdef DRAWPERCENT if((result.Distance()> 5000) && bFAITri) { TCHAR text[180]; SIZE tsize; fTotalPercent -= fDist/result.Distance(); _stprintf(text, TEXT("%3.1f%%"), (fDist/result.Distance()*100.0)); Surface.GetTextSize(text, _tcslen(text), &tsize); #ifndef UNDITHER Surface.SetTextColor(RGB_BLUE); #else Surface.SetTextColor(RGB_BLACK); #endif Surface.DrawText(ScaleX(rc, x1 +( x2-x1)/2)-tsize.cx/2, ScaleY(rc,y1 + (y2-y1)/2), text, _tcslen(text)); } #endif DrawLine(Surface, rc, x1, y1, x2, y2, style); } } if(bFAITri) { if(points.size() >3) { if(ISPARAGLIDER) { lat0 = CContestMgr::Instance().GetBestNearClosingPoint().Latitude(); lon0 = CContestMgr::Instance().GetBestNearClosingPoint().Longitude(); lat1 = CContestMgr::Instance().GetBestClosingPoint().Latitude(); lon1 = CContestMgr::Instance().GetBestClosingPoint().Longitude(); x1 = (lon0-lon_c)*fastcosine(lat0); y1 = (lat0-lat_c); x2 = (lon1-lon_c)*fastcosine(lat1); y2 = (lat1-lat_c); DrawLine(Surface, rc, x1, y1, x2, y2, STYLE_ORANGETHIN ); //result.Predicted() ? STYLE_BLUETHIN : STYLE_REDTHICK); } lat1 = points[1].Latitude(); lon1 = points[1].Longitude(); lat2 = points[3].Latitude(); lon2 = points[3].Longitude(); x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); x2 = (lon2-lon_c)*fastcosine(lat2); y2 = (lat2-lat_c); DrawLine(Surface, rc, x1, y1, x2, y2, STYLE_THINDASHPAPER ); //result.Predicted() ? STYLE_BLUETHIN : STYLE_REDTHICK); #ifdef DRAWPERCENT TCHAR text[180]; SIZE tsize; _stprintf(text, TEXT("%3.1f%%"), (fTotalPercent*100.0)); Surface.GetTextSize(text, _tcslen(text), &tsize); #ifndef UNDITHER Surface.SetTextColor(RGB_LIGHTBLUE); #else Surface.SetTextColor(RGB_RED); #endif Surface.DrawText(ScaleX(rc, x1 +( x2-x1)/2)-tsize.cx/2, ScaleY(rc,y1 + (y2-y1)/2), text, _tcslen(text)); #endif lat0 = CContestMgr::Instance().GetClosingPoint().Latitude(); lon0 = CContestMgr::Instance().GetClosingPoint().Longitude(); x0 = (lon0-lon_c)*fastcosine(lat0); y0 = (lat0-lat_c); DrawLine(Surface, rc, xp, yp, x0, y0, STYLE_REDTHICK); } } } DrawXGrid(Surface, rc, 1.0, 0, STYLE_THINDASHPAPER, 1.0, false); DrawYGrid(Surface, rc, 1.0, 0, STYLE_THINDASHPAPER, 1.0, false); Surface.SetBackgroundTransparent(); #ifndef UNDITHER Surface.SetTextColor(RGB_MAGENTA); #else Surface.SetTextColor(RGB_BLACK); #endif DrawLabel(Surface, rc, TEXT("O"), xp, yp); Surface.SelectObject(hfOldU); }
void LatLon2Flat(const GEOPOINT &location, POINT &screen) { screen.x = (location.Longitude*fastcosine(location.Latitude)*100); screen.y = (location.Latitude*100); }
// Used by dlgTarget only // A note about this function. We are changing map drawing parameters here, but we paint from the winmain thread. // We are NOT using this from drawthread! the dialog target pan is sort of an hack, and not a good example. // Do not consider emulating the target dialog, because it should be moved to draw thread somehow. void MapWindow::SetTargetPan(bool do_pan, int target_point, DWORD dlgSize /* = 0 */) { static double old_latitude; static double old_longitude; if(dlgSize) targetPanSize = dlgSize; if (!mode.Is(Mode::MODE_TARGET_PAN) || (TargetPanIndex != target_point)) { targetMoved = false; } TargetPanIndex = target_point; if (do_pan && !mode.Is(Mode::MODE_TARGET_PAN)) { old_latitude = PanLatitude; old_longitude = PanLongitude; mode.Special(do_pan ? Mode::MODE_SPECIAL_TARGET_PAN : Mode::MODE_SPECIAL_PAN, true); zoom.SwitchMode(); } if (do_pan) { LockTaskData(); if (ValidTaskPoint(target_point)) { PanLongitude = WayPointList[Task[target_point].Index].Longitude; PanLatitude = WayPointList[Task[target_point].Index].Latitude; if (target_point==0) { TargetZoomDistance = max(2e3, (double)StartRadius*2); } else if (!ValidTaskPoint(target_point+1)) { TargetZoomDistance = max(2e3, (double)FinishRadius*2); } else if (AATEnabled) { if (Task[target_point].AATType == SECTOR) { const double start = Task[target_point].AATStartRadial; const double finish = Task[target_point].AATFinishRadial; const double xs = fastsine(start); const double ys = fastcosine(start); const double xf = fastsine(finish); const double yf = fastcosine(finish); // calculate rectangle area taken by the sector const double top = AngleInRange(start, finish, 0, true) ? 1 : max(max(ys, yf), 0.0); const double right = AngleInRange(start, finish, 90, true) ? 1 : max(max(xs, xf), 0.0); const double bottom = AngleInRange(start, finish, 180, true) ? -1 : min(min(ys, yf), 0.0); const double left = AngleInRange(start, finish, 270, true) ? -1 : min(min(xs, xf), 0.0); // get area center const double radius = Task[target_point].AATSectorRadius; const double x = (left + right) / 2; const double y = (top + bottom) / 2; double bearing, range; xXY_Brg_Rng(0, 0, x, y, &bearing, &range); // find area center geographic data FindLatitudeLongitude(WayPointList[Task[target_point].Index].Latitude, WayPointList[Task[target_point].Index].Longitude, bearing, range * radius, &PanLatitude, &PanLongitude); TargetZoomDistance = max(2e3, max(right - left, top - bottom) * radius); } else { TargetZoomDistance = max(2e3, Task[target_point].AATCircleRadius*2); } } else { TargetZoomDistance = max(2e3, (double)SectorRadius*2); } } UnlockTaskData(); } else if (mode.Is(Mode::MODE_TARGET_PAN)) { PanLongitude = old_longitude; PanLatitude = old_latitude; mode.Special(Mode::MODE_SPECIAL_TARGET_PAN, do_pan); zoom.SwitchMode(); } mode.Special(Mode::MODE_SPECIAL_TARGET_PAN, do_pan); }
void MapWindow::DrawTask(HDC hdc, RECT rc, const POINT &Orig_Aircraft) { int i; double tmp; COLORREF whitecolor = RGB_WHITE; COLORREF origcolor = SetTextColor(hDCTemp, whitecolor); HPEN oldpen = 0; HBRUSH oldbrush = 0; static short size_tasklines=0; if (DoInit[MDI_DRAWTASK]) { switch (ScreenSize) { case ss480x272: case ss272x480: case ss320x240: case ss240x320: size_tasklines=NIBLSCALE(4); break; default: size_tasklines=NIBLSCALE(3); break; } DoInit[MDI_DRAWTASK]=false; } if (!WayPointList) return; oldpen = (HPEN) SelectObject(hdc, hpStartFinishThick); oldbrush = (HBRUSH) SelectObject(hdc, GetStockObject(HOLLOW_BRUSH)); LockTaskData(); // protect from external task changes for (i = 1; ValidTaskPoint(i); i++) { if (!ValidTaskPoint(i + 1)) { // final waypoint if (ActiveWayPoint > 1 || !ValidTaskPoint(2)) { // only draw finish line when past the first // waypoint. FIXED 110307: or if task is with only 2 tps DrawStartEndSector(hdc, rc, Task[i].Start, Task[i].End, Task[i].Index, FinishLine, FinishRadius); } } else { // normal sector if (AATEnabled != TRUE) { //_DrawLine(hdc, PS_DASH, NIBLSCALE(3), WayPointList[Task[i].Index].Screen, Task[i].Start, RGB_PETROL, rc); //_DrawLine(hdc, PS_DASH, NIBLSCALE(3), WayPointList[Task[i].Index].Screen, Task[i].End, RGB_PETROL, rc); // DrawDashLine(hdc, size_tasklines, WayPointList[Task[i].Index].Screen, Task[i].Start, RGB_PETROL, rc); // DrawDashLine(hdc, size_tasklines, WayPointList[Task[i].Index].Screen, Task[i].End, RGB_PETROL, rc); } int Type = 0; double Radius = 0.; GetTaskSectorParameter(i, &Type, &Radius); switch (Type) { case CIRCLE: tmp = Radius * zoom.ResScaleOverDistanceModify(); Circle(hdc, WayPointList[Task[i].Index].Screen.x, WayPointList[Task[i].Index].Screen.y, (int) tmp, rc, false, false); break; case SECTOR: tmp = Radius * zoom.ResScaleOverDistanceModify(); Segment(hdc, WayPointList[Task[i].Index].Screen.x, WayPointList[Task[i].Index].Screen.y, (int) tmp, rc, Task[i].AATStartRadial - DisplayAngle, Task[i].AATFinishRadial - DisplayAngle); break; case DAe: if (!AATEnabled) { // this Type exist only if not AAT task // JMW added german rules tmp = 500 * zoom.ResScaleOverDistanceModify(); Circle(hdc, WayPointList[Task[i].Index].Screen.x, WayPointList[Task[i].Index].Screen.y, (int) tmp, rc, false, false); tmp = 10e3 * zoom.ResScaleOverDistanceModify(); Segment(hdc, WayPointList[Task[i].Index].Screen.x, WayPointList[Task[i].Index].Screen.y, (int) tmp, rc, Task[i].AATStartRadial - DisplayAngle, Task[i].AATFinishRadial - DisplayAngle); } break; case LINE: if (!AATEnabled) { // this Type exist only if not AAT task if(ISGAAIRCRAFT) { POINT start,end; double rotation=AngleLimit360(Task[i].Bisector-DisplayAngle); int length=14*ScreenScale; //Make intermediate WP lines always of the same size independent by zoom level start.x=WayPointList[Task[i].Index].Screen.x+(long)(length*fastsine(rotation)); start.y=WayPointList[Task[i].Index].Screen.y-(long)(length*fastcosine(rotation)); rotation=Reciprocal(rotation); end.x=WayPointList[Task[i].Index].Screen.x+(long)(length*fastsine(rotation)); end.y=WayPointList[Task[i].Index].Screen.y-(long)(length*fastcosine(rotation)); _DrawLine(hdc, PS_SOLID, NIBLSCALE(3), start, end, taskcolor, rc); } else _DrawLine(hdc, PS_SOLID, NIBLSCALE(3), Task[i].Start, Task[i].End, taskcolor, rc); } break; case CONE: tmp = Radius * zoom.ResScaleOverDistanceModify(); int center_x = WayPointList[Task[i].Index].Screen.x; int center_y = WayPointList[Task[i].Index].Screen.y; Circle(hdc, center_x, center_y, (int) tmp, rc, false, false); HPEN prevPen = (HPEN)::SelectObject(hdc, hpTerrainLine); for( int j = 1; j < 5 && tmp > 0; ++j) { Circle(hdc, center_x, center_y, tmp -= NIBLSCALE(5), rc, true, true); } ::SelectObject(hdc, prevPen); break; } if (AATEnabled && !DoOptimizeRoute()) { // ELSE HERE IS *** AAT *** // JMW added iso lines if ((i == ActiveWayPoint) || (mode.Is(Mode::MODE_TARGET_PAN) && (i == TargetPanIndex))) { // JMW 20080616 flash arc line if very close to target static bool flip = false; if (DerivedDrawInfo.WaypointDistance < AATCloseDistance()*2.0) { flip = !flip; } else { flip = true; } if (flip) { for (int j = 0; j < MAXISOLINES - 1; j++) { if (TaskStats[i].IsoLine_valid[j] && TaskStats[i].IsoLine_valid[j + 1]) { _DrawLine(hdc, PS_SOLID, NIBLSCALE(2), TaskStats[i].IsoLine_Screen[j], TaskStats[i].IsoLine_Screen[j + 1], RGB(0, 0, 255), rc); } } } } } } } if ((ActiveWayPoint < 2) && ValidTaskPoint(0) && ValidTaskPoint(1)) { DrawStartEndSector(hdc, rc, Task[0].Start, Task[0].End, Task[0].Index, StartLine, StartRadius); if (EnableMultipleStartPoints) { for (i = 0; i < MAXSTARTPOINTS; i++) { if (StartPoints[i].Active && ValidWayPoint(StartPoints[i].Index)) { DrawStartEndSector(hdc, rc, StartPoints[i].Start, StartPoints[i].End, StartPoints[i].Index, StartLine, StartRadius); } } } } for (i = 0; ValidTaskPoint(i + 1); i++) { int imin = min(Task[i].Index, Task[i + 1].Index); int imax = max(Task[i].Index, Task[i + 1].Index); // JMW AAT! double bearing = Task[i].OutBound; POINT sct1, sct2; if (AATEnabled) { LatLon2Screen(Task[i].AATTargetLon, Task[i].AATTargetLat, sct1); LatLon2Screen(Task[i + 1].AATTargetLon, Task[i + 1].AATTargetLat, sct2); DistanceBearing(Task[i].AATTargetLat, Task[i].AATTargetLon, Task[i + 1].AATTargetLat, Task[i + 1].AATTargetLon, NULL, &bearing); // draw nominal track line DrawDashLine(hdc, NIBLSCALE(1), // 091217 WayPointList[imin].Screen, WayPointList[imax].Screen, taskcolor, rc); } else { sct1 = WayPointList[imin].Screen; sct2 = WayPointList[imax].Screen; } if ((i >= ActiveWayPoint && DoOptimizeRoute()) || !DoOptimizeRoute()) { POINT ClipPt1 = sct1, ClipPt2 = sct2; if(LKGeom::ClipLine((POINT) {rc.left, rc.top}, (POINT) {rc.right, rc.bottom}, ClipPt1, ClipPt2)) { DrawMulticolorDashLine(hdc, size_tasklines, sct1, sct2, taskcolor, RGB_BLACK,rc); // draw small arrow along task direction POINT p_p; POINT Arrow[2] = { {6, 6}, {-6, 6} }; ScreenClosestPoint(sct1, sct2, Orig_Aircraft, &p_p, NIBLSCALE(25)); threadsafePolygonRotateShift(Arrow, 2, p_p.x, p_p.y, bearing - DisplayAngle); _DrawLine(hdc, PS_SOLID, size_tasklines-NIBLSCALE(1), Arrow[0], p_p, taskcolor, rc); _DrawLine(hdc, PS_SOLID, size_tasklines-NIBLSCALE(1), Arrow[1], p_p, taskcolor, rc); } } } // Draw DashLine From current position to Active TurnPoint center if(ValidTaskPoint(ActiveWayPoint)) { POINT ptStart; LatLon2Screen(DrawInfo.Longitude, DrawInfo.Latitude, ptStart); DrawDashLine(hdc, NIBLSCALE(1), ptStart, WayPointList[Task[ActiveWayPoint].Index].Screen, taskcolor, rc); } { UnlockTaskData(); } // restore original color SetTextColor(hDCTemp, origcolor); SelectObject(hdc, oldpen); SelectObject(hdc, oldbrush); }
void LatLon2Flat(double lon, double lat, int *scx, int *scy) { *scx = (int)(lon*fastcosine(lat)*100); *scy = (int)(lat*100); }
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); } }