// // Paint a circle around thermal multitarget // Called only during map mode L> // void MapWindow::DrawThermalEstimateMultitarget(LKSurface& Surface, const RECT& rc, const ScreenProjection& _Proj) { int idx=0; // do not mix old and new thermals if (mode.Is(Mode::MODE_CIRCLING)) return; // draw only when visible , at high zoom level if ( MapWindow::zoom.RealScale() >1 ) return; idx=GetThermalMultitarget(); // no L> target destination if (idx <0) return; const POINT screen = _Proj.LonLat2Screen( ThermalHistory[idx].Longitude, ThermalHistory[idx].Latitude); double tradius; if (ISPARAGLIDER) tradius=100; else tradius=200; const auto oldPen = Surface.SelectObject(LKPen_White_N3); Surface.DrawCircle(screen.x, screen.y, (int)(tradius*zoom.ResScaleOverDistanceModify()), rc, false); Surface.SelectObject(LKPen_White_N2); Surface.DrawCircle(screen.x, screen.y, (int)(tradius*zoom.ResScaleOverDistanceModify())+NIBLSCALE(2), rc, false); Surface.DrawCircle(screen.x, screen.y, (int)(tradius*zoom.ResScaleOverDistanceModify()), rc, false); Surface.SelectObject(oldPen); }
// // Draw circles and gadgets for thermals // void MapWindow::DrawThermalEstimate(LKSurface& Surface, const RECT& rc, const ScreenProjection& _Proj) { if (!EnableThermalLocator) return; if (mode.Is(Mode::MODE_CIRCLING)) { if (DerivedDrawInfo.ThermalEstimate_R>0) { const POINT screen = _Proj.LonLat2Screen(DerivedDrawInfo.ThermalEstimate_Longitude, DerivedDrawInfo.ThermalEstimate_Latitude); DrawBitmapIn(Surface, screen, hBmpThermalSource); const auto oldBrush = Surface.SelectObject(LKBrush_Hollow); double tradius; if (ISPARAGLIDER) tradius=50; else tradius=100; const auto oldPen = Surface.SelectObject(LKPen_White_N3); Surface.DrawCircle(screen.x, screen.y, (int)(tradius*zoom.ResScaleOverDistanceModify()), rc, true); Surface.SelectObject(LKPen_Black_N1); Surface.DrawCircle(screen.x, screen.y, (int)(tradius*zoom.ResScaleOverDistanceModify())+NIBLSCALE(2), rc, true); Surface.DrawCircle(screen.x, screen.y, (int)(tradius*zoom.ResScaleOverDistanceModify()), rc, true); Surface.SelectObject(oldPen); Surface.SelectObject(oldBrush); } } else { if (zoom.RealScale() <= 4) { for (int i=0; i<MAX_THERMAL_SOURCES; i++) { if (DerivedDrawInfo.ThermalSources[i].Visible) { DrawBitmapIn(Surface, DerivedDrawInfo.ThermalSources[i].Screen, hBmpThermalSource); } } } } }
void MapWindow::DrawTeammate(LKSurface& Surface, const RECT& rc, const ScreenProjection& _Proj) { if (TeammateCodeValid) { if (PointVisible(TeammateLongitude, TeammateLatitude)) { const POINT point = _Proj.LonLat2Screen(TeammateLongitude, TeammateLatitude); hBmpTeammatePosition.Draw(Surface, point.x - NIBLSCALE(10), point.y - NIBLSCALE(10), IBLSCALE(20), IBLSCALE(20)); } } }
// // Draw bearing line to target // void MapWindow::DrawGreatCircle(LKSurface& Surface, const RECT& rc, const ScreenProjection& _Proj, double startLon, double startLat, double targetLon, double targetLat) { POINT pt[2] = { _Proj.LonLat2Screen(startLon, startLat), _Proj.LonLat2Screen(targetLon, targetLat) }; if(LKGeom::ClipLine(rc, pt[0], pt[1])) { const auto hpOld = Surface.SelectObject(LKPen_GABRG); Surface.Polyline(pt, 2); Surface.SelectObject(LK_BLACK_PEN); Surface.Polyline(pt, 2); Surface.SelectObject(hpOld); } }
void MapWindow::LKDrawLongTrail( LKSurface& Surface, const RECT& rc, const ScreenProjection& _Proj) { static RasterPoint snail_polyline[array_size(LongSnailTrail)+1]; // +1 for last point of "normal" snail trail if (TrailActive != 3) return; // only when full trail is selected if (iLongSnailNext < 2) return; // no reason to draw a single point if (MapWindow::mode.Is(MapWindow::Mode::MODE_CIRCLING)) { return; } // pixel manhattan distance // It is the sum of x and y differences between previous and next point on screen, in pixels. // below this distance, no painting const unsigned nearby=10; const LONG_SNAIL_POINT* end_iterator = std::begin(LongSnailTrail); const LONG_SNAIL_POINT* cur_iterator = std::prev(std::next(LongSnailTrail,iLongSnailNext)); RasterPoint* polyline_iterator = std::begin(snail_polyline); const SNAIL_POINT* last_point = std::next(std::next(SnailTrail, iSnailNext)); if(last_point == std::end(SnailTrail)) { last_point = std::begin(SnailTrail); } (*polyline_iterator) = _Proj.LonLat2Screen(last_point->Longitude, last_point->Latitude); polyline_iterator = std::next(polyline_iterator); const auto oldPen = Surface.SelectObject(hSnailPens[3]); // blue color while(cur_iterator != end_iterator) { (*polyline_iterator) = _Proj.LonLat2Screen(cur_iterator->Longitude, cur_iterator->Latitude); if(manhattan_distance(*std::prev(polyline_iterator),(*polyline_iterator)) > nearby) { polyline_iterator = std::next(polyline_iterator); } cur_iterator = std::prev(cur_iterator); } Surface.Polyline(snail_polyline, std::distance(snail_polyline, polyline_iterator) , rc); Surface.SelectObject(oldPen); }
void MapWindow::Event_PanCursor(int dx, int dy) { const ScreenProjection _Proj; RasterPoint pt = { (MapRect.right+MapRect.left)/2, (MapRect.bottom+MapRect.top)/2 }; double Xstart, Ystart, Xnew, Ynew; _Proj.Screen2LonLat(pt, Xstart, Ystart); pt.x += (MapRect.right-MapRect.left)*dx/4; pt.y += (MapRect.bottom-MapRect.top)*dy/4; _Proj.Screen2LonLat(pt, Xnew, Ynew); if(mode.AnyPan()) { PanLongitude += Xstart-Xnew; PanLatitude += Ystart-Ynew; } RefreshMap(); }
void GLShapeRenderer::renderPolygon(LKSurface& Surface, const XShape& shape, Brush& brush, const ScreenProjection& _Proj) { /* OpenGL cannot draw complex polygons so we need to use a Tessallator to draw the polygon using a GL_TRIANGLE_FAN */ #ifdef USE_GLSL OpenGL::solid_shader->Use(); #endif brush.Bind(); std::unique_ptr<const GLBlend> blend; if(!brush.IsOpaque()) { blend = std::make_unique<const GLBlend>(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } curr_LabelPos = clipRect.GetBottomRight(); const shapeObj& shp = shape.shape; gluTessBeginPolygon(tess, this ); for (int j = 0; j < shp.numlines; j++) { gluTessBeginContour(tess); for (int i = 0; i < shp.line[j].numpoints; i++) { const RasterPoint pt = _Proj.LonLat2Screen(shp.line[j].point[i]); if (!noLabel && (pt.x<=curr_LabelPos.x)) { curr_LabelPos = pt; } vertex_t& vertex = *(pointers.insert(pointers.end(), vertex_t({{(GLdouble)pt.x, (GLdouble)pt.y, 0.}}))); gluTessVertex(tess, vertex.data(), vertex.data()); } gluTessEndContour(tess); } gluTessEndPolygon(tess); if(shape.HasLabel() && clipRect.IsInside(curr_LabelPos)) { shape.renderSpecial(Surface, curr_LabelPos.x, curr_LabelPos.y, clipRect); } pointers.clear(); }
void MapWindow::LKDrawTrail(LKSurface& Surface, const RECT& rc, const ScreenProjection& _Proj) { static RasterPoint snail_polyline[array_size(SnailTrail)]; if (!TrailActive) return; const double display_time = DrawInfo.Time; const bool use_colors = (MapWindow::zoom.RealScale() < 2); // 1.5 is also quite good; // Trail size int num_trail_max = TRAILSIZE; if (TrailActive == 2) { // scan only recently for lift magnitude (10 min) num_trail_max /= TRAILSHRINK; } if (MapWindow::mode.Is(MapWindow::Mode::MODE_CIRCLING)) { num_trail_max /= TRAILSHRINK; // ( 2 min for short track ? ) } const SNAIL_POINT* end_iterator = std::next(SnailTrail,iSnailNext); const SNAIL_POINT* cur_iterator = end_iterator; if(cur_iterator != std::begin(SnailTrail)) { cur_iterator = std::prev(cur_iterator); } else { cur_iterator = std::prev(std::end(SnailTrail)); } RasterPoint* polyline_iterator = &snail_polyline[0]; unsigned short prev_color = 2; if(use_colors) { prev_color = cur_iterator->Colour; } Surface.SelectObject(hSnailPens[prev_color]); const bool trail_is_drifted = (EnableTrailDrift && MapWindow::mode.Is(MapWindow::Mode::MODE_CIRCLING) && DerivedDrawInfo.WindSpeed >= 1); double traildrift_lat = 0; double traildrift_lon = 0; if(trail_is_drifted) { double tlat1, tlon1; FindLatitudeLongitude(DrawInfo.Latitude, DrawInfo.Longitude, DerivedDrawInfo.WindBearing, DerivedDrawInfo.WindSpeed, &tlat1, &tlon1); traildrift_lat = (DrawInfo.Latitude - tlat1); traildrift_lon = (DrawInfo.Longitude - tlon1); } while( (num_trail_max--) > 0 && cur_iterator->Time && cur_iterator != end_iterator) { double this_lat = cur_iterator->Latitude; double this_lon = cur_iterator->Longitude; if (trail_is_drifted) { double dt = std::max(0.0, (display_time - cur_iterator->Time) * cur_iterator->DriftFactor); this_lat += traildrift_lat * dt; this_lon += traildrift_lon * dt; } (*polyline_iterator) = _Proj.LonLat2Screen(this_lon, this_lat); if(use_colors && prev_color != cur_iterator->Colour) { // draw polyline before change color. Surface.Polyline(snail_polyline, std::distance(snail_polyline, polyline_iterator)+1 , rc); // reset polyline snail_polyline[0] = *polyline_iterator; polyline_iterator = &snail_polyline[1]; // select new Color prev_color = cur_iterator->Colour; Surface.SelectObject(hSnailPens[prev_color]); } else { polyline_iterator = std::next(polyline_iterator); } if(cur_iterator == std::begin(SnailTrail)) { cur_iterator = std::end(SnailTrail); } cur_iterator = std::prev(cur_iterator); } Surface.Polyline(snail_polyline, std::distance(snail_polyline, polyline_iterator) , 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); }