Part 6 of 7

Creating a Cairo-Inspired Graphics Library for MetaTrader 5 (Part 6): Curves and Adaptive Flattening

Creating a Cairo-Inspired Graphics Library for MetaTrader 5 (Part 6): Curves and Adaptive Flattening

Why this article was written

After Part 5 the renderer fills arbitrary outlines, anti-aliases their edges and punches real holes through them. What it still could not draw was a curve.

Every demo up to this point faked them. A "circle" was a polygon the demo computed itself, with a segment count picked by hand. That works until the shape changes size — too few segments and the curve shows facets, too many and you pay for vertices nobody can see.

Part 6 adds CurveTo, and with it the question that really matters: how many straight segments, and where?

What is inside

The answer is not a fixed number. It is De Casteljau subdivision — the method Paul de Casteljau worked out at Citroën in 1959 — which splits a curve in half using nothing but midpoint averages. Six additions and a halving give you both halves exactly. No trigonometry, no polynomial evaluation.

Knowing when to stop. A new Path.mqh helper, DistanceToChord, measures how far the two control points sit from the straight line between the endpoints. If that total is within tolerance, the curve is already flat enough and the chord is emitted. Otherwise it splits and asks each half the same question.

What adaptive actually buys you. Over one test path — a 280 px sweep, a 110 px bend and a 40 px corner — adaptive flattening at 0.30 px produced 46, 27 and 15 vertices. A fixed loop of 32 segments produced 33 for each: too many for the gentle sweep, too few for the hairpin. The article is careful to say this is not a universal theorem, and shows where the comparison is fair.

Flatten now, or store the curve? Both options are laid out honestly. The library flattens immediately into the same vertex array MoveTo and LineTo already use, so BuildEdges and the rasterizer need no curve awareness at all. The cost is stated plainly: a path is fixed at the resolution it was built for, which rules out transforms, dashed strokes, hit testing and morphing on the original analytic curve.

One dial, and the dial it is not. Config.mqh gains CairoFlattenTolerance = 0.30, a runtime global rather than a #define. A comparison table separates it from CairoAaSamples: one controls geometric fidelity, the other paint smoothness. Turning up anti-aliasing will never fix a faceted curve, and the article explains why.

Two verbs, one of them free. CurveTo takes a cubic. QuadTo takes a quadratic — the form TrueType outlines use — and converts it to a cubic by degree elevation, which is exact, not an approximation.

An honest note on scope

Circles and arcs are not in this part. A circle is not a Bézier curve, and approximating one with the usual 0.5523 constant is a compromise this series declines to make. Part 7 derives the arc properly.

State of the library after this part:

MQL5
Color.mqh      Part 1    the ARGB color type
               Part 4    + CairoBlendOver
Config.mqh     Part 4    CairoAaSamples - the AA quality dial
               Part 6    + CairoFlattenTolerance                  <- today
Surface.mqh    Part 1    a pixel buffer bound to one chart object
Path.mqh       Part 2    points, contours, the pen
               Part 3    + BuildEdges
               Part 5    + AddThickLine
               Part 6    + CurveTo, QuadTo, the flattener         <- today
Raster.mqh     Part 3/4  the scanline fill, with coverage
               Part 5    + the fill rule

Raster.mqh is untouched. Curves never reach it — by the time it runs, there are only line segments.

More in this series

Building a real 2D renderer for MetaTrader 5 in pure MQL5 — anti-aliased shapes, transparency and gradients, with no DLLs and no external tools. About this series

  1. Part 1Why the terminal needs its own 2D-rendererSeptember 3, 2026
  2. Part 2Points, Contours and the PathSeptember 10, 2026
  3. Part 3Edges and the First Filled ShapeSeptember 28, 2026
  4. Part 4Anti-Aliasing, Coverage and CompositingSeptember 28, 2026
  5. Part 5Fill Rules, Holes and BordersOctober 1, 2026
  6. Part 6Curves and Adaptive Flattening — you are hereOctober 23, 2026
  7. Part 7Arcs, Circles and Rounded RectanglesOctober 27, 2026

Continue reading on MQL5.com

The full article with complete source code is published on MQL5.com.

Read the full article