bez.intersectionPoints() doesn't work with open paths
I understand why boolean operations don't support open paths: because it is not well defined how that should work. However, this doesn't hold for bez.intersectionPoints(), where the result for open paths is completely well defined. Is this a fundamental limitation of clipper, or booleanOperations, or is it something we could work around?
From an API perspective I see no reason why this shouldn't work:
bez1 = BezierPath()
bez1.moveTo((50, 50))
bez1.lineTo((300, 300))
bez2 = BezierPath()
bez2.rect(100, 65, 200, 200)
stroke(0)
fill(None)
drawPath(bez1)
drawPath(bez2)
r = 4
for x, y in bez1.intersectionPoints(bez2):
oval(x - r, y - r, r * 2, r * 2)
Subject' paths may be either open (lines) or closed (polygons) or even a mixture of both, but 'clipping' paths must always be closed. Clipper allows polygons to clip both lines and other polygons, but doesn't allow lines to clip either lines or polygons.
http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Classes/ClipperBase/Methods/AddPaths.htm
only the PolyTree structure can differentiate between open and closed paths since each PolyNode has an IsOpen property. (The Path structure has no member indicating whether it's open or closed.) For this reason, when open paths are passed to a Clipper object, the user must use a PolyTree object as the solution parameter, otherwise an exception will be raised.
http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Classes/Clipper/Methods/Execute.htm
pyclipper supports all of that in theory, but booleanOperations constructs Path objects instead of PolyTree objects and sets closed=True in AddPath function.
I wonder whether/how skia-pathops deals with this issue of clipping open paths (can’t remember). https://github.com/fonttools/skia-pathops
pyclipper can idd handle this:
I will fix this in booleanOperations
bez1 = BezierPath()
bez1.moveTo((50, 50))
bez1.lineTo((300, 300))
bez2 = BezierPath()
bez2.rect(100, 65, 200, 200)
fill(None)
stroke(0)
drawPath(bez1)
drawPath(bez2)
import pyclipper
pc = pyclipper.Pyclipper()
pc.AddPath(bez2.points, pyclipper.PT_SUBJECT, True)
pc.AddPath(bez1.points, pyclipper.PT_SUBJECT, False)
solution = pc.Execute2(pyclipper.CT_UNION, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO)
allSolutionPoints = set()
for contour in pyclipper.OpenPathsFromPolyTree(solution):
for x, y in contour:
allSolutionPoints.add((x, y))
for contour in pyclipper.ClosedPathsFromPolyTree(solution):
for x, y in contour:
allSolutionPoints.add((x, y))
allPoints = set(bez1.points) | set(bez2.points)
intersections = allSolutionPoints - allPoints
s = 5
for x, y in intersections:
oval(x-s, y-s, s*2, s*2)
this only works where at least 1 path is a closed path, pyclipper cannot handle finding intersection of a list of only open paths. I would like to keep it as it is: all boolean operations requires closed paths...