void Statistics::DrawNoData(LKSurface& Surface, const RECT& rc) {

  SIZE tsize;
  TCHAR text[80];
	// LKTOKEN  _@M470_ = "No data" 
  _stprintf(text,TEXT("%s"), gettext(TEXT("_@M470_")));
  Surface.GetTextSize(text, _tcslen(text), &tsize);
  int x = (int)(rc.left+rc.right-tsize.cx)/2;
  int y = (int)(rc.top+rc.bottom-tsize.cy)/2;
  #if (WINDOWSPC>0)
  Surface.SetBackgroundOpaque();
  #endif
  Surface.DrawText(x, y, text, _tcslen(text));
  Surface.SetBackgroundTransparent();
}
Beispiel #2
0
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);
}
Beispiel #3
0
void Statistics::RenderSpeed(LKSurface& Surface, const RECT& rc)
{

  if ((flightstats.Task_Speed.sum_n<2)
      || !ValidTaskPoint(ActiveTaskPoint)) {
    DrawNoData(Surface, rc);
    return;
  }

  ResetScale();

  ScaleXFromData(rc, &flightstats.Task_Speed);
  ScaleYFromData(rc, &flightstats.Task_Speed);
  ScaleYFromValue(rc, 0);
  ScaleXFromValue(rc, flightstats.Task_Speed.x_min+1.0); // in case no data
  ScaleXFromValue(rc, flightstats.Task_Speed.x_min); 

  for(int j=1;j<MAXTASKPOINTS;j++) {
    if (ValidTaskPoint(j) && (flightstats.LegStartTime[j]>=0)) {
      double xx = 
        (flightstats.LegStartTime[j]-CALCULATED_INFO.TaskStartTime)/3600.0;
      if (xx>=0) {
        DrawLine(Surface, rc,
                 xx, y_min,
                 xx, y_max,
                 STYLE_REDTHICK);
      }
    }
  }

  DrawXGrid(Surface, rc,
            0.5, flightstats.Task_Speed.x_min,
            STYLE_THINDASHPAPER, 0.5, true);

 /* DrawYGrid(hdc, rc, 10/TASKSPEEDMODIFY, 0, STYLE_THINDASHPAPER,
            10, true);*/
  if(Units::GetUserHorizontalSpeedUnit() == unStatuteMilesPerHour) {
    DrawYGrid(Surface, rc, 5.0/TASKSPEEDMODIFY, 0, STYLE_THINDASHPAPER, 5.0, true);
  } else {
    DrawYGrid(Surface, rc, 10/TASKSPEEDMODIFY, 0, STYLE_THINDASHPAPER, 10, true);
  }

  DrawLineGraph(Surface, rc, &flightstats.Task_Speed,STYLE_MEDIUMBLACK);

  DrawTrend(Surface, rc, &flightstats.Task_Speed, STYLE_BLUETHIN);


  if(INVERTCOLORS || IsDithered())
    Surface.SetTextColor(RGB_DARKGREEN);
  else
    Surface.SetTextColor(RGB_GREEN);

  Surface.SetBackgroundOpaque();

  TCHAR text[80];
  DrawXLabel(Surface, rc, TEXT(" t/h "));
  _stprintf(text,TEXT(" v/%s "),Units::GetHorizontalSpeedName());
  DrawYLabel(Surface, rc, text);


//  DrawXLabel(hdc, rc, TEXT("t"));
//  DrawYLabel(hdc, rc, TEXT("V"));

}
void Statistics::RenderTemperature(LKSurface& Surface, const RECT& rc)
{
  ResetScale();

  int i;
  float hmin= 10000;
  float hmax= -10000;
  float tmin= (float)CuSonde::maxGroundTemperature;
  float tmax= (float)CuSonde::maxGroundTemperature;

  // find range for scaling of graph
  for (i=0; i<CUSONDE_NUMLEVELS-1; i++) {
    if (CuSonde::cslevels[i].nmeasurements) {

      hmin = min(hmin, (float)i);
      hmax = max(hmax, (float)i);
      tmin = min(tmin, (float)min(CuSonde::cslevels[i].tempDry,
			   (double)min(CuSonde::cslevels[i].airTemp,
                                      (double)CuSonde::cslevels[i].dewpoint)));
      tmax = max(tmax, (float)max(CuSonde::cslevels[i].tempDry,
			   (double)max(CuSonde::cslevels[i].airTemp,
			       (double)CuSonde::cslevels[i].dewpoint)));
    }
  }

  if (hmin>= hmax) {
    DrawNoData(Surface, rc);
    return;
  }

  ScaleYFromValue(rc, hmin);
  ScaleYFromValue(rc, hmax);
  ScaleXFromValue(rc, tmin);
  ScaleXFromValue(rc, tmax);

  bool labelDry = false;
  bool labelAir = false;
  bool labelDew = false;

  int ipos = 0;

  for (i=0; i<CUSONDE_NUMLEVELS-1; i++) {

    if (CuSonde::cslevels[i].nmeasurements &&
	CuSonde::cslevels[i+1].nmeasurements) {

      ipos++;

      DrawLine(Surface, rc,
	       CuSonde::cslevels[i].tempDry, i,
	       CuSonde::cslevels[i+1].tempDry, (i+1), 
	       STYLE_REDTHICK);

      DrawLine(Surface, rc,
	       CuSonde::cslevels[i].airTemp, i,
	       CuSonde::cslevels[i+1].airTemp, (i+1), 
	       STYLE_MEDIUMBLACK);

      DrawLine(Surface, rc,
	       CuSonde::cslevels[i].dewpoint, i,
	       CuSonde::cslevels[i+1].dewpoint, i+1, 
	       STYLE_BLUETHIN);

      if (ipos> 2) {
	if (!labelDry) {
	  DrawLabel(Surface, rc, TEXT("DALR"),
		    CuSonde::cslevels[i+1].tempDry, i);
	  labelDry = true;
	} else {
	  if (!labelAir) {
	    DrawLabel(Surface, rc, TEXT("Air"),
		      CuSonde::cslevels[i+1].airTemp, i);
	    labelAir = true;
	  } else {
	    if (!labelDew) {
	      DrawLabel(Surface, rc, TEXT("Dew"),
			CuSonde::cslevels[i+1].dewpoint, i);
	      labelDew = true;
	    }
	  }
	}
      }
    }
  }

  if(INVERTCOLORS)
    Surface.SetTextColor(RGB_DARKGREEN);
  else
    Surface.SetTextColor(RGB_GREEN);
    #if (WINDOWSPC>0)
  Surface.SetBackgroundOpaque();
    #endif
  TCHAR text[80];
  _stprintf(text,TEXT(" T/%sC "), gettext(_T("_@M2179_")));
  DrawXLabel(Surface, rc, text);
  _stprintf(text,TEXT(" h/%s "),Units::GetAltitudeName());
  DrawYLabel(Surface, rc, text);


//  DrawXLabel(hdc, rc, TEXT("T")TEXT(DEG));
//  DrawYLabel(hdc, rc, TEXT("h"));
}
Beispiel #5
0
void Statistics::DrawYGrid(LKSurface& Surface, const RECT& rc,
			   const double tic_step,
			   const double zero,
                           const int Style,
			   const double unit_step, bool draw_units) {

  POINT line[2];
  SIZE tsize;
  double yval;

  if(INVERTCOLORS || IsDithered())
    Surface.SelectObject(LK_BLACK_PEN);


  int xmin, ymin, xmax, ymax;

  if (!tic_step) return;

  for (yval=zero; yval<= y_max; yval+= tic_step) {

    xmin = rc.left;
    ymin = (int)((y_max-yval)*yscale)+rc.top -BORDER_Y;
    xmax = rc.right;
    ymax = ymin;
    line[0].x = xmin+BORDER_X;
    line[0].y = ymin;
    line[1].x = xmax;
    line[1].y = ymax;

    // STYLE_THINDASHPAPER
    if ((yval< y_max) &&
        (ymin>=rc.top) && (ymin<=rc.bottom-BORDER_Y)) {

      StyleLine(Surface, line[0], line[1], Style, rc);

      if (draw_units) {
	TCHAR unit_text[MAX_PATH];
	FormatTicText(unit_text, yval*unit_step/tic_step, unit_step);
	Surface.GetTextSize(unit_text, &tsize);
	Surface.SetBackgroundOpaque();
	Surface.DrawText(xmin, ymin-tsize.cy/2, unit_text);
    Surface.SetBackgroundTransparent();
      }
    }
  }

  for (yval=zero-tic_step; yval>= y_min; yval-= tic_step) {

    xmin = rc.left;
    ymin = (int)((y_max-yval)*yscale)+rc.top-BORDER_Y;
    xmax = rc.right;
    ymax = ymin;
    line[0].x = xmin+BORDER_X;
    line[0].y = ymin;
    line[1].x = xmax;
    line[1].y = ymax;

    // STYLE_THINDASHPAPER
    if ((yval> y_min) &&
        (ymin>=rc.top) && (ymin<=rc.bottom-BORDER_Y)) {

      StyleLine(Surface, line[0], line[1], Style, rc);

      if (draw_units) {
	TCHAR unit_text[MAX_PATH];
	FormatTicText(unit_text, yval*unit_step/tic_step, unit_step);
	Surface.GetTextSize(unit_text, &tsize);
    Surface.SetBackgroundOpaque();
	Surface.DrawText(xmin, ymin-tsize.cy/2, unit_text);
    Surface.SetBackgroundTransparent();
      }
    }
  }
}
Beispiel #6
0
void Statistics::DrawXGrid(LKSurface& Surface, const RECT& rc,
			   const double tic_step,
			   const double zero,
                           const int Style,
			   const double unit_step, bool draw_units) {

  if(INVERTCOLORS || IsDithered())
    Surface.SelectObject(LK_BLACK_PEN);


  POINT line[2];

  double xval;
  SIZE tsize;

  int xmin, ymin, xmax, ymax;
  if (!tic_step) return;
  LKASSERT(tic_step!=0);

  //  bool do_units = ((x_max-zero)/tic_step)<10;

  for (xval=zero; xval<= x_max; xval+= tic_step) {

    xmin = (int)((xval-x_min)*xscale)+rc.left+BORDER_X;
    ymin = rc.top;
    xmax = xmin;
    ymax = rc.bottom;
    line[0].x = xmin;
    line[0].y = ymin;
    line[1].x = xmax;
    line[1].y = ymax-BORDER_Y;

    // STYLE_THINDASHPAPER
    if ((xval< x_max)
        && (xmin>=rc.left+BORDER_X) && (xmin<=rc.right)) {
      StyleLine(Surface, line[0], line[1], Style, rc);

      if (draw_units) {
	TCHAR unit_text[MAX_PATH];
	FormatTicText(unit_text, xval*unit_step/tic_step, unit_step);

//	SetBkMode(hdc, OPAQUE);
	Surface.GetTextSize(unit_text, &tsize);
	Surface.SetBackgroundOpaque();
	Surface.DrawText(xmin-tsize.cx/2, ymax-tsize.cy, unit_text);
	Surface.SetBackgroundTransparent();
      }
    }

  }

  for (xval=zero-tic_step; xval>= x_min; xval-= tic_step) {

    xmin = (int)((xval-x_min)*xscale)+rc.left+BORDER_X;
    ymin = rc.top;
    xmax = xmin;
    ymax = rc.bottom;
    line[0].x = xmin;
    line[0].y = ymin;
    line[1].x = xmax;
    line[1].y = ymax-BORDER_Y;

    // STYLE_THINDASHPAPER

    if ((xval> x_min)
        && (xmin>=rc.left+BORDER_X) && (xmin<=rc.right)) {

      StyleLine(Surface, line[0], line[1], Style, rc);

      if (draw_units) {
	TCHAR unit_text[MAX_PATH];
	FormatTicText(unit_text, xval*unit_step/tic_step, unit_step);
//	SetBkMode(hdc, OPAQUE);
	Surface.GetTextSize(unit_text, &tsize);
	Surface.SetBackgroundOpaque();
	Surface.DrawText(xmin-tsize.cx/2, ymax-tsize.cy, unit_text);
	Surface.SetBackgroundTransparent();
      }
    }

  }

}
void MapWindow::RenderNearAirspace(LKSurface& Surface, const RECT& rci) {
    RECT rc = rci; /* rectangle for sideview */
    RECT rct = rc; /* rectangle for topview */

    rc.top = (int) ((double) (rci.bottom - rci.top) * fSplitFact);
    rct.bottom = rc.top;
    // Expose the topview rect size in use..
    Current_Multimap_TopRect = rct;

    auto hfOldFnt = Surface.SelectObject(LK8PanelUnitFont/* Sender->GetFont()*/);

    int *iSplit = &Multimap_SizeY[Get_Current_Multimap_Type()];

    static double fHeigtScaleFact = 1.0;


    double GPSlat, GPSlon, GPSalt, GPSbrg;
    double calc_terrainalt;
    double calc_altitudeagl;

    // double alt;
    TCHAR text[TBSIZE + 1];
    TCHAR buffer[TBSIZE + 1];

    CAirspaceBase near_airspace;
    CAirspace *found = NULL;
    //  bool bFound = false;
    DiagrammStruct sDia;
    bool bAS_Inside = false;
    int iAS_Bearing = 0;
    int iAS_HorDistance = 15000;
    int iABS_AS_HorDistance = 0;
    int iAS_VertDistance = 0;
    bool bValid;
    static bool bHeightScale = false;
    long wpt_brg = 0;
    POINT line[2];
    POINT TxYPt;
    POINT TxXPt;
    SIZE tsize;
    LKColor GREEN_COL = RGB_GREEN;
    LKColor BLUE_COL = RGB_BLUE;
    LKColor LIGHTBLUE_COL = RGB_LIGHTBLUE;
    BOOL bInvCol = true; //INVERTCOLORS

    unsigned short getsideviewpage = GetSideviewPage();
    LKASSERT(getsideviewpage < 3);

    if (bInvCol)
        Sideview_TextColor = INV_GROUND_TEXT_COLOUR;
    else
        Sideview_TextColor = RGB_WHITE;

    switch (LKevent) {
        case LKEVENT_NEWRUN:
            // CALLED ON ENTRY: when we select this page coming from another mapspace
            bHeightScale = false;
            // fZOOMScale[getsideviewpage] = 1.0;
            fHeigtScaleFact = 1.0;
            if (IsMultimapTopology()) ForceVisibilityScan = true;
            break;
        case LKEVENT_UP:
            // click on upper part of screen, excluding center
            if (bHeightScale)
                fHeigtScaleFact /= ZOOMFACTOR;
            else
                fZOOMScale[getsideviewpage] /= ZOOMFACTOR;

            if (IsMultimapTopology()) ForceVisibilityScan = true;
            break;

        case LKEVENT_DOWN:
            // click on lower part of screen,  excluding center
            if (bHeightScale)
                fHeigtScaleFact *= ZOOMFACTOR;
            else
                fZOOMScale[getsideviewpage] *= ZOOMFACTOR;
            if (IsMultimapTopology()) ForceVisibilityScan = true;
            break;

        case LKEVENT_LONGCLICK:
            if (Sideview_iNoHandeldSpaces) {
                bool bShow = false;
                for (int k = 0; k <= Sideview_iNoHandeldSpaces; k++) {
                    if (Sideview_pHandeled[k].psAS != NULL) {
                        if (PtInRect(&(Sideview_pHandeled[k].rc), startScreen)) {
                            dlgAddMultiSelectListItem((long*) Sideview_pHandeled[k].psAS, 0, IM_AIRSPACE, 0);
                            bShow = true;
                        }
                    }
                }
                if (bShow) {
                    /*
                     * we can't show dialog from Draw thread
                     * instead, new event is queued, dialog will be popup by main thread 
                     */
                    InputEvents::processGlideComputer(GCE_POPUP_MULTISELECT);

                    // reset event, otherwise Distance/height zoom mod are also triggered
                    LKevent = LKEVENT_NONE;
                }
            }

            if (LKevent != LKEVENT_NONE) {
                if (PtInRect(&rc, startScreen)) {
                    bHeightScale = !bHeightScale;
                } else if (PtInRect(&rct, startScreen)) {
                    bHeightScale = false;
                }
            }
            break;

        case LKEVENT_PAGEUP:
#ifdef OFFSET_SETP
            if (bHeightScale)
                fOffset -= OFFSET_SETP;
            else
#endif
            {
                if (*iSplit == SIZE1) *iSplit = SIZE0;
                if (*iSplit == SIZE2) *iSplit = SIZE1;
                if (*iSplit == SIZE3) *iSplit = SIZE2;
            }
            break;
        case LKEVENT_PAGEDOWN:
#ifdef OFFSET_SETP
            if (bHeightScale)
                fOffset += OFFSET_SETP;
            else
#endif
            {
                if (*iSplit == SIZE2) *iSplit = SIZE3;
                if (*iSplit == SIZE1) *iSplit = SIZE2;
                if (*iSplit == SIZE0) *iSplit = SIZE1;
            }
            break;

    }

    LKASSERT(((*iSplit == SIZE0) || (*iSplit == SIZE1) || (*iSplit == SIZE2) || (*iSplit == SIZE3) || (*iSplit == SIZE4)));

    LKevent = LKEVENT_NONE;

    // Current_Multimap_SizeY is global, and must be used by all multimaps!
    // It is defined in Multimap.cpp and as an external in Multimap.h
    // It is important that it is updated, because we should resize terrain
    // only if needed! Resizing terrain takes some cpu and some time.
    // So we need to know when this is not necessary, having the same size of previous
    // multimap, if we are switching.
    // The current implementation is terribly wrong by managing resizing of sideview in
    // each multimap: it should be done by a common layer.
    // CAREFUL:
    // If for any reason DrawTerrain() is called after resizing to 0 (full sideview)
    // LK WILL CRASH with no hope to recover.
    if (Current_Multimap_SizeY != *iSplit) {
        Current_Multimap_SizeY = *iSplit;
        SetSplitScreenSize(*iSplit);
        rc.top = (long) ((double) (rci.bottom - rci.top) * fSplitFact);
        rct.bottom = rc.top;
    }


    if (bInvCol) {
        GREEN_COL = GREEN_COL.ChangeBrightness(0.6);
        BLUE_COL = BLUE_COL.ChangeBrightness(0.6);
        ;
        LIGHTBLUE_COL = LIGHTBLUE_COL.ChangeBrightness(0.4);
        ;
    }

    GPSlat = DrawInfo.Latitude;
    GPSlon = DrawInfo.Longitude;
    GPSalt = DrawInfo.Altitude;
    GPSbrg = DrawInfo.TrackBearing;
    calc_terrainalt = DerivedDrawInfo.TerrainAlt;
    calc_altitudeagl = DerivedDrawInfo.AltitudeAGL;
    GPSalt = DerivedDrawInfo.NavAltitude;

    bValid = false;
    iAS_HorDistance = 5000;
    iAS_Bearing = (int) GPSbrg;
    iAS_VertDistance = 0;
    found = CAirspaceManager::Instance().GetNearestAirspaceForSideview();
    if (found != NULL) {
        near_airspace = CAirspaceManager::Instance().GetAirspaceCopy(found);
        bValid = near_airspace.GetDistanceInfo(bAS_Inside, iAS_HorDistance, iAS_Bearing, iAS_VertDistance);
    }
    iABS_AS_HorDistance = abs(iAS_HorDistance);
    wpt_brg = (long) AngleLimit360(GPSbrg - iAS_Bearing + 90.0);


    // Variables from ASP system here contain the following informations:
    // fAS_HorDistance - always contains horizontal distance from the asp, negative if horizontally inside (This does not mean that we're inside vertically as well!)
    // fAS_Bearing - always contains bearing to the nearest horizontal point
    // bValid - true if bAS_Inside, iAS_HorDistance, iAS_Bearing, iAS_VertDistance contains valid informations
    //          this will be true if the asp border is close enough to be tracked by the warning system
    // bAS_Inside - current position is inside in the asp, calculated by the warning system
    // iAS_HorDistance - horizontal distance to the nearest horizontal border, negative if horizontally inside, calculated by the warning system
    // iAS_Bearing - bearing to the nearest horizontal border, calculated by the warning system
    // iAS_VertDistance - vertical distance to the nearest asp border, negative if the border is above us, positive if the border below us, calculated by the warning system
    // near_airspace.WarningLevel():
    //           awNone - no warning condition exists
    //           awYellow - current position is near to a warning position
    //           awRed - current posisiton is forbidden by asp system, we are in a warning position


    /*********************************************************************
     * calc the horizontal zoom
     *********************************************************************/
    sDia.fXMin = -5000.0;
    sDia.fXMax = 5000.0;
    /* even when invalid the horizontal distance is calculated correctly */


    if (bValid) {
        double fScaleDist = iABS_AS_HorDistance;

        sDia.fXMin = min(-2500.0, fScaleDist * 1.5);
        sDia.fXMax = max(2500.0, fScaleDist * 1.5);

#ifdef NEAR_AS_ZOOM_1000M
        if (((iABS_AS_HorDistance) < 900) && (bValid)) // 1km zoom
        {
            sDia.fXMin = min(-900.0, fScaleDist * 1.5);
            sDia.fXMax = max(900.0, fScaleDist * 1.5);

        }
#endif
#ifdef NEAR_AS_ZOOM_1000FT
        if ((abs(iABS_AS_HorDistance) < 333)) // 1000ft zoom
        {
            sDia.fXMin = min(-333.0, fScaleDist * 1.5);
            sDia.fXMax = max(333.0, fScaleDist * 1.5);
        }
#endif

    }


#define RND_FACT 10.0


    if ((sDia.fXMax * fZOOMScale[getsideviewpage]) > 100000)
        fZOOMScale[getsideviewpage] /= ZOOMFACTOR;

    if ((sDia.fXMax * fZOOMScale[getsideviewpage]) < 500) {
        fZOOMScale[getsideviewpage] *= ZOOMFACTOR;
    }

    double fOldZoomScale = -1;
    if (fZOOMScale[getsideviewpage] != fOldZoomScale) {
        fOldZoomScale = fZOOMScale[getsideviewpage];
        sDia.fXMax = sDia.fXMax * fZOOMScale[getsideviewpage];
        sDia.fXMin = -sDia.fXMax / 5;
    }


    /*********************************************************************
     * calc the vertical zoom
     *********************************************************************/
    sDia.fYMin = max(0.0, GPSalt - 2300);
    sDia.fYMax = max(MAXALTTODAY, GPSalt + 1000);

    if (bValid) {
        double fBottom = near_airspace.Base()->Altitude;
        sDia.fYMin = min(fBottom * 0.8, sDia.fYMin);
        sDia.fYMin = max(0.0, sDia.fYMin);
        if (sDia.fYMin < 300) sDia.fYMin = 0;
        sDia.fYMax = max((fBottom * 1.2f), sDia.fYMax);

        if (abs(iAS_VertDistance) < 250) {
            sDia.fYMax = ((int) ((GPSalt + abs(iAS_VertDistance)) / 400) + 2) *400;
            sDia.fYMin = ((int) ((GPSalt - abs(iAS_VertDistance)) / 400) - 1) *400;
            if (sDia.fYMin - MIN_ALTITUDE < 0) sDia.fYMin = 0;
        }

#ifdef VERTICAL_ZOOM_50
        if (abs(iAS_VertDistance) < 50) {
            sDia.fYMax = ((int) ((GPSalt + abs(iAS_VertDistance)) / 100) + 2) *100;
            sDia.fYMin = ((int) ((GPSalt - abs(iAS_VertDistance)) / 100) - 1) *100;
            if (sDia.fYMin - MIN_ALTITUDE < 0) sDia.fYMin = 0;
        }
#endif
        sDia.fYMin = max((double) 0.0f, (double) sDia.fYMin);

#ifdef OFFSET_SETP
        if ((sDia.fYMax + fOffset) > MAX_ALTITUDE)
            fOffset -= OFFSET_SETP;
        if ((sDia.fYMin + fOffset) < 0.0)
            fOffset += OFFSET_SETP;

        sDia.fYMin += fOffset;
        sDia.fYMax += fOffset;
#endif
        //  if(fHeigtScaleFact * sDia.fYMax > MAX_ALTITUDE )
        //    fHeigtScaleFact /=ZOOMFACTOR;

        if (fHeigtScaleFact * sDia.fYMax < MIN_ALTITUDE)
            fHeigtScaleFact *= ZOOMFACTOR;
        sDia.fYMax *= fHeigtScaleFact;
    }


    /****************************************************************************************************
     * draw topview first
     ****************************************************************************************************/

    if (fSplitFact > 0.0) {
        sDia.rc = rct;
        sDia.rc.bottom -= 1;
        SharedTopView(Surface, &sDia, (double) iAS_Bearing, (double) wpt_brg);

    }

    /****************************************************************************************************
     * draw airspace and terrain elements
     ****************************************************************************************************/
    RECT rcc = rc; /* rc corrected      */
    if (sDia.fYMin < GC_SEA_LEVEL_TOLERANCE)
        rcc.bottom -= SV_BORDER_Y; /* scale witout sea  */
    sDia.rc = rcc;

    RenderAirspaceTerrain(Surface, GPSlat, GPSlon, iAS_Bearing, &sDia);

    const auto hfOld = Surface.SelectObject(LK8InfoNormalFont);
    if (bValid) {
        LKASSERT(_tcslen(near_airspace.Name()) < TBSIZE); // Diagnostic only in 3.1j, to be REMOVED
        LK_tcsncpy(Sideview_szNearAS, near_airspace.Name(), TBSIZE);
    } else {
        _stprintf(text, TEXT("%s"), MsgToken(1259)); // LKTOKEN _@M1259_ "Too far, not calculated"
        Surface.GetTextSize(text, &tsize);
        TxYPt.x = (rc.right - rc.left - tsize.cx) / 2;
        TxYPt.y = (rc.bottom - rc.top) / 2;

        Surface.SetBackgroundTransparent();
        Surface.DrawText(TxYPt.x, TxYPt.y - 20, text);

        _stprintf(Sideview_szNearAS, TEXT("%s"), text);

    }
    Surface.SelectObject(hfOld);
    /****************************************************************************************************
     * draw airspace and terrain elements
     ****************************************************************************************************/

    /****************************************************************************************************
     * draw diagram
     ****************************************************************************************************/
    double xtick = 1.0;
    double fRange = fabs(sDia.fXMax - sDia.fXMin);
    if (fRange > 3.0 * 1000.0) xtick = 2.0;
    if (fRange > 15 * 1000.0) xtick = 5.0;
    if (fRange > 50.0 * 1000.0) xtick = 10.0;
    if (fRange > 100.0 * 1000.0) xtick = 20.0;
    if (fRange > 200.0 * 1000.0) xtick = 25.0;
    if (fRange > 250.0 * 1000.0) xtick = 50.0;
    if (fRange > 500.0 * 1000.0) xtick = 100.0;
    if (fRange > 1000.0 * 1000.0) xtick = 1000.0;

    if (bInvCol) {
        Surface.SelectObject(LK_BLACK_PEN);
        Surface.SelectObject(LKBrush_Black);
    } else {
        Surface.SelectObject(LK_WHITE_PEN);
        Surface.SelectObject(LKBrush_White);
    }

    LKColor txtCol = GROUND_TEXT_COLOUR;
    if (bInvCol)
        if (sDia.fYMin > GC_SEA_LEVEL_TOLERANCE)
            txtCol = INV_GROUND_TEXT_COLOUR;
    Surface.SetBackgroundTransparent();
    Surface.SetTextColor(txtCol);
    Surface.SelectObject(LK8PanelUnitFont);
    _stprintf(text, TEXT("%s"), Units::GetUnitName(Units::GetUserDistanceUnit()));

    switch (GetMMNorthUp(getsideviewpage)) {
        case NORTHUP:
        default:
            DrawXGrid(Surface, rc, xtick / DISTANCEMODIFY, xtick, 0, TEXT_ABOVE_LEFT, RGB_BLACK, &sDia, text);
            break;

        case TRACKUP:
            DrawXGrid(Surface, rci, xtick / DISTANCEMODIFY, xtick, 0, TEXT_ABOVE_LEFT, RGB_BLACK, &sDia, text);
            break;
    }

    Surface.SetTextColor(Sideview_TextColor);

    double fHeight = (sDia.fYMax - sDia.fYMin);
    double ytick = 100.0;
    if (fHeight > 500.0) ytick = 200.0;
    if (fHeight > 1000.0) ytick = 500.0;
    if (fHeight > 2000.0) ytick = 1000.0;
    if (fHeight > 4000.0) ytick = 2000.0;
    if (fHeight > 8000.0) ytick = 4000.0;

    if (Units::GetUserAltitudeUnit() == unFeet)
        ytick = ytick * FEET_FACTOR;

    _stprintf(text, TEXT("%s"), Units::GetUnitName(Units::GetUserAltitudeUnit()));
    if (sDia.fYMin < GC_SEA_LEVEL_TOLERANCE)
        rc.bottom -= SV_BORDER_Y; /* scale witout sea  */
    DrawYGrid(Surface, rc, ytick / ALTITUDEMODIFY, ytick, 0, TEXT_UNDER_RIGHT, Sideview_TextColor, &sDia, text);


    Surface.SetBkColor(RGB_WHITE);

    if (!bInvCol)
        Surface.SetBackgroundOpaque();
    /****************************************************************************************************
     * draw AGL
     ****************************************************************************************************/
    if (calc_altitudeagl - sDia.fYMin > 500) {
        Surface.SetTextColor(LIGHTBLUE_COL);
        Units::FormatUserAltitude(calc_altitudeagl, buffer, 7);
        LK_tcsncpy(text, MsgToken(1742), TBSIZE - _tcslen(buffer)); // AGL:
        _tcscat(text, buffer);
        Surface.GetTextSize(text, &tsize);
        TxYPt.x = CalcDistanceCoordinat(0, &sDia) - tsize.cx / 2;
        TxYPt.y = CalcHeightCoordinat((calc_terrainalt + calc_altitudeagl)*0.8, &sDia);
        if ((tsize.cy) < (CalcHeightCoordinat(calc_terrainalt, &sDia) - TxYPt.y)) {
            Surface.DrawText(TxYPt.x + IBLSCALE(1), TxYPt.y, text);
        }
    }

    Surface.SetBackgroundTransparent();

    /****************************************************************************************************
     * Print current Elevation
     ****************************************************************************************************/
    Surface.SetTextColor(RGB_BLACK);
    int x, y;
    if ((calc_terrainalt - sDia.fYMin) > 0) {
        Units::FormatUserAltitude(calc_terrainalt, buffer, 7);
        LK_tcsncpy(text, MsgToken(1743), TBSIZE - _tcslen(buffer)); // ELV:
        _tcscat(text, buffer);
        Surface.GetTextSize(text, &tsize);
        x = CalcDistanceCoordinat(0, &sDia) - tsize.cx / 2;
        y = CalcHeightCoordinat(calc_terrainalt, &sDia);
        if ((ELV_FACT * tsize.cy) < abs(rc.bottom - y)) {
            Surface.DrawText(x, rc.bottom - (int) (ELV_FACT * tsize.cy), text);
        }
    }


    /****************************************************************************************************
     * draw side elements
     ****************************************************************************************************/
    Surface.SetTextColor(Sideview_TextColor);
    Surface.SetBackgroundOpaque();
    const auto hfOld2 = Surface.SelectObject(LK8InfoNormalFont);

    //  DrawTelescope      ( hdc, iAS_Bearing-90.0, rc.right  - NIBLSCALE(13),  rc.top   + NIBLSCALE(58));

    Surface.SelectObject(hfOld2);
    Surface.SetBackgroundTransparent();

    Surface.SelectObject(hfOld);
    Surface.SetTextColor(GROUND_TEXT_COLOUR);
    if (bInvCol)
        if (sDia.fYMin > GC_SEA_LEVEL_TOLERANCE)
            Surface.SetTextColor(INV_GROUND_TEXT_COLOUR);



    /****************************************************************************************************/
    /****************************************************************************************************/
    /****************************************************************************************************
     * draw distances to next airspace
     ****************************************************************************************************/
    /****************************************************************************************************/
    /****************************************************************************************************/
    if (bValid) {

        /****************************************************************************************************
         * draw horizontal distance to next airspace
         ****************************************************************************************************/
        Surface.SetTextColor(Sideview_TextColor);
        Surface.SetBackgroundOpaque();
        const auto hfOldU = Surface.SelectObject(LK8InfoNormalFont);
        // horizontal distance
        line[0].x = CalcDistanceCoordinat(0, &sDia);
        line[0].y = CalcHeightCoordinat(GPSalt, &sDia);
        line[1].x = CalcDistanceCoordinat(iABS_AS_HorDistance, &sDia);
        line[1].y = line[0].y;
        Surface.DrawDashLine(THICK_LINE, line[0], line[1], Sideview_TextColor, rc);
        if (iAS_HorDistance < 0) {
            line[0].y = CalcHeightCoordinat(GPSalt - (double) iAS_VertDistance, &sDia);
            line[1].y = line[0].y;

            Surface.DrawDashLine(THICK_LINE, line[0], line[1], Sideview_TextColor, rc);
        }

        bool bLeft = false;
        if (line[0].x < line[1].x)
            bLeft = false;
        else
            bLeft = true;

        Units::FormatUserDistance(iABS_AS_HorDistance, buffer, 7);
        _stprintf(text, _T(" %s"), buffer);
        Surface.GetTextSize(text, &tsize);

        if ((GPSalt - sDia.fYMin /*-calc_terrainalt */) < 300)
            TxXPt.y = CalcHeightCoordinat(GPSalt, &sDia) - tsize.cy;
        else
            TxXPt.y = CalcHeightCoordinat(GPSalt, &sDia) + NIBLSCALE(3);


        if (tsize.cx > (line[1].x - line[0].x))
            TxXPt.x = CalcDistanceCoordinat(iABS_AS_HorDistance, &sDia) - tsize.cx - NIBLSCALE(3);
        else
            TxXPt.x = CalcDistanceCoordinat(iABS_AS_HorDistance / 2.0, &sDia) - tsize.cx / 2;
        Surface.DrawText(TxXPt.x, TxXPt.y, text);



        /****************************************************************************************************
         * draw vertical distance to next airspace
         ****************************************************************************************************/
        line[0].x = CalcDistanceCoordinat(iABS_AS_HorDistance, &sDia);
        line[0].y = CalcHeightCoordinat(GPSalt, &sDia);
        line[1].x = line[0].x;
        line[1].y = CalcHeightCoordinat(GPSalt - (double) iAS_VertDistance, &sDia);

        Surface.DrawDashLine(THICK_LINE, line[0], line[1], Sideview_TextColor, rc);
        Units::FormatUserAltitude((double) abs(iAS_VertDistance), buffer, 7);
        _stprintf(text, _T(" %s"), buffer);
        Surface.GetTextSize(text, &tsize);

        if (bLeft)
            TxYPt.x = CalcDistanceCoordinat(iABS_AS_HorDistance, &sDia) - tsize.cx - NIBLSCALE(3);
        else
            TxYPt.x = CalcDistanceCoordinat(iABS_AS_HorDistance, &sDia) + NIBLSCALE(5);
        if (abs(line[0].y - line[1].y) > tsize.cy)
            TxYPt.y = CalcHeightCoordinat(GPSalt - (double) iAS_VertDistance / 2.0, &sDia) - tsize.cy / 2;
        else
            TxYPt.y = min(line[0].y, line[1].y) - tsize.cy;
        Surface.DrawText(TxYPt.x, TxYPt.y, text);
        Surface.SelectObject(hfOldU);
    }

    /****************************************************************************************************
     * draw plane sideview at least
     ****************************************************************************************************/
    RenderPlaneSideview(Surface, 0.0, GPSalt, wpt_brg, &sDia);

    hfOldFnt = Surface.SelectObject(LK8InfoNormalFont/* Sender->GetFont()*/);

    DrawMultimap_SideTopSeparator(Surface, rct);

    /****************************************************************************************************
     * draw selection frame
     ****************************************************************************************************/
    if (bHeightScale)
        DrawSelectionFrame(Surface, rc);
#ifdef TOP_SELECTION_FRAME
    else
        DrawSelectionFrame(hdc, rci);
#endif
    Surface.SelectObject(hfOldFnt/* Sender->GetFont()*/);
    Surface.SetBackgroundTransparent();
    Surface.SelectObject(hfOldFnt/* Sender->GetFont()*/);
}