Skip to content
This repository has been archived by the owner on Aug 9, 2023. It is now read-only.

add pens module containing Cu2QuPen, Cu2QuPointPen, etc. #20

Merged
merged 15 commits into from Apr 21, 2016

Conversation

anthrotype
Copy link
Member

I will add docstrings and tests tomorrow, but this is a start.

The Cu2QuPen follows the fonttools (segment) pen protocol, whereas the Cu2QuPointPen follows the robofab point pen protocol. They both take another segment or point pen in the constructor, and call that with the result of the cubic-to-quadratic conversion.

I believe it's useful to have a reverse_direction argument to invert the contours' winding direction. Now, the ReverseContourPointPen from the robofab.pens does the job. However, I didn't want to add a dependency on robofab, since things are in transition, so I simply copied it here...
We can add it to the future "penBox" package (or whatever it'll be called) once that is set up, no?

Please excuse the mixing of underscores and camelCase: cu2qu uses the former, the pens traditionally use the latter. I tried to to be consistent as much as possible.

Let me know if you have any comments.
Thanks

… and ReverseContourPointPen

I copied the ReverseContourPointPen from the robofab.pens. I think it's useful for the Cu2QuPen to
have a `reverse_direction` argument which inverts the contours' winding direction. I didn't want to
add a dependency on robofab, since things are in transitions... We will add it to the future "penBox"
package (or whatever it'll be called) once that is set up.
@anthrotype
Copy link
Member Author

PS: All pens work on a single-glyph basis. I still haven't figured out how to properly handle collections of glyphs as in cu2qu.rf to maintain the interpolation compatibility. I was thinking of a PenCollection but it didn't work very well. Ideally the GlyphCollection should have a getPen, draw and drawPoints methods like regular glyph objects do. But it's complicated.

@adrientetar
Copy link

r? @behdad @jamesgk

@anthrotype
Copy link
Member Author

please do not merge this just yet as I'm still working on the tests. Thanks

@anthrotype
Copy link
Member Author

Sorry I got sidetracked with other stuff. I've finally pushed the promised unit tests for the Cu2Qu pens. I'll send another PR for setting up the continuous integration.

In the next days I'll look into ways of integrating the pen protocol with the GlyphCollection class (i.e. to keep interpolation compatibility across multiple fonts).

Please let me know if you have any comments. Thanks

@anthrotype
Copy link
Member Author

Ah, about the *.glif test files that are in the test/data/cubic folder: I could have made these up but I wished to use some "real" glyphs. So I took them from existing open source fonts:

  • "a.glif" is from Roboto_Regular.ufo;
  • "A_.glif" and the "E" contour in "E_acute.glif" are from Pablo Impallari's Lobster; I converted them from the vfb using vfb2ufo and normalized the indentation.

The corresponding *.glif files in test/data/quadratic -- i.e. the expected results -- were converted using the current cu2qu.rf.font_to_quadratic.

@jamesgk
Copy link
Contributor

jamesgk commented Mar 28, 2016

I feel like collection classes are less useful with this pen approach. It might be easier to do the error checking outside of init or the pen, instead in some new fonts_to_quadratic which uses pens to draw quadratic curves with a fixed # of points and then checks errors and bumps up # points itself. Though this may be slower and seems to require that the pen take in an optional fixed num points argument.

@jamesgk
Copy link
Contributor

jamesgk commented Mar 29, 2016

Never mind, of course that won't work because you have different # points for different segments in a single glyph. Hmm.

@jamesgk
Copy link
Contributor

jamesgk commented Mar 29, 2016

OK, one idea for using collections with pens. It's kind of messy and involves many passes over a glyph (i.e. "drawing" the glyph many times).

  1. Draw the glyph once to get a count "n" of the cubic curves. Save an array of n 1s representing the necessary control points for each approximation. Assert n is equal for every glyph in the collection.
  2. Draw each glyph in the collection, approximating each i'th cubic with # control points determined by the value in our array at i, and keeping track of each error. If any glyph's error is beyond the bound for an i'th cubic, increment our array at i and try again. Repeat until no error is beyond the bound.

This still doesn't really require any collection objects. You can just do it by zipping the UFOs and extracting lists of glyphs.

else:
# on-curves of sub-segments are always "smooth"
new_segment.append((sub_points[-1], True, None, {}))
sub_segments.append(new_segment)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's a super Bézier?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it a curve segment with implicit inflexion point?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any tool out there that produces these?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not that I know of. Maybe @justvanrossum may now, as he is the original author of the basePen module.
Anyway, since they are part of the Pen Protocol, I implemented them here too.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They're implicitly supported in UFO, too, through BasePen, so we need to be cautious. @typesupply, any thoughts on this?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They were in UFO 1 and 2, but as of UFO 3 curve is limited to one or two offcurves. See here:

http://unifiedfontobject.org/versions/ufo3/glif.html#point

I love super beziers (and desperately need them on something I'm drawing right now) but there wasn't must interest in them when I was updating the spec.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love super beziers (and desperately need them on something I'm drawing right now)

How are they useful?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They allow you to draw a sequence of perfectly smoothly connected cubics with only a few points, so you'll get more flexibility at a low cost. (The number of resulting cubic segments is the number of offcurve points minus one.) Compare that to the need to add three more points (one oncurve, two offcurve points) in your "regular" bezier world, when a single cubic bezier segment simply doesn't cut it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like Robofont supports these curves. I don't know if there's a tool to manipulate them from the GUI, but I could draw one from Python code. Then the control points can be moved inside glyph view. They appear without the handles. Interesting.

g = CurrentGlyph()
pen = g.getPen()
pen.moveTo((10, 10))
pen.curveTo((-1, 28), (-5, 60), (10, 84), (31, 94), (55, 95), (78, 87), (97, 72), (103, 61))
pen.closePath()

@anthrotype
Copy link
Member Author

anthrotype commented Apr 21, 2016

I think this PR can be merged, as it's already useful as is: if, say, one wants to use cu2qu in environments with different glyph APIs than defcon or robofab.objectsRF, and does not need to keep interpolatability.

I would still like to add support in the top-level cu2qu.__init__ for converting groups of "glyphs" compatibly; not just "UFO" glyphs, but any objects having either a drawPoints and/or draw methods (e.g. fonttools, robofab.objectsFL, etc.); such general glyphs_to_quadratic function should not make assumptions about implementation details like glyph.clearContours(), etc., which are not available in all environments; and should not modify the input glyph objects in-place, but only return new glyph-like objects exposing draw/drawPoints methods which the caller can then use to extract the quadratic segments and draw them on their canvas.

I see that in PR #23, James added a file called Lib/cu2qu/test.py. This conflicts with the Lib/cu2qu/test/__init__.py module in this PR.
I'd suggest we merge this one first in master, and then modify #23 so that the content of test.py goes into test/__init__.py?

@jamesgk jamesgk merged commit c82ca16 into googlefonts:master Apr 21, 2016
@jamesgk
Copy link
Contributor

jamesgk commented Apr 21, 2016

I would still like to add support in the top-level cu2qu.__init__ for converting groups of "glyphs" compatibly; not just "UFO" glyphs, but any objects having either a drawPoints and/or draw methods (e.g. fonttools, robofab.objectsFL, etc.); such general glyphs_to_quadratic function should not make assumptions about implementation details like glyph.clearContours(), etc., which are not available in all environments; and should not modify the input glyph objects in-place, but only return new glyph-like objects exposing draw/drawPoints methods which the caller can then use to extract the quadratic segments and draw them on their canvas.

Interesting. I definitely want to reduce duplicate functionality throughout cu2qu, but maybe the ufo module can be adjusted to use a model like this.

@anthrotype
Copy link
Member Author

anthrotype commented Apr 21, 2016

Thanks James!

About googlefonts/ufo2ft#35, now that #20 is merged and we have a ReverseContourPointPen at disposal, I think cu2qu.font[s]_to_quadratic could expose a reverse_direction=False or similar option, and just flip the path orientation if True (provided a UFO editor has already correctly set the PS contour direction)?

@anthrotype
Copy link
Member Author

maybe the ufo module can be adjusted to use a model like this.

definitely. I just need to find the time to finish it. Unless you fix it first ;)

@behdad
Copy link
Contributor

behdad commented Apr 21, 2016

@anthrotype Let's also review this together in Berlin. I haven't had time to do that.

jamesgk pushed a commit that referenced this pull request May 11, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants