//
// 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);
    }
}
Beispiel #2
0
void MapWindow::DrawTeammate(HDC hdc, RECT rc)
{
  POINT point;

  if (TeammateCodeValid)
    {
      if(PointVisible(TeammateLongitude, TeammateLatitude) )
	{
	  LatLon2Screen(TeammateLongitude, TeammateLatitude, point);

	  SelectObject(hDCTemp,hBmpTeammatePosition);
	  DrawBitmapX(hdc,
		      point.x-NIBLSCALE(10), 
		      point.y-NIBLSCALE(10),
		      20,20,
		      hDCTemp,0,0,SRCPAINT,true);
	
	  DrawBitmapX(hdc,
		      point.x-NIBLSCALE(10), 
		      point.y-NIBLSCALE(10),
		      20,20,
		      hDCTemp,20,0,SRCAND,true);
	}
    }
}
void MapWindow::CalculateScreenPositionsThermalSources() {
    for (int i=0; i<MAX_THERMAL_SOURCES; i++) {
        if (DerivedDrawInfo.ThermalSources[i].LiftRate>0) {
            double dh = DerivedDrawInfo.NavAltitude
                        -DerivedDrawInfo.ThermalSources[i].GroundHeight;
            if (dh<0) {
                DerivedDrawInfo.ThermalSources[i].Visible = false;
                continue;
            }

            double t = dh/DerivedDrawInfo.ThermalSources[i].LiftRate;
            double lat, lon;
            FindLatitudeLongitude(DerivedDrawInfo.ThermalSources[i].Latitude,
                                  DerivedDrawInfo.ThermalSources[i].Longitude,
                                  DerivedDrawInfo.WindBearing,
                                  -DerivedDrawInfo.WindSpeed*t,
                                  &lat, &lon);
            if (PointVisible(lon,lat)) {
                LatLon2Screen(lon,
                              lat,
                              DerivedDrawInfo.ThermalSources[i].Screen);
                DerivedDrawInfo.ThermalSources[i].Visible =
                    PointVisible(DerivedDrawInfo.ThermalSources[i].Screen);
            } else {
                DerivedDrawInfo.ThermalSources[i].Visible = false;
            }
        } else {
            DerivedDrawInfo.ThermalSources[i].Visible = false;
        }
    }
}
void MapWindow::CalculateScreenPositionsGroundline(void) {
    bool mm=IsMultiMapSharedNoMain();
    if (FinalGlideTerrain) {
        if (mm) {
            LatLon2ScreenMultimap(DerivedDrawInfo.GlideFootPrint, Groundline, NUMTERRAINSWEEPS+1, 1);
        } else {
            LatLon2Screen(DerivedDrawInfo.GlideFootPrint, Groundline, NUMTERRAINSWEEPS+1, 1);
        }
#ifdef GTL2
        if (FinalGlideTerrain > 2) {// show next-WP line
            if (mm) {
                LatLon2ScreenMultimap(GlideFootPrint2, Groundline2, NUMTERRAINSWEEPS+1, 1);
            } else {
                LatLon2Screen(GlideFootPrint2, Groundline2, NUMTERRAINSWEEPS+1, 1);
            }
        }
#endif
    }
}
Beispiel #5
0
void MapWindow::DrawAirspaceLabels(HDC hdc, const RECT rc, const POINT Orig_Aircraft)
{
  static short int label_sequencing_divider = 0;
  CAirspaceList::const_iterator it;
  const CAirspaceList& airspaces_to_draw = CAirspaceManager::Instance().GetAirspacesForWarningLabels();
  
  if (label_sequencing_divider) --label_sequencing_divider;

  // Draw warning position and label on top of all airspaces
  if (1) {
  CCriticalSection::CGuard guard(CAirspaceManager::Instance().MutexRef());
  for (it=airspaces_to_draw.begin(); it != airspaces_to_draw.end(); ++it) {
        if ((*it)->WarningLevel() > awNone) {
          POINT sc;
          double lon;
          double lat;
          int vdist;
          AirspaceWarningDrawStyle_t vlabeldrawstyle, hlabeldrawstyle;
          bool distances_ready = (*it)->GetWarningPoint(lon, lat, hlabeldrawstyle, vdist, vlabeldrawstyle);
          TCHAR hbuf[NAME_SIZE+16], vDistanceText[16];
          TextInBoxMode_t TextDisplayMode = {0};
          bool hlabel_draws = false;
          bool vlabel_draws = false;
          
          // Horizontal warning point
          if (distances_ready && (hlabeldrawstyle > awsHidden) && PointVisible(lon, lat)) {

              LatLon2Screen(lon, lat, sc);
              DrawBitmapIn(hdc, sc, hAirspaceWarning,true);
              
              Units::FormatUserAltitude(vdist, vDistanceText, sizeof(vDistanceText)/sizeof(vDistanceText[0]));
              _tcscpy(hbuf, (*it)->Name());
              wcscat(hbuf, TEXT(" "));
              wcscat(hbuf, vDistanceText);
              
              switch (hlabeldrawstyle) {
                default:
                case awsHidden:
                case awsBlack:
                  TextDisplayMode.Color = RGB_BLACK;
                  break;
                case awsAmber:
                  TextDisplayMode.Color = RGB_ORANGE;
                  break;
                case awsRed:
                  TextDisplayMode.Color = RGB_RED;
                  break;
              } // sw
              TextDisplayMode.SetTextColor = 1;
              TextDisplayMode.AlligneCenter = 1;
              if ( (MapBox == (MapBox_t)mbBoxed) || (MapBox == (MapBox_t)mbBoxedNoUnit)) {
                  TextDisplayMode.Border = 1;
              } else {
		  if (TextDisplayMode.Color==RGB_BLACK)
                     TextDisplayMode.WhiteBold = 0; // no black outline for black background..
                  else
                     TextDisplayMode.WhiteBold = 1; // outlined  
              }

              hlabel_draws = TextInBox(hdc, &rc, hbuf, sc.x, sc.y+NIBLSCALE(15), 0, &TextDisplayMode, true);
           }
           
          // Vertical warning point
          if (distances_ready && vlabeldrawstyle > awsHidden) {

              //DrawBitmapIn(hdc, Orig_Aircraft, hAirspaceWarning);
              
              Units::FormatUserAltitude(vdist, vDistanceText, sizeof(vDistanceText)/sizeof(vDistanceText[0]));
              _tcscpy(hbuf, (*it)->Name());
              wcscat(hbuf, TEXT(" "));
              wcscat(hbuf, vDistanceText);
              
              switch (vlabeldrawstyle) {
                default:
                case awsHidden:
                case awsBlack:
                  TextDisplayMode.Color = RGB_BLACK;
                  break;
                case awsAmber:
                  TextDisplayMode.Color = RGB_ORANGE;
                  break;
                case awsRed:
                  TextDisplayMode.Color = RGB_RED;
                  break;
              } // sw
              TextDisplayMode.SetTextColor = 1;
              TextDisplayMode.AlligneCenter = 1;
              if ( (MapBox == (MapBox_t)mbBoxed) || (MapBox == (MapBox_t)mbBoxedNoUnit)) {
                  TextDisplayMode.Border = 1;
              } else {
		  if (TextDisplayMode.Color==RGB_BLACK)
                     TextDisplayMode.WhiteBold = 0; // no black outline for black background..
                  else
                     TextDisplayMode.WhiteBold = 1; // outlined  
              }

              vlabel_draws = TextInBox(hdc, &rc, hbuf, Orig_Aircraft.x, Orig_Aircraft.y+NIBLSCALE(15), 0, &TextDisplayMode, true);
           }
           if (!label_sequencing_divider) CAirspaceManager::Instance().AirspaceWarningLabelPrinted(**it, hlabel_draws || vlabel_draws);
           
         }// if warnlevel>awnone
  }//for
  }// if(1) mutex
  if (!label_sequencing_divider) label_sequencing_divider=3;		// Do label sequencing slower than update rate
}
Beispiel #6
0
void MapWindow::DrawBearing(HDC hdc, const RECT rc)
{
  int overindex=GetOvertargetIndex();
  if (overindex<0) return;

  double startLat = DrawInfo.Latitude;
  double startLon = DrawInfo.Longitude;
  double targetLat;
  double targetLon;

  if (OvertargetMode>OVT_TASK) {
    LockTaskData();
    targetLat = WayPointList[overindex].Latitude;
    targetLon = WayPointList[overindex].Longitude;
    UnlockTaskData();
    DrawGreatCircle(hdc, startLon, startLat, targetLon, targetLat, rc);
  }
  else {
    if (!ValidTaskPoint(ActiveWayPoint)) {
      return; 
    }
    LockTaskData();

    if (AATEnabled && ( DoOptimizeRoute() || ((ActiveWayPoint>0) && ValidTaskPoint(ActiveWayPoint+1))) ) {
      targetLat = Task[ActiveWayPoint].AATTargetLat;
      targetLon = Task[ActiveWayPoint].AATTargetLon; 
    } else {
      targetLat = WayPointList[Task[ActiveWayPoint].Index].Latitude;
      targetLon = WayPointList[Task[ActiveWayPoint].Index].Longitude; 
    }
    UnlockTaskData();

    DrawGreatCircle(hdc, startLon, startLat, targetLon, targetLat, rc);

    if (mode.Is(Mode::MODE_TARGET_PAN)) {
      // Draw all of task if in target pan mode
      startLat = targetLat;
      startLon = targetLon;

      LockTaskData();
      for (int i=ActiveWayPoint+1; i<MAXTASKPOINTS; i++) {
        if (ValidTaskPoint(i)) {

          if (AATEnabled && ValidTaskPoint(i+1)) {
            targetLat = Task[i].AATTargetLat;
            targetLon = Task[i].AATTargetLon; 
          } else {
            targetLat = WayPointList[Task[i].Index].Latitude;
            targetLon = WayPointList[Task[i].Index].Longitude; 
          }
       
          DrawGreatCircle(hdc, startLon, startLat,
                          targetLon, targetLat, rc);

          startLat = targetLat;
          startLon = targetLon;
        }
      }
      UnlockTaskData();
    }
  }

  if (AATEnabled) {
    // draw symbol at target, makes it easier to see
    LockTaskData();
    if(mode.Is(Mode::MODE_TARGET_PAN)) {
      for(int i=ActiveWayPoint+1; i<MAXTASKPOINTS; i++) {
        if(ValidTaskPoint(i) && ValidTaskPoint(i+1)) {
          if(i>= ActiveWayPoint) {
            POINT sct;
            LatLon2Screen(Task[i].AATTargetLon, 
                          Task[i].AATTargetLat, 
                          sct);
            DrawBitmapIn(hdc, sct, hBmpTarget,true);
          }
        }
      }
    }
    if(ValidTaskPoint(ActiveWayPoint+1) && (DoOptimizeRoute() || (ActiveWayPoint>0)) ) {
      POINT sct;
      LatLon2Screen(Task[ActiveWayPoint].AATTargetLon, 
                    Task[ActiveWayPoint].AATTargetLat, 
                    sct);
      DrawBitmapIn(hdc, sct, hBmpTarget,true);
    }
    UnlockTaskData();
  }
}
Beispiel #7
0
void MapWindow::DrawTask(HDC hdc, RECT rc, const POINT &Orig_Aircraft) {
    int i;
    double tmp;

    COLORREF whitecolor = RGB_WHITE;
    COLORREF origcolor = SetTextColor(hDCTemp, whitecolor);
    HPEN oldpen = 0;
    HBRUSH oldbrush = 0;

    static short size_tasklines=0;

    if (DoInit[MDI_DRAWTASK]) {
switch (ScreenSize) {
case ss480x272:
case ss272x480:
case ss320x240:
case ss240x320:
size_tasklines=NIBLSCALE(4);
break;
default:
size_tasklines=NIBLSCALE(3);
break;
}
DoInit[MDI_DRAWTASK]=false;
    }

    if (!WayPointList) return;

    oldpen = (HPEN) SelectObject(hdc, hpStartFinishThick);
    oldbrush = (HBRUSH) SelectObject(hdc, GetStockObject(HOLLOW_BRUSH));

    LockTaskData(); // protect from external task changes

    for (i = 1; ValidTaskPoint(i); i++) {
        if (!ValidTaskPoint(i + 1)) { // final waypoint
            if (ActiveWayPoint > 1 || !ValidTaskPoint(2)) {
                // only draw finish line when past the first
                // waypoint. FIXED 110307: or if task is with only 2 tps
                DrawStartEndSector(hdc, rc, Task[i].Start, Task[i].End, Task[i].Index, FinishLine, FinishRadius);
            }
        } else { // normal sector
            if (AATEnabled != TRUE) {
                //_DrawLine(hdc, PS_DASH, NIBLSCALE(3), WayPointList[Task[i].Index].Screen, Task[i].Start, RGB_PETROL, rc);
                //_DrawLine(hdc, PS_DASH, NIBLSCALE(3), WayPointList[Task[i].Index].Screen, Task[i].End, RGB_PETROL, rc);
         // DrawDashLine(hdc, size_tasklines, WayPointList[Task[i].Index].Screen, Task[i].Start, RGB_PETROL, rc);
         // DrawDashLine(hdc, size_tasklines, WayPointList[Task[i].Index].Screen, Task[i].End, RGB_PETROL, rc);
            }

            int Type = 0;
            double Radius = 0.;
            GetTaskSectorParameter(i, &Type, &Radius);
            switch (Type) {
                case CIRCLE:
                    tmp = Radius * zoom.ResScaleOverDistanceModify();
                    Circle(hdc,
                            WayPointList[Task[i].Index].Screen.x,
                            WayPointList[Task[i].Index].Screen.y,
                            (int) tmp, rc, false, false);
                    break;
                case SECTOR:
                    tmp = Radius * zoom.ResScaleOverDistanceModify();
                    Segment(hdc,
                            WayPointList[Task[i].Index].Screen.x,
                            WayPointList[Task[i].Index].Screen.y, (int) tmp, rc,
                            Task[i].AATStartRadial - DisplayAngle,
                            Task[i].AATFinishRadial - DisplayAngle);
                    break;
                case DAe:
                    if (!AATEnabled) { // this Type exist only if not AAT task
                        // JMW added german rules
                        tmp = 500 * zoom.ResScaleOverDistanceModify();
                        Circle(hdc,
                                WayPointList[Task[i].Index].Screen.x,
                                WayPointList[Task[i].Index].Screen.y,
                                (int) tmp, rc, false, false);

                        tmp = 10e3 * zoom.ResScaleOverDistanceModify();

                        Segment(hdc,
                                WayPointList[Task[i].Index].Screen.x,
                                WayPointList[Task[i].Index].Screen.y, (int) tmp, rc,
                                Task[i].AATStartRadial - DisplayAngle,
                                Task[i].AATFinishRadial - DisplayAngle);
                    }
                    break;
                case LINE:
                    if (!AATEnabled) { // this Type exist only if not AAT task
                    	if(ISGAAIRCRAFT) {
                    		POINT start,end;
                    		double rotation=AngleLimit360(Task[i].Bisector-DisplayAngle);
                    		int length=14*ScreenScale; //Make intermediate WP lines always of the same size independent by zoom level
                    		start.x=WayPointList[Task[i].Index].Screen.x+(long)(length*fastsine(rotation));
                    		start.y=WayPointList[Task[i].Index].Screen.y-(long)(length*fastcosine(rotation));
                    		rotation=Reciprocal(rotation);
                    		end.x=WayPointList[Task[i].Index].Screen.x+(long)(length*fastsine(rotation));
                    		end.y=WayPointList[Task[i].Index].Screen.y-(long)(length*fastcosine(rotation));
                    		_DrawLine(hdc, PS_SOLID, NIBLSCALE(3), start, end, taskcolor, rc);
                    	} else _DrawLine(hdc, PS_SOLID, NIBLSCALE(3), Task[i].Start, Task[i].End, taskcolor, rc);
                    }
                    break;
                case CONE:
                    tmp = Radius * zoom.ResScaleOverDistanceModify();
                    int center_x = WayPointList[Task[i].Index].Screen.x;
                    int center_y = WayPointList[Task[i].Index].Screen.y;
                    Circle(hdc, center_x, center_y, (int) tmp, rc, false, false);
                    HPEN prevPen = (HPEN)::SelectObject(hdc, hpTerrainLine);
                    for( int j = 1; j < 5 && tmp > 0; ++j) {
                        Circle(hdc, center_x, center_y, tmp -= NIBLSCALE(5), rc, true, true);
                    }
                    ::SelectObject(hdc, prevPen);
                    break;
            }

            if (AATEnabled && !DoOptimizeRoute()) {
                // ELSE HERE IS *** AAT ***
                // JMW added iso lines
                if ((i == ActiveWayPoint) || (mode.Is(Mode::MODE_TARGET_PAN) && (i == TargetPanIndex))) {
                    // JMW 20080616 flash arc line if very close to target
                    static bool flip = false;

                    if (DerivedDrawInfo.WaypointDistance < AATCloseDistance()*2.0) {
                        flip = !flip;
                    } else {
                        flip = true;
                    }
                    if (flip) {
                        for (int j = 0; j < MAXISOLINES - 1; j++) {
                            if (TaskStats[i].IsoLine_valid[j]
                                    && TaskStats[i].IsoLine_valid[j + 1]) {
                                _DrawLine(hdc, PS_SOLID, NIBLSCALE(2),
                                        TaskStats[i].IsoLine_Screen[j],
                                        TaskStats[i].IsoLine_Screen[j + 1],
                                        RGB(0, 0, 255), rc);
                            }
                        }
                    }
                }
            }
        }
    }

    if ((ActiveWayPoint < 2) && ValidTaskPoint(0) && ValidTaskPoint(1)) {
        DrawStartEndSector(hdc, rc, Task[0].Start, Task[0].End, Task[0].Index, StartLine, StartRadius);
        if (EnableMultipleStartPoints) {
            for (i = 0; i < MAXSTARTPOINTS; i++) {
                if (StartPoints[i].Active && ValidWayPoint(StartPoints[i].Index)) {
                    DrawStartEndSector(hdc, rc, StartPoints[i].Start, StartPoints[i].End,
                            StartPoints[i].Index, StartLine, StartRadius);
                }
            }
        }
    }
    
    for (i = 0; ValidTaskPoint(i + 1); i++) {
        int imin = min(Task[i].Index, Task[i + 1].Index);
        int imax = max(Task[i].Index, Task[i + 1].Index);
        // JMW AAT!
        double bearing = Task[i].OutBound;
        POINT sct1, sct2;
        if (AATEnabled) {
            LatLon2Screen(Task[i].AATTargetLon,
                    Task[i].AATTargetLat,
                    sct1);
            LatLon2Screen(Task[i + 1].AATTargetLon,
                    Task[i + 1].AATTargetLat,
                    sct2);
            DistanceBearing(Task[i].AATTargetLat,
                    Task[i].AATTargetLon,
                    Task[i + 1].AATTargetLat,
                    Task[i + 1].AATTargetLon,
                    NULL, &bearing);

            // draw nominal track line
            DrawDashLine(hdc, NIBLSCALE(1), // 091217
                    WayPointList[imin].Screen,
                    WayPointList[imax].Screen,
                    taskcolor, rc);
        } else {
            sct1 = WayPointList[imin].Screen;
            sct2 = WayPointList[imax].Screen;
        }

        if ((i >= ActiveWayPoint && DoOptimizeRoute()) || !DoOptimizeRoute()) {
            POINT ClipPt1 = sct1, ClipPt2 = sct2;
            if(LKGeom::ClipLine((POINT) {rc.left, rc.top}, (POINT) {rc.right, rc.bottom}, ClipPt1, ClipPt2)) {
                DrawMulticolorDashLine(hdc, size_tasklines,
                        sct1,
                        sct2,
                        taskcolor, RGB_BLACK,rc);
                
                // draw small arrow along task direction
                POINT p_p;
                POINT Arrow[2] = {
                    {6, 6},
                    {-6, 6}
                };
                ScreenClosestPoint(sct1, sct2,
                        Orig_Aircraft, &p_p, NIBLSCALE(25));
                threadsafePolygonRotateShift(Arrow, 2, p_p.x, p_p.y, bearing - DisplayAngle);

                _DrawLine(hdc, PS_SOLID, size_tasklines-NIBLSCALE(1), Arrow[0], p_p, taskcolor, rc);
                _DrawLine(hdc, PS_SOLID, size_tasklines-NIBLSCALE(1), Arrow[1], p_p, taskcolor, rc);
            }
        }
    }
    
    // Draw DashLine From current position to Active TurnPoint center
    if(ValidTaskPoint(ActiveWayPoint)) {
        POINT ptStart;
        LatLon2Screen(DrawInfo.Longitude, DrawInfo.Latitude, ptStart);
        DrawDashLine(hdc, NIBLSCALE(1),
                    ptStart,
                    WayPointList[Task[ActiveWayPoint].Index].Screen,
                    taskcolor, rc);

    }

    {
        UnlockTaskData();
    }

    // restore original color
    SetTextColor(hDCTemp, origcolor);
    SelectObject(hdc, oldpen);
    SelectObject(hdc, oldbrush);
}
Beispiel #8
0
// This is painting traffic icons on the screen.
void MapWindow::LKDrawFLARMTraffic(HDC hDC, RECT rc, POINT Orig_Aircraft) {

  if (!EnableFLARMMap) return;

  if (!DrawInfo.FLARM_Available) return;

  // init scaled coords for traffic icon
static int	iCircleSize = 7;
static int	iRectangleSize = 4;
  static short scaler[5];
  static short tscaler=0;
  if (DoInit[MDI_DRAWFLARMTRAFFIC]) {

	switch (ScreenSize) {
		case ss480x640:
		case ss480x800:
		case ss896x672:
		case ss800x480:
		case ss640x480:
			iCircleSize = 9;
			iRectangleSize = 5;
			scaler[0]=-1*(NIBLSCALE(4)-2);
			scaler[1]=NIBLSCALE(5)-2;
			scaler[2]=-1*(NIBLSCALE(6)-2);
			scaler[3]=NIBLSCALE(4)-2;
			scaler[4]=NIBLSCALE(2)-2;
			tscaler=NIBLSCALE(7)-2;
			break;
		case ss240x320:
		case ss272x480:
		case ss320x240:
		case ss480x272:
		case ss720x408:
		case ss480x234:
		case ss400x240:
			iCircleSize = 7;
			iRectangleSize = 4;
			scaler[0]=-1*(NIBLSCALE(8)-2);
			scaler[1]=NIBLSCALE(10)-2;
			scaler[2]=-1*(NIBLSCALE(12)-2);
			scaler[3]=NIBLSCALE(8)-2;
			scaler[4]=NIBLSCALE(4)-2;
			tscaler=NIBLSCALE(13)-2;
			break;
		default:
			iCircleSize = 7;
			iRectangleSize = 4;
			scaler[0]=-1*NIBLSCALE(4);
			scaler[1]=NIBLSCALE(5);
			scaler[2]=-1*NIBLSCALE(6);
			scaler[3]=NIBLSCALE(4);
			scaler[4]=NIBLSCALE(2);
			tscaler=NIBLSCALE(7);
			break;
	}


	DoInit[MDI_DRAWFLARMTRAFFIC]=false;
  }

  HPEN hpold;
  HPEN thinBlackPen = LKPen_Black_N1;
  POINT Arrow[5];

  TCHAR lbuffer[50];

  hpold = (HPEN)SelectObject(hDC, thinBlackPen);

  int i;
  int painted=0;

//  double dX, dY;

  TextInBoxMode_t displaymode = {0};
  displaymode.NoSetFont = 1;

  #if 0
  double screenrange = GetApproxScreenRange();
  double scalefact = screenrange/6000.0; // FIX 100820
  #endif




  HFONT  oldfont = (HFONT)SelectObject(hDC, LK8MapFont);

  for (i=0,painted=0; i<FLARM_MAX_TRAFFIC; i++) {

	// limit to 10 icons map traffic
	if (painted>=10) {
		i=FLARM_MAX_TRAFFIC;
		continue;
	}

	if ( (DrawInfo.FLARM_Traffic[i].ID !=0) && (DrawInfo.FLARM_Traffic[i].Status != LKT_ZOMBIE) ) {

		painted++;

		double target_lon;
		double target_lat;

		target_lon = DrawInfo.FLARM_Traffic[i].Longitude;
		target_lat = DrawInfo.FLARM_Traffic[i].Latitude;

		#if (0) // No scaling, wrong
		if ((EnableFLARMMap==2)&&(scalefact>1.0)) {

			double distance;
			double bearing;

			DistanceBearing(DrawInfo.Latitude, DrawInfo.Longitude, target_lat, target_lon, &distance, &bearing);
			FindLatitudeLongitude(DrawInfo.Latitude, DrawInfo.Longitude, bearing, distance*scalefact, &target_lat, &target_lon);
		}
		#endif
      
		POINT sc, sc_name, sc_av;
		LatLon2Screen(target_lon, target_lat, sc);

		sc_name = sc;

		sc_name.y -= NIBLSCALE(16);
		sc_av = sc_name;

		wsprintf(lbuffer,_T(""));
		if (DrawInfo.FLARM_Traffic[i].Cn && DrawInfo.FLARM_Traffic[i].Cn[0]!=_T('?')) { // 100322
			_tcscat(lbuffer,DrawInfo.FLARM_Traffic[i].Cn);
		}
		if (DrawInfo.FLARM_Traffic[i].Average30s>=0.1) {
			if (_tcslen(lbuffer) >0)
				_stprintf(lbuffer,_T("%s:%.1f"),lbuffer,LIFTMODIFY*DrawInfo.FLARM_Traffic[i].Average30s);
			else
				_stprintf(lbuffer,_T("%.1f"),LIFTMODIFY*DrawInfo.FLARM_Traffic[i].Average30s);
		}

		displaymode.Border=1;

		if (_tcslen(lbuffer)>0)
		TextInBox(hDC, lbuffer, sc.x+tscaler, sc.y+tscaler, 0, &displaymode, false);

		// red circle
		if ((DrawInfo.FLARM_Traffic[i].AlarmLevel>0) && (DrawInfo.FLARM_Traffic[i].AlarmLevel<4)) {
			DrawBitmapIn(hDC, sc, hFLARMTraffic,true);
		}
#if 0
		Arrow[0].x = -4;
		Arrow[0].y = 5;
		Arrow[1].x = 0;
		Arrow[1].y = -6;
		Arrow[2].x = 4;
		Arrow[2].y = 5;
		Arrow[3].x = 0;
		Arrow[3].y = 2;
		Arrow[4].x = -4;
		Arrow[4].y = 5;
#endif

		Arrow[0].x = scaler[0];
		Arrow[0].y = scaler[1];
		Arrow[1].x = 0;
		Arrow[1].y = scaler[2];
		Arrow[2].x = scaler[3];
		Arrow[2].y = scaler[1];
		Arrow[3].x = 0;
		Arrow[3].y = scaler[4];
		Arrow[4].x = scaler[0];
		Arrow[4].y = scaler[1];
/*
		switch (DrawInfo.FLARM_Traffic[i].Status) { // 100321
			case LKT_GHOST:
				SelectObject(hDC, yellowBrush);
				break;
			case LKT_ZOMBIE:
				SelectObject(hDC, redBrush);
				break;
			default:
				SelectObject(hDC, greenBrush);
				break;
		}
*/
		  /*************************************************************************
		   * calculate climb color
		   *************************************************************************/

		  int iVarioIdx = (int)(2*DrawInfo.FLARM_Traffic[i].Average30s  -0.5)+NO_VARIO_COLORS/2;
		  if(iVarioIdx < 0) iVarioIdx =0;
		  if(iVarioIdx >= NO_VARIO_COLORS) iVarioIdx =NO_VARIO_COLORS-1;
		  SelectObject(hDC, *variobrush[iVarioIdx]);

		  switch (DrawInfo.FLARM_Traffic[i].Status) { // 100321
			case LKT_GHOST:
				Rectangle(hDC, sc.x-iRectangleSize,  sc.y-iRectangleSize,sc.x+iRectangleSize, sc.y+iRectangleSize);
				break;
			case LKT_ZOMBIE:
				Circle(hDC,  sc.x,  sc.x, iCircleSize, rc, true, true );
				break;
			default:
				PolygonRotateShift(Arrow, 5, sc.x, sc.y, DrawInfo.FLARM_Traffic[i].TrackBearing - DisplayAngle);
				Polygon(hDC,Arrow,5);
				break;
		  }

	}
  }

  SelectObject(hDC, oldfont);
  SelectObject(hDC, hpold);

}
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);
}
Beispiel #10
0
void MapWindow::DrawTask(HDC hdc, RECT rc, const POINT &Orig_Aircraft) {
    int i;
    double tmp;

    COLORREF whitecolor = RGB_WHITE;
    COLORREF origcolor = SetTextColor(hDCTemp, whitecolor);
    HPEN oldpen = 0;
    HBRUSH oldbrush = 0;

    static short size_tasklines=0;

    if (DoInit[MDI_DRAWTASK]) {
	switch (ScreenSize) {
		case ss480x272:
		case ss272x480:
		case ss320x240:
		case ss240x320:
			size_tasklines=NIBLSCALE(4);
			break;
		default:
			size_tasklines=NIBLSCALE(3);
			break;
	}
	DoInit[MDI_DRAWTASK]=false;
    }

    if (!WayPointList) return;

    oldpen = (HPEN) SelectObject(hdc, hpStartFinishThick);
    oldbrush = (HBRUSH) SelectObject(hdc, GetStockObject(HOLLOW_BRUSH));

    LockTaskData(); // protect from external task changes

    for (i = 1; ValidTaskPoint(i); i++) {
        if (!ValidTaskPoint(i + 1)) { // final waypoint
            if (ActiveWayPoint > 1 || !ValidTaskPoint(2)) {
                // only draw finish line when past the first
                // waypoint. FIXED 110307: or if task is with only 2 tps
                DrawStartEndSector(hdc, rc, Task[i].Start, Task[i].End, Task[i].Index, FinishLine, FinishRadius);
            }
        } else { // normal sector
            if (AATEnabled != TRUE) {
                //_DrawLine(hdc, PS_DASH, NIBLSCALE(3), WayPointList[Task[i].Index].Screen, Task[i].Start, RGB_PETROL, rc);
                //_DrawLine(hdc, PS_DASH, NIBLSCALE(3), WayPointList[Task[i].Index].Screen, Task[i].End, RGB_PETROL, rc);
                DrawDashLine(hdc,  size_tasklines, WayPointList[Task[i].Index].Screen, Task[i].Start, RGB_PETROL, rc);
                DrawDashLine(hdc,  size_tasklines, WayPointList[Task[i].Index].Screen, Task[i].End, RGB_PETROL, rc);
            }

            int Type = SectorType;
            double Radius = SectorRadius;
            if (AATEnabled) {
                Type = Task[i].AATType;
                Radius = Task[i].AATCircleRadius;
            }

            switch (Type) {
                case CIRCLE:
                    tmp = Radius * zoom.ResScaleOverDistanceModify();
                    Circle(hdc,
                            WayPointList[Task[i].Index].Screen.x,
                            WayPointList[Task[i].Index].Screen.y,
                            (int) tmp, rc, false, false);
                    break;
                case SECTOR:
                    tmp = Radius * zoom.ResScaleOverDistanceModify();
                    Segment(hdc,
                            WayPointList[Task[i].Index].Screen.x,
                            WayPointList[Task[i].Index].Screen.y, (int) tmp, rc,
                            Task[i].AATStartRadial - DisplayAngle,
                            Task[i].AATFinishRadial - DisplayAngle);
                    break;
                case 2:
                    if (!AATEnabled) { // this Type exist only if not AAT task
                        // JMW added german rules
                        tmp = 500 * zoom.ResScaleOverDistanceModify();
                        Circle(hdc,
                                WayPointList[Task[i].Index].Screen.x,
                                WayPointList[Task[i].Index].Screen.y,
                                (int) tmp, rc, false, false);

                        tmp = 10e3 * zoom.ResScaleOverDistanceModify();

                        Segment(hdc,
                                WayPointList[Task[i].Index].Screen.x,
                                WayPointList[Task[i].Index].Screen.y, (int) tmp, rc,
                                Task[i].AATStartRadial - DisplayAngle,
                                Task[i].AATFinishRadial - DisplayAngle);
                    }
                    break;
            }

            if (AATEnabled && !DoOptimizeRoute()) {
                // ELSE HERE IS   *** AAT ***
                // JMW added iso lines
                if ((i == ActiveWayPoint) || (mode.Is(Mode::MODE_TARGET_PAN) && (i == TargetPanIndex))) {
                    // JMW 20080616 flash arc line if very close to target
                    static bool flip = false;

                    if (DerivedDrawInfo.WaypointDistance < AATCloseDistance()*2.0) {
                        flip = !flip;
                    } else {
                        flip = true;
                    }
                    if (flip) {
                        for (int j = 0; j < MAXISOLINES - 1; j++) {
                            if (TaskStats[i].IsoLine_valid[j]
                                    && TaskStats[i].IsoLine_valid[j + 1]) {
                                _DrawLine(hdc, PS_SOLID, NIBLSCALE(2),
                                        TaskStats[i].IsoLine_Screen[j],
                                        TaskStats[i].IsoLine_Screen[j + 1],
                                        RGB(0, 0, 255), rc);
                            }
                        }
                    }
                }
            }
        }
    }

    if ((ActiveWayPoint < 2) && ValidTaskPoint(0) && ValidTaskPoint(1)) {
        DrawStartEndSector(hdc, rc, Task[0].Start, Task[0].End, Task[0].Index, StartLine, StartRadius);
        if (EnableMultipleStartPoints) {
            for (i = 0; i < MAXSTARTPOINTS; i++) {
                if (StartPoints[i].Active && ValidWayPoint(StartPoints[i].Index)) {
                    DrawStartEndSector(hdc, rc, StartPoints[i].Start, StartPoints[i].End,
                            StartPoints[i].Index, StartLine, StartRadius);
                }
            }
        }
    }    
    
    for (i = 0; ValidTaskPoint(i + 1); i++) {
        bool is_first = (Task[i].Index < Task[i + 1].Index);
        int imin = min(Task[i].Index, Task[i + 1].Index);
        int imax = max(Task[i].Index, Task[i + 1].Index);
        // JMW AAT!
        double bearing = Task[i].OutBound;
        POINT sct1, sct2;
        if (AATEnabled) {
            LatLon2Screen(Task[i].AATTargetLon,
                    Task[i].AATTargetLat,
                    sct1);
            LatLon2Screen(Task[i + 1].AATTargetLon,
                    Task[i + 1].AATTargetLat,
                    sct2);
            DistanceBearing(Task[i].AATTargetLat,
                    Task[i].AATTargetLon,
                    Task[i + 1].AATTargetLat,
                    Task[i + 1].AATTargetLon,
                    NULL, &bearing);

            // draw nominal track line
            DrawDashLine(hdc, NIBLSCALE(1), // 091217
                    WayPointList[imin].Screen,
                    WayPointList[imax].Screen,
                    taskcolor, rc);
        } else {
            sct1 = WayPointList[Task[i].Index].Screen;
            sct2 = WayPointList[Task[i + 1].Index].Screen;
        }

        if ((i >= ActiveWayPoint && DoOptimizeRoute()) || !DoOptimizeRoute()) {
            if (is_first) {
                DrawMulticolorDashLine(hdc, size_tasklines,
                        sct1,
                        sct2,
                        taskcolor, RGB_BLACK,rc);
            } else {
                DrawMulticolorDashLine(hdc, size_tasklines,
                        sct2,
                        sct1,
                        taskcolor, RGB_BLACK,rc);
            }

            // draw small arrow along task direction
            POINT p_p;
            POINT Arrow[2] = {
                {6, 6},
                {-6, 6}
            };
            ScreenClosestPoint(sct1, sct2,
                    Orig_Aircraft, &p_p, NIBLSCALE(25));
            PolygonRotateShift(Arrow, 2, p_p.x, p_p.y,
                    bearing - DisplayAngle);

            _DrawLine(hdc, PS_SOLID, size_tasklines-NIBLSCALE(1), Arrow[0], p_p, taskcolor, rc);
            _DrawLine(hdc, PS_SOLID, size_tasklines-NIBLSCALE(1), Arrow[1], p_p, taskcolor, rc);
        }
    }

    {
        UnlockTaskData();
    }

    // restore original color
    SetTextColor(hDCTemp, origcolor);
    SelectObject(hdc, oldpen);
    SelectObject(hdc, oldbrush);
}
Beispiel #11
0
void MapWindow::DrawProjectedTrack(HDC hdc, const RECT rc, const POINT Orig) {
  if ((ActiveWayPoint<=0) || !ValidTaskPoint(ActiveWayPoint) || !AATEnabled) { 
    return;
  }
  if (DerivedDrawInfo.Circling) {
    // don't display in various modes
    return;
  }

  // TODO feature: maybe have this work even if no task?
  // TODO feature: draw this also when in target pan mode

  LockTaskData();  // protect from external task changes

  double startLat = DrawInfo.Latitude;
  double startLon = DrawInfo.Longitude;
  double previousLat;
  double previousLon;
  if (AATEnabled) {
    previousLat = Task[max(0,ActiveWayPoint-1)].AATTargetLat;
    previousLon = Task[max(0,ActiveWayPoint-1)].AATTargetLon; 
  } else {
    previousLat = WayPointList[Task[max(0,ActiveWayPoint-1)].Index].Latitude;
    previousLon = WayPointList[Task[max(0,ActiveWayPoint-1)].Index].Longitude; 
  }
  UnlockTaskData();

  double distance_from_previous, bearing;
  DistanceBearing(previousLat, previousLon,
		  startLat, startLon,
		  &distance_from_previous,
		  &bearing);

  if (distance_from_previous < 100.0) {
    bearing = DrawInfo.TrackBearing;
    // too short to have valid data
  }
  POINT pt[2] = {{0,-75},{0,-400}};
  if (mode.Is(Mode::MODE_TARGET_PAN)) {
    double screen_range = GetApproxScreenRange();
    double flow = 0.4;
    double fhigh = 1.5;
    screen_range = max(screen_range, DerivedDrawInfo.WaypointDistance);

    double p1Lat;
    double p1Lon;
    double p2Lat;
    double p2Lon;
    FindLatitudeLongitude(startLat, startLon, 
			  bearing, flow*screen_range,
			  &p1Lat, &p1Lon);
    FindLatitudeLongitude(startLat, startLon, 
			  bearing, fhigh*screen_range,
			  &p2Lat, &p2Lon);
    LatLon2Screen(p1Lon, p1Lat, pt[0]);
    LatLon2Screen(p2Lon, p2Lat, pt[1]);
  } else if (fabs(bearing-DerivedDrawInfo.WaypointBearing)<10) {
    // too small an error to bother
    return;
  } else {
    pt[1].y = (long)(-max(MapRect.right-MapRect.left,
			  MapRect.bottom-MapRect.top)*1.2);
    PolygonRotateShift(pt, 2, Orig.x, Orig.y, 
		       bearing-DisplayAngle);
  }
  DrawDashLine(hdc, 2, pt[0], pt[1], RGB(0,0,0), rc);
}
rectObj MapWindow::CalculateScreenBounds(double scale, const RECT& rc) {
    // compute lat lon extents of visible screen
    rectObj sb;

    if (scale>= 1.0) {
        POINT screen_center;
        LatLon2Screen(PanLongitude,
                      PanLatitude,
                      screen_center);

        sb.minx = sb.maxx = PanLongitude;
        sb.miny = sb.maxy = PanLatitude;

        unsigned int dx, dy;
        unsigned int maxsc=0;
        dx = screen_center.x-rc.right;
        dy = screen_center.y-rc.top;
        maxsc = max(maxsc, dx*dx+dy*dy);
        dx = screen_center.x-rc.left;
        dy = screen_center.y-rc.top;
        maxsc = max(maxsc, dx*dx+dy*dy);
        dx = screen_center.x-rc.left;
        dy = screen_center.y-rc.bottom;
        maxsc = max(maxsc, dx*dx+dy*dy);
        dx = screen_center.x-rc.right;
        dy = screen_center.y-rc.bottom;
        maxsc = max(maxsc, dx*dx+dy*dy);
        maxsc = isqrt4(maxsc);

        for (int i=0; i<10; i++) {
            double ang = i*360.0/10;
            POINT p;
            double X, Y;
            p.x = screen_center.x + iround(fastcosine(ang)*maxsc*scale);
            p.y = screen_center.y + iround(fastsine(ang)*maxsc*scale);
            Screen2LatLon(p.x, p.y, X, Y);
            sb.minx = min(X, sb.minx);
            sb.miny = min(Y, sb.miny);
            sb.maxx = max(X, sb.maxx);
            sb.maxy = max(Y, sb.maxy);
        }

    } else {

        double xmin, xmax, ymin, ymax;
        int x, y;
        double X, Y;

        x = rc.left;
        y = rc.top;
        Screen2LatLon(x, y, X, Y);
        xmin = X;
        xmax = X;
        ymin = Y;
        ymax = Y;

        x = rc.right;
        y = rc.top;
        Screen2LatLon(x, y, X, Y);
        xmin = min(xmin, X);
        xmax = max(xmax, X);
        ymin = min(ymin, Y);
        ymax = max(ymax, Y);

        x = rc.right;
        y = rc.bottom;
        Screen2LatLon(x, y, X, Y);
        xmin = min(xmin, X);
        xmax = max(xmax, X);
        ymin = min(ymin, Y);
        ymax = max(ymax, Y);

        x = rc.left;
        y = rc.bottom;
        Screen2LatLon(x, y, X, Y);
        xmin = min(xmin, X);
        xmax = max(xmax, X);
        ymin = min(ymin, Y);
        ymax = max(ymax, Y);


        sb.minx = xmin;
        sb.maxx = xmax;
        sb.miny = ymin;
        sb.maxy = ymax;

    }

    return sb;
}
void MapWindow::CalculateScreenPositions(POINT Orig, RECT rc,
        POINT *Orig_Aircraft)
{

    unsigned int i;

    Orig_Screen = Orig;

    if (!mode.AnyPan()) {

        if (GliderCenter
                && DerivedDrawInfo.Circling
                && (EnableThermalLocator==2)) {

            if (DerivedDrawInfo.ThermalEstimate_R>0) {
                PanLongitude = DerivedDrawInfo.ThermalEstimate_Longitude;
                PanLatitude = DerivedDrawInfo.ThermalEstimate_Latitude;
                // TODO enhancement: only pan if distance of center to
                // aircraft is smaller than one third screen width

                POINT screen;
                LatLon2Screen(PanLongitude,
                              PanLatitude,
                              screen);

                LatLon2Screen(DrawInfo.Longitude,
                              DrawInfo.Latitude,
                              *Orig_Aircraft);
                if ((fabs((double)Orig_Aircraft->x-screen.x)<(rc.right-rc.left)/3)
                        && (fabs((double)Orig_Aircraft->y-screen.y)<(rc.bottom-rc.top)/3)) {

                } else {
                    // out of bounds, center on aircraft
                    PanLongitude = DrawInfo.Longitude;
                    PanLatitude = DrawInfo.Latitude;
                }
            } else {
                PanLongitude = DrawInfo.Longitude;
                PanLatitude = DrawInfo.Latitude;
            }
        } else {
            // Pan is off
            PanLongitude = DrawInfo.Longitude;
            PanLatitude = DrawInfo.Latitude;
        }
    }

    LatLon2Screen(DrawInfo.Longitude,
                  DrawInfo.Latitude,
                  *Orig_Aircraft);

    // very important
    screenbounds_latlon = CalculateScreenBounds(0.0, rc);

    // Old note obsoleted 121111:
    // preserve this calculation for 0.0 until next round!
    // This is already done since screenbounds_latlon is global. Beware that DrawTrail will change it later on
    // to expand boundaries by 1 minute

    // get screen coordinates for all task waypoints

    LockTaskData();

    if (!WayPointList.empty()) {
        for (i=0; i<MAXTASKPOINTS; i++) {
            unsigned index = Task[i].Index;
            if (index < WayPointList.size()) {

                LatLon2Screen(WayPointList[index].Longitude,
                              WayPointList[index].Latitude,
                              WayPointList[index].Screen);
                WayPointList[index].Visible =
                    PointVisible(WayPointList[index].Screen);
            } else {
                // No need to continue.
                break;
            }
        }
        if (EnableMultipleStartPoints) {
            for(i=0; i<MAXSTARTPOINTS-1; i++) {
                unsigned index = StartPoints[i].Index;
                if (StartPoints[i].Active && (index < WayPointList.size())) {

                    LatLon2Screen(WayPointList[index].Longitude,
                                  WayPointList[index].Latitude,
                                  WayPointList[index].Screen);
                    WayPointList[index].Visible =
                        PointVisible(WayPointList[index].Screen);
                } else {
                    // No Need to continue.
                    break;
                }
            }
        }

        // only calculate screen coordinates for waypoints that are visible

        // TODO 110203 OPTIMIZE THIS !
        for(i=0; i<WayPointList.size(); i++)
        {
            WayPointList[i].Visible = false;
            if (!WayPointList[i].FarVisible) continue;
            if(PointVisible(WayPointList[i].Longitude, WayPointList[i].Latitude) )
            {
                LatLon2Screen(WayPointList[i].Longitude, WayPointList[i].Latitude,
                              WayPointList[i].Screen);
                WayPointList[i].Visible = PointVisible(WayPointList[i].Screen);
            }
        }
    }

    if(TrailActive)
    {
        iSnailNext = SnailNext;
        iLongSnailNext = LongSnailNext;
        // set this so that new data doesn't arrive between calculating
        // this and the screen updates
    }

    if (EnableMultipleStartPoints) {
        for(i=0; i<MAXSTARTPOINTS-1; i++) {
            if (StartPoints[i].Active && ValidWayPointFast(StartPoints[i].Index)) {
                LatLon2Screen(StartPoints[i].SectorEndLon,
                              StartPoints[i].SectorEndLat, StartPoints[i].End);
                LatLon2Screen(StartPoints[i].SectorStartLon,
                              StartPoints[i].SectorStartLat, StartPoints[i].Start);
            }
        }
    }

    for(i=0; i<MAXTASKPOINTS-1; i++)
    {
        bool this_valid = ValidTaskPointFast(i);
        bool next_valid = ValidTaskPointFast(i+1);
        if (AATEnabled && this_valid) {
            LatLon2Screen(Task[i].AATTargetLon, Task[i].AATTargetLat,
                          Task[i].Target);
        }

        if(this_valid && !next_valid)
        {
            // finish
            LatLon2Screen(Task[i].SectorEndLon, Task[i].SectorEndLat, Task[i].End);
            LatLon2Screen(Task[i].SectorStartLon, Task[i].SectorStartLat, Task[i].Start);

            // No need to continue.
            break;
        }
        if(this_valid && next_valid)
        {
            LatLon2Screen(Task[i].SectorEndLon, Task[i].SectorEndLat, Task[i].End);
            LatLon2Screen(Task[i].SectorStartLon, Task[i].SectorStartLat, Task[i].Start);

            if((AATEnabled) && (Task[i].AATType == SECTOR))
            {
                LatLon2Screen(Task[i].AATStartLon, Task[i].AATStartLat, Task[i].AATStart);
                LatLon2Screen(Task[i].AATFinishLon, Task[i].AATFinishLat, Task[i].AATFinish);
            }
            if (AATEnabled && (((int)i==ActiveWayPoint) ||
                               (mode.Is(Mode::MODE_TARGET_PAN) && ((int)i==TargetPanIndex)))) {

                for (int j=0; j<MAXISOLINES; j++) {
                    if (TaskStats[i].IsoLine_valid[j]) {
                        LatLon2Screen(TaskStats[i].IsoLine_Longitude[j],
                                      TaskStats[i].IsoLine_Latitude[j],
                                      TaskStats[i].IsoLine_Screen[j]);
                    }
                }
            }
        }
    }

    UnlockTaskData();

}