otfried / ipe

The Ipe extensible drawing editor
http://ipe.otfried.org
125 stars 9 forks source link

Inaccuracy when exporting small circles to SVG #461

Closed Willem3141 closed 1 year ago

Willem3141 commented 1 year ago

When exporting small circles to SVG (radius smaller than approximately 4?) Ipe only uses two cubic Bézier splines rather than four like it does for big circles. While the approximation with four splines is indistinguishable from an actual circle, the approximation with two splines makes for a "fatter" shape than a circle. The difference is small but visually noticeable: I found out about this behavior when I exported a logo with some small circles to SVG and noticed that the circles looked "off" in the SVG version.

To demonstrate, I created an Ipe file with two circles, one with radius 6.4 and one with radius 3.2. For both circles I added small marks positioned exactly on the circle. In Ipe these marks are indeed shown correctly:
image

After exporting to SVG and opening the result in Inkscape, it looks like this:
image

On the small circle, the marks' position deviates noticeably from the "circle":
image

otfried commented 1 year ago

Ipe simply calls cairo_arc to draw this ellipse. I'm surprised that Cairo doesn't produce an SVG arc primitive, and instead converts to Bezier curves.

One should probably make a minimal Cairo example that shows why the SVG backend is producing the imprecise approximation and report that to the Cairo maintainers.

otfried commented 1 year ago

Hmm, maybe we need to try a development version of cairo first. The release version is nearly five years old, and there was significant work done on the SVG backend since then.

Willem3141 commented 1 year ago

Based on your comment that Cairo handles ellipse drawing, I took a quick look at the current Cairo development source code. Some preliminary conclusions:

So I'm assuming that in the Ipe interface, when you zoom in, Cairo dynamically decides that at some point it will need more curve segments to stay below the 0.1 pixel tolerance. In the SVG output in my example file, apparently the deviation is below 0.1 "pixel", but if you actually zoom in on the resulting SVG file this deviation is of course blown up and becomes visible.

So in summary, it seems like making the tolerance configurable would solve this issue.

otfried commented 1 year ago

Thanks for the detective work!

If I add a parameter --tolerance to iperender, would that be good enough for your needs?

Willem3141 commented 1 year ago

Yes, that would be perfect for me. (Assuming that cairo_set_tolerance works as advertised – I haven't actually tested it.)

otfried commented 1 year ago

I can confirm that iperender -svg -tolerance 0.01 circle-test.ipe circle-test.svg now looks as it does in your first screen shot.

It'll be in 7.2.28.

Willem3141 commented 1 year ago

Excellent, thank you!