Skip to content

Draw thick curves as several one-pixel strokes on screen (30-50x faster) - #84

Merged
PierreRaybaut merged 1 commit into
developfrom
feature/82-fast-thick-curves
Oct 29, 2026
Merged

PierreRaybaut merged 1 commit into
developfrom
feature/82-fast-thick-curves

Conversation

@PierreRaybaut

Copy link
Copy Markdown
Contributor

Closes #82. Follow-up of #81, part of DataLab-Platform/DataLab#453 (curve readability).

Problem

Qt's raster engine draws pens wider than one device pixel much more slowly than one-pixel pens, which prevents applications from using thicker, more readable curves.

Change

  • CurveItem.drawLines uses the new get_thick_line_strokes() helper on screen (raster engine, no scaling transform).
  • An opaque solid curve wider than one device pixel is drawn as several cosmetic one-device-pixel strokes:
    • the strokes are offset horizontally and vertically by at most one device pixel from each other;
    • the device pixel ratio is taken into account;
    • dash patterns are scaled by the line width, as for the original pen;
    • the polyline is computed once, and the curve is filled once.
  • The original pen is still used in the following cases:
    • printing and exporting (other paint engines, scaled painters);
    • translucent colors and non-solid pen brushes;
    • lines wider than 8 device pixels (THICK_LINE_MAX_STROKES_WIDTH);
    • when the new curve/fast_thick_lines option of the plot configuration section is disabled (enabled by default).

Measurements

Noisy curve, 2000 points, width 2, antialiased, CurveItem.drawSeries on a QImage:

Line style DPR Original pen Strokes
Solid 1.0 366 ms 9.8 ms
Solid 1.5 569 ms 18.0 ms
Dashed 1.0 502 ms 9.6 ms
Dashed 1.5 742 ms 15.9 ms

Fidelity compared with the original pen (noisy sine curve, widths 1.5/2/3, DPR 1 and 1.5):

  • total ink within 4 %;
  • pixel difference below 8 % of the total ink.

Tests

New plotpy/tests/unit/test_curve_thick_strokes.py:

  • stroke offsets, including with the device pixel ratio;
  • dash pattern scaling;
  • cases keeping the original pen (thin, translucent, very wide, scaled painter, other paint engine, option disabled);
  • rendering fidelity against the original pen;
  • translucent curves rendered exactly as before.

plotpy/tests/unit and plotpy/tests/items pass locally: 325 passed, 5 skipped. test_edit_point_tool was deselected because it also fails locally without this change (mouse simulation).

Qt's raster engine draws pens wider than one device pixel much more
slowly than one-pixel pens. On screen (raster engine without scaling
transform), opaque solid curves wider than one device pixel are now
drawn as several cosmetic one-pixel strokes, offset horizontally and
vertically by at most one device pixel from each other, with dash
patterns scaled by the line width. The polyline is computed once and the
curve is filled once.

A noisy 2000-point curve of width 2 now takes about 10 ms instead of
370 ms to draw with antialiasing, with almost the same appearance.
Printing, exporting, translucent colors and lines wider than 8 device
pixels still use the original pen. The new `curve/fast_thick_lines`
option of the `plot` section restores the previous behavior.

Closes #82

Assisted-by: Claude Opus 5.5
@PierreRaybaut
PierreRaybaut merged commit 8042fd5 into develop Oct 29, 2026
4 checks passed
@PierreRaybaut
PierreRaybaut deleted the feature/82-fast-thick-curves branch October 29, 2026 15:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant