/** * 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 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); }