void MapWindow::MapWaypointLabelSortAndRender(Canvas &canvas) { qsort(&MapWaypointLabelList, MapWaypointLabelListCount, sizeof(MapWaypointLabel_t), MapWaypointLabelListCompare); // now draw task/landable waypoints in order of range (closest last) // writing unconditionally for (int j = MapWaypointLabelListCount - 1; j >= 0; j--){ MapWaypointLabel_t *E = &MapWaypointLabelList[j]; // draws if they are in task unconditionally, // otherwise, does comparison if (E->inTask) { TextInBox(canvas, E->Name, E->Pos.x, E->Pos.y, E->Mode, MapRect, NULL); } } // now draw normal waypoints in order of range (furthest away last) // without writing over each other (or the task ones) for (unsigned i = 0; i < MapWaypointLabelListCount; i++) { MapWaypointLabel_t *E = &MapWaypointLabelList[i]; if (!E->inTask) { TextInBox(canvas, E->Name, E->Pos.x, E->Pos.y, E->Mode, MapRect, &label_block); } } }
void MapWindow::DrawCpuStats(HDC hdc, RECT rc) { if (Appearance.InverseInfoBox == true) return; TCHAR Buffer[LKSIZEBUFFERLARGE]; TextInBoxMode_t TextDisplayMode = {0}; TextDisplayMode.Color = RGB_WHITE; TextDisplayMode.WhiteBorder = 1; // inside a white circle TextDisplayMode.Border = 1; // add a black border to the circle #if (WINDOWSPC>0) wsprintf(Buffer,_T("CPU Draw=%d Calc=%d us"), Cpu_Draw, Cpu_Calc); #else wsprintf(Buffer,_T("CPU Draw=%d Calc=%d ms"), Cpu_Draw, Cpu_Calc); #endif TextInBox(hdc, &rc, Buffer, 000, 200 , 0, &TextDisplayMode, false); #if (WINDOWSPC>0) wsprintf(Buffer,_T("CPU Inst=%d PortA=%d PortB=%d us"), Cpu_Instrument, Cpu_PortA, Cpu_PortB); #else wsprintf(Buffer,_T("CPU Inst=%d PortA=%d PortB=%d ms"), Cpu_Instrument, Cpu_PortA, Cpu_PortB); #endif TextInBox(hdc, &rc, Buffer, 000, 240 , 0, &TextDisplayMode, false); //wsprintf(Buffer,_T("Landsc=%d Geom=%d"), InfoBoxLayout::landscape, InfoBoxLayout::InfoBoxGeometry); //TextInBox(hdc, Buffer, 000, 280 , 0, TextDisplayMode, false); //wsprintf(Buffer,_T("Recents=%d"), RecentNumber); //TextInBox(hdc, Buffer, 000, 280 , 0, TextDisplayMode, false); }
void GlueMapWindow::DrawPanInfo(Canvas &canvas) const { GeoPoint location = render_projection.GetGeoLocation(); TextInBoxMode mode; mode.mode = RenderMode::RM_OUTLINED_INVERTED; mode.bold = true; mode.align = A_RIGHT; UPixelScalar padding = Layout::FastScale(4); UPixelScalar height = Fonts::map_bold.GetHeight(); PixelScalar y = 0 + padding; PixelScalar x = render_projection.GetScreenWidth() - padding; if (terrain) { short elevation = terrain->GetTerrainHeight(location); if (!RasterBuffer::IsSpecial(elevation)) { StaticString<64> elevation_short, elevation_long; FormatUserAltitude(fixed(elevation), elevation_short.buffer(), elevation_short.MAX_SIZE); elevation_long = _("Elevation: "); elevation_long += elevation_short; TextInBox(canvas, elevation_long, x, y, mode, render_projection.GetScreenWidth(), render_projection.GetScreenHeight()); y += height; } } TCHAR buffer[256]; FormatGeoPoint(location, buffer, ARRAY_SIZE(buffer), _T('\n')); TCHAR *start = buffer; while (true) { TCHAR *newline = _tcschr(start, _T('\n')); if (newline != NULL) *newline = _T('\0'); TextInBox(canvas, start, x, y, mode, render_projection.GetScreenWidth(), render_projection.GetScreenHeight()); y += height; if (newline == NULL) break; start = newline + 1; } }
void MapWindow::DrawDebug(HDC hdc, RECT rc) { TCHAR Buffer[LKSIZEBUFFERLARGE]; TextInBoxMode_t TextDisplayMode = {0}; TextDisplayMode.Color = RGB_WHITE; TextDisplayMode.WhiteBorder = 1; // inside a white circle TextDisplayMode.Border = 1; // add a black border to the circle _stprintf(Buffer,_T("ModeIndex=%d CURTYPE=%d MSM=%d"), ModeIndex, ModeType[ModeIndex],MapSpaceMode ); TextInBox(hdc, &rc, Buffer, 000, 200 , 0, &TextDisplayMode, false); _stprintf(Buffer,_T("MTableTop=%d ModeTable=%d=MSM"), ModeTableTop[ModeIndex], ModeTable[ModeIndex][ModeType[ModeIndex]] ); TextInBox(hdc, &rc, Buffer, 000, 240 , 0, &TextDisplayMode, false); }
void GlueMapWindow::DrawGPSStatus(Canvas &canvas, const PixelRect &rc, const NMEAInfo &info) const { const TCHAR *txt; MaskedIcon *icon = NULL; if (!info.connected) { icon = &Graphics::hGPSStatus2; txt = _("GPS not connected"); } else if (!info.location_available) { icon = &Graphics::hGPSStatus1; txt = _("GPS waiting for fix"); } else { return; // early exit } int x = rc.left + Layout::FastScale(2); int y = rc.bottom - Layout::FastScale(35); icon->draw(canvas, x, y); x += icon->get_size().cx + Layout::FastScale(4); y = rc.bottom - Layout::FastScale(34); TextInBoxMode mode; mode.Mode = RoundedBlack; mode.Bold = true; TextInBox(canvas, txt, x, y, mode, rc, NULL); }
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); }
void MapWindow::DrawGPSStatus(Canvas &canvas, const RECT rc) { if (Basic().Connected && !Basic().NAVWarning && Basic().SatellitesUsed) // nothing to do, all OK return; TCHAR gpswarningtext1[] = TEXT("GPS not connected"); TCHAR gpswarningtext2[] = TEXT("GPS waiting for fix"); TextInBoxMode_t TextInBoxMode = {2}; TCHAR *txt=NULL; Bitmap *bmp=NULL; if (!Basic().Connected) { bmp = &MapGfx.hGPSStatus2; txt = gpswarningtext1; } else if (Basic().NAVWarning || (Basic().SatellitesUsed == 0)) { bmp = &MapGfx.hGPSStatus2; txt = gpswarningtext2; } else { return; // early exit } draw_bitmap(canvas, *bmp, rc.left + IBLSCALE(2), rc.bottom +IBLSCALE(Appearance.GPSStatusOffset.y - 22), 0, 0, 20, 20, false); TextInBox(canvas, gettext(txt), rc.left+IBLSCALE(24), rc.bottom+IBLSCALE(Appearance.GPSStatusOffset.y-19), TextInBoxMode, rc); }
void GlueMapWindow::DrawGPSStatus(Canvas &canvas, const PixelRect &rc, const NMEAInfo &info) const { const TCHAR *txt; const MaskedIcon *icon; if (!info.alive) { icon = &look.no_gps_icon; txt = _("GPS not connected"); } else if (!info.location_available) { icon = &look.waiting_for_fix_icon; txt = _("GPS waiting for fix"); } else // early exit return; PixelScalar x = rc.left + Layout::FastScale(2); PixelScalar y = rc.bottom - Layout::FastScale(35); icon->Draw(canvas, x, y); x += icon->GetSize().cx + Layout::FastScale(4); y = rc.bottom - Layout::FastScale(34); TextInBoxMode mode; mode.shape = LabelShape::ROUNDED_BLACK; const Font &font = *look.overlay_font; canvas.Select(font); TextInBox(canvas, txt, x, y, mode, rc, nullptr); }
static void MapWaypointLabelRender(Canvas &canvas, UPixelScalar width, UPixelScalar height, LabelBlock &label_block, WaypointLabelList &labels) { labels.Sort(); for (const auto &l : labels) { canvas.Select(l.bold ? Fonts::map_bold : Fonts::map); TextInBox(canvas, l.Name, l.Pos.x, l.Pos.y, l.Mode, width, height, &label_block); } }
bool TextInBox(Canvas &canvas, const TCHAR *Value, int x, int y, TextInBoxMode_t Mode, unsigned screen_width, unsigned screen_height, LabelBlock *label_block) { PixelRect rc; rc.left = 0; rc.top = 0; rc.right = screen_width; rc.bottom = screen_height; return TextInBox(canvas, Value, x, y, Mode, rc, label_block); }
static void MapWaypointLabelRender(Canvas &canvas, unsigned width, unsigned height, LabelBlock &label_block, WaypointLabelList &labels, const WaypointLook &look) { labels.Sort(); for (const auto &l : labels) { canvas.Select(l.bold ? *look.bold_font : *look.font); TextInBox(canvas, l.Name, l.Pos.x, l.Pos.y, l.Mode, width, height, &label_block); } }
// LK Status message void MapWindow::DrawLKStatus(HDC hdc, RECT rc) { TextInBoxMode_t TextDisplayMode = {0}; TCHAR Buffer[LKSIZEBUFFERLARGE]; short bottomlines; short middlex=(rc.right-rc.left)/2; short left=rc.left+NIBLSCALE(5); short contenttop=rc.top+NIBLSCALE(50); TextDisplayMode.Color = RGB_BLACK; TextDisplayMode.NoSetFont = 1; //TextDisplayMode.AlligneRight = 0; TextDisplayMode.AlligneCenter = 1; TextDisplayMode.WhiteBold = 1; TextDisplayMode.Border = 1; // HFONT oldfont=(HFONT)Surface.SelectObject(LK8PanelBigFont); switch(ModeIndex) { case LKMODE_MAP: _stprintf(Buffer,TEXT("MAP mode, 1 of 1")); break; case LKMODE_INFOMODE: _stprintf(Buffer,TEXT("%d-%d"), ModeIndex,CURTYPE+1); break; case LKMODE_WP: _stprintf(Buffer,TEXT("%d-%d"), ModeIndex,CURTYPE+1); break; case LKMODE_NAV: _stprintf(Buffer,TEXT("%d-%d"), ModeIndex,CURTYPE+1); break; default: _stprintf(Buffer,TEXT("UNKOWN mode")); break; } TextInBox(hdc, &rc, Buffer, middlex, 200 , 0, &TextDisplayMode, false); //Surface.SelectObject(oldfont); return; }
void GlueMapWindow::DrawPanInfo(Canvas &canvas) const { if (!render_projection.IsValid()) return; GeoPoint location = render_projection.GetGeoLocation(); TextInBoxMode mode; mode.shape = LabelShape::OUTLINED; mode.align = TextInBoxMode::Alignment::RIGHT; const Font &font = *look.overlay_font; canvas.Select(font); UPixelScalar padding = Layout::FastScale(4); UPixelScalar height = font.GetHeight(); PixelScalar y = 0 + padding; PixelScalar x = render_projection.GetScreenWidth() - padding; if (compass_visible) /* don't obscure the north arrow */ /* TODO: obtain offset from CompassRenderer */ y += Layout::Scale(19) + Layout::FastScale(13); if (terrain) { short elevation = terrain->GetTerrainHeight(location); if (!RasterBuffer::IsSpecial(elevation)) { StaticString<64> elevation_short, elevation_long; FormatUserAltitude(fixed(elevation), elevation_short.buffer(), elevation_short.MAX_SIZE); elevation_long = _("Elevation: "); elevation_long += elevation_short; TextInBox(canvas, elevation_long, x, y, mode, render_projection.GetScreenWidth(), render_projection.GetScreenHeight()); y += height; } } TCHAR buffer[256]; FormatGeoPoint(location, buffer, ARRAY_SIZE(buffer), _T('\n')); TCHAR *start = buffer; while (true) { TCHAR *newline = _tcschr(start, _T('\n')); if (newline != nullptr) *newline = _T('\0'); TextInBox(canvas, start, x, y, mode, render_projection.GetScreenWidth(), render_projection.GetScreenHeight()); y += height; if (newline == nullptr) break; start = newline + 1; } }
void MapWindow::DrawFinalGlide(Canvas &canvas, const RECT rc) { /* POINT Scale[18] = { {5,-50 }, {14,-60 }, {23, -50}, {5,-40 }, {14,-50 }, {23, -40}, {5,-30 }, {14,-40 }, {23, -30}, {5,-20 }, {14,-30 }, {23, -20}, {5,-10 }, {14,-20 }, {23, -10}, {5, 0 }, {14,-10 }, {23, 0}, };*/ POINT GlideBar[6] = { {0,0},{9,-9},{18,0},{18,0},{9,0},{0,0} }; POINT GlideBar0[6] = { {0,0},{9,-9},{18,0},{18,0},{9,0},{0,0} }; TCHAR Value[10]; int Offset; int Offset0; int i; if (task.Valid()){ const int y0 = ( (rc.bottom - rc.top )/2)+rc.top; // 60 units is size, div by 8 means 60*8 = 480 meters. Offset = ((int)Calculated().TaskAltitudeDifference)/8; Offset0 = ((int)Calculated().TaskAltitudeDifference0)/8; // TODO feature: should be an angle if in final glide mode if(Offset > 60) Offset = 60; if(Offset < -60) Offset = -60; Offset = IBLSCALE(Offset); if(Offset<0) { GlideBar[1].y = IBLSCALE(9); } if(Offset0 > 60) Offset0 = 60; if(Offset0 < -60) Offset0 = -60; Offset0 = IBLSCALE(Offset0); if(Offset0<0) { GlideBar0[1].y = IBLSCALE(9); } for(i=0;i<6;i++) { GlideBar[i].y += y0; GlideBar[i].x = IBLSCALE(GlideBar[i].x)+rc.left; } GlideBar[0].y -= Offset; GlideBar[1].y -= Offset; GlideBar[2].y -= Offset; for(i=0;i<6;i++) { GlideBar0[i].y += y0; GlideBar0[i].x = IBLSCALE(GlideBar0[i].x)+rc.left; } GlideBar0[0].y -= Offset0; GlideBar0[1].y -= Offset0; GlideBar0[2].y -= Offset0; if ((Offset<0)&&(Offset0<0)) { // both below if (Offset0!= Offset) { int dy = (GlideBar0[0].y-GlideBar[0].y) +(GlideBar0[0].y-GlideBar0[3].y); dy = max(IBLSCALE(3), dy); GlideBar[3].y = GlideBar0[0].y-dy; GlideBar[4].y = GlideBar0[1].y-dy; GlideBar[5].y = GlideBar0[2].y-dy; GlideBar0[0].y = GlideBar[3].y; GlideBar0[1].y = GlideBar[4].y; GlideBar0[2].y = GlideBar[5].y; } else { Offset0 = 0; } } else if ((Offset>0)&&(Offset0>0)) { // both above GlideBar0[3].y = GlideBar[0].y; GlideBar0[4].y = GlideBar[1].y; GlideBar0[5].y = GlideBar[2].y; if (abs(Offset0-Offset)<IBLSCALE(4)) { Offset= Offset0; } } // draw actual glide bar if (Offset<=0) { if (Calculated().LandableReachable) { canvas.select(MapGfx.hpFinalGlideBelowLandable); canvas.select(MapGfx.hbFinalGlideBelowLandable); } else { canvas.select(MapGfx.hpFinalGlideBelow); canvas.select(MapGfx.hbFinalGlideBelow); } } else { canvas.select(MapGfx.hpFinalGlideAbove); canvas.select(MapGfx.hbFinalGlideAbove); } canvas.polygon(GlideBar, 6); // draw glide bar at mc 0 if (Offset0<=0) { if (Calculated().LandableReachable) { canvas.select(MapGfx.hpFinalGlideBelowLandable); canvas.hollow_brush(); } else { canvas.select(MapGfx.hpFinalGlideBelow); canvas.hollow_brush(); } } else { canvas.select(MapGfx.hpFinalGlideAbove); canvas.hollow_brush(); } if (Offset!=Offset0) { canvas.polygon(GlideBar0, 6); } // JMW draw x on final glide bar if unreachable at current Mc // hpAircraftBorder if ((Calculated().TaskTimeToGo>0.9*ERROR_TIME) || ((GlidePolar::GetMacCready()<0.01) && (Calculated().TaskAltitudeDifference<0))) { canvas.select(MapGfx.hpAircraftBorder); POINT Cross[4] = { {-5, -5}, { 5, 5}, {-5, 5}, { 5, -5} }; for (i=0; i<4; i++) { Cross[i].x = IBLSCALE(Cross[i].x+9); Cross[i].y = IBLSCALE(Cross[i].y+9)+y0; } canvas.polygon(Cross, 2); canvas.polygon(&Cross[2], 2); } if (Appearance.IndFinalGlide == fgFinalGlideDefault){ _stprintf(Value,TEXT("%1.0f "), ALTITUDEMODIFY*Calculated().TaskAltitudeDifference); if (Offset>=0) { Offset = GlideBar[2].y+Offset+IBLSCALE(5); } else { if (Offset0>0) { Offset = GlideBar0[1].y-IBLSCALE(15); } else { Offset = GlideBar[2].y+Offset-IBLSCALE(15); } } TextInBoxMode_t TextInBoxMode = {1|8}; TextInBox(canvas, Value, 0, (int)Offset, TextInBoxMode, rc); } else if (Appearance.IndFinalGlide == fgFinalGlideAltA){ SIZE TextSize; int y = GlideBar[3].y; // was ((rc.bottom - rc.top )/2)-rc.top- // Appearance.MapWindowBoldFont.CapitalHeight/2-1; int x = GlideBar[2].x+IBLSCALE(1); const Bitmap *Bmp; POINT BmpPos; POINT BmpSize; _stprintf(Value, TEXT("%1.0f"), Units::ToUserAltitude(Calculated().TaskAltitudeDifference)); canvas.select(MapWindowBoldFont); TextSize = canvas.text_size(Value); canvas.white_brush(); canvas.white_pen(); canvas.rectangle(x, y, x + IBLSCALE(1) + TextSize.cx, y + Appearance.MapWindowBoldFont.CapitalHeight + IBLSCALE(2)); canvas.text(x + IBLSCALE(1), y + Appearance.MapWindowBoldFont.CapitalHeight - Appearance.MapWindowBoldFont.AscentHeight + IBLSCALE(1), Value); if (Units::GetUnitBitmap(Units::GetUserAltitudeUnit(), &Bmp, &BmpPos, &BmpSize, 0)){ draw_bitmap(canvas, *Bmp, x + TextSize.cx + IBLSCALE(1), y, BmpPos.x, BmpPos.y, BmpSize.x, BmpSize.y, false); } } } }
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); } }
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 GLEnable blend(GL_BLEND); #endif RasterPoint GlideBar[6] = { { 0, 0 }, { 9, -9 }, { 18, 0 }, { 18, 0 }, { 9, 0 }, { 0, 0 } }; RasterPoint GlideBar0[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_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; PixelScalar dy_glidebar = 0; PixelScalar dy_glidebar0 = 0; FormatUserAltitude(solution.SelectAltitudeDifference(glide_settings), Value, false); canvas.Select(*look.font); const PixelSize text_size = canvas.CalcTextSize(Value); PixelScalar clipping_arrow_offset = Layout::Scale(4); PixelScalar 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 / 9; 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 / 9; 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 && (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); }
// 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); }
// // Called by LKDrawLook8000, this is what happens when we change mapspace mode, advancing through types. // We paint infopages, nearest, tri, etc.etc. // Normally there is plenty of cpu available because the map is not even calculated. // This is why we bring to the Draw thread, in the nearest pages case, also calculations. // void MapWindow::DrawMapSpace(HDC hdc, RECT rc ) { HFONT oldfont; HBRUSH hB; TextInBoxMode_t TextDisplayMode = {0}; TCHAR Buffer[LKSIZEBUFFERLARGE*2]; #ifdef DRAWLKSTATUS bool dodrawlkstatus=false; #endif static POINT p[10]; if (MapSpaceMode==MSM_WELCOME) { if (INVERTCOLORS) hB=LKBrush_Petrol; else hB=LKBrush_Mlight; } else { if (INVERTCOLORS) hB=LKBrush_Mdark; else hB=LKBrush_Mlight; } oldfont = (HFONT)SelectObject(hdc, LKINFOFONT); // save font if (MapSpaceMode!=MSM_WELCOME) FillRect(hdc,&rc, hB); if (DoInit[MDI_DRAWMAPSPACE]) { p[0].x=0; p[0].y=rc.bottom-BottomSize-NIBLSCALE(2); p[1].x=rc.right-1; p[1].y=p[0].y; p[2].x=0; p[2].y=0; p[3].x=rc.right-1; p[3].y=0; // 091230 right-1 p[4].x=0; p[4].y=0; p[5].x=0; p[5].y=rc.bottom-BottomSize-NIBLSCALE(2); p[6].x=rc.right-1; p[6].y=0; p[7].x=rc.right-1; p[7].y=rc.bottom-BottomSize-NIBLSCALE(2); // 091230 right-1 // p[8].x=0; p[8].y=rc.bottom-BottomSize-NIBLSCALE(2); p[9].x=rc.right; p[9].y=p[8].y; /* StartupStore(_T("DOINIT DRAWMAPSPACE 21=%d=%d 22=%d=%d 23=%d=%d 24=%d=%d 31=%d=%d 32=%d=%d\n"), ConfIP[LKMODE_WP][0],ConfIP21, ConfIP[LKMODE_WP][1],ConfIP22, ConfIP[LKMODE_WP][2],ConfIP23, ConfIP[LKMODE_WP][3],ConfIP24, ConfIP[LKMODE_NAV][0],ConfIP31, ConfIP[LKMODE_NAV][1],ConfIP32); */ if (MapSpaceMode==MSM_WELCOME) LoadSplash(hdc,_T("LKPROFILE")); DoInit[MDI_DRAWMAPSPACE]=false; } // Paint borders in green, but only in nearest pages and welcome if (MapSpaceMode==MSM_WELCOME || (!IsMultiMap() && MapSpaceMode!=MSM_MAP) ) { if (INVERTCOLORS) { _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[2], p[3], RGB_GREEN, rc); _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[4], p[5], RGB_GREEN, rc); _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[6], p[7], RGB_GREEN, rc); _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[0], p[1], RGB_GREEN, rc); } else { _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[2], p[3], RGB_DARKGREEN, rc); _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[4], p[5], RGB_DARKGREEN, rc); _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[6], p[7], RGB_DARKGREEN, rc); _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[0], p[1], RGB_DARKGREEN, rc); } } #ifdef DRAWLKSTATUS if (LKevent==LKEVENT_NEWRUN) dodrawlkstatus=true; #endif // We are entering mapspacemodes with no initial check on configured subpages. // Thus we need to ensure that the page is really available, or find the first valid. // However, this will prevent direct customkey access to pages! // Instead, we do it when we call next page from InfoPageChange // if (!ConfIP[ModeIndex][CURTYPE]) NextModeType(); switch (MapSpaceMode) { case MSM_WELCOME: #if (1) if (!DrawInfo.NAVWarning) { static double firsttime=DrawInfo.Time; // delayed automatic exit from welcome mode if ( DrawInfo.Time > (firsttime+1.0) ) { SetModeType(LKMODE_MAP,MP_MOVING); LKevent=LKEVENT_NONE; if (EnableSoundModes) LKSound(_T("LK_BEEP1.WAV")); RefreshMap(); break; } } #endif if(GlobalModelType==MODELTYPE_PNA_MINIMAP) { SetModeType(LKMODE_MAP,MP_MOVING); LKevent=LKEVENT_NONE; break; } DrawWelcome8000(hdc, rc); break; case MSM_MAPTRK: SetSideviewPage(IM_HEADING); LKDrawMultimap_Asp(hdc,rc); break; case MSM_MAPWPT: #if 0 // If there is no destination, force jump to the map if (GetOvertargetIndex()<0) { SetModeType(LKMODE_MAP,MP_MOVING); LKevent=LKEVENT_NONE; break; } #endif SetSideviewPage(IM_NEXT_WP); LKDrawMultimap_Asp(hdc,rc); break; case MSM_MAPASP: SetSideviewPage(IM_NEAR_AS); LKDrawMultimap_Asp(hdc,rc); break; case MSM_MAPRADAR: LKDrawMultimap_Radar(hdc,rc); break; case MSM_VISUALGLIDE: SetSideviewPage(IM_VISUALGLIDE); LKDrawMultimap_Asp(hdc,rc); break; case MSM_MAPTEST: LKDrawMultimap_Test(hdc,rc); break; case MSM_LANDABLE: case MSM_NEARTPS: case MSM_AIRPORTS: DrawNearest(hdc, rc); break; case MSM_AIRSPACES: DrawAspNearest(hdc, rc); break; case MSM_COMMON: case MSM_RECENT: DrawCommon(hdc, rc); break; case MSM_MAP: break; case MSM_INFO_THERMAL: case MSM_INFO_CRUISE: case MSM_INFO_TASK: case MSM_INFO_AUX: case MSM_INFO_TRI: case MSM_INFO_HSI: case MSM_INFO_TRF: case MSM_INFO_TARGET: case MSM_INFO_CONTEST: DrawInfoPage(hdc,rc, false); break; case MSM_TRAFFIC: DrawTraffic(hdc,rc); break; case MSM_THERMALS: DrawThermalHistory(hdc,rc); break; default: memset((void*)&TextDisplayMode, 0, sizeof(TextDisplayMode)); TextDisplayMode.Color = RGB_WHITE; TextDisplayMode.NoSetFont = 1; TextDisplayMode.AlligneCenter = 1; SelectObject(hdc, LK8TargetFont); _stprintf(Buffer,TEXT("MapSpaceMode=%d"),MapSpaceMode); TextInBox(hdc, &rc, Buffer, (rc.right-rc.left)/2, NIBLSCALE(50) , 0, &TextDisplayMode, false); break; } #ifdef DRAWLKSTATUS // no need to clear dodrawlkstatus, it is already reset at each run if (dodrawlkstatus) DrawLKStatus(hdc, rc); #endif SelectObject(hdc, oldfont); }
// // Called by DrawThread // void MapWindow::DrawLKAlarms(HDC hDC, const RECT rc) { static unsigned short displaycounter=0; static short oldvalidalarm=-1; short validalarm=-1; // Alarms are working only with a valid GPS fix. No navigator, no alarms. if (DrawInfo.NAVWarning) return; // give priority to the lowest alarm in list if (CheckAlarms(2)) validalarm=2; if (CheckAlarms(1)) validalarm=1; if (CheckAlarms(0)) validalarm=0; // If we have a new alarm, play sound if available and enabled if (validalarm>=0) { if (EnableSoundModes) { switch (validalarm) { case 0: LKSound(_T("LK_ALARM_ALT1.WAV")); break; case 1: LKSound(_T("LK_ALARM_ALT2.WAV")); break; case 2: LKSound(_T("LK_ALARM_ALT3.WAV")); break; default: break; } } displaycounter=12; // seconds to display alarm on screen, resetting anything set previously } // Now paint message, even for passed alarms if (displaycounter) { if (--displaycounter>60) displaycounter=0; // safe check TCHAR textalarm[100]; short currentalarm=0; if (validalarm>=0) { currentalarm=validalarm; oldvalidalarm=validalarm; } else if (oldvalidalarm>=0) currentalarm=oldvalidalarm; // safety check switch(currentalarm) { case 0: case 1: case 2: wsprintf(textalarm,_T("%s %d: %s %d"), gettext(_T("_@M1650_")), currentalarm+1, gettext(_T("_@M1651_")), // ALARM ALTITUDE ((int)((double)LKalarms[currentalarm].triggervalue*ALTITUDEMODIFY))); break; default: break; } HFONT oldfont=NULL; if (ScreenLandscape) oldfont=(HFONT)SelectObject(hDC,LK8TargetFont); else oldfont=(HFONT)SelectObject(hDC,LK8MediumFont); TextInBoxMode_t TextInBoxMode = {0}; TextInBoxMode.Color = RGB_WHITE; TextInBoxMode.NoSetFont=1; TextInBoxMode.AlligneCenter = 1; TextInBoxMode.WhiteBorder = 1; TextInBoxMode.Border = 1; // same position for gps warnings: if navwarning, then no alarms. So no overlapping. TextInBox(hDC, &rc, textalarm , (rc.right-rc.left)/2, (rc.bottom-rc.top)/3, 0, &TextInBoxMode); SelectObject(hDC,oldfont); } }
void FinalGlideBarRenderer::Draw(Canvas &canvas, const PixelRect &rc, const DerivedInfo &calculated) const { RasterPoint GlideBar[6] = { { 0, 0 }, { 9, -9 }, { 18, 0 }, { 18, 0 }, { 9, 0 }, { 0, 0 } }; RasterPoint GlideBar0[6] = { { 0, 0 }, { 9, -9 }, { 18, 0 }, { 18, 0 }, { 9, 0 }, { 0, 0 } }; TCHAR Value[10]; if (!calculated.task_stats.task_valid || !calculated.task_stats.total.solution_remaining.IsOk() || !calculated.task_stats.total.solution_mc0.IsDefined()) return; const int y0 = (rc.bottom + rc.top) / 2; // 60 units is size, div by 8 means 60*8 = 480 meters. int Offset = ((int)calculated.task_stats.total.solution_remaining.altitude_difference) / 8; int Offset0 = ((int)calculated.task_stats.total.solution_mc0.altitude_difference) / 8; // TODO feature: should be an angle if in final glide mode if (Offset > 60) Offset = 60; if (Offset < -60) Offset = -60; Offset = Layout::Scale(Offset); if (Offset < 0) GlideBar[1].y = Layout::Scale(9); if (Offset0 > 60) Offset0 = 60; if (Offset0 < -60) Offset0 = -60; Offset0 = Layout::Scale(Offset0); if (Offset0 < 0) GlideBar0[1].y = Layout::Scale(9); for (unsigned i = 0; i < 6; i++) { GlideBar[i].y += y0; 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 < 6; i++) { GlideBar0[i].y += y0; GlideBar0[i].x = Layout::Scale(GlideBar0[i].x) + rc.left; } GlideBar0[0].y -= Offset0; GlideBar0[1].y -= Offset0; GlideBar0[2].y -= Offset0; if ((Offset < 0) && (Offset0 < 0)) { // both below if (Offset0 != Offset) { PixelScalar dy = (GlideBar0[0].y - GlideBar[0].y) + (GlideBar0[0].y - GlideBar0[3].y); dy = max(Layout::Scale(3), dy); GlideBar[3].y = GlideBar0[0].y - dy; GlideBar[4].y = GlideBar0[1].y - dy; GlideBar[5].y = GlideBar0[2].y - dy; GlideBar0[0].y = GlideBar[3].y; GlideBar0[1].y = GlideBar[4].y; GlideBar0[2].y = GlideBar[5].y; } else { Offset0 = 0; } } else if ((Offset > 0) && (Offset0 > 0)) { // both above GlideBar0[3].y = GlideBar[0].y; GlideBar0[4].y = GlideBar[1].y; GlideBar0[5].y = GlideBar[2].y; if (abs(Offset0 - Offset) < Layout::Scale(4)) Offset = Offset0; } // draw actual glide bar if (Offset <= 0) { if (calculated.common_stats.landable_reachable) { canvas.Select(look.hpFinalGlideBelowLandable); canvas.Select(look.hbFinalGlideBelowLandable); } else { canvas.Select(look.hpFinalGlideBelow); canvas.Select(look.hbFinalGlideBelow); } } else { canvas.Select(look.hpFinalGlideAbove); canvas.Select(look.hbFinalGlideAbove); } canvas.polygon(GlideBar, 6); // draw glide bar at mc 0 if (Offset0 <= 0) { if (calculated.common_stats.landable_reachable) { canvas.Select(look.hpFinalGlideBelowLandable); canvas.SelectHollowBrush(); } else { canvas.Select(look.hpFinalGlideBelow); canvas.SelectHollowBrush(); } } else { canvas.Select(look.hpFinalGlideAbove); canvas.SelectHollowBrush(); } if (Offset != Offset0) canvas.polygon(GlideBar0, 6); // 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 (!calculated.task_stats.total.IsAchievable()) cross_sign = 1; if (calculated.terrain_warning && (Offset>0)) cross_sign = -1; if (cross_sign != 0) { canvas.Select(task_look.bearing_pen); canvas.line(Layout::Scale(9 - 5), y0 + cross_sign * Layout::Scale(9 - 5), Layout::Scale(9 + 5), y0 + cross_sign * Layout::Scale(9 + 5)); canvas.line(Layout::Scale(9 - 5), y0 + cross_sign * Layout::Scale(9 + 5), Layout::Scale(9 + 5), y0 + cross_sign * Layout::Scale(9 - 5)); } Units::FormatUserAltitude(calculated.task_stats.total.solution_remaining.altitude_difference, Value, ARRAY_SIZE(Value), false); if (Offset >= 0) Offset = GlideBar[2].y + Offset + Layout::Scale(5); else if (Offset0 > 0) Offset = GlideBar0[1].y - Layout::Scale(15); else Offset = GlideBar[2].y + Offset - Layout::Scale(15); canvas.SetTextColor(COLOR_BLACK); canvas.SetBackgroundColor(COLOR_WHITE); TextInBoxMode style; style.mode = RM_ROUNDED_BLACK; style.bold = true; style.move_in_view = true; TextInBox(canvas, Value, 0, (int)Offset, style, rc); }
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 MapWindow::DrawWaypointsNew(HDC hdc, const RECT rc) { unsigned int i; int bestwp=-1; TCHAR Buffer[LKSIZEBUFFER]; TCHAR Buffer2[LKSIZEBUFFER]; TCHAR sAltUnit[LKSIZEBUFFERUNIT]; TextInBoxMode_t TextDisplayMode = {0}; static int resizer[10]={ 20,20,20,3,5,8,10,12,0 }; // if pan mode, show full names int pDisplayTextType = DisplayTextType; if (!WayPointList) return; _tcscpy(sAltUnit, Units::GetAltitudeName()); MapWaypointLabelListCount = 0; int arrivalcutoff=0, foundairport=0; bool isairport; bool islandpoint; // setting decluttericons will not paint outlanding, and use minrunway to declutter even more bool decluttericons=false; // inrange : max scale allowed to print non-landable waypoints bool inrange=true; // minimal size of a runway to paint it while decluttering int minrunway=0; // // RealScale // // 2km 1.42 // 3.5km 2.5 // 5km 3.57 // 7.5km 5.35 // 10km 7.14 // 15km 10.71 // 20km 14.28 // 25km 17.85 // 40km 28.57 // 50km 35.71 // 75km 53.57 switch(DeclutterMode) { case dmDisabled: //inrange=(MapWindow::zoom.RealScale() <=18 ? true:false); // 17.85, 25km scale inrange=(MapWindow::zoom.RealScale() <=15 ? true:false); // 14.28, 20km scale decluttericons=false; break; case dmLow: inrange=(MapWindow::zoom.RealScale() <=11 ? true:false); // 10.71, 15km scale decluttericons=(MapWindow::zoom.RealScale() >=14 ? true : false); minrunway=200; break; case dmMedium: inrange=(MapWindow::zoom.RealScale() <=10 ? true:false); decluttericons=(MapWindow::zoom.RealScale() >=10 ? true : false); minrunway=400; break; case dmHigh: inrange=(MapWindow::zoom.RealScale() <=10 ? true:false); decluttericons=(MapWindow::zoom.RealScale() >=10 ? true : false); minrunway=800; break; case dmVeryHigh: inrange=(MapWindow::zoom.RealScale() <=10 ? true:false); decluttericons=(MapWindow::zoom.RealScale() >=10 ? true : false); minrunway=1600; break; default: LKASSERT(0); break; } if (MapWindow::zoom.RealScale() <=20) for(i=0;i<NumberOfWayPoints;i++) { if (WayPointList[i].Visible != TRUE ) continue; // false may not be FALSE? if (WayPointCalc[i].IsAirport) { if (WayPointList[i].Reachable == FALSE) { SelectObject(hDCTemp,hBmpAirportUnReachable); } else { SelectObject(hDCTemp,hBmpAirportReachable); if ( arrivalcutoff < (int)(WayPointList[i].AltArivalAGL)) { arrivalcutoff = (int)(WayPointList[i].AltArivalAGL); bestwp=i; foundairport++; } } } else { if ( WayPointCalc[i].IsOutlanding ) { // outlanding if (WayPointList[i].Reachable == FALSE) SelectObject(hDCTemp,hBmpFieldUnReachable); else { SelectObject(hDCTemp,hBmpFieldReachable); // get the outlanding as bestwp only if no other choice if (foundairport == 0) { // do not set arrivalcutoff: any next reachable airport is better than an outlanding if ( arrivalcutoff < (int)(WayPointList[i].AltArivalAGL)) bestwp=i; } } } else continue; // do not draw icons for normal turnpoints here } if(Appearance.IndLandable == wpLandableDefault) { double fScaleFact =MapWindow::zoom.RealScale(); if(fScaleFact < 0.1) fScaleFact = 0.1; // prevent division by zero fScaleFact = zoom.DrawScale(); if(fScaleFact > 20000.0) fScaleFact = 20000.0; // limit to prevent huge airfiel symbols if(fScaleFact < 1600) fScaleFact = 1600; // limit to prevent tiny airfiel symbols if (decluttericons) { if (WayPointCalc[i].IsAirport && (WayPointList[i].RunwayLen>minrunway || WayPointList[i].RunwayLen==0)) { DrawRunway(hdc,&WayPointList[i],rc, fScaleFact); } } else DrawRunway(hdc,&WayPointList[i],rc, fScaleFact); } else { DrawBitmapX(hdc, WayPointList[i].Screen.x-10, WayPointList[i].Screen.y-10, 20,20, hDCTemp,0,0,SRCPAINT,false); DrawBitmapX(hdc, WayPointList[i].Screen.x-10, WayPointList[i].Screen.y-10, 20,20, hDCTemp,20,0,SRCAND,false); } } // for all waypoints if (foundairport==0 && bestwp>=0) arrivalcutoff = (int)WayPointList[bestwp].AltArivalAGL; for(i=0;i<NumberOfWayPoints;i++) { if(WayPointList[i].Visible ) { bool irange = false; bool intask = false; bool islandable; // isairport+islandpoint bool excluded=false; bool dowrite; intask = WaypointInTask(i); dowrite = intask; // initially set only for intask memset((void*)&TextDisplayMode, 0, sizeof(TextDisplayMode)); // airports are also landpoints. should be better handled isairport=((WayPointList[i].Flags & AIRPORT) == AIRPORT); islandpoint=((WayPointList[i].Flags & LANDPOINT) == LANDPOINT); islandable=WayPointCalc[i].IsLandable; // always in range if MapScale <=10 irange = inrange; if(MapWindow::zoom.RealScale() > 20) { SelectObject(hDCTemp,hInvSmall); irange=false; goto NiklausWirth; // with compliments } if (decluttericons) { if (! (WayPointCalc[i].IsAirport && (WayPointList[i].RunwayLen>minrunway || WayPointList[i].RunwayLen==0))) { SelectObject(hDCTemp,hInvSmall); irange=false; goto NiklausWirth; } } if( islandable ) { if(WayPointList[i].Reachable){ TextDisplayMode.Reachable = 1; if ( isairport ) SelectObject(hDCTemp,hBmpAirportReachable); else SelectObject(hDCTemp,hBmpFieldReachable); if ((GetMultimap_Labels()<MAPLABELS_ALLOFF)||intask) { dowrite = true; // exclude outlandings worst than visible airports, only when there are visible reachable airports! if ( isairport==false && islandpoint==true ) { if ( (int)WayPointList[i].AltArivalAGL >=2000 ) { // more filter excluded=true; } else { if ( (bestwp>=0) && (i==(unsigned)bestwp) && (foundairport==0) ) { // this outlanding is the best option isairport=true; islandpoint=false; // make it an airport TODO paint it as best } else { if ( foundairport >0 ) { if ( (int)WayPointList[i].AltArivalAGL <= arrivalcutoff ) { excluded=true; } } } } } else // do not display airport arrival if close to the best so far. // ex: best arrival is 1200m, include onlye below 1200/4 (prevent division by zero) // This way we only display far points, and skip closer points // WE NEED MORE INFO ABOUT LANDING POINTS: THE .CUP FORMAT WILL LET US KNOW WHAT IS // BEST TO SHOW AND WHAT IS NOT. Winpilot format is useless here. { dowrite=true;// TEST FIX not necessary probably // it's an airport if ( (bestwp>=0) && (i != (unsigned)bestwp) && (arrivalcutoff>600) ) { if ( (arrivalcutoff / ((int)WayPointList[i].AltArivalAGL+1))<4 ) { excluded=true; } } } } } else // landable waypoint is unreachable { dowrite=true; if ( isairport ) { SelectObject(hDCTemp,hBmpAirportUnReachable); } else { SelectObject(hDCTemp,hBmpFieldUnReachable); } } } else { // waypoint is an ordinary turnpoint if(MapWindow::zoom.RealScale() > 4) { if (BlackScreen) SelectObject(hDCTemp,hInvSmall); else SelectObject(hDCTemp,hSmall); } else { if (BlackScreen) SelectObject(hDCTemp,hInvTurnPoint); else SelectObject(hDCTemp,hTurnPoint); } } // end landable-not landable NiklausWirth: if (intask || (OutlinedTp==(OutlinedTp_t)otAll) ) { TextDisplayMode.WhiteBold = 1; TextDisplayMode.Color=RGB_WHITE; } // No matter of how we thought to draw it, let it up to the user.. switch(NewMapDeclutter) { case 0: excluded=false; // no decluttering: show all airports and outlandings break; case 1: if ( isairport ) excluded=false; // show all airports, declutter outlandings break; default: break; // else work normally } // here come both turnpoints and landables.. if( intask || irange || dowrite) { // irange always set when MapScale <=10 bool draw_alt = TextDisplayMode.Reachable && ((GetMultimap_Labels()<MAPLABELS_ONLYTOPO) || intask); // 100711 reachable landing point! if (excluded==true) draw_alt=false; // exclude close outlandings switch(pDisplayTextType) { case DISPLAYNAME: case DISPLAYFIRSTTHREE: case DISPLAYFIRSTFIVE: case DISPLAYFIRST8: case DISPLAYFIRST10: case DISPLAYFIRST12: dowrite = (GetMultimap_Labels()<MAPLABELS_ONLYTOPO) || intask || islandable; // 100711 if ( (islandable && !isairport) && MapWindow::zoom.RealScale() >=10 ) dowrite=0; // FIX then no need to go further // 101215 if (DisplayTextType == DISPLAYNAME) { _tcscpy(Buffer2,WayPointList[i].Name); } else { LK_tcsncpy(Buffer2, WayPointList[i].Name, resizer[DisplayTextType]); } // ConvToUpper(Buffer2); if (draw_alt) { if ( ArrivalValue == (ArrivalValue_t) avAltitude ) { if ( (MapBox == (MapBox_t)mbUnboxedNoUnit) || (MapBox == (MapBox_t)mbBoxedNoUnit) ) wsprintf(Buffer, TEXT("%s:%d"), Buffer2, (int)(WayPointList[i].AltArivalAGL*ALTITUDEMODIFY)); else wsprintf(Buffer, TEXT("%s:%d%s"), Buffer2, (int)(WayPointList[i].AltArivalAGL*ALTITUDEMODIFY), sAltUnit); } else wsprintf(Buffer, TEXT("%s:%d"), Buffer2, (int)WayPointCalc[i].GR); if ( (MapBox == (MapBox_t)mbBoxed) || (MapBox == (MapBox_t)mbBoxedNoUnit)) { TextDisplayMode.Border = 1; TextDisplayMode.WhiteBold = 0; } else TextDisplayMode.WhiteBold = 1; // outlined TextDisplayMode.Color=RGB_WHITE; } else { //wsprintf(Buffer, TEXT("%s"),Buffer2); _tcscpy(Buffer,Buffer2); if (islandable && isairport) { TextDisplayMode.WhiteBold = 1; // outlined TextDisplayMode.Color=RGB_WHITE; } } break; case DISPLAYNUMBER: dowrite = (GetMultimap_Labels()<MAPLABELS_ONLYTOPO) || intask || islandable; if ( (islandable && !isairport) && MapWindow::zoom.RealScale() >=10 ) dowrite=0; // FIX then no need to go further if (draw_alt) { if ( ArrivalValue == (ArrivalValue_t) avAltitude ) { if ( (MapBox == (MapBox_t)mbUnboxedNoUnit) || (MapBox == (MapBox_t)mbBoxedNoUnit) ) wsprintf(Buffer, TEXT("%d:%d"), WayPointList[i].Number, (int)(WayPointList[i].AltArivalAGL*ALTITUDEMODIFY)); else wsprintf(Buffer, TEXT("%d:%d%s"), WayPointList[i].Number, (int)(WayPointList[i].AltArivalAGL*ALTITUDEMODIFY), sAltUnit); } else wsprintf(Buffer, TEXT("%d:%d"), WayPointList[i].Number, (int)(WayPointCalc[i].GR)); if ( (MapBox == (MapBox_t)mbBoxed) || (MapBox == (MapBox_t)mbBoxedNoUnit)) { TextDisplayMode.Border = 1; TextDisplayMode.WhiteBold = 0; } else TextDisplayMode.WhiteBold = 1; // outlined TextDisplayMode.Color=RGB_WHITE; } else { wsprintf(Buffer, TEXT("%d"),WayPointList[i].Number); if (islandable && isairport) { TextDisplayMode.WhiteBold = 1; // outlined TextDisplayMode.Color=RGB_WHITE; } } break; case DISPLAYNAMEIFINTASK: dowrite = intask; if (intask) { if (draw_alt) { if ( ArrivalValue == (ArrivalValue_t) avAltitude ) { if ( (MapBox == (MapBox_t)mbUnboxedNoUnit) || (MapBox == (MapBox_t)mbBoxedNoUnit) ) wsprintf(Buffer, TEXT("%s:%d"), WayPointList[i].Name, (int)(WayPointList[i].AltArivalAGL*ALTITUDEMODIFY)); else wsprintf(Buffer, TEXT("%s:%d%s"), WayPointList[i].Name, (int)(WayPointList[i].AltArivalAGL*ALTITUDEMODIFY), sAltUnit); } else wsprintf(Buffer, TEXT("%s:%d"), WayPointList[i].Name, (int)(WayPointCalc[i].GR)); if ( (MapBox == (MapBox_t)mbBoxed) || (MapBox == (MapBox_t)mbBoxedNoUnit)) { TextDisplayMode.Border = 1; TextDisplayMode.WhiteBold = 0; } else TextDisplayMode.WhiteBold = 1; // outlined TextDisplayMode.Color=RGB_WHITE; } else { wsprintf(Buffer, TEXT("%s"),WayPointList[i].Name); // TODO CHECK THIS, UNTESTED.. if (islandable && isairport) { TextDisplayMode.WhiteBold = 1; // outlined TextDisplayMode.Color=RGB_WHITE; } } } else { wsprintf(Buffer, TEXT(" ")); dowrite=true; } break; case DISPLAYNONE: dowrite = (GetMultimap_Labels()<MAPLABELS_ONLYTOPO) || intask || islandable; if (draw_alt) { if ( ArrivalValue == (ArrivalValue_t) avAltitude ) { if ( (MapBox == (MapBox_t)mbUnboxedNoUnit) || (MapBox == (MapBox_t)mbBoxedNoUnit) ) wsprintf(Buffer, TEXT("%d"), (int)(WayPointList[i].AltArivalAGL*ALTITUDEMODIFY)); else wsprintf(Buffer, TEXT("%d%s"), (int)(WayPointList[i].AltArivalAGL*ALTITUDEMODIFY), sAltUnit); } else wsprintf(Buffer, TEXT("%d"), (int)(WayPointCalc[i].GR) ); if ( (MapBox == (MapBox_t)mbBoxed) || (MapBox == (MapBox_t)mbBoxedNoUnit)) { TextDisplayMode.Border = 1; TextDisplayMode.WhiteBold = 0; } else TextDisplayMode.WhiteBold = 1; // outlined TextDisplayMode.Color=RGB_WHITE; } else { wsprintf(Buffer, TEXT(" ")); } break; default: #if (WINDOWSPC<1) //ASSERT(0); #endif break; } // end intask/irange/dowrite if (MapWindow::zoom.RealScale()<20 && islandable && dowrite) { TextInBox(hdc, &rc, Buffer, WayPointList[i].Screen.x+5, WayPointList[i].Screen.y, 0, &TextDisplayMode, true); dowrite=false; // do not pass it along } // Do not show takeoff for gliders, check TakeOffWayPoint if (i==RESWP_TAKEOFF) { if (TakeOffWayPoint) { intask=false; // 091031 let TAKEOFF be decluttered WayPointList[i].Visible=TRUE; } else { WayPointList[i].Visible=FALSE; dowrite=false; } } if(i==RESWP_OPTIMIZED) { dowrite = DoOptimizeRoute(); } if (dowrite) { MapWaypointLabelAdd( Buffer, WayPointList[i].Screen.x+5, WayPointList[i].Screen.y, &TextDisplayMode, (int)(WayPointList[i].AltArivalAGL*ALTITUDEMODIFY), intask,islandable,isairport,excluded,i,WayPointList[i].Style); } } // end if intask { ; } } // if visible } // for all waypoints qsort(&MapWaypointLabelList, MapWaypointLabelListCount, sizeof(MapWaypointLabel_t), MapWaypointLabelListCompare); int j; // now draw task/landable waypoints in order of range (closest last) // writing unconditionally for (j=MapWaypointLabelListCount-1; j>=0; j--){ MapWaypointLabel_t *E = &MapWaypointLabelList[j]; // draws if they are in task unconditionally, // otherwise, does comparison if ( E->inTask || (E->isLandable && !E->isExcluded) ) { TextInBox(hdc, &rc, E->Name, E->Pos.x, E->Pos.y, 0, &(E->Mode), false); // At low zoom, dont print the bitmap because drawn task would make it look offsetted if(MapWindow::zoom.RealScale() > 2) continue; // If we are at low zoom, use a dot for icons, so we dont clutter the screen if(MapWindow::zoom.RealScale() > 1) { if (BlackScreen) SelectObject(hDCTemp,hInvSmall); else SelectObject(hDCTemp,hSmall); } else { if (BlackScreen) SelectObject(hDCTemp,hInvTurnPoint); else SelectObject(hDCTemp,hTurnPoint); } DrawBitmapX(hdc, E->Pos.x-10, E->Pos.y-10, 20,20, hDCTemp,0,0,SRCPAINT,false); DrawBitmapX(hdc, E->Pos.x-10, E->Pos.y-10, 20,20, hDCTemp,20,0,SRCAND,false); } // wp in task } // for all waypoint, searching for those in task // now draw normal waypoints in order of range (furthest away last) // without writing over each other (or the task ones) for (j=0; j<MapWaypointLabelListCount; j++) { MapWaypointLabel_t *E = &MapWaypointLabelList[j]; if (!E->inTask && !E->isLandable ) { if ( TextInBox(hdc, &rc, E->Name, E->Pos.x, E->Pos.y, 0, &(E->Mode), true) == true) { // If we are at low zoom, use a dot for icons, so we dont clutter the screen if(MapWindow::zoom.RealScale() > 4) { if (BlackScreen) SelectObject(hDCTemp,hInvSmall); else SelectObject(hDCTemp,hSmall); } else { // We switch all styles in the correct order, to force a jump table by the compiler // It would be much better to use an array of bitmaps, but no time to do it for 3.0 switch(E->style) { case STYLE_NORMAL: goto turnpoint; break; // These are not used here in fact case STYLE_AIRFIELDGRASS: case STYLE_OUTLANDING: case STYLE_GLIDERSITE: case STYLE_AIRFIELDSOLID: goto turnpoint; break; case STYLE_MTPASS: SelectObject(hDCTemp,hMountpass); break; case STYLE_MTTOP: SelectObject(hDCTemp,hMountop); break; case STYLE_SENDER: SelectObject(hDCTemp,hSender); break; case STYLE_VOR: goto turnpoint; break; case STYLE_NDB: SelectObject(hDCTemp,hNdb); break; case STYLE_COOLTOWER: goto turnpoint; break; case STYLE_DAM: SelectObject(hDCTemp,hDam); break; case STYLE_TUNNEL: goto turnpoint; break; case STYLE_BRIDGE: SelectObject(hDCTemp,hBridge); break; case STYLE_POWERPLANT: case STYLE_CASTLE: goto turnpoint; break; case STYLE_INTERSECTION: SelectObject(hDCTemp,hIntersect); break; case STYLE_TRAFFIC: goto turnpoint; break; case STYLE_THERMAL: SelectObject(hDCTemp,hLKThermal); break; case STYLE_MARKER: SelectObject(hDCTemp,hBmpMarker); break; default: turnpoint: if (BlackScreen) SelectObject(hDCTemp,hInvTurnPoint); else SelectObject(hDCTemp,hTurnPoint); break; } // switch estyle } // below zoom threshold // We dont do stretching here. We are using different bitmaps for hi res. // The 20x20 size is large enough to make much bigger icons than the old ones. DrawBitmapX(hdc, E->Pos.x-10, E->Pos.y-10, 20,20, hDCTemp,0,0,SRCPAINT,false); DrawBitmapX(hdc, E->Pos.x-10, E->Pos.y-10, 20,20, hDCTemp,20,0,SRCAND,false); } } } } // end DrawWaypoint
void GlueMapWindow::DrawMapScale(Canvas &canvas, const PixelRect &rc, const MapWindowProjection &projection) const { if (!projection.IsValid()) return; StaticString<80> buffer; fixed map_width = projection.GetScreenWidthMeters(); const Font &font = *look.overlay_font; canvas.Select(font); FormatUserMapScale(map_width, buffer.buffer(), true); PixelSize text_size = canvas.CalcTextSize(buffer); const PixelScalar text_padding_x = Layout::GetTextPadding(); const PixelScalar height = font.GetCapitalHeight() + Layout::GetTextPadding(); PixelScalar x = 0; look.map_scale_left_icon.Draw(canvas, 0, rc.bottom - height); x += look.map_scale_left_icon.GetSize().cx; canvas.DrawFilledRectangle(x, rc.bottom - height, x + 2 * text_padding_x + text_size.cx, rc.bottom, COLOR_WHITE); canvas.SetBackgroundTransparent(); canvas.SetTextColor(COLOR_BLACK); x += text_padding_x; canvas.DrawText(x, rc.bottom - font.GetAscentHeight() - Layout::Scale(1), buffer); x += text_padding_x + text_size.cx; look.map_scale_right_icon.Draw(canvas, x, rc.bottom - height); buffer.clear(); if (GetMapSettings().auto_zoom_enabled) buffer = _T("AUTO "); switch (follow_mode) { case FOLLOW_SELF: break; case FOLLOW_PAN: buffer += _T("PAN "); break; } const UIState &ui_state = GetUIState(); if (ui_state.auxiliary_enabled) { buffer += ui_state.panel_name; buffer += _T(" "); } if (Basic().gps.replay) buffer += _T("REPLAY "); else if (Basic().gps.simulator) { buffer += _("Simulator"); buffer += _T(" "); } if (GetComputerSettings().polar.ballast_timer_active) buffer.AppendFormat( _T("BALLAST %d LITERS "), (int)GetComputerSettings().polar.glide_polar_task.GetBallastLitres()); if (weather != nullptr && weather->GetParameter() > 0) { const TCHAR *label = weather->ItemLabel(weather->GetParameter()); if (label != nullptr) buffer += label; } if (!buffer.empty()) { int y = rc.bottom - height; TextInBoxMode mode; mode.vertical_position = TextInBoxMode::VerticalPosition::ABOVE; mode.shape = LabelShape::OUTLINED; TextInBox(canvas, buffer, 0, y, mode, rc, nullptr); } }
void MapWindow::DrawGlideThroughTerrain(LKSurface& Surface, const RECT& rc) { LKPen hpOld; //double h,dh; TCHAR hbuf[10]; static bool doinit=true; static TextInBoxMode_t tmode = {0}; bool wrotevalue=false; if (doinit) { memset((void*)&tmode, 0, sizeof(TextInBoxMode_t)); tmode.Border=1; doinit=false; } #ifdef GTL2 bool ValidTP = ValidTaskPoint(ActiveWayPoint); // draw glide terrain line around next WP bool DrawGTL2 = ValidTP && (FinalGlideTerrain > 2); static bool LastDrewGTL2 = false; if (DrawGTL2) { int wp_index = (DoOptimizeRoute() || ACTIVE_WP_IS_AAT_AREA) ? RESWP_OPTIMIZED : TASKINDEX; double alt_arriv = WayPointCalc[wp_index].AltArriv[AltArrivMode]; // Calculate arrival altitude at the next waypoint relative to // the "terrain height" safety setting. if (CheckSafetyAltitudeApplies(wp_index)) alt_arriv += SAFETYALTITUDEARRIVAL/10; // AGL alt_arriv -= SAFETYALTITUDETERRAIN/10; // rel. to "terrain height" if (alt_arriv <= 0) DrawGTL2 = false; } if (LastDrewGTL2 != DrawGTL2) { LastDrewGTL2 = DrawGTL2; if (!DrawGTL2) ClearGTL2(); // clear next-WP glide terrain line } #endif hpOld = Surface.SelectObject(hpTerrainLineBg); #ifdef GTL2 // Draw the wide, solid part of the glide terrain line. #else // draw a dashed perimetral line first #endif Surface.Polyline(Groundline,NUMTERRAINSWEEPS+1, rc); // draw perimeter if selected and during a flight #ifdef GTL2 if (((FinalGlideTerrain == 1) || (FinalGlideTerrain == 3)) || ((!IsMultimapTerrain() || !DerivedDrawInfo.Flying) && FinalGlideTerrain)) { #else if ((FinalGlideTerrain==1) || ((!IsMultimapTerrain() || !DerivedDrawInfo.Flying) && (FinalGlideTerrain==2))) { #endif Surface.SelectObject(hpTerrainLine); Surface.Polyline(Groundline,NUMTERRAINSWEEPS+1, rc); } #ifdef GTL2 // draw glide terrain line around next waypoint if (DrawGTL2) { // Draw a solid white line. Surface.SelectObject(LKPen_White_N2); Surface.Polyline(Groundline2, NUMTERRAINSWEEPS+1, rc); // Draw a dashed red line. Surface.DrawDashPoly(NIBLSCALE(2), RGB_RED, Groundline2, NUMTERRAINSWEEPS+1, rc); } #endif // draw red cross obstacles only if destination looks reachable! // only if using OVT_TASK of course! #ifdef GTL2 if ((OvertargetMode == OVT_TASK) && DerivedDrawInfo.Flying && ValidTP) #else if ( (OvertargetMode==OVT_TASK) && DerivedDrawInfo.Flying && ValidTaskPoint(ActiveWayPoint)) #endif if (WayPointCalc[TASKINDEX].AltArriv[AltArrivMode] >0) { POINT sc; // If calculations detected an obstacle... if ((DerivedDrawInfo.TerrainWarningLatitude != 0.0) &&(DerivedDrawInfo.TerrainWarningLongitude != 0.0)) { // only if valid position, and visible if (DerivedDrawInfo.FarObstacle_Lon >0) if (PointVisible(DerivedDrawInfo.FarObstacle_Lon, DerivedDrawInfo.FarObstacle_Lat)) { LatLon2Screen(DerivedDrawInfo.FarObstacle_Lon, DerivedDrawInfo.FarObstacle_Lat, sc); DrawBitmapIn(Surface, sc, hTerrainWarning,true); if (DerivedDrawInfo.FarObstacle_AltArriv <=-50 || DerivedDrawInfo.FarObstacle_Dist<5000 ) { _stprintf(hbuf,_T(" %.0f"),ALTITUDEMODIFY*DerivedDrawInfo.FarObstacle_AltArriv); TextInBox(Surface,&rc,hbuf,sc.x+NIBLSCALE(15), sc.y, 0, &tmode,false); wrotevalue=true; } } // visible far obstacle if (PointVisible(DerivedDrawInfo.TerrainWarningLongitude, DerivedDrawInfo.TerrainWarningLatitude)) { LatLon2Screen(DerivedDrawInfo.TerrainWarningLongitude, DerivedDrawInfo.TerrainWarningLatitude, sc); DrawBitmapIn(Surface, sc, hTerrainWarning,true); #if 0 // 091203 add obstacle altitude on moving map h = max(0,RasterTerrain::GetTerrainHeight(DerivedDrawInfo.TerrainWarningLatitude, DerivedDrawInfo.TerrainWarningLongitude)); if (h==TERRAIN_INVALID) h=0; //@ 101027 FIX but unused dh = CALCULATED_INFO.NavAltitude - h - (SAFETYALTITUDETERRAIN/10); _stprintf(hbuf,_T(" %.0f"),ALTITUDEMODIFY*dh); TextInBox(hDC,&rc,hbuf,sc.x+NIBLSCALE(10), sc.y, 0, tmode,false); #else // if far obstacle was painted with value... if (wrotevalue) { // if it is not too near the nearest.. if ( (fabs(DerivedDrawInfo.FarObstacle_Lon - DerivedDrawInfo.TerrainWarningLongitude) >0.02) && (fabs(DerivedDrawInfo.FarObstacle_Lat - DerivedDrawInfo.TerrainWarningLatitude) >0.02)) { // and it the arrival altitude is actually negative (rounding terrain errors?) if ( DerivedDrawInfo.ObstacleAltArriv <=-50) // and there is a significant difference in the numbers, then paint value also for nearest if ( fabs(DerivedDrawInfo.ObstacleAltArriv - DerivedDrawInfo.FarObstacle_AltArriv) >100 ) { _stprintf(hbuf,_T(" %.0f"),ALTITUDEMODIFY*DerivedDrawInfo.ObstacleAltArriv); TextInBox(Surface,&rc,hbuf,sc.x+NIBLSCALE(15), sc.y, 0, &tmode,false); } } } else { // else paint value only if meaningful or very close to us // -1 to 10m become -1 for rounding errors if ( (DerivedDrawInfo.ObstacleAltArriv >-1) && (DerivedDrawInfo.ObstacleAltArriv <10)) DerivedDrawInfo.ObstacleAltArriv=-1; if (DerivedDrawInfo.ObstacleAltArriv <=-50 || ((DerivedDrawInfo.ObstacleAltArriv<0) && (DerivedDrawInfo.ObstacleDistance<5000)) ) { _stprintf(hbuf,_T(" %.0f"),ALTITUDEMODIFY*DerivedDrawInfo.ObstacleAltArriv); TextInBox(Surface,&rc,hbuf,sc.x+NIBLSCALE(15), sc.y, 0, &tmode,false); } } #endif } // visible nearest obstacle } // obstacles detected } // within glide range Surface.SelectObject(hpOld); }
// 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); }
void MapWindow::DrawAirspaceLabels(HDC hdc, const RECT rc, const POINT Orig_Aircraft) { static short int label_sequencing_divider = 0; CAirspaceList::const_iterator it; const CAirspaceList& airspaces_to_draw = CAirspaceManager::Instance().GetAirspacesForWarningLabels(); if (label_sequencing_divider) --label_sequencing_divider; // Draw warning position and label on top of all airspaces if (1) { CCriticalSection::CGuard guard(CAirspaceManager::Instance().MutexRef()); for (it=airspaces_to_draw.begin(); it != airspaces_to_draw.end(); ++it) { if ((*it)->WarningLevel() > awNone) { POINT sc; double lon; double lat; int vdist; AirspaceWarningDrawStyle_t vlabeldrawstyle, hlabeldrawstyle; bool distances_ready = (*it)->GetWarningPoint(lon, lat, hlabeldrawstyle, vdist, vlabeldrawstyle); TCHAR hbuf[NAME_SIZE+16], vDistanceText[16]; TextInBoxMode_t TextDisplayMode = {0}; bool hlabel_draws = false; bool vlabel_draws = false; // Horizontal warning point if (distances_ready && (hlabeldrawstyle > awsHidden) && PointVisible(lon, lat)) { LatLon2Screen(lon, lat, sc); DrawBitmapIn(hdc, sc, hAirspaceWarning,true); Units::FormatUserAltitude(vdist, vDistanceText, sizeof(vDistanceText)/sizeof(vDistanceText[0])); _tcscpy(hbuf, (*it)->Name()); wcscat(hbuf, TEXT(" ")); wcscat(hbuf, vDistanceText); switch (hlabeldrawstyle) { default: case awsHidden: case awsBlack: TextDisplayMode.Color = RGB_BLACK; break; case awsAmber: TextDisplayMode.Color = RGB_ORANGE; break; case awsRed: TextDisplayMode.Color = RGB_RED; break; } // sw TextDisplayMode.SetTextColor = 1; TextDisplayMode.AlligneCenter = 1; if ( (MapBox == (MapBox_t)mbBoxed) || (MapBox == (MapBox_t)mbBoxedNoUnit)) { TextDisplayMode.Border = 1; } else { if (TextDisplayMode.Color==RGB_BLACK) TextDisplayMode.WhiteBold = 0; // no black outline for black background.. else TextDisplayMode.WhiteBold = 1; // outlined } hlabel_draws = TextInBox(hdc, &rc, hbuf, sc.x, sc.y+NIBLSCALE(15), 0, &TextDisplayMode, true); } // Vertical warning point if (distances_ready && vlabeldrawstyle > awsHidden) { //DrawBitmapIn(hdc, Orig_Aircraft, hAirspaceWarning); Units::FormatUserAltitude(vdist, vDistanceText, sizeof(vDistanceText)/sizeof(vDistanceText[0])); _tcscpy(hbuf, (*it)->Name()); wcscat(hbuf, TEXT(" ")); wcscat(hbuf, vDistanceText); switch (vlabeldrawstyle) { default: case awsHidden: case awsBlack: TextDisplayMode.Color = RGB_BLACK; break; case awsAmber: TextDisplayMode.Color = RGB_ORANGE; break; case awsRed: TextDisplayMode.Color = RGB_RED; break; } // sw TextDisplayMode.SetTextColor = 1; TextDisplayMode.AlligneCenter = 1; if ( (MapBox == (MapBox_t)mbBoxed) || (MapBox == (MapBox_t)mbBoxedNoUnit)) { TextDisplayMode.Border = 1; } else { if (TextDisplayMode.Color==RGB_BLACK) TextDisplayMode.WhiteBold = 0; // no black outline for black background.. else TextDisplayMode.WhiteBold = 1; // outlined } vlabel_draws = TextInBox(hdc, &rc, hbuf, Orig_Aircraft.x, Orig_Aircraft.y+NIBLSCALE(15), 0, &TextDisplayMode, true); } if (!label_sequencing_divider) CAirspaceManager::Instance().AirspaceWarningLabelPrinted(**it, hlabel_draws || vlabel_draws); }// if warnlevel>awnone }//for }// if(1) mutex if (!label_sequencing_divider) label_sequencing_divider=3; // Do label sequencing slower than update rate }
// // Final Glide Bar, revised for variometer gauge // void MapWindow::DrawFinalGlide(HDC hDC, const RECT rc) { SIZE TextSize; if ((GlideBarMode == (GlideBarMode_t)gbDisabled)) { GlideBarOffset=0; return; } POINT GlideBar[6] = { {0,0},{9,-9},{18,0},{18,0},{9,0},{0,0} }; POINT GlideBar0[6] = { {0,0},{9,-9},{18,0},{18,0},{9,0},{0,0} }; HPEN hpOld; HBRUSH hbOld; TCHAR Value[10]; int Offset; int Offset0; int i; int lkVarioOffset=0, minBar, maxBar; if (LKVarioBar) lkVarioOffset=LKVarioSize+NIBLSCALE(2); //@ 091114 // 091114 switch(ScreenSize) { case (ScreenSize_t)ss480x234: case (ScreenSize_t)ss480x272: case (ScreenSize_t)ss720x408: minBar=-40; maxBar=40; break; case (ScreenSize_t)ss800x480: case (ScreenSize_t)ss400x240: minBar=-45; maxBar=45; break; default: minBar=-50; // was 60 maxBar=50; break; } LockTaskData(); // protect from external task changes bool invalidbar=false; #if 101004 int barindex; barindex=GetOvertargetIndex(); if (barindex>=0) { #else if (ValidTaskPoint(ActiveWayPoint)) { #endif const int y0 = ( (rc.bottom - rc.top )/2)+rc.top; #if 110609 if ( ValidTaskPoint(1) && OvertargetMode == OVT_TASK && GlideBarMode == (GlideBarMode_t)gbFinish ) { // Before the start, there is no task altitude available! if (DerivedDrawInfo.ValidStart) { Offset = ((int)DerivedDrawInfo.TaskAltitudeDifference)/8; Offset0 = ((int)DerivedDrawInfo.TaskAltitudeDifference0)/8; } else { // In this case, print an invalid bar invalidbar=true; Offset=0; Offset0=0; } } else { Offset=(int)WayPointCalc[barindex].AltArriv[AltArrivMode]; Offset0=Offset; } #else // This is wrong, we are painting values relative to MC and ignoring safetyMC if (OvertargetMode != OVT_TASK) { //@ 101004 Offset=(int)WayPointCalc[barindex].AltArriv[AltArrivMode]; Offset0=Offset; } else { // 60 units is size, div by 8 means 60*8 = 480 meters. if ( (GlideBarMode == (GlideBarMode_t)gbFinish)) { Offset = ((int)DerivedDrawInfo.TaskAltitudeDifference)/8; Offset0 = ((int)DerivedDrawInfo.TaskAltitudeDifference0)/8; } else { Offset = ((int)DerivedDrawInfo.NextAltitudeDifference)/8; Offset0 = ((int)DerivedDrawInfo.NextAltitudeDifference0)/8; } } #endif // TODO feature: should be an angle if in final glide mode if(Offset > maxBar) Offset = maxBar; if(Offset < minBar) Offset = minBar; Offset = IBLSCALE(Offset); if(Offset<0) { GlideBar[1].y = NIBLSCALE(9); } if(Offset0 > maxBar) Offset0 = maxBar; if(Offset0 < minBar) Offset0 = minBar; Offset0 = IBLSCALE(Offset0); if(Offset0<0) { GlideBar0[1].y = NIBLSCALE(9); } for(i=0; i<6; i++) { GlideBar[i].y += y0; // if vario activated GlideBar[i].x = IBLSCALE(GlideBar[i].x)+rc.left+lkVarioOffset; //@ 091114 } GlideBar[0].y -= Offset; GlideBar[1].y -= Offset; GlideBar[2].y -= Offset; for(i=0; i<6; i++) { GlideBar0[i].y += y0; GlideBar0[i].x = IBLSCALE(GlideBar0[i].x)+rc.left+lkVarioOffset; //@ 091114 } GlideBar0[0].y -= Offset0; GlideBar0[1].y -= Offset0; GlideBar0[2].y -= Offset0; if ((Offset<0)&&(Offset0<0)) { // both below if (Offset0!= Offset) { int dy = (GlideBar0[0].y-GlideBar[0].y) +(GlideBar0[0].y-GlideBar0[3].y); dy = max(NIBLSCALE(3), dy); GlideBar[3].y = GlideBar0[0].y-dy; GlideBar[4].y = GlideBar0[1].y-dy; GlideBar[5].y = GlideBar0[2].y-dy; GlideBar0[0].y = GlideBar[3].y; GlideBar0[1].y = GlideBar[4].y; GlideBar0[2].y = GlideBar[5].y; } else { Offset0 = 0; } } else if ((Offset>0)&&(Offset0>0)) { // both above GlideBar0[3].y = GlideBar[0].y; GlideBar0[4].y = GlideBar[1].y; GlideBar0[5].y = GlideBar[2].y; if (abs(Offset0-Offset)<NIBLSCALE(4)) { Offset= Offset0; } } // draw actual glide bar if (Offset<=0) { hpOld = (HPEN)SelectObject(hDC, hpFinalGlideBelow); hbOld = (HBRUSH)SelectObject(hDC, LKBrush_Red); } else { hpOld = (HPEN)SelectObject(hDC, hpFinalGlideAbove); hbOld = (HBRUSH)SelectObject(hDC, LKBrush_Green); } Polygon(hDC,GlideBar,6); // in case of invalid bar because finish mode with real task but no valid start, we skip if (invalidbar) { _tcscpy(Value,_T("---")); goto _skipout; } // draw glide bar at mc 0 and X only for OVT_TASK 101004 // we dont have mc0 calc ready for other overtargets, not granted at least if (OvertargetMode == OVT_TASK) { if (Offset0<=0) { SelectObject(hDC, hpFinalGlideBelow); SelectObject(hDC, GetStockObject(HOLLOW_BRUSH)); } else { SelectObject(hDC, hpFinalGlideAbove); SelectObject(hDC, GetStockObject(HOLLOW_BRUSH)); } if (Offset!=Offset0) { Polygon(hDC,GlideBar0,6); } // Draw an X on final glide bar if unreachable at current Mc if ( (GlideBarMode == (GlideBarMode_t)gbFinish) ) { if ((DerivedDrawInfo.TaskTimeToGo>0.9*ERROR_TIME) || ((MACCREADY<0.01) && (DerivedDrawInfo.TaskAltitudeDifference<0))) { SelectObject(hDC, LKPen_White_N2); POINT Cross[4] = { {-5, -5}, { 5, 5}, {-5, 5}, { 5, -5} }; for (i=0; i<4; i++) { Cross[i].x = IBLSCALE(Cross[i].x+9)+lkVarioOffset; //@ 091114 Cross[i].y = IBLSCALE(Cross[i].y+9)+y0; } Polygon(hDC,Cross,2); Polygon(hDC,&Cross[2],2); } } else { if ((MACCREADY<0.01) && (DerivedDrawInfo.NextAltitudeDifference<0)) { SelectObject(hDC, LKPen_White_N2); POINT Cross[4] = { {-5, -5}, { 5, 5}, {-5, 5}, { 5, -5} }; for (i=0; i<4; i++) { Cross[i].x = IBLSCALE(Cross[i].x+9)+lkVarioOffset; Cross[i].y = IBLSCALE(Cross[i].y+9)+y0; } Polygon(hDC,Cross,2); Polygon(hDC,&Cross[2],2); } } } // draw boxed value in the center if (OvertargetMode == OVT_TASK ) { //@ 101004 // A task is made of at least 2 tps, otherwise its a goto if (( (GlideBarMode == (GlideBarMode_t)gbFinish) && ValidTaskPoint(1)) ) { if(ISPARAGLIDER && DerivedDrawInfo.TaskAltitudeDifference > 0.0) { if ( (ALTITUDEMODIFY*DerivedDrawInfo.TaskAltitudeArrival) <ALTDIFFLIMIT) //@ 091114 _stprintf(Value,TEXT(" --- ")); else _stprintf(Value,TEXT("%1.0f "), ALTITUDEMODIFY*DerivedDrawInfo.TaskAltitudeArrival); } else { if ( (ALTITUDEMODIFY*DerivedDrawInfo.TaskAltitudeDifference) <ALTDIFFLIMIT) //@ 091114 _stprintf(Value,TEXT(" --- ")); else _stprintf(Value,TEXT("%1.0f "), ALTITUDEMODIFY*DerivedDrawInfo.TaskAltitudeDifference); } } else { if ( (ALTITUDEMODIFY*WayPointCalc[barindex].AltArriv[AltArrivMode]) < ALTDIFFLIMIT) _stprintf(Value,TEXT(" --- ")); else _stprintf(Value,TEXT("%1.0f "), ALTITUDEMODIFY*WayPointCalc[barindex].AltArriv[AltArrivMode]); /* * Well this was the reason why the glidebar value was out of sync with overlays if ( (ALTITUDEMODIFY*DerivedDrawInfo.NextAltitudeDifference) < ALTDIFFLIMIT) //@ 091114 _stprintf(Value,TEXT(" --- ")); else _stprintf(Value,TEXT("%1.0f "), ALTITUDEMODIFY*DerivedDrawInfo.NextAltitudeDifference); */ } } else { if ( (ALTITUDEMODIFY*WayPointCalc[barindex].AltArriv[AltArrivMode]) < ALTDIFFLIMIT) _stprintf(Value,TEXT(" --- ")); else _stprintf(Value,TEXT("%1.0f "), ALTITUDEMODIFY*WayPointCalc[barindex].AltArriv[AltArrivMode]); } _skipout: // in case of invalidbar we get here with Offset 0 if (Offset>=0) { Offset = GlideBar[2].y+Offset+NIBLSCALE(5); } else { if (Offset0>0) { Offset = GlideBar0[1].y-NIBLSCALE(15); } else { Offset = GlideBar[2].y+Offset-NIBLSCALE(15); } } // VENTA10 GetTextExtentPoint(hDC, Value, _tcslen(Value), &TextSize); GlideBarOffset=max(NIBLSCALE(11),(int)TextSize.cx) - NIBLSCALE(2); TextInBoxMode_t TextInBoxMode = {0}; TextInBoxMode.Border = true; //={1|8}; TextInBoxMode.Reachable = true; // boxed numbers are a bit too much on the left, so increase the offset TextInBox(hDC, &rc,Value, lkVarioOffset+NIBLSCALE(1), (int)Offset, 0, &TextInBoxMode); //@ 091114 SelectObject(hDC, hbOld); SelectObject(hDC, hpOld); } else GlideBarOffset=0; // 091125 BUGFIX glidebaroffset is zero when no task point { UnlockTaskData(); } }
/** * Draws the GliderLink traffic icons onto the given canvas * @param canvas Canvas for drawing */ void MapWindow::DrawGLinkTraffic(Canvas &canvas, const PixelPoint aircraft_pos) const { #ifdef ANDROID // Return if FLARM icons on moving map are disabled if (!GetMapSettings().show_flarm_on_map) return; const GliderLinkTrafficList &traffic = Basic().glink_data.traffic; if (traffic.IsEmpty()) return; const MoreData &basic = Basic(); const WindowProjection &projection = render_projection; canvas.Select(*traffic_look.font); // Circle through the GliderLink targets for (const auto &traf : traffic.list) { // Save the location of the target GeoPoint target_loc = traf.location; // Points for the screen coordinates for the icon, name and average climb PixelPoint sc, sc_name, sc_av, sc_alt; // If FLARM target not on the screen, move to the next one if (!projection.GeoToScreenIfVisible(target_loc, sc)) continue; // Draw the callsign above the icon sc_name = sc; sc_name.x -= Layout::Scale(10); sc_name.y -= Layout::Scale(15); // Draw the average climb to the right of the icon sc_av = sc; sc_av.x += Layout::Scale(10); sc_av.y -= Layout::Scale(8); // Location of altitude label sc_alt = sc; sc_alt.x -= Layout::Scale(10); sc_alt.y -= Layout::Scale(0); TextInBoxMode mode; mode.shape = LabelShape::OUTLINED; mode.align = TextInBoxMode::Alignment::RIGHT; // If callsign/name available draw it to the canvas if (traf.HasName() && !StringIsEmpty(traf.name)) TextInBox(canvas, traf.name, sc_name.x, sc_name.y, mode, GetClientRect()); if (traf.climb_rate_received) { // If average climb data available draw it to the canvas TCHAR label_avg[100]; FormatUserVerticalSpeed(traf.climb_rate, label_avg, false); mode.align = TextInBoxMode::Alignment::LEFT; TextInBox(canvas, label_avg, sc_av.x, sc_av.y, mode, GetClientRect()); } // use GPS altitude to be consistent with GliderLink if(basic.gps_altitude_available && traf.altitude_received && fabs(double(traf.altitude) - basic.gps_altitude) >= 100.0) { // If average climb data available draw it to the canvas TCHAR label_alt[100]; double alt = (double(traf.altitude) - basic.gps_altitude) / 100.0; FormatRelativeUserAltitude(alt, label_alt, false); mode.align = TextInBoxMode::Alignment::RIGHT; TextInBox(canvas, label_alt, sc_alt.x, sc_alt.y, mode, GetClientRect()); } TrafficRenderer::Draw(canvas, traffic_look, traf, traf.track - projection.GetScreenAngle(), sc); } #endif }
/** * Draws the FLARM traffic icons onto the given canvas * @param canvas Canvas for drawing */ void MapWindow::DrawFLARMTraffic(Canvas &canvas, const PixelPoint aircraft_pos) const { // Return if FLARM icons on moving map are disabled if (!GetMapSettings().show_flarm_on_map) return; // Return if FLARM data is not available const TrafficList &flarm = Basic().flarm.traffic; if (flarm.IsEmpty()) return; const WindowProjection &projection = render_projection; // if zoomed in too far out, dont draw traffic since it will be too close to // the glider and so will be meaningless (serves only to clutter, cant help // the pilot) if (projection.GetMapScale() > 7300) return; canvas.Select(*traffic_look.font); // Circle through the FLARM targets for (auto it = flarm.list.begin(), end = flarm.list.end(); it != end; ++it) { const FlarmTraffic &traffic = *it; if (!traffic.location_available) continue; // Save the location of the FLARM target GeoPoint target_loc = traffic.location; // Points for the screen coordinates for the icon, name and average climb PixelPoint sc, sc_name, sc_av; // If FLARM target not on the screen, move to the next one if (!projection.GeoToScreenIfVisible(target_loc, sc)) continue; // Draw the name 16 points below the icon sc_name = sc; sc_name.y -= Layout::Scale(20); // Draw the average climb value above the icon sc_av = sc; sc_av.y += Layout::Scale(5); TextInBoxMode mode; mode.shape = LabelShape::OUTLINED; // JMW TODO enhancement: decluttering of FLARM altitudes (sort by max lift) int dx = sc_av.x - aircraft_pos.x; int dy = sc_av.y - aircraft_pos.y; // only draw labels if not close to aircraft if (dx * dx + dy * dy > Layout::Scale(30 * 30)) { // If FLARM callsign/name available draw it to the canvas if (traffic.HasName() && !StringIsEmpty(traffic.name)) TextInBox(canvas, traffic.name, sc_name.x, sc_name.y, mode, GetClientRect()); if (traffic.climb_rate_avg30s >= 0.1) { // If average climb data available draw it to the canvas TCHAR label_avg[100]; FormatUserVerticalSpeed(traffic.climb_rate_avg30s, label_avg, false); TextInBox(canvas, label_avg, sc_av.x, sc_av.y, mode, GetClientRect()); } } auto color = FlarmFriends::GetFriendColor(traffic.id); TrafficRenderer::Draw(canvas, traffic_look, traffic, traffic.track - projection.GetScreenAngle(), color, sc); } }