drawbot icon indicating copy to clipboard operation
drawbot copied to clipboard

bez.intersectionPoints() doesn't work with open paths

Open justvanrossum opened this issue 8 years ago • 5 comments

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)

justvanrossum avatar Dec 22 '17 15:12 justvanrossum

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

anthrotype avatar Dec 23 '17 12:12 anthrotype

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

anthrotype avatar Dec 23 '17 12:12 anthrotype

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

anthrotype avatar Dec 23 '17 12:12 anthrotype

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)

typemytype avatar Dec 23 '17 23:12 typemytype

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...

typemytype avatar Dec 25 '17 20:12 typemytype