/** * Paints the basic info for the selected target on the given canvas * @param canvas The canvas to paint on */ void FlarmTrafficControl::PaintTrafficInfo(Canvas &canvas) const { // Don't paint numbers if no plane selected if (selection == -1 && !WarningMode()) return; // Shortcut to the selected traffic FlarmTraffic traffic = data.list[WarningMode() ? warning : selection]; assert(traffic.IsDefined()); const unsigned padding = Layout::GetTextPadding(); PixelRect rc; rc.left = padding; rc.top = padding; rc.right = canvas.GetWidth() - padding; rc.bottom = canvas.GetHeight() - padding; // Set the text color and background switch (traffic.alarm_level) { case FlarmTraffic::AlarmType::LOW: case FlarmTraffic::AlarmType::INFO_ALERT: canvas.SetTextColor(look.warning_color); break; case FlarmTraffic::AlarmType::IMPORTANT: case FlarmTraffic::AlarmType::URGENT: canvas.SetTextColor(look.alarm_color); break; case FlarmTraffic::AlarmType::NONE: canvas.SetTextColor(look.default_color); break; } canvas.SetBackgroundTransparent(); // Climb Rate if (!WarningMode() && traffic.climb_rate_avg30s_available) PaintClimbRate(canvas, rc, traffic.climb_rate_avg30s); // Distance PaintDistance(canvas, rc, traffic.distance); // Relative Height PaintRelativeAltitude(canvas, rc, traffic.relative_altitude); // ID / Name if (!traffic.HasAlarm()) canvas.SetTextColor(look.selection_color); PaintID(canvas, rc, traffic); }
/** * Paints the traffic symbols on the given canvas * @param canvas The canvas to paint on */ void FlarmTrafficWindow::PaintRadarTraffic(Canvas &canvas) { if (!data.FLARM_Available || data.GetActiveTrafficCount() == 0) { PaintRadarNoTraffic(canvas); return; } // Iterate through the traffic (normal traffic) for (unsigned i = 0; i < FLARM_STATE::FLARM_MAX_TRAFFIC; ++i) { const FLARM_TRAFFIC &traffic = data.FLARM_Traffic[i]; if (traffic.defined() && !traffic.HasAlarm() && static_cast<unsigned> (selection) != i) PaintRadarTarget(canvas, traffic, i); } if (selection >= 0 && selection < FLARM_STATE::FLARM_MAX_TRAFFIC) { const FLARM_TRAFFIC &traffic = data.FLARM_Traffic[selection]; if (traffic.defined() && !traffic.HasAlarm()) PaintRadarTarget(canvas, traffic, selection); } if (!WarningMode()) return; // Iterate through the traffic (alarm traffic) for (unsigned i = 0; i < FLARM_STATE::FLARM_MAX_TRAFFIC; ++i) { const FLARM_TRAFFIC &traffic = data.FLARM_Traffic[i]; if (traffic.defined() && traffic.HasAlarm()) PaintRadarTarget(canvas, traffic, i); } }
/** * Paints the traffic symbols on the given canvas * @param canvas The canvas to paint on */ void FlarmTrafficWindow::PaintRadarTraffic(Canvas &canvas) { if (!data.available || data.GetActiveTrafficCount() == 0) { PaintRadarNoTraffic(canvas); return; } // Iterate through the traffic (normal traffic) for (unsigned i = 0; i < data.traffic.size(); ++i) { const FlarmTraffic &traffic = data.traffic[i]; if (!traffic.HasAlarm() && static_cast<unsigned> (selection) != i) PaintRadarTarget(canvas, traffic, i); } if (selection >= 0) { const FlarmTraffic &traffic = data.traffic[selection]; if (!traffic.HasAlarm()) PaintRadarTarget(canvas, traffic, selection); } if (!WarningMode()) return; // Iterate through the traffic (alarm traffic) for (unsigned i = 0; i < data.traffic.size(); ++i) { const FlarmTraffic &traffic = data.traffic[i]; if (traffic.HasAlarm()) PaintRadarTarget(canvas, traffic, i); } }
void FlarmTrafficControl::CalcAutoZoom() { bool warning_mode = WarningMode(); fixed zoom_dist = fixed_zero; for (unsigned i = 0; i < FLARM_STATE::FLARM_MAX_TRAFFIC; i++) { if (!data.FLARM_Traffic[i].defined()) continue; if (warning_mode && !data.FLARM_Traffic[i].HasAlarm()) continue; fixed dist = data.FLARM_Traffic[i].RelativeNorth * data.FLARM_Traffic[i].RelativeNorth + data.FLARM_Traffic[i].RelativeEast * data.FLARM_Traffic[i].RelativeEast; zoom_dist = max(dist, zoom_dist); } for (unsigned i = 0; i <= 4; i++) { if (i == 4 || fixed(GetZoomDistance(i) * GetZoomDistance(i)) >= zoom_dist) { SetZoom(i); break; } } }
void FlarmTrafficControl::PaintID(Canvas &canvas, PixelRect rc, const FlarmTraffic &traffic) const { TCHAR buffer[20]; unsigned font_size; if (traffic.HasName()) { canvas.Select(look.call_sign_font); font_size = look.call_sign_font.GetHeight(); _tcscpy(buffer, traffic.name); } else { canvas.Select(look.info_labels_font); font_size = look.info_labels_font.GetHeight(); traffic.id.Format(buffer); } if (!WarningMode()) { // Team color dot FlarmFriends::Color team_color = FlarmFriends::GetFriendColor(traffic.id); // If no color found but target is teammate if (team_color == FlarmFriends::Color::NONE && settings.team_flarm_tracking && traffic.id == settings.team_flarm_id) // .. use green color team_color = FlarmFriends::Color::GREEN; // If team color found -> draw a colored circle in front of the name if (team_color != FlarmFriends::Color::NONE) { switch (team_color) { case FlarmFriends::Color::GREEN: canvas.Select(look.team_brush_green); break; case FlarmFriends::Color::BLUE: canvas.Select(look.team_brush_blue); break; case FlarmFriends::Color::YELLOW: canvas.Select(look.team_brush_yellow); break; case FlarmFriends::Color::MAGENTA: canvas.Select(look.team_brush_magenta); break; default: break; } canvas.SelectNullPen(); canvas.DrawCircle(rc.left + Layout::FastScale(7), rc.top + (font_size / 2), Layout::FastScale(7)); rc.left += Layout::FastScale(16); } } canvas.DrawText(rc.left, rc.top, buffer); }
void FlarmTrafficControl::Update(Angle new_direction, const TrafficList &new_data, const TeamCodeSettings &new_settings) { FlarmTrafficWindow::Update(new_direction, new_data, new_settings); if (enable_auto_zoom || WarningMode()) CalcAutoZoom(); }
void FlarmTrafficControl::Update(Angle new_direction, const FLARM_STATE &new_data, const SETTINGS_TEAMCODE &new_settings) { FlarmTrafficWindow::Update(new_direction, new_data, new_settings); if (enable_auto_zoom || WarningMode()) CalcAutoZoom(); }
/** * Zoom out one step */ void FlarmTrafficControl::ZoomOut() { if (WarningMode()) return; if (zoom < 4) SetZoom(zoom + 1); SetAutoZoom(false); }
/** * Zoom in one step */ void FlarmTrafficControl::ZoomIn() { if (WarningMode()) return; if (zoom > 0) SetZoom(zoom - 1); SetAutoZoom(false); }
bool FlarmTrafficControl::OnMouseUp(PixelScalar x, PixelScalar y) { const TCHAR *gesture = gestures.Finish(); if (gesture && on_mouse_gesture(gesture)) return true; if (!WarningMode()) SelectNearTarget(x, y, Layout::Scale(15)); return true; }
bool FlarmTrafficControl::on_mouse_up(int x, int y) { if (XCSoarInterface::SettingsComputer().EnableGestures) { const char* gesture = gestures.Finish(); if (gesture && on_mouse_gesture(gesture)) return true; } if (!WarningMode()) SelectNearTarget(x, y, Layout::Scale(15)); return true; }
void FlarmTrafficControl::OpenDetails() { // If warning is displayed -> prevent from opening details dialog if (WarningMode()) return; // Don't open the details dialog if no plane selected const FlarmTraffic *traffic = GetTarget(); if (traffic == NULL) return; // Show the details dialog dlgFlarmTrafficDetailsShowModal(traffic->id); }
bool FlarmTrafficControl::OnMouseUp(PixelScalar x, PixelScalar y) { if (dragging) { StopDragging(); const TCHAR *gesture = gestures.Finish(); if (gesture && OnMouseGesture(gesture)) return true; } if (!WarningMode()) SelectNearTarget(x, y, Layout::Scale(15)); return true; }
/** * Tries to select the previous target, if impossible selection = -1 */ void FlarmTrafficWindow::PrevTarget() { // If warning is displayed -> prevent selector movement if (WarningMode()) return; assert(selection < FLARM_STATE::FLARM_MAX_TRAFFIC); const FLARM_TRAFFIC *traffic; if (selection >= 0) traffic = data.PreviousTraffic(&data.FLARM_Traffic[selection]); else traffic = NULL; if (traffic == NULL) traffic = data.LastTraffic(); SetTarget(traffic); }
/** * Tries to select the next target, if impossible selection = -1 */ void FlarmTrafficWindow::NextTarget() { // If warning is displayed -> prevent selector movement if (WarningMode()) return; assert(selection < (int)data.traffic.size()); const FlarmTraffic *traffic; if (selection >= 0) traffic = data.NextTraffic(&data.traffic[selection]); else traffic = NULL; if (traffic == NULL) traffic = data.FirstTraffic(); SetTarget(traffic); }
void FlarmTrafficControl::CalcAutoZoom() { bool warning_mode = WarningMode(); RoughDistance zoom_dist = fixed(0); for (auto it = data.list.begin(), end = data.list.end(); it != end; ++it) { if (warning_mode && !it->HasAlarm()) continue; zoom_dist = std::max(it->distance, zoom_dist); } fixed zoom_dist2 = zoom_dist; for (unsigned i = 0; i <= 4; i++) { if (i == 4 || fixed(GetZoomDistance(i)) >= zoom_dist2) { SetZoom(i); break; } } }
/** * Paints the traffic symbols on the given canvas * @param canvas The canvas to paint on */ void FlarmTrafficWindow::PaintRadarTarget(Canvas &canvas, const FlarmTraffic &traffic, unsigned i) { // Save relative East/North fixed x = traffic.relative_east; fixed y = -traffic.relative_north; // Calculate the distance in pixels fixed scale = RangeScale(traffic.distance); // Don't display distracting, far away targets in WarningMode if (WarningMode() && !traffic.HasAlarm() && scale == fixed(radius)) return; // x and y are not between 0 and 1 (distance will be handled via scale) if (!traffic.distance.IsZero()) { x /= traffic.distance; y /= traffic.distance; } else { x = fixed(0); y = fixed(0); } if (!enable_north_up) { // Rotate x and y to have a track up display FastRotation::Pair p = fr.Rotate(x, y); x = fixed(p.first); y = fixed(p.second); } // Calculate screen coordinates sc[i].x = radar_mid.x + iround(x * scale); sc[i].y = radar_mid.y + iround(y * scale); const Color *text_color; const Pen *target_pen, *circle_pen; const Brush *target_brush, *arrow_brush; bool hollow_brush = false; unsigned circles = 0; // Set the arrow color depending on alarm level switch (traffic.alarm_level) { case FlarmTraffic::AlarmType::LOW: case FlarmTraffic::AlarmType::INFO_ALERT: text_color = &look.default_color; target_pen = circle_pen = &look.warning_pen; target_brush = &look.warning_brush; arrow_brush = &look.default_brush; circles = 1; break; case FlarmTraffic::AlarmType::IMPORTANT: case FlarmTraffic::AlarmType::URGENT: text_color = &look.default_color; target_pen = circle_pen = &look.alarm_pen; target_brush = &look.alarm_brush; arrow_brush = &look.default_brush; circles = 2; break; case FlarmTraffic::AlarmType::NONE: if (WarningMode()) { text_color = &look.passive_color; target_pen = &look.passive_pen; arrow_brush = &look.passive_brush; hollow_brush = true; } else { // Search for team color const FlarmColor team_color = FlarmFriends::GetFriendColor(traffic.id); // If team color found -> draw a colored circle around the target if (team_color != FlarmColor::NONE) { switch (team_color) { case FlarmColor::GREEN: circle_pen = &look.team_pen_green; break; case FlarmColor::BLUE: circle_pen = &look.team_pen_blue; break; case FlarmColor::YELLOW: circle_pen = &look.team_pen_yellow; break; case FlarmColor::MAGENTA: circle_pen = &look.team_pen_magenta; break; default: break; } circles = 1; } if (!small && static_cast<unsigned> (selection) == i) { text_color = &look.selection_color; target_brush = arrow_brush = &look.selection_brush; target_pen = &look.selection_pen; } else { hollow_brush = true; if (traffic.IsPassive()) { text_color = &look.passive_color; target_pen = &look.passive_pen; arrow_brush = &look.passive_brush; } else { text_color = &look.default_color; target_pen = &look.default_pen; arrow_brush = &look.default_brush; } } } break; } if (circles > 0) { canvas.SelectHollowBrush(); canvas.Select(*circle_pen); canvas.DrawCircle(sc[i].x, sc[i].y, Layout::FastScale(small ? 8 : 16)); if (circles == 2) canvas.DrawCircle(sc[i].x, sc[i].y, Layout::FastScale(small ? 10 : 19)); } // Create an arrow polygon RasterPoint Arrow[5]; if (small) { Arrow[0].x = -3; Arrow[0].y = 4; Arrow[1].x = 0; Arrow[1].y = -5; Arrow[2].x = 3; Arrow[2].y = 4; Arrow[3].x = 0; Arrow[3].y = 2; Arrow[4].x = -3; Arrow[4].y = 4; } else { Arrow[0].x = -6; Arrow[0].y = 8; Arrow[1].x = 0; Arrow[1].y = -10; Arrow[2].x = 6; Arrow[2].y = 8; Arrow[3].x = 0; Arrow[3].y = 5; Arrow[4].x = -6; Arrow[4].y = 8; } // Rotate and shift the arrow PolygonRotateShift(Arrow, 5, sc[i].x, sc[i].y, traffic.track - (enable_north_up ? Angle::Zero() : heading)); // Select pen and brush canvas.Select(*target_pen); if (hollow_brush) canvas.SelectHollowBrush(); else canvas.Select(*target_brush); // Draw the polygon canvas.DrawPolygon(Arrow, 5); if (small) { if (!WarningMode() || traffic.HasAlarm()) PaintTargetInfoSmall(canvas, traffic, i, *text_color, *arrow_brush); return; } // if warning exists -> don't draw vertical speeds if (WarningMode()) return; // if vertical speed to small or negative -> skip this one if (side_display_type == SIDE_INFO_VARIO && (!traffic.climb_rate_avg30s_available || traffic.climb_rate_avg30s < fixed(0.5) || traffic.IsPowered())) return; // Select font canvas.SetBackgroundTransparent(); canvas.Select(look.side_info_font); // Format string TCHAR tmp[10]; if (side_display_type == SIDE_INFO_VARIO) FormatUserVerticalSpeed(traffic.climb_rate_avg30s, tmp, false); else FormatRelativeUserAltitude(traffic.relative_altitude, tmp, true); PixelSize sz = canvas.CalcTextSize(tmp); // Draw vertical speed shadow canvas.SetTextColor(COLOR_WHITE); canvas.DrawText(sc[i].x + Layout::FastScale(11) + 1, sc[i].y - sz.cy / 2 + 1, tmp); canvas.DrawText(sc[i].x + Layout::FastScale(11) - 1, sc[i].y - sz.cy / 2 - 1, tmp); // Select color canvas.SetTextColor(*text_color); // Draw vertical speed canvas.DrawText(sc[i].x + Layout::FastScale(11), sc[i].y - sz.cy / 2, tmp); }
/** * Paints the basic info for the selected target on the given canvas * @param canvas The canvas to paint on */ void FlarmTrafficControl::PaintTrafficInfo(Canvas &canvas) const { // Don't paint numbers if no plane selected if (selection == -1) return; assert(data.FLARM_Traffic[selection].defined()); // Temporary string TCHAR tmp[20]; // Temporary string size SIZE sz; // Shortcut to the selected traffic FLARM_TRAFFIC traffic; if (WarningMode()) traffic = data.FLARM_Traffic[warning]; else traffic = data.FLARM_Traffic[selection]; assert(traffic.defined()); RECT rc; rc.left = padding; rc.top = padding; rc.right = canvas.get_width() - padding; rc.bottom = canvas.get_height() - padding; // Set the text color and background switch (traffic.AlarmLevel) { case 1: canvas.set_text_color(hcWarning); break; case 2: case 3: canvas.set_text_color(hcAlarm); break; case 4: case 0: default: canvas.set_text_color(hcStandard); break; } canvas.background_transparent(); // Climb Rate if (!WarningMode()) { Units::FormatUserVSpeed(traffic.Average30s, tmp, 20); canvas.select(hfInfoValues); sz = canvas.text_size(tmp); canvas.text(rc.right - sz.cx, rc.top + hfInfoLabels.get_height(), tmp); canvas.select(hfInfoLabels); sz = canvas.text_size(_("Vario:")); canvas.text(rc.right - sz.cx, rc.top, _("Vario:")); } // Distance Units::FormatUserDistance(hypot(traffic.RelativeEast, traffic.RelativeNorth), tmp, 20); canvas.select(hfInfoValues); sz = canvas.text_size(tmp); canvas.text(rc.left, rc.bottom - sz.cy, tmp); canvas.select(hfInfoLabels); canvas.text(rc.left, rc.bottom - hfInfoValues.get_height() - hfInfoLabels.get_height(), _("Distance:")); // Relative Height Units::FormatUserArrival(traffic.RelativeAltitude, tmp, 20); canvas.select(hfInfoValues); sz = canvas.text_size(tmp); canvas.text(rc.right - sz.cx, rc.bottom - sz.cy, tmp); canvas.select(hfInfoLabels); sz = canvas.text_size(_("Rel. Alt.:")); canvas.text(rc.right - sz.cx, rc.bottom - hfInfoValues.get_height() - hfInfoLabels.get_height(), _("Rel. Alt.:")); // ID / Name if (traffic.HasName()) { canvas.select(hfCallSign); if (!traffic.HasAlarm()) { if (settings.TeamFlarmTracking && traffic.ID == settings.TeamFlarmIdTarget) canvas.set_text_color(hcTeam); else canvas.set_text_color(hcSelection); } _tcscpy(tmp, traffic.Name); } else { traffic.ID.format(tmp); } canvas.text(rc.left, rc.top, tmp); }
/** * Paints the basic info for the selected target on the given canvas * @param canvas The canvas to paint on */ void FlarmTrafficControl::PaintTrafficInfo(Canvas &canvas) const { // Don't paint numbers if no plane selected if (selection == -1 && !WarningMode()) return; // Shortcut to the selected traffic FlarmTraffic traffic = data.traffic[WarningMode() ? warning : selection]; assert(traffic.IsDefined()); // Temporary string TCHAR tmp[20]; // Temporary string size PixelSize sz; PixelRect rc; rc.left = padding; rc.top = padding; rc.right = canvas.get_width() - padding; rc.bottom = canvas.get_height() - padding; // Set the text color and background switch (traffic.alarm_level) { case FlarmTraffic::AlarmType::LOW: canvas.SetTextColor(look.warning_color); break; case FlarmTraffic::AlarmType::IMPORTANT: case FlarmTraffic::AlarmType::URGENT: canvas.SetTextColor(look.alarm_color); break; case FlarmTraffic::AlarmType::NONE: canvas.SetTextColor(look.default_color); break; } canvas.SetBackgroundTransparent(); // Climb Rate if (!WarningMode() && traffic.climb_rate_avg30s_available) { Units::FormatUserVerticalSpeed(traffic.climb_rate_avg30s, tmp, 20); canvas.Select(look.info_values_font); sz = canvas.CalcTextSize(tmp); canvas.text(rc.right - sz.cx, rc.top + look.info_labels_font.GetHeight(), tmp); canvas.Select(look.info_labels_font); sz = canvas.CalcTextSize(_("Vario")); canvas.text(rc.right - sz.cx, rc.top, _("Vario")); } // Distance Units::FormatUserDistanceSmart(traffic.distance, tmp, 20); canvas.Select(look.info_values_font); sz = canvas.CalcTextSize(tmp); canvas.text(rc.left, rc.bottom - sz.cy, tmp); canvas.Select(look.info_labels_font); canvas.text(rc.left, rc.bottom - look.info_values_font.GetHeight() - look.info_labels_font.GetHeight(), _("Distance")); // Relative Height Units::FormatRelativeUserAltitude(traffic.relative_altitude, tmp, 20); canvas.Select(look.info_values_font); sz = canvas.CalcTextSize(tmp); canvas.text(rc.right - sz.cx, rc.bottom - sz.cy, tmp); canvas.Select(look.info_labels_font); sz = canvas.CalcTextSize(_("Rel. Alt.")); canvas.text(rc.right - sz.cx, rc.bottom - look.info_values_font.GetHeight() - look.info_labels_font.GetHeight(), _("Rel. Alt.")); // ID / Name unsigned font_size; if (traffic.HasName()) { canvas.Select(look.call_sign_font); font_size = look.call_sign_font.GetHeight(); if (!traffic.HasAlarm()) canvas.SetTextColor(look.selection_color); _tcscpy(tmp, traffic.name); } else { font_size = look.info_labels_font.GetHeight(); traffic.id.Format(tmp); } if (!WarningMode()) { // Team color dot FlarmFriends::Color team_color = FlarmFriends::GetFriendColor(traffic.id); // If no color found but target is teammate if (team_color == FlarmFriends::NONE && settings.team_flarm_tracking && traffic.id == settings.team_flarm_id) // .. use yellow color team_color = FlarmFriends::GREEN; // If team color found -> draw a colored circle around the target if (team_color != FlarmFriends::NONE) { switch (team_color) { case FlarmFriends::GREEN: canvas.Select(look.team_brush_green); break; case FlarmFriends::BLUE: canvas.Select(look.team_brush_blue); break; case FlarmFriends::YELLOW: canvas.Select(look.team_brush_yellow); break; case FlarmFriends::MAGENTA: canvas.Select(look.team_brush_magenta); break; default: break; } canvas.SelectNullPen(); canvas.circle(rc.left + Layout::FastScale(7), rc.top + (font_size / 2), Layout::FastScale(7)); rc.left += Layout::FastScale(16); } } canvas.text(rc.left, rc.top, tmp); }
/** * Paints the traffic symbols on the given canvas * @param canvas The canvas to paint on */ void FlarmTrafficWindow::PaintRadarTarget(Canvas &canvas, const FLARM_TRAFFIC &traffic, unsigned i) { // Save relative East/North fixed x, y; x = traffic.RelativeEast; y = -traffic.RelativeNorth; // Calculate the distance in meters fixed d = hypot(x, y); // Calculate the distance in pixels fixed scale = RangeScale(d); // Don't display distracting, far away targets in WarningMode if (WarningMode() && !traffic.HasAlarm() && scale == fixed(radius)) return; // x and y are not between 0 and 1 (distance will be handled via scale) if (positive(d)) { x /= d; y /= d; } else { x = fixed_zero; y = fixed_zero; } // Rotate x and y to have a track up display FastRotation::Pair p = fr.Rotate(x, y); x = fixed(p.first); y = fixed(p.second); // Calculate screen coordinates sc[i].x = radar_mid.x + iround(x * scale); sc[i].y = radar_mid.y + iround(y * scale); // Set the arrow color depending on alarm level switch (traffic.AlarmLevel) { case 1: canvas.hollow_brush(); canvas.select(hpWarning); canvas.circle(sc[i].x, sc[i].y, Layout::FastScale(small ? 8 : 16)); canvas.select(hbWarning); break; case 2: case 3: canvas.hollow_brush(); canvas.select(hpAlarm); canvas.circle(sc[i].x, sc[i].y, Layout::FastScale(small ? 8 : 16)); canvas.circle(sc[i].x, sc[i].y, Layout::FastScale(small ? 10 : 19)); canvas.select(hbAlarm); break; case 0: case 4: if (WarningMode()) { canvas.hollow_brush(); canvas.select(hpPassive); } else { if (!small && static_cast<unsigned> (selection) == i) { canvas.select(hpSelection); canvas.select(hbSelection); } else { canvas.hollow_brush(); if (traffic.Type != FLARM_TRAFFIC::acGlider && traffic.Type != FLARM_TRAFFIC::acHangGlider && traffic.Type != FLARM_TRAFFIC::acParaGlider) canvas.select(hpPassive); else canvas.select(hpStandard); } if (settings.TeamFlarmTracking && traffic.ID == settings.TeamFlarmIdTarget) { canvas.select(hbTeam); } } break; } // Create an arrow polygon POINT Arrow[5]; if (small) { Arrow[0].x = -3; Arrow[0].y = 4; Arrow[1].x = 0; Arrow[1].y = -5; Arrow[2].x = 3; Arrow[2].y = 4; Arrow[3].x = 0; Arrow[3].y = 2; Arrow[4].x = -3; Arrow[4].y = 4; } else { Arrow[0].x = -6; Arrow[0].y = 8; Arrow[1].x = 0; Arrow[1].y = -10; Arrow[2].x = 6; Arrow[2].y = 8; Arrow[3].x = 0; Arrow[3].y = 5; Arrow[4].x = -6; Arrow[4].y = 8; } // Rotate and shift the arrow PolygonRotateShift(Arrow, 5, sc[i].x, sc[i].y, traffic.TrackBearing - direction); // Draw the polygon canvas.polygon(Arrow, 5); if (small) { if (WarningMode() && !traffic.HasAlarm()) return; const short relalt = iround(Units::ToUserAltitude(traffic.RelativeAltitude / 100)); // if (relative altitude is other than zero) if (relalt == 0) return; // Write the relativ altitude devided by 100 to the Buffer TCHAR Buffer[10]; _stprintf(Buffer, _T("%d"), abs(relalt)); // Select font canvas.background_transparent(); canvas.select(hfSideInfo); canvas.set_text_color(Color::BLACK); // Calculate size of the output string SIZE tsize = canvas.text_size(Buffer); int dist = Layout::FastScale(traffic.HasAlarm() ? 12 : 8); // Draw string canvas.text(sc[i].x + dist, sc[i].y - tsize.cy / 2, Buffer); // Set black brush for the up/down arrow canvas.black_brush(); canvas.null_pen(); // Prepare the triangular polygon POINT triangle[4]; triangle[0].x = 0; triangle[0].y = -4; triangle[1].x = 3; triangle[1].y = 0; triangle[2].x = -3; triangle[2].y = 0; // Flip = -1 for arrow pointing downwards short flip = 1; if (relalt < 0) flip = -1; // Shift the arrow to the right position for (int j = 0; j < 3; j++) { triangle[j].x = Layout::FastScale(triangle[j].x); triangle[j].y = Layout::FastScale(triangle[j].y); triangle[j].x = sc[i].x + dist + triangle[j].x + tsize.cx / 2; triangle[j].y = sc[i].y + flip * (triangle[j].y - tsize.cy / 2); } triangle[3].x = triangle[0].x; triangle[3].y = triangle[0].y; // Draw the arrow canvas.polygon(triangle, 4); return; } // if warning exists -> don't draw vertical speeds if (WarningMode()) return; // if vertical speed to small or negative -> skip this one if (side_display_type == 1 && (traffic.Average30s < fixed(0.5) || (traffic.Type != FLARM_TRAFFIC::acGlider && traffic.Type != FLARM_TRAFFIC::acHangGlider && traffic.Type != FLARM_TRAFFIC::acParaGlider))) return; // Select font canvas.background_transparent(); canvas.select(hfSideInfo); // Format string TCHAR tmp[10]; if (side_display_type == 1) Units::FormatUserVSpeed(traffic.Average30s, tmp, 10, false); else Units::FormatUserArrival(traffic.RelativeAltitude, tmp, 10, true); SIZE sz = canvas.text_size(tmp); // Draw vertical speed shadow canvas.set_text_color(Color::WHITE); canvas.text(sc[i].x + Layout::FastScale(11) + 1, sc[i].y - sz.cy / 2 + 1, tmp); canvas.text(sc[i].x + Layout::FastScale(11) - 1, sc[i].y - sz.cy / 2 - 1, tmp); // Select color if (static_cast<unsigned> (selection) == i) canvas.set_text_color(hcSelection); else canvas.set_text_color(hcStandard); // Draw vertical speed canvas.text(sc[i].x + Layout::FastScale(11), sc[i].y - sz.cy / 2, tmp); }
/** * Paints the traffic symbols on the given canvas * @param canvas The canvas to paint on */ void FlarmTrafficWindow::PaintRadarTarget(Canvas &canvas, const FlarmTraffic &traffic, unsigned i) { // Save relative East/North fixed x = traffic.relative_east; fixed y = -traffic.relative_north; // Calculate the distance in pixels fixed scale = RangeScale(traffic.distance); // Don't display distracting, far away targets in WarningMode if (WarningMode() && !traffic.HasAlarm() && scale == fixed(radius)) return; // x and y are not between 0 and 1 (distance will be handled via scale) if (!traffic.distance.IsZero()) { x /= traffic.distance; y /= traffic.distance; } else { x = fixed_zero; y = fixed_zero; } if (!enable_north_up) { // Rotate x and y to have a track up display FastRotation::Pair p = fr.Rotate(x, y); x = fixed(p.first); y = fixed(p.second); } // Calculate screen coordinates sc[i].x = radar_mid.x + iround(x * scale); sc[i].y = radar_mid.y + iround(y * scale); const Color *text_color; const Pen *target_pen, *circle_pen; const Brush *target_brush, *arrow_brush; bool hollow_brush = false; unsigned circles = 0; // Set the arrow color depending on alarm level switch (traffic.alarm_level) { case FlarmTraffic::AlarmType::LOW: text_color = &look.default_color; target_pen = circle_pen = &look.warning_pen; target_brush = &look.warning_brush; arrow_brush = &look.default_brush; circles = 1; break; case FlarmTraffic::AlarmType::IMPORTANT: case FlarmTraffic::AlarmType::URGENT: text_color = &look.default_color; target_pen = circle_pen = &look.alarm_pen; target_brush = &look.alarm_brush; arrow_brush = &look.default_brush; circles = 2; break; case FlarmTraffic::AlarmType::NONE: if (WarningMode()) { text_color = &look.passive_color; target_pen = &look.passive_pen; arrow_brush = &look.passive_brush; hollow_brush = true; } else { // Search for team color FlarmFriends::Color team_color = FlarmFriends::GetFriendColor(traffic.id); // If no color found but target is teammate if (team_color == FlarmFriends::NONE && settings.team_flarm_tracking && traffic.id == settings.team_flarm_id) // .. use yellow color team_color = FlarmFriends::GREEN; // If team color found -> draw a colored circle around the target if (team_color != FlarmFriends::NONE) { switch (team_color) { case FlarmFriends::GREEN: circle_pen = &look.team_pen_green; break; case FlarmFriends::BLUE: circle_pen = &look.team_pen_blue; break; case FlarmFriends::YELLOW: circle_pen = &look.team_pen_yellow; break; case FlarmFriends::MAGENTA: circle_pen = &look.team_pen_magenta; break; default: break; } circles = 1; } if (!small && static_cast<unsigned> (selection) == i) { text_color = &look.selection_color; target_brush = arrow_brush = &look.selection_brush; target_pen = &look.selection_pen; } else { hollow_brush = true; if (traffic.IsPassive()) { text_color = &look.passive_color; target_pen = &look.passive_pen; arrow_brush = &look.passive_brush; } else { text_color = &look.default_color; target_pen = &look.default_pen; arrow_brush = &look.default_brush; } } } break; } if (circles > 0) { canvas.SelectHollowBrush(); canvas.Select(*circle_pen); canvas.circle(sc[i].x, sc[i].y, Layout::FastScale(small ? 8 : 16)); if (circles == 2) canvas.circle(sc[i].x, sc[i].y, Layout::FastScale(small ? 10 : 19)); } // Create an arrow polygon RasterPoint Arrow[5]; if (small) { Arrow[0].x = -3; Arrow[0].y = 4; Arrow[1].x = 0; Arrow[1].y = -5; Arrow[2].x = 3; Arrow[2].y = 4; Arrow[3].x = 0; Arrow[3].y = 2; Arrow[4].x = -3; Arrow[4].y = 4; } else { Arrow[0].x = -6; Arrow[0].y = 8; Arrow[1].x = 0; Arrow[1].y = -10; Arrow[2].x = 6; Arrow[2].y = 8; Arrow[3].x = 0; Arrow[3].y = 5; Arrow[4].x = -6; Arrow[4].y = 8; } // Rotate and shift the arrow PolygonRotateShift(Arrow, 5, sc[i].x, sc[i].y, traffic.track - (enable_north_up ? Angle::Zero() : heading)); // Select pen and brush canvas.Select(*target_pen); if (hollow_brush) canvas.SelectHollowBrush(); else canvas.Select(*target_brush); // Draw the polygon canvas.polygon(Arrow, 5); if (small) { if (WarningMode() && !traffic.HasAlarm()) return; const short relalt = iround(Units::ToUserAltitude(traffic.relative_altitude) / 100); // if (relative altitude is other than zero) if (relalt == 0) return; // Write the relativ altitude devided by 100 to the Buffer StaticString<10> buffer; buffer.Format(_T("%d"), abs(relalt)); // Select font canvas.SetBackgroundTransparent(); canvas.Select(look.side_info_font); canvas.SetTextColor(*text_color); // Calculate size of the output string PixelSize tsize = canvas.CalcTextSize(buffer); UPixelScalar dist = Layout::FastScale(traffic.HasAlarm() ? 12 : 8); // Draw string canvas.text(sc[i].x + dist, sc[i].y - tsize.cy / 2, buffer); // Set target_brush for the up/down arrow canvas.Select(*arrow_brush); canvas.SelectNullPen(); // Prepare the triangular polygon RasterPoint triangle[4]; triangle[0].x = 0; triangle[0].y = -4; triangle[1].x = 3; triangle[1].y = 0; triangle[2].x = -3; triangle[2].y = 0; // Flip = -1 for arrow pointing downwards short flip = 1; if (relalt < 0) flip = -1; // Shift the arrow to the right position for (int j = 0; j < 3; j++) { triangle[j].x = Layout::FastScale(triangle[j].x); triangle[j].y = Layout::FastScale(triangle[j].y); triangle[j].x = sc[i].x + dist + triangle[j].x + tsize.cx / 2; triangle[j].y = sc[i].y + flip * (triangle[j].y - tsize.cy / 2); } triangle[3].x = triangle[0].x; triangle[3].y = triangle[0].y; // Draw the arrow canvas.DrawTriangleFan(triangle, 4); return; } // if warning exists -> don't draw vertical speeds if (WarningMode()) return; // if vertical speed to small or negative -> skip this one if (side_display_type == 1 && (!traffic.climb_rate_avg30s_available || traffic.climb_rate_avg30s < fixed(0.5) || traffic.IsPowered())) return; // Select font canvas.SetBackgroundTransparent(); canvas.Select(look.side_info_font); // Format string TCHAR tmp[10]; if (side_display_type == 1) FormatUserVerticalSpeed(traffic.climb_rate_avg30s, tmp, false); else FormatRelativeUserAltitude(traffic.relative_altitude, tmp, true); PixelSize sz = canvas.CalcTextSize(tmp); // Draw vertical speed shadow canvas.SetTextColor(COLOR_WHITE); canvas.text(sc[i].x + Layout::FastScale(11) + 1, sc[i].y - sz.cy / 2 + 1, tmp); canvas.text(sc[i].x + Layout::FastScale(11) - 1, sc[i].y - sz.cy / 2 - 1, tmp); // Select color canvas.SetTextColor(*text_color); // Draw vertical speed canvas.text(sc[i].x + Layout::FastScale(11), sc[i].y - sz.cy / 2, tmp); }