lines - open path intersection with paths



  • Hey, i'm trying to create a grid of lines that whenever intersect a font (shape) they get thicker. The rough sketch looks like this: 0_1526367427664_Schermata 2018-05-15 alle 08.56.18.png
    I haven't found a better way to get intersection points with open paths ( https://github.com/typemytype/drawbot/issues/160 )
    and i'm doing everything by hand.

    
    bez2 = BezierPath()
    bez2.text("c", font="Helvetica-Bold", fontSize=500)
    translate(width()*.3, height()*.3)
    fill(None)
    stroke(0)
    
    bez3 = BezierPath()
    bez3.moveTo((0, 50))
    bez3.lineTo((300, 50))
    
    bez1 = BezierPath()
    bez1.moveTo((0, 250))
    bez1.lineTo((300, 250))
    
    drawPath(bez1)
    drawPath(bez2)
    drawPath(bez3)
    
    import pyclipper
    
    def split(arr, size):
         arrs = []
         while len(arr) > size:
             pice = arr[:size]
             arrs.append(pice)
             arr   = arr[size:]
         arrs.append(arr)
         return arrs
         
    pc = pyclipper.Pyclipper()
    pc.AddPath(bez2.points, pyclipper.PT_SUBJECT, True)
    pc.AddPath(bez1.points, pyclipper.PT_SUBJECT, False)
    pc.AddPath(bez3.points, pyclipper.PT_SUBJECT, False)
    
    solution = pc.Execute2(pyclipper.CT_UNION, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO)
    
    allSolutionPoints = set(bez1.points) |  set(bez2.points)  |  set(bez3.points)  
    
    for contour in pyclipper.OpenPathsFromPolyTree(solution):
        for x, y in contour:
            allSolutionPoints.add((x, y))
    
    allPoints = set(bez1.points) |  set(bez2.points)  |  set(bez3.points)  
    intersections = allSolutionPoints - allPoints 
    
    s = 5
    
    coord =[]
    splitted_coord =[]
    print(intersections)
    
    for x, y in intersections:
        oval(x-s, y-s, s*2, s*2)
        coord.append(x)
        coord.append(y)
            
         
    splitted_coord = split(coord, 4)
    print(splitted_coord)
    strokeWidth(5)
    
    for elem in splitted_coord :
        line((elem[0],elem[1]),(elem[2],elem[3]))
        
    # check original points
    for x,y in bez2.points:
        stroke(None)
        fill(1,0,0)
        #oval(x-s, y-s, s*2, s*2)
         
    

    Is there a better way to do it? If i were to continue like this at a certain point everything will mess up:
    0_1526367665614_Schermata 2018-05-15 alle 09.00.52.png
    In this case the points are in the right positions, but the lines should be horizontal and it's driving me crazy.



  • updates:

    newPage(500,500)
    rect(0, 0, width(), height())
    fill(0)
    
    word = "a"
    
    testo0 = BezierPath()
    testo0.text(word, font="Helvetica-Bold", fontSize=500)
    
    testo1 = BezierPath()
    testo1.text(word, font="Helvetica-Bold", fontSize=500)
    
    testo2 = BezierPath()
    testo2.text(word, font="Helvetica-Bold", fontSize=500)
    
    testo3 = BezierPath()
    testo3.text(word, font="Helvetica-Bold", fontSize=500)
    
    testo4 = BezierPath()
    testo4.text(word, font="Helvetica-Bold", fontSize=500)
    
    testo5 = BezierPath()
    testo5.text(word, font="Helvetica-Bold", fontSize=500)
    
    testo6 = BezierPath()
    testo6.text(word, font="Helvetica-Bold", fontSize=500)
    
    
    translate(width()/4, height()/4)
    
    
    fill(None)
    stroke(1)
    
    bez0 = BezierPath()
    bez0.moveTo((0, 5))
    bez0.lineTo((300, 5))
    
    
    bez1 = BezierPath()
    bez1.moveTo((0, 45))
    bez1.lineTo((300, 45))
    
    bez2 = BezierPath()
    bez2.moveTo((0, 90))
    bez2.lineTo((300, 90))
    
    
    bez3 = BezierPath()
    bez3.moveTo((0, 135))
    bez3.lineTo((300, 135))
    
    bez4 = BezierPath()
    bez4.moveTo((0, 185))
    bez4.lineTo((300, 185))
    
    bez5 = BezierPath()
    bez5.moveTo((0, 225))
    bez5.lineTo((300, 225))
    
    bez6 = BezierPath()
    bez6.moveTo((0, 270))
    bez6.lineTo((300, 270))
    
    #drawPath(testo1)
    drawPath(bez1)
    drawPath(bez2)
    drawPath(bez3)
    drawPath(bez4)
    drawPath(bez0)
    drawPath(bez5)
    drawPath(bez6)
    
    import pyclipper
    
    def split(arr, size):
         arrs = []
         while len(arr) > size:
             pice = arr[:size]
             arrs.append(pice)
             arr   = arr[size:]
         arrs.append(arr)
         return arrs
    
    pc0 = pyclipper.Pyclipper()
    pc0.AddPath(testo0.points, pyclipper.PT_SUBJECT, True)
    pc0.AddPath(bez0.points, pyclipper.PT_SUBJECT, False)
         
    pc = pyclipper.Pyclipper()
    pc.AddPath(testo1.points, pyclipper.PT_SUBJECT, True)
    pc.AddPath(bez1.points, pyclipper.PT_SUBJECT, False)
    
    pc1 = pyclipper.Pyclipper()
    pc1.AddPath(testo2.points, pyclipper.PT_SUBJECT, True)
    pc1.AddPath(bez2.points, pyclipper.PT_SUBJECT, False)
    
    pc2 = pyclipper.Pyclipper()
    pc2.AddPath(testo3.points, pyclipper.PT_SUBJECT, True)
    pc2.AddPath(bez3.points, pyclipper.PT_SUBJECT, False)
    
    pc3 = pyclipper.Pyclipper()
    pc3.AddPath(testo4.points, pyclipper.PT_SUBJECT, True)
    pc3.AddPath(bez4.points, pyclipper.PT_SUBJECT, False)
    
    pc4 = pyclipper.Pyclipper()
    pc4.AddPath(testo5.points, pyclipper.PT_SUBJECT, True)
    pc4.AddPath(bez5.points, pyclipper.PT_SUBJECT, False)
    
    pc5 = pyclipper.Pyclipper()
    pc5.AddPath(testo6.points, pyclipper.PT_SUBJECT, True)
    pc5.AddPath(bez6.points, pyclipper.PT_SUBJECT, False)
    
    solution0 = pc0.Execute2(pyclipper.CT_UNION, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO)
    solution = pc.Execute2(pyclipper.CT_UNION, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO)
    solution1 = pc1.Execute2(pyclipper.CT_UNION, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO)
    solution2 = pc2.Execute2(pyclipper.CT_UNION, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO)
    solution3 = pc3.Execute2(pyclipper.CT_UNION, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO)
    solution4 = pc4.Execute2(pyclipper.CT_UNION, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO)
    solution5 = pc5.Execute2(pyclipper.CT_UNION, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO)
    
    allSolutionPoints0 =  set()
    allSolutionPoints =  set()
    allSolutionPoints1 =  set()
    allSolutionPoints2 = set()
    allSolutionPoints3 = set()
    allSolutionPoints4 = set()
    allSolutionPoints5 = set()
    
    for contour in pyclipper.OpenPathsFromPolyTree(solution0):
        for x, y in contour:
            allSolutionPoints0.add((x, y))
    
    for contour in pyclipper.OpenPathsFromPolyTree(solution):
        for x, y in contour:
            allSolutionPoints.add((x, y))
    
    for contour in pyclipper.OpenPathsFromPolyTree(solution1):
        for x, y in contour:
            allSolutionPoints1.add((x, y))
    
    for contour in pyclipper.OpenPathsFromPolyTree(solution2):
        for x, y in contour:
            allSolutionPoints2.add((x, y))
            
    for contour in pyclipper.OpenPathsFromPolyTree(solution3):
        for x, y in contour:
            allSolutionPoints3.add((x, y))
    for contour in pyclipper.OpenPathsFromPolyTree(solution4):
        for x, y in contour:
            allSolutionPoints4.add((x, y))    
    for contour in pyclipper.OpenPathsFromPolyTree(solution5):
        for x, y in contour:
            allSolutionPoints5.add((x, y))    
                
    allPoints = set(bez0.points) |  set(bez1.points)  | set(bez2.points) | set(bez3.points) | set(bez4.points) | set(bez5.points)  | set(bez6.points) 
    
    
    
    intersections0 = allSolutionPoints0 - allPoints 
    intersections = allSolutionPoints - allPoints 
    intersections1 = allSolutionPoints1 - allPoints 
    intersections2 = allSolutionPoints2 - allPoints 
    intersections3 = allSolutionPoints3 - allPoints 
    intersections4 = allSolutionPoints4 - allPoints 
    intersections5 = allSolutionPoints5 - allPoints 
    
    s = 10
    
    coord =[]
    splitted_coord =[]
    print("0",intersections0)
    print("-",intersections)
    print("1",intersections1)
    print("2",intersections2)
    print("3",intersections3)
    print("4",intersections4)
    print("5",intersections5)
    
    print("")
    
    fill(1,1,1)
    
    for x, y in intersections0:
        oval(x-s, y-s, s*2, s*2)
        coord.append(x)
        coord.append(y)
        
    for x, y in intersections:
        oval(x-s, y-s, s*2, s*2)
        coord.append(x)
        coord.append(y)
        
    for x, y in intersections1:
        oval(x-s, y-s, s*2, s*2)
        coord.append(x)
        coord.append(y)
       
    for x, y in intersections2:
        oval(x-s, y-s, s*2, s*2)
        coord.append(x)
        coord.append(y)   
                 
    for x, y in intersections3:
        oval(x-s, y-s, s*2, s*2)
        coord.append(x)
        coord.append(y)    
                
    for x, y in intersections4:
        oval(x-s, y-s, s*2, s*2)
        coord.append(x)
        coord.append(y)
        
    for x, y in intersections5:
        oval(x-s, y-s, s*2, s*2)
        coord.append(x)
        coord.append(y)  
                 
    splitted_coord = split(coord, 4)
    print("split2",split(coord, 2))
    print("split4",split(coord, 4))
    
    strokeWidth(20)
    for elem in splitted_coord :
        try:
            print (elem[0],elem[1]),(elem[2],elem[3])
            line((elem[0],elem[1]),(elem[2],elem[3]))
            
        except:
            continue
            
    stroke(1,0,0) 
    #line((53, 135) ,(158, 135))
            
    # check original points
    for x,y in testo1.points:
        stroke(None)
        fill(1,0,1)
        #oval(x-s, y-s, s*2, s*2)
         
    

    0_1526383380440_Schermata 2018-05-15 alle 13.21.49.png

    It just works with some letters, i don't get the order it follows when i add the elements to the array, coord.append(x) coord.append(y). Sometimes the x points shift and it mess everything again.

    0_1526383829092_Schermata 2018-05-15 alle 13.30.17.png



  • drawBot includes the fontPens library, which contains MarginPen; you can use it to get the intersections of a line with a shape.

    here’s an example:

    from fontPens.marginPen import MarginPen
    
    fill(None)
    stroke(0)
    
    B = BezierPath()
    B.text("g", font="Helvetica-Bold", fontSize=1000)
    drawPath(B)
    
    for y in range(0, height(), 100):
    
        strokeWidth(1)
        line((0, y), (width(), y))
    
        pen = MarginPen(dict(), y, isHorizontal=True)
        B.drawToPen(pen)
    
        strokeWidth(10)
        intersections = pen.getAll()
        for i, x in enumerate(intersections):
            if not i % 2:
                xNext = intersections[i+1]
                line((x, y), (xNext, y))
    

    0_1526384199816_marginPen-example.png



  • @gferreira Perfect, thanks! silly question: where did you find fontPens in the documentation?



  • @sinanatra MarginPen used to live in roboFab.pens. with the retirement of roboFab, some pens were moved to a new library called fontPens.


Log in to reply