Open typemytype opened 6 years ago
yeah, the handling of contour direction in the resulting path sometimes is completely wrong, I still haven't figured out why. I have to say I've lost most of my initial enthusiasm. I'm not looking forward to fix skia bugs.
@anthrotype If you think Skia is not suitable for our needs, we better kill this experiment now and start over with something else.
I don't know, Khaled. Maybe we are using the API incorrectly... I need help from you guys debugging this. I can expose more SkPath methods to Python to help debugging, but I don't know if I have the ability/time to dig deeper in the C++ implementation.
It's fine, we just need to shift the start point to the next on curve and reverse each contour in the resulting path.
We can also try reproducing the issue using this interactive page https://fiddle.skia.org/c/@pathops you can write some C++ code that uses skia and see the rendering live. If we can repro then we can file a bug and hope they fix it upstream.
It's not a bug: https://groups.google.com/d/msg/skia-discuss/9xieDIhMoxk/XbfbmHOTAAAJ
But the transform to what we want is (afaict) deterministic.
so if skia cannot give us a result path with nonzero winding fill type, but always returns a path with even-odd fill type, then we would need a reliable way to change it back to non-zero winding...
Actually yeah, with the example of the OP it doesn't work, one contour needs not be reverse.
Can someone give me a python snippet that I can test with?
Anyway yeah assuming it's a valid even odd contour (which I assume it is, for proper rendering) there must be an algorithm to change the contour according to the other fill rule.
in TruFont, you can do
from pathops import *
glyph = CurrentGlyph()
contours = list(glyph)
glyph.clearContours()
union(contours, glyph.getPen())
note that the union
function is internally calling the binary Op
function with a UNION operator and the second operand being another empty Path.
You could alternatively try using a OpBuilder instance (wrapper for SkOpBuilder.cpp), call add methods on it, and then finally the resolve method, to see if anything changes.
And I noticed sometimes one gets it right, while the other doesn't. I still haven't understood the difference between the two though.
Seems converting from even odd to winding might be quite complex. @behdad thoughts?
also, in the functions defined in operations.py
module, we are accumulating multiple contours in a single Path, and pass that to Op function as a whole.
We could alternatively try calling builder.add for as many contours in a glyph and see if that changes the result. In my tests, it didn't help much (some inner contours would even disappear altogether!)
Interestingly, Skia’s canvas is able to draw the glyph correctly after the union operation https://fiddle.skia.org/c/4873ecb267c61ff616953a3b3887ad9e
@khaledhosny yeah, because it's probably filling them with even-odd rule.
Seems converting from even odd to winding might be quite complex. @behdad thoughts?
Not more complex than doing it with outlines with overlaps! We should ask if Skia has that already. If not, something along https://github.com/behdad/glyphy/blob/master/src/glyphy-outline.cc#L268
its seems like fix_winding
is solving lots of issues...
but still finding issues
(and some other I cannot share publicly without asking permission first)
I think FixWinding is written for single contour paths (it's called by the builder on final paths being finally merging them), which is why it can have weird results for multiple contours.
The core developer of Skia, Cary Clark is willing to help but he first want us to write down the requirements: https://groups.google.com/d/msg/skia-discuss/9xieDIhMoxk/NlQq-AfQBAAJ
we need to reply to him
I can list where booleanOperations interferes with the contours and how it handles different situation. what is the structure of such a requirements? meaning how to write that down?
not sure. he mentions writing up some sample code using http://fiddle.skia.org/ (so it's easy to visualize and we can just share a link) with the desired outcome. he also would like to see how we're using the API. Maybe it'd be easier to just arrange a hangout with him? @behdad
The requirements: to preserve contour direction and start points as much as possible (when the contours are modified and when they aren't).
Also we ought to provide sample results. @typemytype Do you have other boolean ops inputs you can share? The Q in the first post is a good one.
We should have inputs and the results of booleanOperations in SkPath form, i.e. make a path and then call path.dump(). That will print the c++ repr (like I did here).
Have we got back to Cary on this?
No, someone ought to do it.
As an update, I responded in the thread a while ago and bungeman@ pointed to this skia bug about having pathops output proper winding paths (assigned to Cary Clark).
@typemytype @adrientetar @khaledhosny can you retry with the latest skia-pathops (v0.1.3) and see if it fixes the issue with winding direction? There should be wheels available from PyPI shortly (if all the builds complete).
Yes it seems correct now, nice work! I guess the only remaining issue now is the jumping start points.
Yes it seems correct now, nice work!
Yay!
I guess the only remaining issue now is the jumping start points
I'll work on fixing #9 now
https://bugs.chromium.org/p/skia/issues/detail?id=7682
they just added a new SkPathOps::AsWinding
function to convert SkPath from even odd fill to non-zero winding. I'll see if it fixes this bug and if so I'll remove my own winding_from_even_odd
function.
I just enabled the new AsWinding
function, it seems to work however the feature seems unfinished. They seem to have forgotten a stray debug print statement so now we get loads of "incomplete!"...
I may revert for now.
I dont know why, but pathops slowed down a lot... (more correct but a lot slower)
I didn’t notice that. Since what version? How much slower? I’ll take a look after I’m back in September.
The first drawing the source, second the result through skia, the third with booleanOperations