Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add filter pen that explicitly emits closing line when lastPt != movePt #3100

Merged
merged 1 commit into from May 25, 2023

Conversation

anthrotype
Copy link
Member

In the FontTools segment pen protocol, when the last segment of a closed contour is a line, the same contour can be represented in two alternative ways:

  1. with an explicit lineTo command connecting the penultimate segment's end point to the first moveTo point: in this case, closePath does nothing else than signalling that the contour is "closed", i.e. the first and last point coincide, they are the very same point, not simply two overlapping endpoints of a zero-length line;
  2. with an implicit closing line (the final lineTo omitted) implied by the closePath command, like PostScript closepath or SVG's Z commands.

This new filter pen makes sure that the final line segment (iff there is one, which is not necessarily the case for a closed contour may well end with a curve) is always drawing explicitly with its own lineTo command, and never left implicit by closePath. This is basically equivalent to doing PointToSegmentPen(SegmentToPointPen(pen), outputImpliedClosingLine=True), but is more direct.
This can be useful when working with pen drawing commands (as opposed to unambiguously explicit contour points) and one intends to normalize two paths in order to test whether they are interpolation compatible (i.e. contain the same number/types of segments).

>>> r1 = RecordingPen()
>>> p1 = ExplicitClosingLinePen(r1)
>>> p1.moveTo((0,0))
>>> p1.curveTo((1,1), (2,2), (3,3))
>>> p1.curveTo((4,4), (5,5), (0,0))
>>> p1.closePath()
>>> r2 = RecordingPen()
>>> p2 = ExplicitClosingLinePen(r2)
>>> p2.moveTo((0,0))
>>> p2.curveTo((1,1), (2,2), (3,3))
>>> p2.curveTo((4,4), (5,5), (6,6))
>>> p2.closePath()
>>> len(r1.value) != len(r2.value)  # different number of segments
>>> r1.value
[('moveTo', ((0, 0),)),
 ('curveTo', ((1, 1), (2, 2), (3, 3))),
 ('curveTo', ((4, 4), (5, 5), (0, 0))),
 ('closePath', ())]
>>> r2.value
[('moveTo', ((0, 0),)),
 ('curveTo', ((1, 1), (2, 2), (3, 3))),
 ('curveTo', ((4, 4), (5, 5), (6, 6))),
 ('lineTo', ((0, 0),)),
 ('closePath', ())]

it can be useful when comparing two paths and testing whether then contain the same number/types of segments
@anthrotype anthrotype merged commit 9877995 into main May 25, 2023
10 checks passed
@anthrotype anthrotype deleted the explicit-closing-line-pen branch May 25, 2023 11:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant