memononen / nanovg

Antialiased 2D vector drawing library on top of OpenGL for UI and visualizations.
zlib License
5.06k stars 767 forks source link

Draw an Arc with a Hole #651

Closed DCubix closed 1 year ago

DCubix commented 1 year ago

I'm trying to draw an Arc using NanoVG in C++ but I get the following artifact: image

That triangle in the middle... The desired result would be this: image

This is my code:

Rect b = bounds;
float radius = std::min(b.width, b.height) / 2;

const float thickness = 16.0f;
const float rotation = PI / 2;
const float gap = PI / 4.5f;

const float angleFrom = rotation - gap;
const float angleSpan = (PI * 2.0f) - (gap * 2.0f);

nvgBeginPath(ctx);
nvgArc(ctx, b.width / 2, b.height / 2, radius, angleFrom + gap * 2, angleFrom, NVG_CW);
nvgLineTo(ctx, b.width / 2, b.height / 2);

nvgPathWinding(ctx, NVG_HOLE);
nvgCircle(ctx, b.width / 2, b.height / 2, radius - thickness);

nvgFillColor(ctx, nvgRGBAf(0.0f, 0.0f, 0.0f, 0.6f));
nvgFill(ctx);
memononen commented 1 year ago

The nvgPathWinding() has weird API, it is not a state, but instead it sets the winding of the last path, so it should come after the nvgCircle().

The composite path support is somewhat limited and you may have some rendering artifacts.

I recommend to draw the shapes as two arcs, one outside and one inside, if you can.

Something along these lines (untested):

nvgBeginPath(ctx);
nvgArc(ctx, b.width / 2, b.height / 2, radius, angleFrom + gap * 2, angleFrom, NVG_CW); // outer
nvgArc(ctx, b.width / 2, b.height / 2, radius - thickness, angleFrom + gap * 2, angleFrom, NVG_CCW); // inner
DCubix commented 1 year ago

@memononen I tested it and I just needed to flip the start and end angles on the second line like this:

nvgBeginPath(ctx);
nvgArc(ctx, b.width / 2, b.height / 2, radius, angleFrom + gap * 2, angleFrom, NVG_CW);
nvgArc(ctx, b.width / 2, b.height / 2, radius - thickness, angleFrom, angleFrom + gap * 2, NVG_CCW);

And it worked :D ModularSynth_XIHZkjT8eZ