Ejemplo n.º 1
0
//
// 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);
  
} 
Ejemplo n.º 2
0
//
// 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);
    }
}
Ejemplo n.º 3
0
//
// 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);
    }
}
Ejemplo n.º 4
0
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);
}
Ejemplo n.º 5
0
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);
}
Ejemplo n.º 6
0
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);
}
Ejemplo n.º 7
0
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;
    }
  }
Ejemplo n.º 8
0
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;
}