Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error in vertex calculation #22

Open
DarkContact opened this issue Aug 23, 2021 · 3 comments
Open

Error in vertex calculation #22

DarkContact opened this issue Aug 23, 2021 · 3 comments

Comments

@DarkContact
Copy link

I tried to make a minimal example to demonstrate the problem.

Let's take a bezier curve made in inkscape:
image
If I try render with vg I see what:
image

Code:

vg::beginPath(vgContext);
float x = 84.889012f; 
float y = 71.749671f;
vg::moveTo(vgContext, x, y);

vg::cubicTo(vgContext,
          x - 2.59f, y + 3.04f,
          x - 6.31f, y + 4.89f,
          x - 10.12f, y + 5.88f);
x = x - 10.12f; y = y + 5.88f;

vg::cubicTo(vgContext,
          x - 3.62f, y + 1.4f,
          x - 6.86f, y + 3.58f,
          x - 10.37f, y + 5.21f);
x = x - 10.37f; y = y + 5.21f;

vg::cubicTo(vgContext,
          x - 2.07f, y + 1.0f,
          x - 4.25f, y + 1.78f,
          x - 6.24f, y + 2.96f);
x = x - 6.24f; y = y + 2.96f;

vg::cubicTo(vgContext, 
          x - 0.509996f, y + 0.1f,
          x + 0.96f, y - 0.67f,
          x + 1.29f, y - 0.85f);
x = x + 1.29f; y = y - 0.85f;

vg::cubicTo(vgContext,
          x + 2.62f, y - 1.3f,
          x + 5.35f, y - 2.37f,
          x + 7.92f, y - 3.78f);
x = x + 7.92f; y = y - 3.78f;

vg::cubicTo(vgContext,
          x + 3.19f, y - 1.6f, 
          x + 6.23f, y - 3.58f,
          x + 9.71f, y - 4.52f);
x = x + 9.71f; y = y - 4.52f;

vg::cubicTo(vgContext,
          x + 2.57f, y - 0.72f,
          x + 4.94f, y - 2.11f,
          x + 6.79f, y - 4.03f);
x = x + 6.79f; y = y - 4.03f; 

vg::cubicTo(vgContext,
          x + 0.34f, y - 0.29f,
          x + 0.58f, y - 0.71f,
          x + 1.02f, y - 0.87f);

vg::closePath(vgContext);
vg::strokePath(vgContext, vg::Colors::Black, 4.0f, vg::StrokeFlags::ButtMiterAA); // Error also with vg::StrokeFlags::ButtMiter

Also the problem is easy to reproduce it to output svg on a small scale (0.1f or less) with AA enabled:
image
image

In an imperial way, I tried to change the kMaxExtrusionScale parameter here:

static const float kMaxExtrusionScale = 1.0f / 100.0f;
and there are fewer chaotic lines. But there are small inaccuracies elsewhere. Any ideas on how to fix this?

@jdryg
Copy link
Owner

jdryg commented Aug 23, 2021

This must be related to miter limit which isn't supported in vg-renderer (see Readme)

Inkscape (and all proper vector graphics renderers) support miter limit which will convert thin long miters into bevel joints. vg-renderer doesn't support miter limit in order to simplify stroke calculations. It was a decision I made very early and never got back into fixing it. I don't really know how much such calculations will affect runtime performance.

Unfortunately, I cannot think of an easy way to fix this, other than rewriting all stroker functions in a way to include this kind of checks and convert the problematic stoke corners into bevels.

EDIT: Added link to stroke-miterlimit SVG attribute.

Not supporting miter limit in vg-renderer is the same as setting the limit to a large value in all other renderers. You can check this by altering stroke-miterlimit in your SVG file and viewing it in your browser. See example in the linked MDN page.

@DarkContact
Copy link
Author

Thanks for the answer. But it seems to me that the problem is not only miter limit. I have attached some images for a better understanding of the problem. In the turquoise rectangles, I have highlighted the problem areas. As the kMaxExtrusionScale ratio increases, there are fewer errors. However, on smaller scales, kMaxExtrusionScale has to be done more in order to achieve acceptable quality. It seems that kMaxExtrusionScale should not be constant. What do you think on this?

svg_010_area
svg_100_area
image
image

@jdryg
Copy link
Owner

jdryg commented Aug 24, 2021

Even path fills suffer from the same problem as strokes without a miter limit when using AA. This is because the same algorithm is used for calculating AA fringes. Fringes as half-width strokes around a filled path. See https://github.com/jdryg/vg-renderer/blob/master/src/stroker.cpp#L867

kMaxExtrusionScale is a hack to limit the amount of extrusion of those problematic cases. The correct way to handle it is to dynamically limit the extrusion and convert those corners into bevels, even for the AA fringes. Problem with dynamically produced bevels is that the amount of vertices isn't known beforehand so extra allocations are necessary inside the inner loop as well as extra checks.

Hope that makes sense. You can check this is due to AA if you disable AA in all the problematic cases you shown above. A polygon fill without AA doesn't introduce any more vertices than those produced by the path tesselation. AA on the other hand produces extra vertices around the polygon with an alpha value of 0 in order to smoothly fade the edges.

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

No branches or pull requests

2 participants