Closed justvanrossum closed 1 month ago
I see what you mean, but it's not us (python bindings) who are doing that, we are just calling the Skia PathOps C++ API (Op
function or SkOpBuilder
class) for binary operations like difference or intersection.
I suspect the pre-semplification of each operands is needed to more easily perform the path operation by clearly distinguishing the two, I don't know.
but it's not us (python bindings)
I know that, but to ask a question to the Skia library community is a way higher threshold... A long shot, for sure.
Thank you for your response!
no worries.. Yeah I know. Skia is a bit of a black box for us too 😅
Are you perhaps using OpBuilder?
I see that one is effectively calling Simplify for each subpath as well as at the end (upon resolve
), see:
https://github.com/google/skia/blob/main/src/pathops/SkOpBuilder.cpp
Maybe you could try using the alternative op
function (wrapper for the C++ Op
function), and see if that changes the result?
I don't see Simplify being called repeatedly in here (but I have only skimmed this and haven't tried myself):
https://github.com/google/skia/blob/main/src/pathops/SkPathOpsOp.cpp
Interesting! I will try to study and understand that, thanks.
like used in here for the binary operations.py
:
https://github.com/fonttools/skia-pathops/blob/815070e964334ec6cdf453f2d859fe2db49d9b06/src/python/pathops/operations.py#L51
We're indeed using OpBuilder. Thanks for the pointer! Will report back.
in theory they should produce the same output, OpBuilder being more efficient when one wants to apply a chain of path operations, as opposed to just one Op between two sets of 'subject' and 'clip' contours.
It would also be interesting to see what booleanOperations do in this case. I tried to design skia-pathops interface to be a drop-in replacement for booleanOperations (in fact ufo2ft can select one or the other). The binary ops (difference, intersection, reverse_difference, xor) take two lists of contours respectively for subject and clip ('contours' are any objects with a draw(pen) method), whereas union only takes a single list. All operations also take a pen to output the result.
I've tried with booleanOperations in DrawBot, and it also seems to remove overlaps.
I've tried with the raw "op" method instead of OpBuilder: no difference.
hm well it was worth a try. I don't think booleanOperations attempts to simplify the contours before processing the binary operations, so if that occurs it must be happening in the underlying Clipper library. Maybe it is in fact necessary for the algorithm to work. If you want to avoid this you'd have to only pass the contours that you want to participate and exclude the ones you don't want to be modified, but I understand this is tricky for fontra from a UI/UX perspective.
It's not about not-participating paths: it could be self-overlapping, or two paths that overlap each other, and after subtraction of another shape could still be overlapping.
For example, before:
After:
For a designer, the fact that the two subject paths merge is unexpected.
good point. Seems like a hard problem and I'm afraid I don't have a solution right now.
Thanks for thinking along. I posted a feature request for the future Kurbo path operations feature :)
I posted a feature request for the future Kurbo path operations feature :)
good idea! This looks beyond my pay-grade but possibly within Raph's :)
I think at least for the case of multiple mutually overlapping subject contours (as in the screenshot) one may perform the difference operation using the same clip path for each distinct subject contour (as opposed to a group of subjects ) such that they will continue to stay distict instead of being merged with one another. However for a single self-overlapping subject contour, that would not work.
I think at least for the case of multiple mutually overlapping subject contours (as in the screenshot) one may perform the difference operation using the same clip path for each distinct subject contour
I was thinking of that as well, but it becomes hard when there are countershapes involved. I even tried this, with setting "fix direction" to False, but somehow failed to get the correct cut for the counter. Maybe I didn't try hard enough.
I think at least for Skia, it doesn't care about keeping overlapping paths since it's a rendering library. The path simplification step that it does first probably simplifies the subsequent boolean op logic.
Before:
After subtracting the selected shape from the rest:
It would be nice if it were possible to keep the overlaps in the subject shape.