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