static void DrawArrow(Canvas &canvas, RasterPoint point, const fixed mag, const Angle angle) { const FastRotation r(angle); auto p = r.Rotate(mag, fixed(0)); canvas.DrawLine(point, point + RasterPoint((int)p.x, (int)p.y)); p = r.Rotate(mag - fixed(5), fixed(-3)); canvas.DrawLine(point, point + RasterPoint((int)p.x, (int)p.y)); p = r.Rotate(mag - fixed(5), fixed(3)); canvas.DrawLine(point, point + RasterPoint((int)p.x, (int)p.y)); }
void BufferCanvas::Commit(Canvas &other) { assert(IsDefined()); assert(active); assert(GetWidth() == other.GetWidth()); assert(GetHeight() == other.GetHeight()); if (frame_buffer != NULL) { frame_buffer->Unbind(); /* restore the old viewport */ assert(OpenGL::translate == RasterPoint(0, 0)); OpenGL::SetupViewport(old_size); OpenGL::translate = old_translate; glPopMatrix(); /* copy frame buffer to screen */ CopyTo(other); } else { assert(offset == other.offset); /* copy screen to texture */ CopyToTexture(*texture, GetRect()); } active = false; }
void BufferCanvas::Commit(Canvas &other) { assert(IsDefined()); assert(active); assert(GetWidth() == other.GetWidth()); assert(GetHeight() == other.GetHeight()); if (frame_buffer != nullptr) { assert(OpenGL::translate.x == 0); assert(OpenGL::translate.y == 0); frame_buffer->Unbind(); /* restore the old viewport */ assert(OpenGL::translate == RasterPoint(0, 0)); #ifdef HAVE_GLES /* there's no glPopAttrib() on GL/ES; emulate it */ glViewport(old_viewport[0], old_viewport[1], old_viewport[2], old_viewport[3]); #else glPopAttrib(); #endif #ifdef USE_GLSL OpenGL::projection_matrix = old_projection_matrix; OpenGL::UpdateShaderProjectionMatrix(); #else glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); #endif OpenGL::translate = old_translate; OpenGL::viewport_size = old_size; #ifdef USE_GLSL glVertexAttrib4f(OpenGL::Attribute::TRANSLATE, OpenGL::translate.x, OpenGL::translate.y, 0, 0); #endif #ifdef SOFTWARE_ROTATE_DISPLAY OpenGL::display_orientation = old_orientation; #endif /* copy frame buffer to screen */ CopyTo(other); } else { assert(offset == other.offset); /* copy screen to texture */ CopyToTexture(*texture, GetRect()); } active = false; }
gcc_const static RasterPoint CirclePoint(int x, int y, int radius, unsigned angle) { assert(angle < ARRAY_SIZE(ISINETABLE)); return RasterPoint(x + ISINETABLE[angle] * radius / 1024, y - ISINETABLE[(angle + INT_QUARTER_CIRCLE) & INT_ANGLE_MASK] * radius / 1024); }
gcc_const static RasterPoint CirclePoint(int x, int y, int radius, unsigned angle) { assert(angle < ARRAY_SIZE(ISINETABLE)); return RasterPoint(x + ISINETABLE[angle] * radius / 1024, y - ISINETABLE[(angle + 1024) & 0xfff] * radius / 1024); }
void LKSurface::DrawCircle(long x, long y, int radius, const RECT& rc, bool fill) { if ((x - radius) > rc.right) return; if ((x + radius) < rc.left) return; if ((y - radius) > rc.bottom) return; if ((y + radius) < rc.top) return; // Only called by ThreadDraw, so static vector can be used. static std::vector<RasterPoint> CirclePt; buildCircle(RasterPoint(x,y), radius, CirclePt); if (fill) { Polygon(CirclePt.data(), CirclePt.size(), rc); } else { Polyline(CirclePt.data(), CirclePt.size(), rc); } }
void FlarmTrafficControl::PaintRelativeAltitude(Canvas &canvas, PixelRect rc, fixed relative_altitude) const { // Format relative altitude TCHAR buffer[20]; Unit unit = Units::GetUserAltitudeUnit(); FormatRelativeUserAltitude(relative_altitude, buffer, false); // Calculate unit size canvas.Select(look.info_units_font); const unsigned unit_width = UnitSymbolRenderer::GetSize(canvas, unit).cx; const unsigned unit_height = UnitSymbolRenderer::GetAscentHeight(look.info_units_font, unit); const unsigned space_width = unit_width / 3; // Calculate value size canvas.Select(look.info_values_font); const unsigned value_height = look.info_values_font.GetAscentHeight(); const unsigned value_width = canvas.CalcTextSize(buffer).cx; // Calculate positions const unsigned max_height = std::max(unit_height, value_height); // Paint value canvas.DrawText(rc.right - unit_width - space_width - value_width, rc.bottom - value_height, buffer); // Paint unit canvas.Select(look.info_units_font); UnitSymbolRenderer::Draw(canvas, RasterPoint(rc.right - unit_width, rc.bottom - unit_height), unit, look.unit_fraction_pen); // Paint label canvas.Select(look.info_labels_font); const unsigned label_width = canvas.CalcTextSize(_("Rel. Alt.")).cx; canvas.DrawText(rc.right - label_width, rc.bottom - max_height - look.info_labels_font.GetHeight(), _("Rel. Alt.")); }
bool SingleWindow::FilterEvent(const Event &_event, Window *allowed) const { assert(allowed != NULL); const SDL_Event &event = _event.event; switch (event.type) { case SDL_MOUSEMOTION: case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: return FilterMouseEvent(RasterPoint(event.button.x, event.button.y), allowed); default: return true; } }
static void Draw(Canvas &canvas) { PixelRect rc = canvas.GetRect(); rc.Grow(-0.2 * rc.GetSize().cx); /* draw the banner text with a large font */ Font small_font; small_font.LoadFile("/opt/LK8000/share/fonts/DejaVuSansCondensed.ttf", (rc.GetSize().cy / 25)); canvas.Select(small_font); canvas.SetTextColor(COLOR_BLACK); canvas.SetBackgroundTransparent(); const TCHAR *const text = _T("Powered Off"); const PixelSize text_size = canvas.CalcTextSize(text); const RasterPoint text_pos = { rc.left + 16, rc.bottom - 16 - text_size.cy }; canvas.DrawText(text_pos.x, text_pos.y, text); Font big_font; big_font.LoadFile("/opt/LK8000/share/fonts/DejaVuSansCondensed-Bold.ttf", (rc.GetSize().cy / 10)); canvas.Select(big_font); const TCHAR *const text2 = _T("LK8000"); const PixelSize text2_size = canvas.CalcTextSize(text2); const RasterPoint text2_pos = { (rc.left + rc.GetSize().cx + text2_size.cx) / 2, (rc.top + (rc.GetSize().cy / 10)) }; canvas.DrawText(text2_pos.x, text2_pos.y, text2); const double Scale = (double)rc.GetSize().cx / (double)bird_size.cx; RasterPoint polygon[array_size(bird_polygon)] = {}; std::transform(std::begin(bird_polygon), std::end(bird_polygon), std::begin(polygon), [Scale, rc, text2_size, text2_pos]( const RasterPoint& pt ) { return RasterPoint(pt.x*Scale + rc.left, pt.y*Scale + text2_pos.y + text2_size.cy); }); canvas.SelectBlackBrush(); canvas.DrawPolygon(polygon, array_size(polygon)); }
void FlarmTrafficControl::PaintClimbRate(Canvas &canvas, PixelRect rc, fixed climb_rate) const { // Paint label canvas.Select(look.info_labels_font); const unsigned label_width = canvas.CalcTextSize(_("Vario")).cx; canvas.DrawText(rc.right - label_width, rc.top, _("Vario")); // Format climb rate TCHAR buffer[20]; Unit unit = Units::GetUserVerticalSpeedUnit(); FormatUserVerticalSpeed(climb_rate, buffer, false); // Calculate unit size canvas.Select(look.info_units_font); const unsigned unit_width = UnitSymbolRenderer::GetSize(canvas, unit).cx; const unsigned unit_height = UnitSymbolRenderer::GetAscentHeight(look.info_units_font, unit); UPixelScalar space_width = unit_width / 3; // Calculate value size canvas.Select(look.info_values_font); const unsigned value_height = look.info_values_font.GetAscentHeight(); const unsigned value_width = canvas.CalcTextSize(buffer).cx; // Calculate positions const int max_height = std::max(unit_height, value_height); const int y = rc.top + look.info_units_font.GetHeight() + max_height; // Paint value canvas.DrawText(rc.right - unit_width - space_width - value_width, y - value_height, buffer); // Paint unit canvas.Select(look.info_units_font); UnitSymbolRenderer::Draw(canvas, RasterPoint(rc.right - unit_width, y - unit_height), unit, look.unit_fraction_pen); }
void FlarmTrafficControl::PaintDistance(Canvas &canvas, PixelRect rc, fixed distance) const { // Format distance TCHAR buffer[20]; Unit unit = FormatUserDistanceSmart(distance, buffer, false, fixed(1000)); // Calculate unit size canvas.Select(look.info_units_font); const unsigned unit_width = UnitSymbolRenderer::GetSize(canvas, unit).cx; const unsigned unit_height = UnitSymbolRenderer::GetAscentHeight(look.info_units_font, unit); const unsigned space_width = unit_width / 3; // Calculate value size canvas.Select(look.info_values_font); const unsigned value_height = look.info_values_font.GetAscentHeight(); const unsigned value_width = canvas.CalcTextSize(buffer).cx; // Calculate positions const unsigned max_height = std::max(unit_height, value_height); // Paint value canvas.DrawText(rc.left, rc.bottom - value_height, buffer); // Paint unit canvas.Select(look.info_units_font); UnitSymbolRenderer::Draw(canvas, RasterPoint(rc.left + value_width + space_width, rc.bottom - unit_height), unit, look.unit_fraction_pen); // Paint label canvas.Select(look.info_labels_font); canvas.DrawText(rc.left, rc.bottom - max_height - look.info_labels_font.GetHeight(), _("Distance")); }
bool TopWindow::OnEvent(const SDL_Event &event) { switch (event.type) { Window *w; #if SDL_MAJOR_VERSION < 2 case SDL_VIDEOEXPOSE: invalidated = false; Expose(); return true; #endif case SDL_KEYDOWN: w = GetFocusedWindow(); if (w == nullptr) w = this; if (!w->IsEnabled()) return false; #if SDL_MAJOR_VERSION >= 2 return w->OnKeyDown(event.key.keysym.sym); #else return w->OnKeyDown(event.key.keysym.sym) || (event.key.keysym.unicode != 0 && w->OnCharacter(event.key.keysym.unicode)); #endif #if SDL_MAJOR_VERSION >= 2 case SDL_TEXTINPUT: w = GetFocusedWindow(); if (w == nullptr) w = this; if (!w->IsEnabled()) return false; if (event.text.text && *event.text.text) { std::pair<unsigned, const char *> next = NextUTF8(event.text.text); bool handled = w->OnCharacter(next.first); while (next.second) { next = NextUTF8(next.second); handled = w->OnCharacter(next.first) || handled; } return handled; } else return false; #endif case SDL_KEYUP: w = GetFocusedWindow(); if (w == nullptr) w = this; if (!w->IsEnabled()) return false; return w->OnKeyUp(event.key.keysym.sym); #ifdef HAVE_MULTI_TOUCH case SDL_FINGERDOWN: if (SDL_GetNumTouchFingers(event.tfinger.touchId) == 2) return OnMultiTouchDown(); else return false; case SDL_FINGERUP: if (SDL_GetNumTouchFingers(event.tfinger.touchId) == 1) return OnMultiTouchUp(); else return false; #endif case SDL_MOUSEMOTION: // XXX keys return OnMouseMove(event.motion.x, event.motion.y, 0); case SDL_MOUSEBUTTONDOWN: #if SDL_MAJOR_VERSION < 2 if (event.button.button == SDL_BUTTON_WHEELUP) return OnMouseWheel(event.button.x, event.button.y, 1); else if (event.button.button == SDL_BUTTON_WHEELDOWN) return OnMouseWheel(event.button.x, event.button.y, -1); #endif return double_click.Check(RasterPoint(event.button.x, event.button.y)) ? OnMouseDouble(event.button.x, event.button.y) : OnMouseDown(event.button.x, event.button.y); case SDL_MOUSEBUTTONUP: #if SDL_MAJOR_VERSION < 2 if (event.button.button == SDL_BUTTON_WHEELUP || event.button.button == SDL_BUTTON_WHEELDOWN) /* the wheel has already been handled in SDL_MOUSEBUTTONDOWN */ return false; #endif double_click.Moved(RasterPoint(event.button.x, event.button.y)); return OnMouseUp(event.button.x, event.button.y); case SDL_QUIT: return OnClose(); #if SDL_MAJOR_VERSION < 2 case SDL_VIDEORESIZE: Resize(event.resize.w, event.resize.h); return true; #endif #if SDL_MAJOR_VERSION >= 2 case SDL_MOUSEWHEEL: int x, y; SDL_GetMouseState(&x, &y); return OnMouseWheel(x, y, event.wheel.y); case SDL_WINDOWEVENT: switch (event.window.event) { case SDL_WINDOWEVENT_RESIZED: Resize(event.window.data1, event.window.data2); return true; case SDL_WINDOWEVENT_RESTORED: case SDL_WINDOWEVENT_MOVED: case SDL_WINDOWEVENT_SHOWN: case SDL_WINDOWEVENT_MAXIMIZED: { SDL_Window* event_window = SDL_GetWindowFromID(event.window.windowID); if (event_window) { int w, h; SDL_GetWindowSize(event_window, &w, &h); if ((w >= 0) && (h >= 0)) { Resize(w, h); } } } return true; case SDL_WINDOWEVENT_EXPOSED: invalidated = false; Expose(); return true; } #endif } return false; }
void GLShapeRenderer::polygonVertex(GLdouble *vertex) { curr_polygon.insert(curr_polygon.end(), RasterPoint(vertex[0], vertex[1])); }
bool TopWindow::OnEvent(const SDL_Event &event) { switch (event.type) { Window *w; #if SDL_MAJOR_VERSION < 2 case SDL_VIDEOEXPOSE: invalidated = false; Expose(); return true; #endif case SDL_KEYDOWN: w = GetFocusedWindow(); if (w == NULL) w = this; if (!w->IsEnabled()) return false; #if SDL_MAJOR_VERSION >= 2 return w->OnKeyDown(event.key.keysym.sym); #else return w->OnKeyDown(event.key.keysym.sym) || (event.key.keysym.unicode != 0 && w->OnCharacter(event.key.keysym.unicode)); #endif #if SDL_MAJOR_VERSION >= 2 case SDL_TEXTINPUT: w = GetFocusedWindow(); if (w == NULL) w = this; if (!w->IsEnabled()) return false; if (event.text.text && *event.text.text) { std::pair<unsigned, const char *> next = NextUTF8(event.text.text); bool handled = w->OnCharacter(next.first); while (next.second) { next = NextUTF8(next.second); handled = w->OnCharacter(next.first) || handled; } return handled; } else return false; #endif case SDL_KEYUP: w = GetFocusedWindow(); if (w == NULL) w = this; if (!w->IsEnabled()) return false; return w->OnKeyUp(event.key.keysym.sym); case SDL_MOUSEMOTION: // XXX keys return OnMouseMove(event.motion.x, event.motion.y, 0); case SDL_MOUSEBUTTONDOWN: #if SDL_MAJOR_VERSION < 2 if (event.button.button == SDL_BUTTON_WHEELUP) return OnMouseWheel(event.button.x, event.button.y, 1); else if (event.button.button == SDL_BUTTON_WHEELDOWN) return OnMouseWheel(event.button.x, event.button.y, -1); #endif return double_click.Check(RasterPoint(event.button.x, event.button.y)) ? OnMouseDouble(event.button.x, event.button.y) : OnMouseDown(event.button.x, event.button.y); case SDL_MOUSEBUTTONUP: #if SDL_MAJOR_VERSION < 2 if (event.button.button == SDL_BUTTON_WHEELUP || event.button.button == SDL_BUTTON_WHEELDOWN) /* the wheel has already been handled in SDL_MOUSEBUTTONDOWN */ return false; #endif double_click.Moved(RasterPoint(event.button.x, event.button.y)); return OnMouseUp(event.button.x, event.button.y); case SDL_QUIT: return OnClose(); #if SDL_MAJOR_VERSION < 2 case SDL_VIDEORESIZE: Resize(event.resize.w, event.resize.h); return true; #endif #if SDL_MAJOR_VERSION >= 2 case SDL_MOUSEWHEEL: int x, y; SDL_GetMouseState(&x, &y); return OnMouseWheel(x, y, event.wheel.y); case SDL_WINDOWEVENT: switch (event.window.event) { case SDL_WINDOWEVENT_RESIZED: Resize(event.window.data1, event.window.data2); return true; case SDL_WINDOWEVENT_EXPOSED: invalidated = false; Expose(); return true; } #endif } return false; }
void ButtonFrameRenderer::DrawButton(Canvas &canvas, PixelRect rc, bool focused, bool pressed) const { const ButtonLook::StateLook &_look = focused ? look.focused : look.standard; canvas.DrawFilledRectangle(rc, _look.background_color); const unsigned margin = GetMargin(); if (margin < 4) { /* draw 1-pixel lines */ canvas.Select(pressed ? _look.dark_border_pen : _look.light_border_pen); for (unsigned i = 0; i < margin; ++i) canvas.DrawTwoLinesExact(rc.left + i, rc.bottom - 2 - i, rc.left + i, rc.top + i, rc.right - 2 - i, rc.top + i); canvas.Select(pressed ? _look.light_border_pen : _look.dark_border_pen); for (unsigned i = 0; i < margin; ++i) canvas.DrawTwoLinesExact(rc.left + 1 + i, rc.bottom - 1 - i, rc.right - 1 - i, rc.bottom - 1 - i, rc.right - 1 - i, rc.top + 1 + i); } else { /* at 4 pixels or more, it's more efficient to draw a filled polygon */ const RasterPoint p1[] = { RasterPoint(rc.left, rc.top), RasterPoint(rc.right, rc.top), RasterPoint(rc.right - margin, rc.top + margin), RasterPoint(rc.left + margin, rc.top + margin), RasterPoint(rc.left + margin, rc.bottom - margin), RasterPoint(rc.left, rc.bottom), }; canvas.SelectNullPen(); canvas.Select(pressed ? _look.dark_border_brush : _look.light_border_brush); canvas.DrawTriangleFan(p1, ARRAY_SIZE(p1)); const RasterPoint p2[] = { RasterPoint(rc.right, rc.bottom), RasterPoint(rc.right, rc.top), RasterPoint(rc.right - margin, rc.top + margin), RasterPoint(rc.right - margin, rc.bottom - margin), RasterPoint(rc.left + margin, rc.bottom - margin), RasterPoint(rc.left, rc.bottom), }; canvas.Select(pressed ? _look.light_border_brush : _look.dark_border_brush); canvas.DrawTriangleFan(p2, ARRAY_SIZE(p2)); } }
bool TopWindow::OnEvent(const SDL_Event &event) { switch (event.type) { Window *w; #if SDL_MAJOR_VERSION < 2 case SDL_VIDEOEXPOSE: invalidated = false; Expose(); return true; #endif case SDL_KEYDOWN: w = GetFocusedWindow(); if (w == nullptr) w = this; if (!w->IsEnabled()) return false; #if SDL_MAJOR_VERSION >= 2 return w->OnKeyDown(event.key.keysym.sym); #else return w->OnKeyDown(event.key.keysym.sym) || (event.key.keysym.unicode != 0 && w->OnCharacter(event.key.keysym.unicode)); #endif #if SDL_MAJOR_VERSION >= 2 case SDL_TEXTINPUT: w = GetFocusedWindow(); if (w == nullptr) w = this; if (!w->IsEnabled()) return false; if (*event.text.text) { std::pair<unsigned, const char *> next = NextUTF8(event.text.text); bool handled = w->OnCharacter(next.first); while (next.second) { next = NextUTF8(next.second); handled = w->OnCharacter(next.first) || handled; } return handled; } else return false; #endif case SDL_KEYUP: w = GetFocusedWindow(); if (w == nullptr) w = this; if (!w->IsEnabled()) return false; return w->OnKeyUp(event.key.keysym.sym); #ifdef HAVE_MULTI_TOUCH case SDL_FINGERDOWN: if (SDL_GetNumTouchFingers(event.tfinger.touchId) == 2) return OnMultiTouchDown(); else return false; case SDL_FINGERUP: if (SDL_GetNumTouchFingers(event.tfinger.touchId) == 1) return OnMultiTouchUp(); else return false; #endif case SDL_MOUSEMOTION: // XXX keys #ifdef HAVE_HIGHDPI_SUPPORT { auto x = event.motion.x; auto y = event.motion.y; PointToReal(x, y); return OnMouseMove(x, y, 0); } #else return OnMouseMove(event.motion.x, event.motion.y, 0); #endif case SDL_MOUSEBUTTONDOWN: { #if SDL_MAJOR_VERSION < 2 if (event.button.button == SDL_BUTTON_WHEELUP) return OnMouseWheel(event.button.x, event.button.y, 1); else if (event.button.button == SDL_BUTTON_WHEELDOWN) return OnMouseWheel(event.button.x, event.button.y, -1); #endif #ifdef HAVE_HIGHDPI_SUPPORT auto x = event.button.x; auto y = event.button.y; PointToReal(x, y); return double_click.Check(RasterPoint(x, y)) ? OnMouseDouble(x, y) : OnMouseDown(x, y); #else return double_click.Check(RasterPoint(event.button.x, event.button.y)) ? OnMouseDouble(event.button.x, event.button.y) : OnMouseDown(event.button.x, event.button.y); #endif } case SDL_MOUSEBUTTONUP: { #if SDL_MAJOR_VERSION < 2 if (event.button.button == SDL_BUTTON_WHEELUP || event.button.button == SDL_BUTTON_WHEELDOWN) /* the wheel has already been handled in SDL_MOUSEBUTTONDOWN */ return false; #endif #ifdef HAVE_HIGHDPI_SUPPORT auto x = event.button.x; auto y = event.button.y; PointToReal(x, y); double_click.Moved(RasterPoint(x, y)); return OnMouseUp(x, y); #else double_click.Moved(RasterPoint(event.button.x, event.button.y)); return OnMouseUp(event.button.x, event.button.y); #endif } case SDL_QUIT: return OnClose(); #if SDL_MAJOR_VERSION < 2 case SDL_VIDEORESIZE: Resize(event.resize.w, event.resize.h); return true; #endif #if SDL_MAJOR_VERSION >= 2 case SDL_MOUSEWHEEL: { int x, y; SDL_GetMouseState(&x, &y); #ifdef HAVE_HIGHDPI_SUPPORT PointToReal(x, y); #endif return OnMouseWheel(x, y, event.wheel.y); } case SDL_WINDOWEVENT: switch (event.window.event) { case SDL_WINDOWEVENT_RESIZED: #ifndef HAVE_HIGHDPI_SUPPORT Resize(event.window.data1, event.window.data2); return true; #endif case SDL_WINDOWEVENT_RESTORED: case SDL_WINDOWEVENT_MOVED: case SDL_WINDOWEVENT_SHOWN: case SDL_WINDOWEVENT_MAXIMIZED: { SDL_Window* event_window = SDL_GetWindowFromID(event.window.windowID); if (event_window) { int w, h; SDL_GetWindowSize(event_window, &w, &h); if ((w >= 0) && (h >= 0)) { #ifdef HAVE_HIGHDPI_SUPPORT int real_w, real_h; SDL_GL_GetDrawableSize(event_window, &real_w, &real_h); point_to_real_x = static_cast<float>(real_w) / static_cast<float>(w); point_to_real_y = static_cast<float>(real_h) / static_cast<float>(h); Resize(real_w, real_h); #else Resize(w, h); #endif } #if defined(__MACOSX__) && __MACOSX__ SDL_SysWMinfo *wm_info = reinterpret_cast<SDL_SysWMinfo *>(alloca(sizeof(SDL_SysWMinfo))); SDL_VERSION(&wm_info->version); if ((SDL_GetWindowWMInfo(event_window, wm_info)) && (wm_info->subsystem == SDL_SYSWM_COCOA)) { [wm_info->info.cocoa.window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary]; } Invalidate(); #endif } } return true; case SDL_WINDOWEVENT_EXPOSED: invalidated = false; Expose(); return true; } #endif }
void TrailRenderer::Draw(Canvas &canvas, const TraceComputer &trace_computer, const WindowProjection &projection, unsigned min_time, bool enable_traildrift, const RasterPoint pos, const NMEAInfo &basic, const DerivedInfo &calculated, const TrailSettings &settings) { if (settings.length == TrailSettings::Length::OFF) return; if (!LoadTrace(trace_computer, min_time, projection)) return; if (!calculated.wind_available) enable_traildrift = false; GeoPoint traildrift; if (enable_traildrift) { GeoPoint tp1 = FindLatitudeLongitude(basic.location, calculated.wind.bearing, calculated.wind.norm); traildrift = basic.location - tp1; } auto minmax = GetMinMax(settings.type, trace); auto value_min = minmax.first; auto value_max = minmax.second; bool scaled_trail = settings.scaling_enabled && projection.GetMapScale() <= 6000; const GeoBounds bounds = projection.GetScreenBounds().Scale(4); RasterPoint last_point = RasterPoint(0, 0); bool last_valid = false; for (auto it = trace.begin(), end = trace.end(); it != end; ++it) { const GeoPoint gp = enable_traildrift ? it->GetLocation().Parametric(traildrift, it->CalculateDrift(basic.time)) : it->GetLocation(); if (!bounds.IsInside(gp)) { /* the point is outside of the MapWindow; don't paint it */ last_valid = false; continue; } RasterPoint pt = projection.GeoToScreen(gp); if (last_valid) { if (settings.type == TrailSettings::Type::ALTITUDE) { unsigned index = GetAltitudeColorIndex(it->GetAltitude(), value_min, value_max); canvas.Select(look.trail_pens[index]); canvas.DrawLinePiece(last_point, pt); } else { unsigned color_index = GetSnailColorIndex(it->GetVario(), value_min, value_max); if (it->GetVario() < 0 && (settings.type == TrailSettings::Type::VARIO_1_DOTS || settings.type == TrailSettings::Type::VARIO_2_DOTS || settings.type == TrailSettings::Type::VARIO_DOTS_AND_LINES)) { canvas.SelectNullPen(); canvas.Select(look.trail_brushes[color_index]); canvas.DrawCircle((pt.x + last_point.x) / 2, (pt.y + last_point.y) / 2, look.trail_widths[color_index]); } else { // positive vario case if (settings.type == TrailSettings::Type::VARIO_DOTS_AND_LINES) { canvas.Select(look.trail_brushes[color_index]); canvas.Select(look.trail_pens[color_index]); //fixed-width pen canvas.DrawCircle((pt.x + last_point.x) / 2, (pt.y + last_point.y) / 2, look.trail_widths[color_index]); } else if (scaled_trail) // width scaled to vario canvas.Select(look.scaled_trail_pens[color_index]); else // fixed-width pen canvas.Select(look.trail_pens[color_index]); canvas.DrawLinePiece(last_point, pt); } } } last_point = pt; last_valid = true; } if (last_valid) canvas.DrawLine(last_point, pos); }