Open ghost opened 4 years ago
Does it work if you reverse the NVG_CCW
and NVG_CW
? NanoVG handles anti-aliasing by insetting the polygon and rendering 1px wide fade around it. That does not work well with inside-out polygons.
Indeed, that did the trick. Damn I thought I tested this case, but I made another "mistake" (see below). With this code:
float mx = 50, my = 50, thick = 8;
nvgPathWinding(vg, NVG_CCW);
nvgRoundedRect(vg, mx+thick, my+thick, width-thick*2, height-thick*2, thick*2);
nvgPathWinding(vg, NVG_CW);
nvgRoundedRect(vg, mx, my, width, height, thick * 3);
nvgFill(vg);
I know get:
Which fits perfectly in the bounding box. So drawing the interior CCW and exterior CW instead of exterior CCW and interior CW.
Another mistake I made, was trying to fill a shape like this (as a single path): Interior rect was declared CCW and exterior rounded rect was CW (both were drawn using the correct™ way), yet I got off by 1 all over the place.
To prevent this, you need to add an nvgMoveTo command to separate both paths.
And indeed it works with all kind of edge cases:
@tpierron
I like your css border style cases. I was wanting to do something similar myself. I'm curious, and it is not clear from the pictures, does your code handle something like this case correctly, where one side has border-width of zero?
#cornerswithhole {
border-radius: 40px;
border-style: solid;
border-width: 20px 20px 20px 0px;
padding: 20px;
}
Edit: Actually, on looking closer, I think you may indeed be having the same issue I raised a little while ago: issues/571 Hope to find a nice solution for this without having to switch off AA.
Yes, this is a similar use case than the 3rd box in the last line: In the screenshot above, there were a few artifacts I didn't noticed, now they are mostly fixed. With your example I got: You can see that the pointy edges are not as sharp as a typical browser (the Firefox version is twice as big, because I did this on a HiDPI screen, where 1px CSS = 2px on screen).
I don't think this is such a big deal, because for most of the use cases, the border thickness will be uniform.
On a side note, I had to add this function to nanovg:
void nvgEllipseArc(NVGcontext* ctx, float cx, float cy, float r0, float r1, float a0, float a1, int dir);
Implementation is trivially derived from nvgArc();
So I'm guessing you are drawing the path+hole as usual, and then correcting the artifact line in some post-processing action? Does this work if drawn over patterned backgrounds?
Edit: oh nevermind, I see that is the result of drawing as a single path. Hmm...
(Note that the artifacts that still remain appear to exist beyond the bounding box. But if you clip that left edge the result will not only be the right size, but also more pointy. A similar approach would be to draw the left border as 1px and then delete.)
If it works for your use case, I agree that it should be good enough. I'm still looking at drawing the whole thing as a single path. Or two separate paths in the case where borders on opposite edges are zero. (I don't need different colours for the borders.)
That nvgEllipseArc() could do with the addition of a rotation parameter, to match the Canvas API. Something along these lines:
void nvgEllipseArc(NVGcontext* ctx, float cx, float cy, float rotation, float r0, float r1, float a0, float a1, int dir)
{
nvgSave(ctx);
nvgTranslate(ctx, cx, cy);
nvgRotate(ctx, rotation);
nvgScale(ctx, r0, r1);
nvgArc(ctx, 0, 0, 1, a0, a1, dir);
nvgRestore(ctx);
}
This is what I have so far. Quite pointy, with no artifacts. Needed to rearrange the command order and move the inner arcs inwards slightly.
Am I missing something or is the precision of filling concave shape with anti-aliasing somewhat not very precise ? Here a very simple example:
It has been generated with a code similar to:
The image has been enlarged with a paint program, the guide lines were also added to show what the bounding box of the round rectangles were. All the coordinates were integer.
As you can see, there's a lot of off by 1 :-/
Interestingly, if I shift the rectangles by 0.02 on X and Y, I got this:
Even weirder, shifted by 0.5 on X and Y (all coordinates have .5 for their decimal part):
Ouch, anti-aliasing introducing ... aliasing :-/
If I disable anti-alias, the shape are fine and fit perfectly within the bounding box, as well as if I use MSAA or if I use convex shape with anti-aliasing.
Is this the expected behavior ?