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); }
void Draw(Canvas &canvas, unsigned start, unsigned n) const { #ifndef ENABLE_OPENGL assert(start + n <= ARRAY_SIZE(points)); #endif canvas.DrawPolygon(points + start, n); }
void RoundRect(Canvas &canvas, int left, int top, int right, int bottom, unsigned radius) { unsigned npoly = 0; RasterPoint pt[66*4]; segment_poly(pt, left + radius, top + radius, radius, INT_ANGLE_RANGE * 3 / 4, INT_ANGLE_RANGE - 1, npoly); segment_poly(pt, right - radius, top + radius, radius, 0, INT_ANGLE_RANGE / 4 - 1, npoly); segment_poly(pt, right - radius, bottom - radius, radius, INT_ANGLE_RANGE / 4, INT_ANGLE_RANGE / 2 - 1, npoly); segment_poly(pt, left + radius, bottom - radius, radius, INT_ANGLE_RANGE / 2, INT_ANGLE_RANGE * 3 / 4 - 1, npoly); assert(npoly < ARRAY_SIZE(pt)); if (npoly) canvas.DrawPolygon(pt, npoly); }
bool KeyHole(Canvas &canvas, PixelScalar x, PixelScalar y, UPixelScalar radius, Angle start, Angle end, UPixelScalar inner_radius) { // dont draw if out of view PixelRect rc, bounds; SetRect(&rc, 0, 0, canvas.get_width(), canvas.get_height()); SetRect(&bounds, x - radius, y - radius, x + radius, y + radius); if (!IntersectRect(&bounds, &bounds, &rc)) return false; const int istart = NATIVE_TO_INT(start.Native()); const int iend = NATIVE_TO_INT(end.Native()); int npoly = 0; RasterPoint pt[66*2]; segment_poly(pt, x, y, radius, istart, iend, npoly); segment_poly(pt, x, y, inner_radius, iend, istart, npoly); assert(npoly <= 66*2); if (npoly) canvas.DrawPolygon(pt, npoly); return true; }
/** * 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); }
void TrailRenderer::DrawPreparedPolygon(Canvas &canvas, unsigned n) { assert(points.size() >= n); canvas.DrawPolygon(points.begin(), n); }
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)); }
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)); }
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)); }
void TerrainXSRenderer::DrawPolygon(Canvas &canvas, RasterBuffer::TerrainType type, const RasterPoint *points, unsigned num_points) const { assert(type != RasterBuffer::TerrainType::UNKNOWN); canvas.Select(type == RasterBuffer::TerrainType::WATER ? look.sea_brush : look.terrain_brush); canvas.DrawPolygon(points, num_points); }
void FinishPolygon(Canvas &canvas) { if (mode != SOLID) { canvas.SelectNullPen(); canvas.Select(*brush); mode = SOLID; } canvas.DrawPolygon(points.begin(), num_points); num_points = 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)); }
void CheckBoxControl::OnPaint(Canvas &canvas) { const auto &cb_look = look->check_box; const bool focused = HasCursorKeys() && HasFocus(); if (focused) canvas.Clear(cb_look.focus_background_brush); else if (HaveClipping()) canvas.Clear(look->background_brush); const auto &state_look = IsEnabled() ? (pressed ? cb_look.pressed : (focused ? cb_look.focused : cb_look.standard)) : cb_look.disabled; unsigned size = canvas.GetHeight() - 4; canvas.Select(state_look.box_brush); canvas.Select(state_look.box_pen); canvas.Rectangle(2, 2, size, size); if (checked) { canvas.Select(state_look.check_brush); canvas.SelectNullPen(); BulkPixelPoint check_mark[] = { {-8, -2}, {-3, 6}, {7, -9}, {8, -5}, {-3, 9}, {-9, 2}, }; unsigned top = canvas.GetHeight() / 2; for (unsigned i = 0; i < ARRAY_SIZE(check_mark); ++i) { check_mark[i].x = (check_mark[i].x * (int)size) / 24 + top; check_mark[i].y = (check_mark[i].y * (int)size) / 24 + top; } canvas.DrawPolygon(check_mark, ARRAY_SIZE(check_mark)); } canvas.Select(*cb_look.font); canvas.SetTextColor(state_look.text_color); canvas.SetBackgroundTransparent(); canvas.DrawText(canvas.GetHeight() + 2, 2, caption.c_str()); }
static void DrawShape(Canvas &canvas, AbstractAirspace::Shape shape, const RasterPoint pt, unsigned radius, const std::vector<RasterPoint> &pts) { if (shape == AbstractAirspace::Shape::CIRCLE) canvas.DrawCircle(pt.x, pt.y, radius); else if (IsAncientHardware()) canvas.Rectangle(pt.x - radius, pt.y - radius, pt.x + radius, pt.y + radius); else canvas.DrawPolygon(&pts[0], (unsigned)pts.size()); }
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); }
void ThermalAssistantWindow::PaintPoints(Canvas &canvas) const { #ifdef ENABLE_OPENGL GLBlend blend(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); #elif defined(USE_GDI) canvas.SetMixMask(); #endif /* GDI */ canvas.Select(look.polygon_brush); canvas.Select(look.polygon_pen); canvas.DrawPolygon(lift_points, 36); }
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)); }
void RoundRect(Canvas &canvas, int left, int top, int right, int bottom, unsigned radius) { unsigned npoly = 0; RasterPoint pt[66*4]; segment_poly(pt, left + radius, top + radius, radius, 3072, 4095, npoly); segment_poly(pt, right - radius, top + radius, radius, 0, 1023, npoly); segment_poly(pt, right - radius, bottom - radius, radius, 1024, 2047, npoly); segment_poly(pt, left + radius, bottom - radius, radius, 2048, 3071, npoly); assert(npoly < ARRAY_SIZE(pt)); if (npoly) canvas.DrawPolygon(pt, npoly); }
void RoundRect(Canvas &canvas, PixelScalar left, PixelScalar top, PixelScalar right, PixelScalar bottom, UPixelScalar radius) { int npoly = 0; RasterPoint pt[66*4]; segment_poly(pt, left + radius, top + radius, radius, 3072, 4095, npoly); segment_poly(pt, right - radius, top + radius, radius, 0, 1023, npoly); segment_poly(pt, right - radius, bottom - radius, radius, 1024, 2047, npoly); segment_poly(pt, left + radius, bottom - radius, radius, 2048, 3071, npoly); assert(npoly <= 66*4); if (npoly) canvas.DrawPolygon(pt, npoly); }
static void Draw(Canvas &canvas) { PixelRect rc = canvas.GetRect(); rc.Grow(-0.2 * rc.GetSize().cx); /* draw the banner text with a large font */ Font small_font; small_font.LoadFile("/opt/LK8000/share/fonts/DejaVuSansCondensed.ttf", (rc.GetSize().cy / 25)); canvas.Select(small_font); canvas.SetTextColor(COLOR_BLACK); canvas.SetBackgroundTransparent(); const TCHAR *const text = _T("Powered Off"); const PixelSize text_size = canvas.CalcTextSize(text); const RasterPoint text_pos = { rc.left + 16, rc.bottom - 16 - text_size.cy }; canvas.DrawText(text_pos.x, text_pos.y, text); Font big_font; big_font.LoadFile("/opt/LK8000/share/fonts/DejaVuSansCondensed-Bold.ttf", (rc.GetSize().cy / 10)); canvas.Select(big_font); const TCHAR *const text2 = _T("LK8000"); const PixelSize text2_size = canvas.CalcTextSize(text2); const RasterPoint text2_pos = { (rc.left + rc.GetSize().cx + text2_size.cx) / 2, (rc.top + (rc.GetSize().cy / 10)) }; canvas.DrawText(text2_pos.x, text2_pos.y, text2); const double Scale = (double)rc.GetSize().cx / (double)bird_size.cx; RasterPoint polygon[array_size(bird_polygon)] = {}; std::transform(std::begin(bird_polygon), std::end(bird_polygon), std::begin(polygon), [Scale, rc, text2_size, text2_pos]( const RasterPoint& pt ) { return RasterPoint(pt.x*Scale + rc.left, pt.y*Scale + text2_pos.y + text2_size.cy); }); canvas.SelectBlackBrush(); canvas.DrawPolygon(polygon, array_size(polygon)); }
void RenderFAISector(Canvas &canvas, const WindowProjection &projection, const GeoPoint &pt1, const GeoPoint &pt2, bool reverse, const FAITriangleSettings &settings) { GeoPoint geo_points[FAI_TRIANGLE_SECTOR_MAX]; GeoPoint *geo_end = GenerateFAITriangleArea(geo_points, pt1, pt2, reverse, settings); GeoPoint clipped[FAI_TRIANGLE_SECTOR_MAX * 3], *clipped_end = clipped + GeoClip(projection.GetScreenBounds().Scale(fixed(1.1))) .ClipPolygon(clipped, geo_points, geo_end - geo_points); RasterPoint points[FAI_TRIANGLE_SECTOR_MAX], *p = points; for (GeoPoint *geo_i = clipped; geo_i != clipped_end;) *p++ = projection.GeoToScreen(*geo_i++); canvas.DrawPolygon(points, p - points); }
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); }
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); }
bool KeyHole(Canvas &canvas, int x, int y, unsigned radius, Angle start, Angle end, unsigned inner_radius) { // dont draw if out of view if (!IsCircleVisible(canvas, x, y, radius)) return false; const int istart = NATIVE_TO_INT(start.Native()); const int iend = NATIVE_TO_INT(end.Native()); unsigned npoly = 0; RasterPoint pt[66*2]; segment_poly(pt, x, y, radius, istart, iend, npoly); segment_poly(pt, x, y, inner_radius, iend, istart, npoly); assert(npoly < ARRAY_SIZE(pt)); if (npoly) canvas.DrawPolygon(pt, npoly); return true; }
bool Annulus(Canvas &canvas, PixelPoint center, unsigned radius, Angle start, Angle end, unsigned inner_radius) { // dont draw if out of view if (!IsCircleVisible(canvas, center, radius)) return false; const int istart = NATIVE_TO_INT(start.Native()); const int iend = NATIVE_TO_INT(end.Native()); unsigned npoly = 0; BulkPixelPoint pt[66*2]; segment_poly(pt, center, radius, istart, iend, npoly); segment_poly(pt, center, inner_radius, iend, istart, npoly, false); assert(npoly <= ARRAY_SIZE(pt)); if (npoly) canvas.DrawPolygon(pt, npoly); return true; }
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]); } }
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]); } }
//------------------------------------------------------------------------------ int main(int argc, char *argv[]) { QApplication app(argc, argv); Canvas c; Pen(Pen::SOLID, 1, Color(0, 0, 0)); { c.Select(Brush(Color(128, 128, 0, Color::TRANSPARENT))); c.DrawKeyhole(200, 100, 50, 100, Angle::Degrees(-20), Angle::Degrees(20)); c.DrawKeyhole(400, 100, 50, 100, Angle::Degrees(70), Angle::Degrees(110)); c.DrawKeyhole(200, 300, 50, 100, Angle::Degrees(160), Angle::Degrees(200)); c.DrawKeyhole(400, 300, 50, 100, Angle::Degrees(-110), Angle::Degrees(-70)); c.show(); app.exec(); } { c.Clear(); c.DrawKeyhole(200, 100, 50, 100, Angle::Degrees(35), Angle::Degrees(55)); c.DrawKeyhole(400, 100, 50, 100, Angle::Degrees(125), Angle::Degrees(145)); c.DrawKeyhole(200, 300, 50, 100, Angle::Degrees(215), Angle::Degrees(235)); c.DrawKeyhole(400, 300, 50, 100, Angle::Degrees(305), Angle::Degrees(325)); c.show(); app.exec(); } { c.Clear(); c.DrawFilledRectangle(0, 0, 100, 100, Color(128, 128, 128, Color::TRANSPARENT)); c.DrawFilledRectangle(100, 100, 200, 200, Color(128, 0, 0, Color::TRANSPARENT)); c.DrawFilledRectangle(150, 150, 250, 250, Color(0, 128, 0, Color::TRANSPARENT)); c.DrawFilledRectangle(200, 200, 300, 300, Color(0, 0, 128, Color::TRANSPARENT)); c.DrawTransparentText(0, 0, "0"); c.DrawTransparentText(0, 100, "100"); c.DrawTransparentText(0, 200, "200"); c.DrawTransparentText(0, 300, "300"); c.DrawTransparentText(0, 400, "400"); c.DrawTransparentText(0, 500, "500"); c.DrawTransparentText(100, c.GetFontHeight(), "100"); c.DrawTransparentText(200, c.GetFontHeight(), "200"); c.DrawTransparentText(300, c.GetFontHeight(), "300"); c.DrawTransparentText(400, c.GetFontHeight(), "400"); c.DrawTransparentText(500, c.GetFontHeight(), "500"); c.show(); app.exec(); } { c.Clear(); c.DrawOutlineRectangle(100, 100, 200, 200, Color(255, 0, 0)); c.show(); app.exec(); } { c.Clear(); c.DrawRoundRectangle(100, 100, 200, 200, 10, 10); c.DrawRoundRectangle(200, 200, 300, 300, 100, 100); c.DrawRoundRectangle(300, 300, 400, 400, 50, 50); c.show(); app.exec(); } { c.Clear(); PixelRect rc; rc.left = 100; rc.top = 100; rc.right = 200; rc.bottom = 200; c.DrawRaisedEdge(rc); c.show(); app.exec(); } { c.Clear(); RasterPoint rp[4]; rp[0] = {100, 100}; rp[1] = {200, 200}; rp[2] = {200, 300}; rp[3] = {300, 400}; c.DrawPolyline(rp, 4); c.show(); app.exec(); } { c.Clear(); RasterPoint rp[6]; rp[0] = {100, 100}; rp[1] = {150, 50}; rp[2] = {200, 100}; rp[3] = {200, 200}; rp[4] = {150, 200}; rp[5] = {100, 100}; c.DrawPolygon(rp, 6); c.show(); app.exec(); } { c.Clear(); RasterPoint rp[4]; rp[0] = {100, 100}; rp[1] = {200, 50}; rp[2] = {200, 150}; rp[3] = {150, 200}; c.DrawTriangleFan(rp, 4); c.show(); app.exec(); } { c.Clear(); c.DrawHLine(100, 200, 100, Color(255, 0, 0)); c.DrawHLine(100, 200, 200, Color(0, 255, 0)); c.DrawHLine(100, 200, 300, Color(0, 0, 255)); c.show(); app.exec(); } { c.Clear(); c.DrawLine(100, 100, 200, 200); c.DrawCircle(250, 250, 50); c.DrawSegment(100, 250, 50, Angle::Degrees(10), Angle::Degrees(30), false); c.show(); app.exec(); } { c.Clear(); c.DrawAnnulus(100, 100, 50, 100, Angle::Degrees(10), Angle::Degrees(60)); c.DrawAnnulus(300, 100, 50, 100, Angle::Degrees(0), Angle::Degrees(360)); c.DrawAnnulus(100, 300, 50, 100, Angle::Degrees(0), Angle::Degrees(0)); c.show(); app.exec(); } { PixelSize rc = c.CalcTextSize("Hello"); std::cout << "Size of \"Hello\": " << rc.cx << ", " << rc.cy << std::endl; c.DrawClippedText(100, 100, rc.cx / 2, "Hello"); c.show(); app.exec(); } { std::cout << "Height of font: " << c.GetFontHeight() << std::endl; } { c.Clear(); c.DrawText(0, 50, "50"); c.Clear(); c.show(); return app.exec(); } }
void FinalGlideBarRenderer::Draw(Canvas &canvas, const PixelRect &rc, const DerivedInfo &calculated, const GlideSettings &glide_settings, const bool final_glide_bar_mc0_enabled) const { #ifdef ENABLE_OPENGL const ScopeAlphaBlend alpha_blend; #endif BulkPixelPoint GlideBar[6] = { { 0, 0 }, { 9, -9 }, { 18, 0 }, { 18, 0 }, { 9, 0 }, { 0, 0 } }; BulkPixelPoint GlideBar0[4] = { { 0, 0 }, { 9, -9 }, { 9, 0 }, { 0, 0 } }; BulkPixelPoint clipping_arrow[6] = { { 0, 0 }, { 9, 9 }, { 18, 0 }, { 18, 6 }, { 9, 15 }, { 0, 6 } }; BulkPixelPoint clipping_arrow0[4] = { { 0, 0 }, { 9, 9 }, { 9, 15 }, { 0, 6 } }; TCHAR Value[10]; const TaskStats &task_stats = calculated.task_stats; const ElementStat &total = task_stats.total; const GlideResult &solution = total.solution_remaining; const GlideResult &solution_mc0 = total.solution_mc0; if (!task_stats.task_valid || !solution.IsOk() || !solution_mc0.IsDefined()) return; const int y0 = (rc.bottom + rc.top) / 2; /* NOTE: size_divisor replaces the fixed value 9 that was used throughout * the code below which caused fixed size rendering regardless of * map size (except the effects of Layout::Scale()). This method * is not usable with variable map sizes (e.g. because of the cross-section * area). size_divisor is used to introduce a screen size dependent scaling. * That workaround is an ugly hack and needs a rework. */ const int size_divisor = std::max(Layout::Scale(3000u / rc.GetHeight()), 4u); int dy_glidebar = 0; int dy_glidebar0 = 0; FormatUserAltitude(solution.SelectAltitudeDifference(glide_settings), Value, false); canvas.Select(*look.font); const PixelSize text_size = canvas.CalcTextSize(Value); int clipping_arrow_offset = Layout::Scale(4); int clipping_arrow0_offset = Layout::Scale(4); // 468 meters is it's size. Will be divided by 9 to fit screen resolution. int altitude_difference = (int) solution.SelectAltitudeDifference(glide_settings); int altitude_difference0 = (int) solution_mc0.SelectAltitudeDifference(glide_settings); // TODO feature: should be an angle if in final glide mode // cut altitude_difference at +- 468 meters (55 units) if (altitude_difference > 468) altitude_difference = 468; if (altitude_difference < -468) altitude_difference = -468; // 55 units is size, 468 meters div by 9 means 55. int Offset = altitude_difference / size_divisor; Offset = Layout::Scale(Offset); if (altitude_difference <= 0) { GlideBar[1].y = Layout::Scale(9); dy_glidebar = text_size.cy + 2; } else { GlideBar[1].y = -Layout::Scale(9); clipping_arrow[1].y = -clipping_arrow[1].y; clipping_arrow[3].y = -clipping_arrow[3].y; clipping_arrow[4].y = -clipping_arrow[4].y; clipping_arrow[5].y = -clipping_arrow[5].y; clipping_arrow_offset = -clipping_arrow_offset; dy_glidebar = -1; } // cut altitude_difference0 at +- 468 meters (55 units) if (altitude_difference0 > 468) altitude_difference0 = 468; if (altitude_difference0 < -468) altitude_difference0 = -468; // 55 units is size, therefore div by 9. int Offset0 = altitude_difference0 / size_divisor; Offset0 = Layout::Scale(Offset0); if (altitude_difference0 <= 0) { GlideBar0[1].y = Layout::Scale(9); dy_glidebar0 = text_size.cy + 2; } else { GlideBar0[1].y = -Layout::Scale(9); clipping_arrow0[1].y = -clipping_arrow0[1].y; clipping_arrow0[2].y = -clipping_arrow0[2].y; clipping_arrow0[3].y = -clipping_arrow0[3].y; clipping_arrow0_offset = -clipping_arrow0_offset; dy_glidebar0 = -1; } for (unsigned i = 0; i < 6; i++) { GlideBar[i].y += y0 + dy_glidebar; GlideBar[i].x = Layout::Scale(GlideBar[i].x) + rc.left; } GlideBar[0].y -= Offset; GlideBar[1].y -= Offset; GlideBar[2].y -= Offset; for (unsigned i = 0; i < 4; i++) { GlideBar0[i].y += y0 + dy_glidebar0; GlideBar0[i].x = Layout::Scale(GlideBar0[i].x) + rc.left; } GlideBar0[0].y -= Offset0; GlideBar0[1].y -= Offset0; if ((altitude_difference0 >= altitude_difference) && (altitude_difference > 0)) { // both above and mc0 arrow larger than mc arrow GlideBar0[2].y = GlideBar[1].y; // both below GlideBar0[3].y = GlideBar[0].y; } // prepare clipping arrow for (unsigned i = 0; i < 6; i++) { clipping_arrow[i].y = Layout::Scale(clipping_arrow[i].y) + y0 - Offset + clipping_arrow_offset + dy_glidebar; clipping_arrow[i].x = Layout::Scale(clipping_arrow[i].x) + rc.left; } // prepare clipping arrow mc0 for (unsigned i = 0; i < 4; i++) { clipping_arrow0[i].y = Layout::Scale(clipping_arrow0[i].y) + y0 - Offset0 + clipping_arrow0_offset + dy_glidebar0; clipping_arrow0[i].x = Layout::Scale(clipping_arrow0[i].x) + rc.left; } // draw actual glide bar if (altitude_difference <= 0) { if (calculated.common_stats.landable_reachable) { canvas.Select(look.pen_below_landable); canvas.Select(look.brush_below_landable); } else { canvas.Select(look.pen_below); canvas.Select(look.brush_below); } } else { canvas.Select(look.pen_above); canvas.Select(look.brush_above); } canvas.DrawPolygon(GlideBar, 6); // draw clipping arrow if ((altitude_difference <= -468 ) || (altitude_difference >= 468)) canvas.DrawPolygon(clipping_arrow, 6); // draw glide bar at mc 0 if (altitude_difference0 <= 0 && final_glide_bar_mc0_enabled) { if (calculated.common_stats.landable_reachable) { canvas.Select(look.pen_below_landable); canvas.Select(look.brush_below_landable_mc0); } else { canvas.Select(look.pen_below); canvas.Select(look.brush_below_mc0); } } else { canvas.Select(look.pen_above); canvas.Select(look.brush_above_mc0); } if ( ( (altitude_difference != altitude_difference0) || (altitude_difference0 < 0) ) && final_glide_bar_mc0_enabled) { canvas.DrawPolygon(GlideBar0, 4); if ((altitude_difference0 <= -468 ) || (altitude_difference0 >= 468)) canvas.DrawPolygon(clipping_arrow0, 4); } // draw cross (x) on final glide bar if unreachable at current Mc // or above final glide but impeded by obstacle int cross_sign = 0; if (!total.IsAchievable()) cross_sign = 1; if (calculated.terrain_warning_location.IsValid() && altitude_difference > 0 ) cross_sign = -1; if (cross_sign != 0) { canvas.Select(task_look.bearing_pen); canvas.DrawLine(Layout::Scale(9 - 5), y0 + cross_sign * Layout::Scale(9 - 5), Layout::Scale(9 + 5), y0 + cross_sign * Layout::Scale(9 + 5)); canvas.DrawLine(Layout::Scale(9 - 5), y0 + cross_sign * Layout::Scale(9 + 5), Layout::Scale(9 + 5), y0 + cross_sign * Layout::Scale(9 - 5)); } canvas.SetTextColor(COLOR_BLACK); canvas.SetBackgroundColor(COLOR_WHITE); TextInBoxMode style; style.shape = LabelShape::ROUNDED_BLACK; style.move_in_view = true; if (text_size.cx < Layout::Scale(18)) { style.align = TextInBoxMode::Alignment::RIGHT; TextInBox(canvas, Value, Layout::Scale(18), y0, style, rc); } else TextInBox(canvas, Value, 0, y0, style, rc); }
void VarioBarRenderer::Draw(Canvas &canvas, const PixelRect &rc, const MoreData &basic, const DerivedInfo &calculated, const GlidePolar &glide_polar, const bool vario_bar_avg_enabled) const { #ifdef ENABLE_OPENGL const ScopeAlphaBlend alpha_blend; #endif RasterPoint VarioBar[6] = { { 0, 0 }, { 9, -9 }, { 18, 0 }, { 18, 0 }, { 9, 0 }, { 0, 0 } }; RasterPoint VarioBarAvg[4] = { { 0, 0 }, { 9, -9 }, { 9, 0 }, { 0, 0 } }; RasterPoint clipping_arrow[6] = { { 0, 0 }, { 9, 9 }, { 18, 0 }, { 18, 6 }, { 9, 15 }, { 0, 6 } }; RasterPoint clipping_arrow_av[4] = { { 0, 0 }, { 9, 9 }, { 9, 15 }, { 0, 6 } }; RasterPoint mc_arrow[6] = { { 0, 0 }, { 9, -9 }, { 18, 0 }, { 18, -2 }, { 9, -11 }, { 0, -2 } }; TCHAR Value[10]; const int y0 = (rc.bottom + rc.top) / 2; /* NOTE: size_divisor replaces the fixed value 9 that was used throughout * the code sink which caused fixed size rendering regardless of * map size (except the effects of Layout::Scale()). This method * is not usable with variable map sizes (e.g. because of the cross-section * area). size_divisor is used to introduce a screen size dependent scaling. * That workaround is an ugly hack and needs a rework. */ const auto size_divisor = std::max((fixed) Layout::Scale(70 / (rc.bottom - rc.top)), fixed(0.15)); PixelScalar dy_variobar = 0; PixelScalar dy_variobar_av = 0; PixelScalar dy_variobar_mc = 0; PixelScalar clipping_arrow_offset = Layout::Scale(4); PixelScalar clipping_arrow_av_offset = Layout::Scale(4); // PixelScalar clipping_arrow_mc_offset = Layout::Scale(4); auto vario_gross = basic.brutto_vario; FormatUserVerticalSpeed(vario_gross, Value, false, true); canvas.Select(*look.font); const PixelSize text_size = canvas.CalcTextSize(Value); auto vario_avg = calculated.average; // cut vario_gross at +- 5 meters/s if (vario_gross > fixed(5)) vario_gross = fixed(5); if (vario_gross < fixed(-5)) vario_gross = fixed(-5); int Offset = (int)(vario_gross / size_divisor); Offset = Layout::Scale(Offset); if (!positive(vario_gross)) { VarioBar[1].y = Layout::Scale(9); dy_variobar = text_size.cy + 2; } else { VarioBar[1].y = -Layout::Scale(9); clipping_arrow[1].y = -clipping_arrow[1].y; clipping_arrow[3].y = -clipping_arrow[3].y; clipping_arrow[4].y = -clipping_arrow[4].y; clipping_arrow[5].y = -clipping_arrow[5].y; clipping_arrow_offset = -clipping_arrow_offset; dy_variobar = -1; } // cut vario_avg at +- 5 meters/s if (vario_avg > fixed(5)) vario_avg = fixed(5); if (vario_avg < fixed(-5)) vario_avg = fixed(-5); int OffsetAvg = int(vario_avg / size_divisor); OffsetAvg = Layout::Scale(OffsetAvg); if (!positive(vario_avg)) { VarioBarAvg[1].y = Layout::Scale(9); dy_variobar_av = text_size.cy + 2; } else { VarioBarAvg[1].y = -Layout::Scale(9); clipping_arrow_av[1].y = -clipping_arrow_av[1].y; clipping_arrow_av[2].y = -clipping_arrow_av[2].y; clipping_arrow_av[3].y = -clipping_arrow_av[3].y; clipping_arrow_av_offset = -clipping_arrow_av_offset; dy_variobar_av = -1; } //clip MC Value auto mc_val = glide_polar.GetMC(); if (mc_val > fixed(5)) mc_val = fixed(5); if (!positive(mc_val)) { dy_variobar_mc = text_size.cy + 2; }else{ dy_variobar_mc = -1; } int OffsetMC = int(mc_val / size_divisor); OffsetMC = Layout::Scale(OffsetMC); for (unsigned i = 0; i < 6; i++) { VarioBar[i].y += y0 + dy_variobar; VarioBar[i].x = rc.right - Layout::Scale(VarioBar[i].x); } VarioBar[0].y -= Offset; VarioBar[1].y -= Offset; VarioBar[2].y -= Offset; for (unsigned i = 0; i < 4; i++) { VarioBarAvg[i].y += y0 + dy_variobar_av; VarioBarAvg[i].x = rc.right-Layout::Scale(VarioBarAvg[i].x); } VarioBarAvg[0].y -= OffsetAvg; VarioBarAvg[1].y -= OffsetAvg; // prepare mc arrow for (unsigned i = 0; i < 6; i++) { mc_arrow[i].y = Layout::Scale(mc_arrow[i].y) + y0 - OffsetMC + dy_variobar_mc; mc_arrow[i].x = rc.right - Layout::Scale(mc_arrow[i].x); } // prepare clipping arrow for (unsigned i = 0; i < 6; i++) { clipping_arrow[i].y = Layout::Scale(clipping_arrow[i].y) + y0 - Offset + clipping_arrow_offset + dy_variobar; clipping_arrow[i].x = rc.right - Layout::Scale(clipping_arrow[i].x); } // prepare clipping avg for (unsigned i = 0; i < 4; i++) { clipping_arrow_av[i].y = Layout::Scale(clipping_arrow_av[i].y) + y0 - OffsetAvg + clipping_arrow_av_offset + dy_variobar_av; clipping_arrow_av[i].x = rc.right-Layout::Scale(clipping_arrow_av[i].x); } // draw actual vario bar if (!positive(vario_gross)) { canvas.Select(look.pen_sink); canvas.Select(look.brush_sink); } else { canvas.Select(look.pen_climb); canvas.Select(look.brush_climb); } canvas.DrawPolygon(VarioBar, 6); // draw clipping arrow if (vario_gross <= fixed(-5) || vario_gross >= fixed(5)) canvas.DrawPolygon(clipping_arrow, 6); // draw avg vario bar if (!positive(vario_avg) && vario_bar_avg_enabled) { canvas.Select(look.pen_sink); canvas.Select(look.brush_sink_avg); } else { canvas.Select(look.pen_climb); canvas.Select(look.brush_climb_avg); } canvas.DrawPolygon(VarioBarAvg, 4); if (vario_avg <= fixed(-5.0) || vario_avg >= fixed(5.0)) canvas.DrawPolygon(clipping_arrow_av, 4); //draw MC arrow canvas.Select(look.pen_mc); canvas.Select(look.brush_mc); canvas.DrawPolygon(mc_arrow, 6); //draw text canvas.SetTextColor(COLOR_BLACK); canvas.SetBackgroundColor(COLOR_WHITE); TextInBoxMode style; style.shape = LabelShape::ROUNDED_BLACK; style.move_in_view = true; if (text_size.cx < Layout::Scale(18)) { style.align = TextInBoxMode::Alignment::RIGHT; TextInBox(canvas, Value, rc.right, y0, style, rc); } else TextInBox(canvas, Value, rc.right-Layout::Scale(18), y0, style, rc); }