fonttools / skia-pathops

Python bindings for the Skia library's Path Ops
https://skia.org/docs/dev/present/pathops/
BSD 3-Clause "New" or "Revised" License
47 stars 14 forks source link

Path.close method make the last point in segments None #71

Closed sakiodre closed 1 year ago

sakiodre commented 1 year ago

The path:

M0.117,0.055 Q0.117,0.029 0.107,0.029 Q0.097,0.029 0.097,0.055 Q0.097,0.081 0.107,0.081 Q0.117,0.081 0.117,0.055 Z

Minimal reproducible code:

skia = pathops.Path(fillType=pathops.FillType.WINDING)
skia.moveTo(0.117, 0.055)
skia.quadTo(0.117, 0.029, 0.107, 0.029)
skia.quadTo(0.097, 0.029, 0.097, 0.055)
skia.quadTo(0.097, 0.081, 0.107, 0.081)
skia.quadTo(0.117, 0.081, 0.117, 0.055)
skia.close()

for cmd, points in skia.segments:
    print(cmd, points)

Output (last point is None):

qCurveTo ((0.11699999868869781, 0.028999999165534973), (0.09700000286102295, 0.028999999165534973), (0.09700000286102295, 0.08100000023841858), (0.11699999868869781, 0.08100000023841858), None)
closePath ()

When not calling close(), the last point is correct:

moveTo ((0.11699999868869781, 0.054999999701976776),)
qCurveTo ((0.11699999868869781, 0.028999999165534973), (0.09700000286102295, 0.028999999165534973), (0.09700000286102295, 0.08100000023841858), (0.11699999868869781, 0.08100000023841858), (0.11699999868869781, 0.054999999701976776))
endPath ()

Additionally, if we don't skia.moveTo(0.117, 0.055), or move to a slightly different position, this won't occur. Is this an expected behavior?

anthrotype commented 1 year ago

Yeah, that's not a bug but a "feature" actually.. was added in https://github.com/fonttools/skia-pathops/pull/66

we use skia-pathops in font building/manipulation, and TrueType outlines can contain closed contours made up of a single quadratic spline in which the quadratic bezier on-curve points are implicit. The segments property returns a SegmentPenIterator that is meant to match the API of FontTools Segment Pen protocol which represents these contours like that (a single qCurveTo with a None on-curve point).

what's your use specific case?

If you want to retrieve the original skia path "verbs" and points, you should not use segments but just iterate over the path itself (which will yield RawPathIterator, not the SegmentPenIterator).

sakiodre commented 1 year ago

Thanks, I'm using nanoemoji which uses picosvg which uses this, I see that you're also a member of googlefonts so would you mind check out my issue picosvg#304?