Beispiel #1
0
void
TaskPointRenderer::DrawTaskLine(const GeoPoint &start, const GeoPoint &end)
{
  canvas.Select(LegActive() ? task_look.leg_active_pen :
                              task_look.leg_inactive_pen);
  canvas.SetBackgroundTransparent();
  map_canvas.DrawLine(start, end);
  canvas.SetBackgroundOpaque();

  // draw small arrow along task direction
  RasterPoint p_p;
  RasterPoint Arrow[3] = { {6,6}, {-6,6}, {0,0} };

  const RasterPoint p_start = m_proj.GeoToScreen(start);
  const RasterPoint p_end = m_proj.GeoToScreen(end);

  const Angle ang = Angle::Radians(atan2(fixed(p_end.x - p_start.x),
                                         fixed(p_start.y - p_end.y))).AsBearing();

  ScreenClosestPoint(p_start, p_end, m_proj.GetScreenOrigin(), &p_p, Layout::Scale(25));
  PolygonRotateShift(Arrow, 2, p_p.x, p_p.y, ang);
  Arrow[2] = Arrow[1];
  Arrow[1] = p_p;

  canvas.Select(task_look.arrow_pen);
  canvas.DrawPolyline(Arrow, 3);
}
Beispiel #2
0
static void
DrawHangGlider(Canvas &canvas, const AircraftLook &look,
               const Angle angle, const RasterPoint aircraft_pos, bool inverse)
{
  RasterPoint aircraft[] = {
    {1, -3},
    {7, 0},
    {13, 4},
    {13, 6},
    {6, 3},
    {1, 2},
    {-1, 2},
    {-6, 3},
    {-13, 6},
    {-13, 4},
    {-7, 0},
    {-1, -3},
   };

  PolygonRotateShift(aircraft, ARRAY_SIZE(aircraft),
                     aircraft_pos.x, aircraft_pos.y, angle);

  if (inverse) {
    canvas.SelectBlackBrush();
    canvas.SelectWhitePen();
  } else {
    canvas.SelectWhiteBrush();
    canvas.SelectBlackPen();
  }

  canvas.DrawPolygon(aircraft, ARRAY_SIZE(aircraft));
}
Beispiel #3
0
void DrawTelescope(HDC hdc, double fAngle, int x, int y)
{
	POINT Telescope[17] = {
			{  6 ,  7  },    // 1
			{  6 ,  2  },    // 2
			{  8 , -2  },    // 3
			{  8 , -7  },    // 4
			{  1 , -7  },    // 5
			{  1 , -2  },    // 6
			{ -1 , -2  },    // 7
			{ -1 , -7  },    // 8
			{ -8 , -7  },    // 9
			{ -8 , -2  },    // 10
			{ -6 ,  2  },    // 11
			{ -6 ,  7  },    // 12
			{ -1 ,  7  },    // 13
			{ -1 ,  3  },    // 14
			{  1 ,  3  },    // 15
			{  1 ,  7  },    // 16
			{  4 ,  7  }     // 17
	};



bool bBlack = true;
DrawWindRoseDirection( hdc, AngleLimit360( fAngle ),  x,  y + NIBLSCALE(18));
PolygonRotateShift(Telescope, 17, x, y, AngleLimit360( fAngle  ));

LKPen	oldBPen ;
LKBrush oldBrush ;
if (!bBlack)
{
  oldBPen  = Surface.SelectObject(LK_WHITE_PEN));
  oldBrush = Surface.SelectObject(LKBrush_White);
}
Beispiel #4
0
void
WindArrowRenderer::Draw(Canvas &canvas, const Angle screen_angle,
                        const SpeedVector wind, const PixelPoint pos,
                        const PixelRect rc, WindArrowStyle arrow_style)
{
  // Draw arrow (and tail)

  const unsigned length = uround(Quadruple(wind.norm));
  DrawArrow(canvas, pos, wind.bearing - screen_angle, length, arrow_style);

  // Draw wind speed label

  StaticString<12> buffer;
  buffer.Format(_T("%i"), iround(Units::ToUserWindSpeed(wind.norm)));

  canvas.SetTextColor(COLOR_BLACK);
  canvas.Select(*look.font);

  const unsigned offset = uround(M_SQRT2 * wind.norm);
  BulkPixelPoint label[] = {
    { 18, -26 - int(offset) },
  };
  PolygonRotateShift(label, ARRAY_SIZE(label),
                     pos, wind.bearing - screen_angle);

  TextInBoxMode style;
  style.align = TextInBoxMode::Alignment::CENTER;
  style.vertical_position = TextInBoxMode::VerticalPosition::CENTERED;
  style.shape = LabelShape::OUTLINED;

  TextInBox(canvas, buffer, label[0].x, label[0].y, style, rc);
}
Beispiel #5
0
/**
 * Paints an arrow into the direction of the current task leg
 * @param canvas The canvas to paint on
 */
void
FlarmTrafficControl::PaintTaskDirection(Canvas &canvas) const
{
  if (task_direction.value_degrees() < fixed_zero)
    return;

  canvas.select(hpRadar);
  canvas.hollow_brush();

  RasterPoint triangle[4];
  triangle[0].x = 0;
  triangle[0].y = -radius / Layout::FastScale(1) + 15;
  triangle[1].x = 7;
  triangle[1].y = triangle[0].y + 30;
  triangle[2].x = -triangle[1].x;
  triangle[2].y = triangle[1].y;
  triangle[3].x = triangle[0].x;
  triangle[3].y = triangle[0].y;

  PolygonRotateShift(triangle, 4, radar_mid.x, radar_mid.y,
                     task_direction - (enable_north_up ?
                                       Angle::native(fixed_zero) : heading));

  // Draw the arrow
  canvas.polygon(triangle, 4);
}
Beispiel #6
0
/**
 * Paints an arrow into the direction of the current task leg
 * @param canvas The canvas to paint on
 */
void
FlarmTrafficControl::PaintTaskDirection(Canvas &canvas) const
{
  if (negative(task_direction.Degrees()))
    return;

  canvas.Select(look.radar_pen);
  canvas.SelectHollowBrush();

  RasterPoint triangle[4];
  triangle[0].x = 0;
  triangle[0].y = -radius / Layout::FastScale(1) + 15;
  triangle[1].x = 7;
  triangle[1].y = triangle[0].y + 30;
  triangle[2].x = -triangle[1].x;
  triangle[2].y = triangle[1].y;
  triangle[3].x = triangle[0].x;
  triangle[3].y = triangle[0].y;

  PolygonRotateShift(triangle, 4, radar_mid,
                     task_direction - (enable_north_up ?
                                       Angle::Zero() : heading));

  // Draw the arrow
  canvas.DrawPolygon(triangle, 4);
}
Beispiel #7
0
void MapWindow::DrawBestCruiseTrack(LKSurface& Surface, const POINT& Orig)
{
  if (OvertargetMode>OVT_TASK) return;

  if (!ValidTaskPoint(ActiveTaskPoint)) return;

  if (DerivedDrawInfo.WaypointDistance < 0.010) return;

  // dont draw bestcruise indicator if not needed
  if (fabs(DerivedDrawInfo.BestCruiseTrack-DerivedDrawInfo.WaypointBearing)<2) { // 091202 10 to 2
	return;
  } 


  const auto hpOld = Surface.SelectObject(LKPen_Blue_N1);
  const auto hbOld = Surface.SelectObject(LKBrush_Blue);

  if (Appearance.BestCruiseTrack == ctBestCruiseTrackDefault){

    int dy = (long)(70); 
    POINT Arrow[7] = { {-1,-40}, {1,-40}, {1,0}, {6,8}, {-6,8}, {-1,0}, {-1,-40}};

    Arrow[2].y -= dy;
    Arrow[3].y -= dy;
    Arrow[4].y -= dy;
    Arrow[5].y -= dy;

    PolygonRotateShift(Arrow, 7, Orig.x, Orig.y, 
                       DerivedDrawInfo.BestCruiseTrack-DisplayAngle);

    Surface.Polygon(Arrow,7);

  } else
  if (Appearance.BestCruiseTrack == ctBestCruiseTrackAltA){

    POINT Arrow[] = { {-1,-40}, {-1,-62}, {-6,-62}, {0,-70}, {6,-62}, {1,-62}, {1,-40}, {-1,-40}};

    PolygonRotateShift(Arrow, sizeof(Arrow)/sizeof(Arrow[0]),
                       Orig.x, Orig.y, 
                       DerivedDrawInfo.BestCruiseTrack-DisplayAngle);
    Surface.Polygon(Arrow, (sizeof(Arrow)/sizeof(Arrow[0])));
  }

  Surface.SelectObject(hpOld);
  Surface.SelectObject(hbOld);
}
Beispiel #8
0
void
TrafficRenderer::Draw(Canvas &canvas, const TrafficLook &traffic_look,
                      const FlarmTraffic &traffic, const Angle angle,
                      const FlarmColor color, const RasterPoint pt)
{
    // Create point array that will form that arrow polygon
    RasterPoint arrow[] = {
        { -4, 6 },
        { 0, -8 },
        { 4, 6 },
        { 0, 3 },
        { -4, 6 },
    };

    // Select brush depending on AlarmLevel
    switch (traffic.alarm_level) {
    case FlarmTraffic::AlarmType::LOW:
    case FlarmTraffic::AlarmType::INFO_ALERT:
        canvas.Select(traffic_look.warning_brush);
        break;
    case FlarmTraffic::AlarmType::IMPORTANT:
    case FlarmTraffic::AlarmType::URGENT:
        canvas.Select(traffic_look.alarm_brush);
        break;
    case FlarmTraffic::AlarmType::NONE:
        canvas.Select(traffic_look.safe_brush);
        break;
    }

    // Select black pen
    canvas.SelectBlackPen();

    // Rotate and shift the arrow to the right position and angle
    PolygonRotateShift(arrow, ARRAY_SIZE(arrow), pt, angle);

    // Draw the arrow
    canvas.DrawPolygon(arrow, ARRAY_SIZE(arrow));

    switch (color) {
    case FlarmColor::GREEN:
        canvas.Select(traffic_look.team_pen_green);
        break;
    case FlarmColor::BLUE:
        canvas.Select(traffic_look.team_pen_blue);
        break;
    case FlarmColor::YELLOW:
        canvas.Select(traffic_look.team_pen_yellow);
        break;
    case FlarmColor::MAGENTA:
        canvas.Select(traffic_look.team_pen_magenta);
        break;
    default:
        return;
    }

    canvas.SelectHollowBrush();
    canvas.DrawCircle(pt.x, pt.y, Layout::FastScale(11));
}
Beispiel #9
0
void
MapWindow::DrawProjectedTrack(Canvas &canvas)
{
  if (task == NULL || !task->Valid() || !task->getSettings().AATEnabled ||
      task->getActiveIndex() ==0)
    return;

  if (Calculated().Circling || task->TaskIsTemporary()) {
    // 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

  GEOPOINT start = Basic().Location;
  GEOPOINT previous_loc = task->getTargetLocation(task->getActiveIndex() - 1);

  double distance_from_previous, bearing;
  DistanceBearing(previous_loc, start,
		  &distance_from_previous,
		  &bearing);

  if (distance_from_previous < 100.0) {
    bearing = Basic().TrackBearing;
    // too short to have valid data
  }
  POINT pt[2] = {{0,-75},{0,-400}};
  if (SettingsMap().TargetPan) {
    double screen_range = GetScreenDistanceMeters();
    double f_low = 0.4;
    double f_high = 1.5;
    screen_range = max(screen_range, Calculated().WaypointDistance);

    GEOPOINT p1, p2;
    FindLatitudeLongitude(start,
			  bearing, f_low*screen_range,
			  &p1);
    FindLatitudeLongitude(start,
			  bearing, f_high*screen_range,
			  &p2);
    LonLat2Screen(p1, pt[0]);
    LonLat2Screen(p2, pt[1]);
  } else if (fabs(bearing-Calculated().WaypointBearing)<10) {
    // too small an error to bother
    return;
  } else {
    pt[1].y = (long)(-max(MapRectBig.right-MapRectBig.left,
			  MapRectBig.bottom-MapRectBig.top)*1.2);
    PolygonRotateShift(pt, 2, Orig_Aircraft.x, Orig_Aircraft.y,
		       bearing-DisplayAngle);
  }

  Pen dash_pen(Pen::DASH, IBLSCALE(2), Color(0, 0, 0));
  canvas.select(dash_pen);
  canvas.line(pt[0], pt[1]);
}
Beispiel #10
0
void
NextArrowRenderer::DrawArrow(Canvas &canvas, const PixelRect &rc,
                             Angle angle)
{
  /*
   * Define arrow geometry for forward pointing arrow.
   * These are the coordinates of the corners, relative to the center (o)
   *
   *                               +   (0,-head_len)
   *                              / \
   *                             /   \
   *                            /     \
   * (-head_width,-head_base)  +-+   +-+  (head_width,-head_base)
   *   (-tail_width,-head_base)  | o |  (tail_width,-head_base)
   *                             |   |
   *                             |   |
   *     (-tail_width,tail_len)  +---+  (tail_width,tail_len)
   *
   * The "tail" of the arrow is slightly shorter than the "head" to avoid
   * the corners of the tail to stick out of the bounding PixelRect.
   */
  static constexpr auto head_len = 50;
  static constexpr auto head_width = 36;
  static constexpr auto head_base = head_len - head_width;
  static constexpr auto tail_width = 16;
  static constexpr auto tail_len = head_len - tail_width / 2;

  // An array of the arrow corner coordinates.
  RasterPoint arrow[] = {
    { 0, -head_len },
    { head_width, -head_base },
    { tail_width, -head_base },
    { tail_width, tail_len },
    { -tail_width, tail_len },
    { -tail_width, -head_base },
    { -head_width, -head_base },
  };

  /*
   * Rotate the arrow, center it in the bounding rectangle, and scale
   * it to fill the rectangle.
   *
   * Note that PolygonRotateShift scales a polygon with coordinates
   * in the range -50 to +50 to fill a square with the size of the 'scale'
   * argument.
   */
  const auto size = std::min(rc.right - rc.left, rc.bottom - rc.top);
  PolygonRotateShift(arrow, ARRAY_SIZE(arrow),
                     rc.GetCenter(), angle,
                     size, false);

  // Draw the arrow.
  canvas.Select(look.arrow_pen);
  canvas.Select(look.arrow_brush);
  canvas.DrawPolygon(arrow, ARRAY_SIZE(arrow));
}
Beispiel #11
0
static void
DrawMirroredPolygon(const BulkPixelPoint *src, unsigned points,
                    Canvas &canvas, const Angle angle,
                    const PixelPoint pos)
{
  BulkPixelPoint dst[64];
  assert(2 * points <= ARRAY_SIZE(dst));

  std::copy_n(src, points, dst);
  for (unsigned i = 0; i < points; ++i) {
    dst[2 * points - i - 1].x = -dst[i].x;
    dst[2 * points - i - 1].y = dst[i].y;
  }
#ifdef ENABLE_OPENGL
  PolygonRotateShift(dst, 2 * points, pos, angle, 70);
#else
  PolygonRotateShift(dst, 2 * points, pos, angle, 50);
#endif
  canvas.DrawPolygon(dst, 2 * points);
}
Beispiel #12
0
void
CompassRenderer::Draw(Canvas &canvas, const Angle screen_angle,
                      const RasterPoint pos)
{
  RasterPoint arrow[5] = { { 0, -13 }, { -6, 10 }, { 0, 4 }, { 6, 10 }, { 0, -13 } };

  canvas.Select(look.compass_pen);
  canvas.Select(look.compass_brush);

  // North arrow
  PolygonRotateShift(arrow, ARRAY_SIZE(arrow), pos.x, pos.y, -screen_angle);
  canvas.DrawPolygon(arrow, ARRAY_SIZE(arrow));

  canvas.Select(look.compass_triangle_pen);
  canvas.Select(look.compass_triangle_brush);

  RasterPoint black_triangle[4] = { { 0, -13 }, { 6, 10}, { 0, 4}, { 0, -13 } };
  PolygonRotateShift(black_triangle, ARRAY_SIZE(black_triangle),
                     pos.x, pos.y, -screen_angle);
  canvas.DrawPolygon(black_triangle, ARRAY_SIZE(black_triangle));
}
Beispiel #13
0
void MapWindow::Initialize() {
#ifndef ENABLE_OPENGL
    ScopeLock Lock(Surface_Mutex);
#endif
    // Reset common topology and waypoint label declutter, first init. Done also in other places.
    ResetLabelDeclutter();

    // Default draw area is full screen, no opacity
    MapRect = MainWindow.GetClientRect();
    DrawRect = MapRect;
    UpdateActiveScreenZone(MapRect);

    UpdateTimeStats(true);

#ifndef ENABLE_OPENGL
    // paint draw window black to start
    DrawSurface.SetBackgroundTransparent();
	DrawSurface.Blackness(MapRect.left, MapRect.top,MapRect.right-MapRect.left, MapRect.bottom-MapRect.top);

    hdcMask.SetBackgroundOpaque();
    BackBufferSurface.Blackness(MapRect.left, MapRect.top,MapRect.right-MapRect.left, MapRect.bottom-MapRect.top);
#endif

    // This is just here to give fully rendered start screen
    UpdateInfo(&GPS_INFO, &CALCULATED_INFO);
    MapDirty = true;

    FillScaleListForEngineeringUnits();
    zoom.RequestedScale(zoom.Scale());
    zoom.ModifyMapScale();

    LKUnloadFixedBitmaps();
    LKUnloadProfileBitmaps();

	LKLoadFixedBitmaps();
	LKLoadProfileBitmaps();

	// This will reset the function for the new ScreenScale
	PolygonRotateShift((POINT*)NULL,0,0,0,DisplayAngle+1);

	// Restart from moving map
	if (MapSpaceMode!=MSM_WELCOME) SetModeType(LKMODE_MAP, MP_MOVING);

	// These should be better checked. first_run is forcing also cache update for topo.
	ForceRenderMap=true;
	first_run=true;
    // Signal that draw thread can run now
    Initialised = TRUE;
#ifndef ENABLE_OPENGL
    drawTriggerEvent.set();
#endif
}
Beispiel #14
0
void
CompassRenderer::Draw(Canvas &canvas, const Angle screen_angle,
                      const RasterPoint pos)
{
  RasterPoint arrow[5] = { { 0, -13 }, { -6, 10 }, { 0, 4 }, { 6, 10 }, { 0, -13 } };

  canvas.select(Graphics::hpCompass);
  canvas.select(Graphics::hbCompass);

  // North arrow
  PolygonRotateShift(arrow, ARRAY_SIZE(arrow), pos.x, pos.y, -screen_angle);
  canvas.polygon(arrow, ARRAY_SIZE(arrow));
}
Beispiel #15
0
  RotatedPolygonRenderer(const RasterPoint *src, unsigned n,
                         const RasterPoint pos, const Angle angle)
#ifdef ENABLE_OPENGL
    :points(src), rotate_shift(pos, angle)
#endif
  {
#ifndef ENABLE_OPENGL
    assert(n <= ARRAY_SIZE(points));

    std::copy(src, src + n, points);
    PolygonRotateShift(points, n, pos.x, pos.y, angle);
#endif
  }
Beispiel #16
0
void MapWindow::DrawBestCruiseTrack(Canvas &canvas)
{
  if (!task.Valid()) {
    return;
  }

  if (Calculated().WaypointDistance < 0.010)
    return;

  canvas.select(MapGfx.hpBestCruiseTrack);
  canvas.select(MapGfx.hbBestCruiseTrack);

  if (Appearance.BestCruiseTrack == ctBestCruiseTrackDefault){

    int dy = (long)(70);
    POINT Arrow[7] = { {-1,-40}, {1,-40}, {1,0}, {6,8}, {-6,8}, {-1,0}, {-1,-40}};

    Arrow[2].y -= dy;
    Arrow[3].y -= dy;
    Arrow[4].y -= dy;
    Arrow[5].y -= dy;

    PolygonRotateShift(Arrow, 7, Orig_Aircraft.x, Orig_Aircraft.y,
                       Calculated().BestCruiseTrack-DisplayAngle);

    canvas.polygon(Arrow, 7);

  } else
  if (Appearance.BestCruiseTrack == ctBestCruiseTrackAltA){

    POINT Arrow[] = { {-1,-40}, {-1,-62}, {-6,-62}, {0,-70},
                      {6,-62}, {1,-62}, {1,-40}, {-1,-40}};

    PolygonRotateShift(Arrow, sizeof(Arrow)/sizeof(Arrow[0]),
                       Orig_Aircraft.x, Orig_Aircraft.y,
                       Calculated().BestCruiseTrack-DisplayAngle);
    canvas.polygon(Arrow, sizeof(Arrow) / sizeof(Arrow[0]));
  }
}
Beispiel #17
0
static void
DrawMirroredPolygon(const RasterPoint *src, RasterPoint *dst, unsigned points,
                    Canvas &canvas, const Angle angle,
                    const RasterPoint pos)
{
  std::copy(src, src + points, dst);
  for (unsigned i = 0; i < points; ++i) {
    dst[2 * points - i - 1].x = -dst[i].x;
    dst[2 * points - i - 1].y = dst[i].y;
  }
  PolygonRotateShift(dst, 2 * points, pos.x, pos.y, angle, 50);
  canvas.DrawPolygon(dst, 2 * points);
}
Beispiel #18
0
static void
DrawParaGlider(Canvas &canvas, const AircraftLook &look,
               const Angle angle, const RasterPoint aircraft_pos, bool inverse)
{
  RasterPoint aircraft[] = {
    // Wing
    {-16, 5},
    {-22, 4},
    {-28, 2},
    {-27, -1},
    {-26, -2},
    {-24, -3},
    {-21, -4},
    {-16, -5},
    {0, -6},
    {16, -5},
    {21, -4},
    {24, -3},
    {26, -2},
    {27, -1},
    {28, 2},
    {22, 4},
    {16, 5},

    // Arrow on wing
    {4, 6},
    {-4, 6},
    {0, -4},
   };

  PolygonRotateShift(aircraft, ARRAY_SIZE(aircraft),
                     aircraft_pos.x, aircraft_pos.y, angle, 50);

  if (inverse) {
    canvas.SelectBlackBrush();
    canvas.SelectWhitePen();
  } else {
    canvas.SelectWhiteBrush();
    canvas.SelectBlackPen();
  }

  canvas.DrawPolygon(aircraft, ARRAY_SIZE(aircraft) - 1);

  canvas.SelectNullPen();
  if (inverse)
    canvas.SelectWhiteBrush();
  else
    canvas.SelectBlackBrush();

  canvas.DrawPolygon(aircraft + ARRAY_SIZE(aircraft) - 3, 3);
}
  RotatedPolygonRenderer(const BulkPixelPoint *src, unsigned n,
                         const PixelPoint pos, const Angle angle,
                         const unsigned scale=100)
#ifdef ENABLE_OPENGL
    :points(src), rotate_shift(pos, angle, scale)
#endif
  {
#ifndef ENABLE_OPENGL
    assert(n <= ARRAY_SIZE(points));

    std::copy_n(src, n, points);
    PolygonRotateShift(points, n, pos, angle, scale);
#endif
  }
Beispiel #20
0
void
WindArrowRenderer::DrawArrow(Canvas &canvas, PixelPoint pos, Angle angle,
                             unsigned length, WindArrowStyle arrow_style,
                             int offset)
{
  // Draw arrow

  BulkPixelPoint arrow[] = {
    { 0, -offset + 3 },
    { -6, -offset - 3 - int(length) },
    { 0, -offset + 3 - int(length) },
    { 6, -offset - 3 - int(length) },
  };

  // Rotate the arrow
  PolygonRotateShift(arrow, ARRAY_SIZE(arrow), pos, angle);

  canvas.Select(look.arrow_pen);
  canvas.Select(look.arrow_brush);
  canvas.DrawPolygon(arrow, ARRAY_SIZE(arrow));

  // Draw arrow tail

  if (arrow_style == WindArrowStyle::FULL_ARROW) {
    BulkPixelPoint tail[] = {
      { 0, -offset + 3 },
      { 0, -offset - 3 - int(std::min(20u, length) * 3u) },
    };

    PolygonRotateShift(tail, ARRAY_SIZE(tail),
                       pos, angle);

    canvas.Select(look.tail_pen);
    canvas.DrawLine(tail[0], tail[1]);
  }
}
Beispiel #21
0
void
WindArrowRenderer::DrawArrow(Canvas &canvas, RasterPoint pos, Angle angle,
                             PixelScalar length, WindArrowStyle arrow_style,
                             PixelScalar offset)
{
  // Draw arrow

  RasterPoint arrow[] = {
    { 0, (PixelScalar)(-offset + 3) },
    { -6, (PixelScalar)(-offset - 3 - length) },
    { 0, (PixelScalar)(-offset + 3 - length) },
    { 6, (PixelScalar)(-offset - 3 - length) },
  };

  // Rotate the arrow
  PolygonRotateShift(arrow, ARRAY_SIZE(arrow), pos.x, pos.y, angle);

  canvas.Select(look.arrow_pen);
  canvas.Select(look.arrow_brush);
  canvas.DrawPolygon(arrow, ARRAY_SIZE(arrow));

  // Draw arrow tail

  if (arrow_style == WindArrowStyle::FULL_ARROW) {
    RasterPoint tail[] = {
      { 0, (PixelScalar)(-offset + 3) },
      { 0, -offset - 3 - std::min(PixelScalar(20), length) * 3 },
    };

    PolygonRotateShift(tail, ARRAY_SIZE(tail),
                       pos.x, pos.y, angle);

    canvas.Select(look.tail_pen);
    canvas.DrawLine(tail[0], tail[1]);
  }
}
void
BestCruiseArrowRenderer::Draw(Canvas &canvas, const TaskLook &look,
                              const Angle screen_angle,
                              const Angle best_cruise_angle,
                              const RasterPoint pos)
{
  canvas.Select(look.best_cruise_track_pen);
  canvas.Select(look.best_cruise_track_brush);

  RasterPoint arrow[] = { { -1, -40 }, { -1, -62 }, { -6, -62 }, {  0, -70 },
                          {  6, -62 }, {  1, -62 }, {  1, -40 }, { -1, -40 } };

  PolygonRotateShift(arrow, ARRAY_SIZE(arrow), pos,
                     best_cruise_angle - screen_angle);
  canvas.DrawPolygon(arrow, ARRAY_SIZE(arrow));
}
Beispiel #23
0
  void
  visit_leg_final(TASK_POINT &point0, const unsigned index0,
                  TASK_POINT &point1, const unsigned index1)
  {
    bool is_first = (point0.Index < point1.Index);
    int imin = min(point0.Index,point1.Index);
    int imax = max(point0.Index,point1.Index);
    // JMW AAT!
    double bearing = point0.OutBound;
    POINT sct1, sct2;

    canvas->select(dash_pen3);

    if (_task->getSettings().AATEnabled && !map_window->SettingsMap().TargetPan) {
      map_window->LonLat2Screen(point0.AATTargetLocation, sct1);
      map_window->LonLat2Screen(point1.AATTargetLocation, sct2);
      bearing = Bearing(point0.AATTargetLocation, point1.AATTargetLocation);

      // draw nominal track line
      canvas->line(way_points.get_calc(imin).Screen,
                   way_points.get_calc(imax).Screen);
    } else {
      sct1 = way_points.get_calc(point0.Index).Screen;
      sct2 = way_points.get_calc(point1.Index).Screen;
    }

    if (is_first) {
      canvas->line(sct1, sct2);
    } else {
      canvas->line(sct2, sct1);
    }

    // draw small arrow along task direction
    POINT p_p;
    POINT Arrow[3] = { {6,6}, {-6,6}, {0,0} };
    ScreenClosestPoint(sct1, sct2, orig, &p_p, IBLSCALE(25));
    PolygonRotateShift(Arrow, 2, p_p.x, p_p.y,
		       bearing-map_window->GetDisplayAngle());
    Arrow[2] = Arrow[1];
    Arrow[1] = p_p;

    canvas->select(pent1);
    canvas->polyline(Arrow, 3);
  };
Beispiel #24
0
static void
DrawMirroredPolygon(const RasterPoint *src, unsigned points,
                    Canvas &canvas, const Angle angle,
                    const RasterPoint pos)
{
  RasterPoint dst[64];
  assert(2 * points <= ARRAY_SIZE(dst));

  std::copy(src, src + points, dst);
  for (unsigned i = 0; i < points; ++i) {
    dst[2 * points - i - 1].x = -dst[i].x;
    dst[2 * points - i - 1].y = dst[i].y;
  }
#ifdef ENABLE_OPENGL
  CanvasRotateShift rotate_shift(pos, angle, 50);
#else
  PolygonRotateShift(dst, 2 * points, pos.x, pos.y, angle, 50);
#endif
  canvas.DrawPolygon(dst, 2 * points);
}
Beispiel #25
0
// This is painting traffic icons on the screen.
void MapWindow::LKDrawFLARMTraffic(LKSurface& Surface, const RECT& rc, const ScreenProjection& _Proj, const 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 tscaler=0;
  if (DoInit[MDI_DRAWFLARMTRAFFIC]) {

	switch (ScreenSize) {
		case ss480x640:
		case ss480x800:
		case ss800x480:
		case ss640x480:
			iCircleSize = 9;
			iRectangleSize = 5;
			tscaler=NIBLSCALE(7)-2;
			break;
		case ss240x320:
		case ss272x480:
		case ss320x240:
		case ss480x272:
		case ss480x234:
		case ss400x240:
			iCircleSize = 7;
			iRectangleSize = 4;
			tscaler=NIBLSCALE(13)-2;
			break;
		default:
			iCircleSize = 7;
			iRectangleSize = 4;
			tscaler=NIBLSCALE(7);
			break;
	}


	DoInit[MDI_DRAWFLARMTRAFFIC]=false;
  }

  POINT Arrow[5];

  TCHAR lbuffer[50];

  const auto hpold = Surface.SelectObject(LKPen_Black_N1);

  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




  const auto oldfont = Surface.SelectObject(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;
		sc = _Proj.LonLat2Screen(target_lon, target_lat);

		sc_name = sc;

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

		_tcscpy(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) {
                  size_t len = _tcslen(lbuffer);
                  if (len > 0)
                    _stprintf(lbuffer + len,_T(":%.1f"),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(Surface, &rc, lbuffer, sc.x+tscaler, sc.y+tscaler, &displaymode, false);

		// red circle
		if ((DrawInfo.FLARM_Traffic[i].AlarmLevel>0) && (DrawInfo.FLARM_Traffic[i].AlarmLevel<4)) {
			DrawBitmapIn(Surface, sc, hFLARMTraffic,true);
		}
#if 1 // 1
		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;

		for (int q=0; q < 5; q++)
		{
			Arrow[q].x  = (LONG) ((double)Arrow[q].x * 1.7);
			Arrow[q].y  = (LONG) ((double)Arrow[q].y * 1.7);
		}
#else

		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];
#endif


/*
		switch (DrawInfo.FLARM_Traffic[i].Status) { // 100321
			case LKT_GHOST:
				Surface.SelectObject(yellowBrush);
				break;
			case LKT_ZOMBIE:
				Surface.SelectObject(redBrush);
				break;
			default:
				Surface.SelectObject(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;
		  Surface.SelectObject(*variobrush[iVarioIdx]);

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

	}
  }

  Surface.SelectObject(oldfont);
  Surface.SelectObject(hpold);

}
Beispiel #26
0
void MapWindow::DrawCompass(Canvas &canvas, const RECT rc)
{
  POINT Start;

  if (Appearance.CompassAppearance == apCompassDefault){

    Start.y = IBLSCALE(19)+rc.top;
    Start.x = rc.right - IBLSCALE(19);

    if (SettingsMap().EnableVarioGauge && MapRectBig.right == rc.right)
        Start.x -= InfoBoxLayout::ControlWidth;

    POINT Arrow[5] = { {0,-18}, {-6,10}, {0,0}, {6,10}, {0,-18}};

    canvas.select(MapGfx.hpCompass);
    canvas.select(MapGfx.hbCompass);

    // North arrow
    PolygonRotateShift(Arrow, 5, Start.x, Start.y, -DisplayAngle);
    canvas.polygon(Arrow, 5);

  } else if (Appearance.CompassAppearance == apCompassAltA) {

    static double lastDisplayAngle = 9999.9;
    static int lastRcRight = 0;
    static POINT Arrow[5] = { {0,-11}, {-5,9}, {0,3}, {5,9}, {0,-11}};

    if (lastDisplayAngle != DisplayAngle || lastRcRight != rc.right){

      Arrow[0].x  = 0;
      Arrow[0].y  = -11;
      Arrow[1].x  = -5;
      Arrow[1].y  = 9;
      Arrow[2].x  = 0;
      Arrow[2].y  = 3;
      Arrow[3].x  = 5;
      Arrow[3].y  = 9;
      Arrow[4].x  = 0;
      Arrow[4].y  = -11;

      Start.y = rc.top + IBLSCALE(10);
      Start.x = rc.right - IBLSCALE(11);

      if (SettingsMap().EnableVarioGauge && MapRectBig.right == rc.right) {
        Start.x -= InfoBoxLayout::ControlWidth;
      }

      // North arrow
      PolygonRotateShift(Arrow, 5, Start.x, Start.y,
                         -DisplayAngle);

      lastDisplayAngle = DisplayAngle;
      lastRcRight = rc.right;
    }

    canvas.polygon(Arrow, 5);

    canvas.select(MapGfx.hpCompass);
    canvas.polygon(Arrow, 5);
  }

}
Beispiel #27
0
void MapWindow::DrawAircraft(Canvas &canvas)
{

  if (Appearance.Aircraft == afAircraftDefault){

#define NUMAIRCRAFTPOINTS 16

    POINT Aircraft[NUMAIRCRAFTPOINTS] = {
      { 1,-6},
      {2,-1},
      {15,0},
      {15,2},
      {1,2},
      {0,10},
      {4,11},
      {4,12},
      {-4,12},
      {-4,11},
      {0,10},
      {-1,2},
      {-15,2},
      {-15,0},
      {-2,-1},
      {-1,-6}
    };

    int i;
    Brush hbAircraftSolid, hbAircraftSolidBg;

    if (Appearance.InverseAircraft) {
      hbAircraftSolid.set(Color(0xff,0xff,0xff));
      hbAircraftSolidBg.set(Color(0x00,0x00,0x00));
    } else {
      hbAircraftSolid.set(Color(0x00,0x00,0x00));
      hbAircraftSolidBg.set(Color(0xff,0xff,0xff));
    }

    canvas.select(hbAircraftSolidBg);
    canvas.select(MapGfx.hpAircraft);

    PolygonRotateShift(Aircraft, NUMAIRCRAFTPOINTS, Orig_Aircraft.x+1, Orig_Aircraft.y+1,
                       DisplayAircraftAngle+
                       (Calculated().Heading-Basic().TrackBearing));

    canvas.polygon(Aircraft, NUMAIRCRAFTPOINTS);

    // draw it again so can get white border
    canvas.select(MapGfx.hpAircraftBorder);
    canvas.select(hbAircraftSolid);

    for(i=0; i<NUMAIRCRAFTPOINTS; i++)
      {
	Aircraft[i].x -= 1;  Aircraft[i].y -= 1;
      }

    canvas.polygon(Aircraft, NUMAIRCRAFTPOINTS);
  } else

    if (Appearance.Aircraft == afAircraftAltA){

      POINT Aircraft[] = {
	{1, -5},
	{1, 0},
	{14, 0},
	{14, 1},
	{1, 1},
	{1, 8},
	{4, 8},
	{4, 9},
	{-3, 9},
	{-3, 8},
	{0, 8},
	{0, 1},
	{-13, 1},
	{-13, 0},
	{0, 0},
	{0, -5},
	{1, -5},
      };

      /* Experiment, when turning show the high wing larger,
	 low wing smaller
	 if (Calculated().TurnRate>10) {
	 Aircraft[3].y = 0;
	 Aircraft[12].y = 2;
	 } else if (Calculated().TurnRate<-10) {
	 Aircraft[3].y = 2;
	 Aircraft[12].y = 0;
	 }
      */

      int n = sizeof(Aircraft)/sizeof(Aircraft[0]);

      double angle = DisplayAircraftAngle+
	(Calculated().Heading-Basic().TrackBearing);

      PolygonRotateShift(Aircraft, n,
			 Orig_Aircraft.x-1, Orig_Aircraft.y, angle);

      canvas.select(MapGfx.hpAircraft);
      canvas.polygon(Aircraft, n);

      if (Appearance.InverseAircraft) {
        canvas.white_brush();
      } else {
        canvas.black_brush();
      }
      canvas.select(MapGfx.hpAircraftBorder); // hpBearing
      canvas.polygon(Aircraft, n);
    }

}
Beispiel #28
0
void MapWindow::DrawWindAtAircraft2(Canvas &canvas, const POINT Orig, const RECT rc) {
  int i;
  POINT Start;
  TCHAR sTmp[12];
  static SIZE tsize = {0,0};

  if (Calculated().WindSpeed<1) {
    return; // JMW don't bother drawing it if not significant
  }

  if (tsize.cx == 0){
    canvas.select(MapWindowBoldFont);
    tsize = canvas.text_size(TEXT("99"));
    tsize.cx = tsize.cx/2;
  }

  canvas.select(MapGfx.hpWind);
  canvas.select(MapGfx.hbWind);

  int wmag = iround(4.0*Calculated().WindSpeed);

  Start.y = Orig.y;
  Start.x = Orig.x;

  int kx = tsize.cx/InfoBoxLayout::scale/2;

  POINT Arrow[7] = { {0,-20}, {-6,-26}, {0,-20},
                     {6,-26}, {0,-20},
                     {8+kx, -24},
                     {-8-kx, -24}};

  for (i=1;i<4;i++)
    Arrow[i].y -= wmag;

  PolygonRotateShift(Arrow, 7, Start.x, Start.y,
		     Calculated().WindBearing-DisplayAngle);
  canvas.polygon(Arrow, 5);

  if (SettingsMap().WindArrowStyle==1) {
    POINT Tail[2] = {{0,-20}, {0,-26-min(20,wmag)*3}};
    double angle = AngleLimit360(Calculated().WindBearing-DisplayAngle);
    for(i=0; i<2; i++) {
      if (InfoBoxLayout::scale>1) {
        Tail[i].x *= InfoBoxLayout::scale;
        Tail[i].y *= InfoBoxLayout::scale;
      }
      protateshift(Tail[i], angle, Start.x, Start.y);
    }

    // optionally draw dashed line
    Pen dash_pen(Pen::DASH, 1, Color(0, 0, 0));
    canvas.select(dash_pen);
    canvas.line(Tail[0], Tail[1]);
  }


  _stprintf(sTmp, TEXT("%i"), iround(Calculated().WindSpeed * SPEEDMODIFY));

  TextInBoxMode_t TextInBoxMode = { 16 | 32 }; // JMW test {2 | 16};
  if (Arrow[5].y>=Arrow[6].y) {
    TextInBox(canvas, sTmp, Arrow[5].x-kx, Arrow[5].y, TextInBoxMode, rc);
  } else {
    TextInBox(canvas, sTmp, Arrow[6].x-kx, Arrow[6].y, TextInBoxMode, rc);
  }
}
Beispiel #29
0
static void
Draw(Canvas &canvas, PixelRect rc,
     const ArrivalAltitudeMapItem &item,
     const TwoTextRowsRenderer &row_renderer,
     const FinalGlideBarLook &look)
{
  const unsigned line_height = rc.GetHeight();

  bool reach_relevant = item.reach.IsReachRelevant();

  int arrival_altitude =
    item.reach.terrain_valid == ReachResult::Validity::VALID
    ? item.reach.terrain
    : item.reach.direct;
  if (item.HasElevation())
    arrival_altitude -= item.elevation;

  bool reachable =
    item.reach.terrain_valid != ReachResult::Validity::UNREACHABLE &&
    arrival_altitude >= 0;

  // Draw final glide arrow icon

  const PixelPoint pt(rc.left + line_height / 2, rc.top + line_height / 2);

  BulkPixelPoint arrow[] = {
      { -7, -3 }, { 0, 4 }, { 7, -3 }
  };

  Angle arrow_angle = reachable ? Angle::HalfCircle() : Angle::Zero();
  PolygonRotateShift(arrow, ARRAY_SIZE(arrow), pt, arrow_angle);

  if (reachable) {
    canvas.Select(look.brush_above);
    canvas.Select(look.pen_above);
  } else {
    canvas.Select(look.brush_below);
    canvas.Select(look.pen_below);
  }
  canvas.DrawPolygon(arrow, ARRAY_SIZE(arrow));

  const unsigned text_padding = Layout::GetTextPadding();
  rc.left += line_height + text_padding;

  // Format title row

  TCHAR altitude_buffer[32];
  StaticString<256> buffer;
  buffer.clear();

  if (item.HasElevation()) {
    int relative_arrival_altitude =
      item.reach.direct - item.elevation;

    FormatRelativeUserAltitude(relative_arrival_altitude,
                               altitude_buffer, ARRAY_SIZE(altitude_buffer));

    buffer.AppendFormat(_T("%s %s, "), altitude_buffer, _("AGL"));
  }

  buffer.AppendFormat(_T("%s %s"),
                      FormatUserAltitude(item.reach.direct).c_str(),
                      _("MSL"));

  // Draw title row

  row_renderer.DrawFirstRow(canvas, rc, buffer);

  // Format comment row

  if (reach_relevant) {
    buffer.Format(_T("%s: "), _("around terrain"));

    if (item.HasElevation()) {
      int relative_arrival_altitude =
          item.reach.terrain - item.elevation;

      FormatRelativeUserAltitude(relative_arrival_altitude,
                                 altitude_buffer, ARRAY_SIZE(altitude_buffer));

     buffer.AppendFormat(_T("%s %s, "), altitude_buffer, _("AGL"));
    }

    buffer.AppendFormat(_T("%s %s, "),
                        FormatUserAltitude(item.reach.terrain).c_str(),
                        _("MSL"));
  } else if (item.HasElevation() &&
             item.reach.direct >= item.elevation &&
             item.reach.terrain_valid == ReachResult::Validity::UNREACHABLE) {
    buffer.UnsafeFormat(_T("%s "), _("Unreachable due to terrain."));
  } else {
    buffer.clear();
  }

  buffer += _("Arrival altitude incl. safety height");

  // Draw comment row

  row_renderer.DrawSecondRow(canvas, rc, buffer);
}
Beispiel #30
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);

}