// // Like DrawDashLine, but with two alternating colors // void MapWindow::DrawMulticolorDashLine(LKSurface& Surface, const int width, const POINT& ptStart, const POINT& ptEnd, const LKColor& cr1, const LKColor& cr2, const RECT& rc) { int i; POINT pt[2]; bool flipcol=false; #ifdef GTL2 int Offset = ((width - 1) / 2) + 1; // amount to shift 1st line to center // the group of lines properly #endif //Create a dot pen LKPen hpDash1(PEN_DASH, 1, cr1); LKPen hpDash2(PEN_DASH, 1, cr2); const auto hpOld = Surface.SelectObject(hpDash1); #ifdef GTL2 pt[0] = ptStart; pt[1] = ptEnd; #else pt[0].x = ptStart.x; pt[0].y = ptStart.y; pt[1].x = ptEnd.x; pt[1].y = ptEnd.y; #endif //increment on smallest variance if(abs(ptStart.x - ptEnd.x) < abs(ptStart.y - ptEnd.y)){ #ifdef GTL2 pt[0].x -= Offset; pt[1].x -= Offset; #endif for (i = 0; i < width; i++, flipcol=!flipcol){ flipcol ? Surface.SelectObject(hpDash2) : Surface.SelectObject(hpDash1); pt[0].x += 1; pt[1].x += 1; Surface.Polyline(pt, 2, rc); } } else { #ifdef GTL2 pt[0].y -= Offset; pt[1].y -= Offset; #endif for (i = 0; i < width; i++, flipcol=!flipcol){ flipcol ? Surface.SelectObject(hpDash2) : Surface.SelectObject(hpDash1); pt[0].y += 1; pt[1].y += 1; Surface.Polyline(pt, 2, rc); } } Surface.SelectObject(hpOld); }
// // Draw bearing line to target // void MapWindow::DrawGreatCircle(LKSurface& Surface, double startLon, double startLat, double targetLon, double targetLat, const RECT& rc) { POINT pt[2]; LatLon2Screen(startLon, startLat, pt[0]); LatLon2Screen(targetLon, targetLat, pt[1]); if(LKGeom::ClipLine(rc, pt[0], pt[1])) { const auto hpOld = Surface.SelectObject(LKPen_GABRG); Surface.Polyline(pt, 2); Surface.SelectObject(LK_BLACK_PEN); Surface.Polyline(pt, 2); Surface.SelectObject(hpOld); } }
// // Draw bearing line to target // void MapWindow::DrawGreatCircle(LKSurface& Surface, const RECT& rc, const ScreenProjection& _Proj, double startLon, double startLat, double targetLon, double targetLat) { POINT pt[2] = { _Proj.LonLat2Screen(startLon, startLat), _Proj.LonLat2Screen(targetLon, targetLat) }; if(LKGeom::ClipLine(rc, pt[0], pt[1])) { const auto hpOld = Surface.SelectObject(LKPen_GABRG); Surface.Polyline(pt, 2); Surface.SelectObject(LK_BLACK_PEN); Surface.Polyline(pt, 2); Surface.SelectObject(hpOld); } }
void MapWindow::LKDrawLongTrail( LKSurface& Surface, const RECT& rc, const ScreenProjection& _Proj) { static RasterPoint snail_polyline[array_size(LongSnailTrail)+1]; // +1 for last point of "normal" snail trail if (TrailActive != 3) return; // only when full trail is selected if (iLongSnailNext < 2) return; // no reason to draw a single point if (MapWindow::mode.Is(MapWindow::Mode::MODE_CIRCLING)) { return; } // pixel manhattan distance // It is the sum of x and y differences between previous and next point on screen, in pixels. // below this distance, no painting const unsigned nearby=10; const LONG_SNAIL_POINT* end_iterator = std::begin(LongSnailTrail); const LONG_SNAIL_POINT* cur_iterator = std::prev(std::next(LongSnailTrail,iLongSnailNext)); RasterPoint* polyline_iterator = std::begin(snail_polyline); const SNAIL_POINT* last_point = std::next(std::next(SnailTrail, iSnailNext)); if(last_point == std::end(SnailTrail)) { last_point = std::begin(SnailTrail); } (*polyline_iterator) = _Proj.LonLat2Screen(last_point->Longitude, last_point->Latitude); polyline_iterator = std::next(polyline_iterator); const auto oldPen = Surface.SelectObject(hSnailPens[3]); // blue color while(cur_iterator != end_iterator) { (*polyline_iterator) = _Proj.LonLat2Screen(cur_iterator->Longitude, cur_iterator->Latitude); if(manhattan_distance(*std::prev(polyline_iterator),(*polyline_iterator)) > nearby) { polyline_iterator = std::next(polyline_iterator); } cur_iterator = std::prev(cur_iterator); } Surface.Polyline(snail_polyline, std::distance(snail_polyline, polyline_iterator) , rc); Surface.SelectObject(oldPen); }
void MapWindow::LKDrawTrail(LKSurface& Surface, const RECT& rc, const ScreenProjection& _Proj) { static RasterPoint snail_polyline[array_size(SnailTrail)]; if (!TrailActive) return; const double display_time = DrawInfo.Time; const bool use_colors = (MapWindow::zoom.RealScale() < 2); // 1.5 is also quite good; // Trail size int num_trail_max = TRAILSIZE; if (TrailActive == 2) { // scan only recently for lift magnitude (10 min) num_trail_max /= TRAILSHRINK; } if (MapWindow::mode.Is(MapWindow::Mode::MODE_CIRCLING)) { num_trail_max /= TRAILSHRINK; // ( 2 min for short track ? ) } const SNAIL_POINT* end_iterator = std::next(SnailTrail,iSnailNext); const SNAIL_POINT* cur_iterator = end_iterator; if(cur_iterator != std::begin(SnailTrail)) { cur_iterator = std::prev(cur_iterator); } else { cur_iterator = std::prev(std::end(SnailTrail)); } RasterPoint* polyline_iterator = &snail_polyline[0]; unsigned short prev_color = 2; if(use_colors) { prev_color = cur_iterator->Colour; } Surface.SelectObject(hSnailPens[prev_color]); const bool trail_is_drifted = (EnableTrailDrift && MapWindow::mode.Is(MapWindow::Mode::MODE_CIRCLING) && DerivedDrawInfo.WindSpeed >= 1); double traildrift_lat = 0; double traildrift_lon = 0; if(trail_is_drifted) { double tlat1, tlon1; FindLatitudeLongitude(DrawInfo.Latitude, DrawInfo.Longitude, DerivedDrawInfo.WindBearing, DerivedDrawInfo.WindSpeed, &tlat1, &tlon1); traildrift_lat = (DrawInfo.Latitude - tlat1); traildrift_lon = (DrawInfo.Longitude - tlon1); } while( (num_trail_max--) > 0 && cur_iterator->Time && cur_iterator != end_iterator) { double this_lat = cur_iterator->Latitude; double this_lon = cur_iterator->Longitude; if (trail_is_drifted) { double dt = std::max(0.0, (display_time - cur_iterator->Time) * cur_iterator->DriftFactor); this_lat += traildrift_lat * dt; this_lon += traildrift_lon * dt; } (*polyline_iterator) = _Proj.LonLat2Screen(this_lon, this_lat); if(use_colors && prev_color != cur_iterator->Colour) { // draw polyline before change color. Surface.Polyline(snail_polyline, std::distance(snail_polyline, polyline_iterator)+1 , rc); // reset polyline snail_polyline[0] = *polyline_iterator; polyline_iterator = &snail_polyline[1]; // select new Color prev_color = cur_iterator->Colour; Surface.SelectObject(hSnailPens[prev_color]); } else { polyline_iterator = std::next(polyline_iterator); } if(cur_iterator == std::begin(SnailTrail)) { cur_iterator = std::end(SnailTrail); } cur_iterator = std::prev(cur_iterator); } Surface.Polyline(snail_polyline, std::distance(snail_polyline, polyline_iterator) , rc); }
void MapWindow::DrawGlideThroughTerrain(LKSurface& Surface, const RECT& rc) { LKPen hpOld; //double h,dh; TCHAR hbuf[10]; static bool doinit=true; static TextInBoxMode_t tmode = {0}; bool wrotevalue=false; if (doinit) { memset((void*)&tmode, 0, sizeof(TextInBoxMode_t)); tmode.Border=1; doinit=false; } #ifdef GTL2 bool ValidTP = ValidTaskPoint(ActiveWayPoint); // draw glide terrain line around next WP bool DrawGTL2 = ValidTP && (FinalGlideTerrain > 2); static bool LastDrewGTL2 = false; if (DrawGTL2) { int wp_index = (DoOptimizeRoute() || ACTIVE_WP_IS_AAT_AREA) ? RESWP_OPTIMIZED : TASKINDEX; double alt_arriv = WayPointCalc[wp_index].AltArriv[AltArrivMode]; // Calculate arrival altitude at the next waypoint relative to // the "terrain height" safety setting. if (CheckSafetyAltitudeApplies(wp_index)) alt_arriv += SAFETYALTITUDEARRIVAL/10; // AGL alt_arriv -= SAFETYALTITUDETERRAIN/10; // rel. to "terrain height" if (alt_arriv <= 0) DrawGTL2 = false; } if (LastDrewGTL2 != DrawGTL2) { LastDrewGTL2 = DrawGTL2; if (!DrawGTL2) ClearGTL2(); // clear next-WP glide terrain line } #endif hpOld = Surface.SelectObject(hpTerrainLineBg); #ifdef GTL2 // Draw the wide, solid part of the glide terrain line. #else // draw a dashed perimetral line first #endif Surface.Polyline(Groundline,NUMTERRAINSWEEPS+1, rc); // draw perimeter if selected and during a flight #ifdef GTL2 if (((FinalGlideTerrain == 1) || (FinalGlideTerrain == 3)) || ((!IsMultimapTerrain() || !DerivedDrawInfo.Flying) && FinalGlideTerrain)) { #else if ((FinalGlideTerrain==1) || ((!IsMultimapTerrain() || !DerivedDrawInfo.Flying) && (FinalGlideTerrain==2))) { #endif Surface.SelectObject(hpTerrainLine); Surface.Polyline(Groundline,NUMTERRAINSWEEPS+1, rc); } #ifdef GTL2 // draw glide terrain line around next waypoint if (DrawGTL2) { // Draw a solid white line. Surface.SelectObject(LKPen_White_N2); Surface.Polyline(Groundline2, NUMTERRAINSWEEPS+1, rc); // Draw a dashed red line. Surface.DrawDashPoly(NIBLSCALE(2), RGB_RED, Groundline2, NUMTERRAINSWEEPS+1, rc); } #endif // draw red cross obstacles only if destination looks reachable! // only if using OVT_TASK of course! #ifdef GTL2 if ((OvertargetMode == OVT_TASK) && DerivedDrawInfo.Flying && ValidTP) #else if ( (OvertargetMode==OVT_TASK) && DerivedDrawInfo.Flying && ValidTaskPoint(ActiveWayPoint)) #endif if (WayPointCalc[TASKINDEX].AltArriv[AltArrivMode] >0) { POINT sc; // If calculations detected an obstacle... if ((DerivedDrawInfo.TerrainWarningLatitude != 0.0) &&(DerivedDrawInfo.TerrainWarningLongitude != 0.0)) { // only if valid position, and visible if (DerivedDrawInfo.FarObstacle_Lon >0) if (PointVisible(DerivedDrawInfo.FarObstacle_Lon, DerivedDrawInfo.FarObstacle_Lat)) { LatLon2Screen(DerivedDrawInfo.FarObstacle_Lon, DerivedDrawInfo.FarObstacle_Lat, sc); DrawBitmapIn(Surface, sc, hTerrainWarning,true); if (DerivedDrawInfo.FarObstacle_AltArriv <=-50 || DerivedDrawInfo.FarObstacle_Dist<5000 ) { _stprintf(hbuf,_T(" %.0f"),ALTITUDEMODIFY*DerivedDrawInfo.FarObstacle_AltArriv); TextInBox(Surface,&rc,hbuf,sc.x+NIBLSCALE(15), sc.y, 0, &tmode,false); wrotevalue=true; } } // visible far obstacle if (PointVisible(DerivedDrawInfo.TerrainWarningLongitude, DerivedDrawInfo.TerrainWarningLatitude)) { LatLon2Screen(DerivedDrawInfo.TerrainWarningLongitude, DerivedDrawInfo.TerrainWarningLatitude, sc); DrawBitmapIn(Surface, sc, hTerrainWarning,true); #if 0 // 091203 add obstacle altitude on moving map h = max(0,RasterTerrain::GetTerrainHeight(DerivedDrawInfo.TerrainWarningLatitude, DerivedDrawInfo.TerrainWarningLongitude)); if (h==TERRAIN_INVALID) h=0; //@ 101027 FIX but unused dh = CALCULATED_INFO.NavAltitude - h - (SAFETYALTITUDETERRAIN/10); _stprintf(hbuf,_T(" %.0f"),ALTITUDEMODIFY*dh); TextInBox(hDC,&rc,hbuf,sc.x+NIBLSCALE(10), sc.y, 0, tmode,false); #else // if far obstacle was painted with value... if (wrotevalue) { // if it is not too near the nearest.. if ( (fabs(DerivedDrawInfo.FarObstacle_Lon - DerivedDrawInfo.TerrainWarningLongitude) >0.02) && (fabs(DerivedDrawInfo.FarObstacle_Lat - DerivedDrawInfo.TerrainWarningLatitude) >0.02)) { // and it the arrival altitude is actually negative (rounding terrain errors?) if ( DerivedDrawInfo.ObstacleAltArriv <=-50) // and there is a significant difference in the numbers, then paint value also for nearest if ( fabs(DerivedDrawInfo.ObstacleAltArriv - DerivedDrawInfo.FarObstacle_AltArriv) >100 ) { _stprintf(hbuf,_T(" %.0f"),ALTITUDEMODIFY*DerivedDrawInfo.ObstacleAltArriv); TextInBox(Surface,&rc,hbuf,sc.x+NIBLSCALE(15), sc.y, 0, &tmode,false); } } } else { // else paint value only if meaningful or very close to us // -1 to 10m become -1 for rounding errors if ( (DerivedDrawInfo.ObstacleAltArriv >-1) && (DerivedDrawInfo.ObstacleAltArriv <10)) DerivedDrawInfo.ObstacleAltArriv=-1; if (DerivedDrawInfo.ObstacleAltArriv <=-50 || ((DerivedDrawInfo.ObstacleAltArriv<0) && (DerivedDrawInfo.ObstacleDistance<5000)) ) { _stprintf(hbuf,_T(" %.0f"),ALTITUDEMODIFY*DerivedDrawInfo.ObstacleAltArriv); TextInBox(Surface,&rc,hbuf,sc.x+NIBLSCALE(15), sc.y, 0, &tmode,false); } } #endif } // visible nearest obstacle } // obstacles detected } // within glide range Surface.SelectObject(hpOld); }
void Topology::Paint(LKSurface& Surface, const RECT& rc) { if (!shapefileopen) return; bool nolabels=false; // 130217 scaleCat 5 and 10 are the same! So careful.. if (scaleCategory==10||scaleCategory==5) { // for water areas, use scaleDefault if ( MapWindow::zoom.RealScale()>scaleDefaultThreshold) { return; } // since we just checked category 10, if we are over scale we set nolabels if ( MapWindow::zoom.RealScale()>scaleThreshold) nolabels=true; } else if (MapWindow::zoom.RealScale() > scaleThreshold) return; // TODO code: only draw inside screen! // this will save time with rendering pixmaps especially // checkVisible does only check lat lon , not screen pixels.. // We need to check also screen. const auto hpOld = Surface.SelectObject(hPen); LKSurface::OldBrush hbOld {}; if (hbBrush) { hbOld = Surface.SelectObject(hbBrush); } const auto hfOld = Surface.SelectObject(MapTopologyFont); // get drawing info int iskip = 1; // attempt to bugfix 100615 polyline glitch with zoom over 33Km // do not skip points, if drawing coast lines which have a scaleThreshold of 100km! // != 5 and != 10 if (scaleCategory>10) { if (MapWindow::zoom.RealScale()>0.25*scaleThreshold) { iskip = 2; } if (MapWindow::zoom.RealScale()>0.5*scaleThreshold) { iskip = 3; } if (MapWindow::zoom.RealScale()>0.75*scaleThreshold) { iskip = 4; } } // use the already existing screenbounds_latlon, calculated by CalculateScreenPositions in MapWindow2 rectObj screenRect = MapWindow::screenbounds_latlon; static POINT pt[MAXCLIPPOLYGON]; for (int ixshp = 0; ixshp < shpfile.numshapes; ixshp++) { XShape *cshape = shpCache[ixshp]; if (!cshape || cshape->hide) continue; shapeObj *shape = &(cshape->shape); switch(shape->type) { case(MS_SHAPE_POINT):{ #if 101016 // -------------------------- NOT PRINTING ICONS --------------------------------------------- bool dobitmap=false; if (scaleCategory<90 || (MapWindow::zoom.RealScale()<2)) dobitmap=true; // first a latlon overlap check, only approximated because of fastcosine in latlon2screen if (checkVisible(*shape, screenRect)) for (int tt = 0; tt < shape->numlines; tt++) { for (int jj=0; jj< shape->line[tt].numpoints; jj++) { POINT sc; MapWindow::LatLon2Screen(shape->line[tt].point[jj].x, shape->line[tt].point[jj].y, sc); if (dobitmap) { // bugfix 101212 missing case for scaleCategory 0 (markers) if (scaleCategory==0||cshape->renderSpecial(Surface, sc.x, sc.y, rc)) MapWindow::DrawBitmapIn(Surface, sc, hBitmap,true); } else { cshape->renderSpecial(Surface, sc.x, sc.y, rc); } } } } #else // -------------------------- PRINTING ICONS --------------------------------------------- // no bitmaps for small town over a certain zoom level and no bitmap if no label at all levels bool nobitmap=false, noiconwithnolabel=false; if (scaleCategory==90 || scaleCategory==100) { noiconwithnolabel=true; if (MapWindow::MapScale>4) nobitmap=true; } if (checkVisible(*shape, screenRect)) for (int tt = 0; tt < shape->numlines; tt++) { for (int jj=0; jj< shape->line[tt].numpoints; jj++) { POINT sc; MapWindow::LatLon2Screen(shape->line[tt].point[jj].x, shape->line[tt].point[jj].y, sc); if (!nobitmap) #if 101016 // only paint icon if label is printed too if (noiconwithnolabel) { if (cshape->renderSpecial(Surface, sc.x, sc.y,labelprinted)) MapWindow::DrawBitmapIn(Surface, sc, hBitmap,true); } else { MapWindow::DrawBitmapIn(Surface, sc, hBitmap,true); cshape->renderSpecial(Surface, sc.x, sc.y,labelprinted); } #else MapWindow::DrawBitmapIn(Surface, sc, hBitmap,true); cshape->renderSpecial(Surface, sc.x, sc.y); #endif } } } #endif // Use optimized point icons 1.23e break; case(MS_SHAPE_LINE): if (checkVisible(*shape, screenRect)) for (int tt = 0; tt < shape->numlines; ++tt) { int minx = rc.right; int miny = rc.bottom; int msize = min(shape->line[tt].numpoints, MAXCLIPPOLYGON); MapWindow::LatLon2Screen(shape->line[tt].point, pt, msize, 1); for (int jj=0; jj< msize; ++jj) { if (pt[jj].x<=minx) { minx = pt[jj].x; miny = pt[jj].y; } } Surface.Polyline(pt, msize, rc); cshape->renderSpecial(Surface,minx,miny,rc); } break; case(MS_SHAPE_POLYGON): // if it's a water area (nolabels), print shape up to defaultShape, but print // labels only up to custom label levels if ( nolabels ) { if (checkVisible(*shape, screenRect)) { for (int tt = 0; tt < shape->numlines; ++tt) { int msize = min(shape->line[tt].numpoints/iskip, MAXCLIPPOLYGON); MapWindow::LatLon2Screen(shape->line[tt].point, pt, msize*iskip, iskip); Surface.Polygon(pt, msize, rc); } } } else if (checkVisible(*shape, screenRect)) { for (int tt = 0; tt < shape->numlines; ++tt) { int minx = rc.right; int miny = rc.bottom; int msize = min(shape->line[tt].numpoints/iskip, MAXCLIPPOLYGON); MapWindow::LatLon2Screen(shape->line[tt].point, pt, msize*iskip, iskip); for (int jj=0; jj< msize; ++jj) { if (pt[jj].x<=minx) { minx = pt[jj].x; miny = pt[jj].y; } } Surface.Polygon(pt, msize, rc); cshape->renderSpecial(Surface,minx,miny,rc); } } break; default: break; } }
int Statistics::RenderFAISector (LKSurface& Surface, const RECT& rc , double lat1, double lon1, double lat2, double lon2, double lat_c, double lon_c , int iOpposite , const LKColor& fillcolor) { float fFAI_Percentage = FAI_NORMAL_PERCENTAGE; double fDist_a, fDist_b, fDist_c, fAngle; int i; unsigned 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 x1=0,y1=0; 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); DrawLine(hdc, 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); x1 = (lon_d - lon_c)*fastcosine(lat_d); y1 = (lat_d - lat_c); LKASSERT(iPolyPtr < MAX_FAI_SECTOR_PTS); apSectorPolygon[iPolyPtr].x = ScaleX(rc, x1); apSectorPolygon[iPolyPtr++].y = ScaleY(rc, y1); fDistTri += fDelta_Dist; } } /******************************************************************** * right threshold extender 2 ********************************************************************/ 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/2-1); for(i =0 ;i < FAI_SECTOR_STEPS/2; 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); x1 = (lon_d - lon_c)*fastcosine(lat_d); y1 = (lat_d - lat_c); LKASSERT(iPolyPtr < MAX_FAI_SECTOR_PTS); apSectorPolygon[iPolyPtr].x = ScaleX(rc, x1); apSectorPolygon[iPolyPtr++].y = ScaleY(rc, y1); 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); x1 = (lon_d - lon_c)*fastcosine(lat_d); y1 = (lat_d - lat_c); LKASSERT(iPolyPtr < MAX_FAI_SECTOR_PTS); apSectorPolygon[iPolyPtr].x = ScaleX(rc, x1); apSectorPolygon[iPolyPtr++].y = ScaleY(rc, y1); fDistTri += fDelta_Dist; } } } /******************************************************************** * TOP limited round 4 ********************************************************************/ // if(fDistMax <= FAI28_45Threshold) if(!bBigFAISector) 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); x1 = (lon_d - lon_c)*fastcosine(lat_d); y1 = (lat_d - lat_c); LKASSERT(iPolyPtr < MAX_FAI_SECTOR_PTS); apSectorPolygon[iPolyPtr].x = ScaleX(rc, x1); apSectorPolygon[iPolyPtr++].y = ScaleY(rc, y1); 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); x1 = (lon_d - lon_c)*fastcosine(lat_d); y1 = (lat_d - lat_c); LKASSERT(iPolyPtr < MAX_FAI_SECTOR_PTS); apSectorPolygon[iPolyPtr].x = ScaleX(rc, x1); apSectorPolygon[iPolyPtr++].y = ScaleY(rc, y1); fDistTri -= fDelta_Dist; } } } /******************************************************************** * LEFT threshold extender ********************************************************************/ if((fDistMin < FAI28_45Threshold) && (FAI28_45Threshold < fDistMax) && (bBigFAISector)) { 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/2-1); for(i =0 ;i < FAI_SECTOR_STEPS/2; 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); x1 = (lon_d - lon_c)*fastcosine(lat_d); y1 = (lat_d - lat_c); LKASSERT(iPolyPtr < MAX_FAI_SECTOR_PTS); apSectorPolygon[iPolyPtr].x = ScaleX(rc, x1); apSectorPolygon[iPolyPtr++].y = ScaleY(rc, y1); 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); x1 = (lon_d - lon_c)*fastcosine(lat_d); y1 = (lat_d - lat_c); LKASSERT(iPolyPtr < MAX_FAI_SECTOR_PTS); apSectorPolygon[iPolyPtr].x = ScaleX(rc, x1); apSectorPolygon[iPolyPtr++].y = ScaleY(rc, y1); 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); x1 = (lon_d - lon_c)*fastcosine(lat_d); y1 = (lat_d - lat_c); LKASSERT(iPolyPtr < MAX_FAI_SECTOR_PTS); apSectorPolygon[iPolyPtr].x = ScaleX(rc, x1); apSectorPolygon[iPolyPtr++].y = ScaleY(rc, y1); fDist_a += fDelta_Dist; fDist_b -= fDelta_Dist; } } /******************************************************************** * draw polygon ********************************************************************/ #ifndef UNDITHER LKPen hpSectorPen(PEN_SOLID, IBLSCALE(1), RGB_GREEN); #else LKPen hpSectorPen(PEN_SOLID, IBLSCALE(1), RGB_RED); #endif const auto hpOldPen = Surface.SelectObject(hpSectorPen); LKBrush hbSectorFill; hbSectorFill.Create(fillcolor); const auto hbOldBrush = Surface.SelectObject(hbSectorFill); /********************************************/ Surface.Polygon(apSectorPolygon,iPolyPtr); /********************************************/ Surface.SelectObject(hpOldPen); Surface.SelectObject(hbOldBrush); hpSectorPen.Release(); /******************************************************************** * calc round leg grid ********************************************************************/ #ifndef UNDITHER hpSectorPen.Create(PEN_SOLID, (1), RGB_GREY ); #else hpSectorPen.Create(PEN_SOLID, (1), RGB_DARKGREY ); #endif Surface.SelectObject(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]; BOOL bFirstUnit = true; LKASSERT(fTic!=0); fDistTri = ((int)(fDistMin/fTic)+1) * fTic ; const auto 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); #ifndef UNDITHER Surface.SetTextColor(RGB_GREY); #else Surface.SetTextColor(RGB_DARKGREY); #endif 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); x1 = (lon_d - lon_c)*fastcosine(lat_d); y1 = (lat_d - lat_c); line[0].x = ScaleX(rc, x1); line[0].y = ScaleY(rc, y1); if(j>0) { Surface.Polyline(line, 2); } if(j==0) { Surface.DrawText(line[0].x, line[0].y, text, _tcslen(text)); j=1; } line[1] = line[0]; fDist_a -= fDelta_Dist; fDist_b += fDelta_Dist; } fDistTri+=fTic;iCnt++; } Surface.SelectObject(hfOld); Surface.SelectObject(hpOldPen); return 0; }