Tutorial request: BezierPath() to pen

  • Is there some example code on how to feed a BezierPath into a custom pen (where I manipulate the coordinates with a function and change the _lineTo) and then draw that transformed path in my canvas?

    thanks, j

  • hallo @jo,

    here’s a quick example using FlattenPen:

    from fontParts.fontshell import RGlyph
    from fontPens.flattenPen import FlattenPen
    # make a bezier shape (oval)
    srcShape = BezierPath()
    srcShape.oval(100, 100, 600, 600)
    # draw bezier shape into a glyph
    srcGlyph = RGlyph()
    srcPen = srcGlyph.getPen()
    # flatten glyph into a new glyph
    dstGlyph = RGlyph()
    dstPen = dstGlyph.getPen()
    flattenPen = FlattenPen(dstPen, approximateSegmentLength=200)
    # draw the result into a bezier shape
    dstShape = BezierPath()

    maybe there are better ways to do it…

  • admin

    thanks Gustavo!

    A BezierPath acts already like a pen or pointPen object and can be draw into a pen using path.drawToPen(anotherPen) or path.drawToPointPen(anotherPointPen)

    see BezierPath.drawToPen

  • @frederik thanks for the clarification. (polymorphism FTW)

    here’s a variation of the example script above, using BezierPaths directly as pens:

    '''transform a bezier path using a pen'''
    from fontPens.flattenPen import FlattenPen
    # make a source shape
    srcShape = BezierPath()
    srcShape.oval(100, 100, 600, 600)
    # make a new shape for the result
    dstShape = BezierPath()
    # get a flatten pen to draw the result
    flattenPen = FlattenPen(dstShape, approximateSegmentLength=200)
    # feed the source shape into the pen
    # draw the resulting shape

  • thanks @gferreira and @frederik!
    great help. i managed to botch my rough attempt at type on a curve.

    # --------------------------------
    #  imports 
    from fontTools.pens.basePen import BasePen
    # --------------------------------
    #  settings 
    pw = ph = 400
    r = 89
    angle = pi * 3.1
    baseline = ph/2 + r
    txt = 'HELLO'
    tang_f = .333 # tangent factor
    center = pw/2, baseline
    focus  = pw/2, baseline - r
    # --------------------------------
    #  functions 
    def ip(a, b, f): return a + (b-a) * f
    def conv_point(p):
        x, y = p
        f = (x - pw/2) / (pw/2)
        a = -angle/2 * f
        x_conv = center[0] + cos(a + pi/2) * (r + y - baseline)
        y_conv = center[1] + sin(a + pi/2) * (r + y - baseline) - r
        return x_conv, y_conv
    class convert_path_pen(BasePen):
        def __init__(self, targetPen):
            self.targetPen = targetPen
        def _moveTo(self, pt):
            self.targetPen.moveTo( conv_point(pt) )
            self.prev_pt = pt
        def _lineTo(self, pt):
            if self.prev_pt[0] == pt[0]:
                self.targetPen.lineTo( conv_point(pt) )
                tang_1 = ip(self.prev_pt[0], pt[0], tang_f), ip(self.prev_pt[1], pt[1], tang_f)
                tang_2 = ip(self.prev_pt[0], pt[0], 1-tang_f), ip(self.prev_pt[1], pt[1], 1-tang_f)
                self.targetPen.curveTo(conv_point(tang_1), conv_point(tang_2), conv_point(pt))
            self.prev_pt = pt
        def _curveToOne(self, tang_1, tang_2, pt):
            self.targetPen.curveTo(conv_point(tang_1), conv_point(tang_2), conv_point(pt))
            self.prev_pt = pt
        def _closePath(self):
    # --------------------------------
    #  drawings 
    path = BezierPath()
    path.text(txt, font="Helvetica", fontSize = 80, align = 'center', offset=(0, baseline))
    newPage(pw, ph)
    trans_path = BezierPath()
    trans_pen = convert_path_pen( trans_path )
    path.drawToPen( trans_pen )

    obligatory gifs

  • admin

    looking good!!

  • @jo this is very nice. thanks for sharing it!

  • admin

    found it back: this reminds me a thing I wrote some years ago

Log in to reply

Looks like your connection to DrawBot Forum was lost, please wait while we try to reconnect.