tfont icon indicating copy to clipboard operation
tfont copied to clipboard

WIP: Implement qcurve handling in tfont

Open madig opened this issue 6 years ago • 16 comments

This makes the text tool work.

Todo: look at what's missing. Intersection to make ruler work.

TestFont.ufo was cribbed from defcon. Had to change public.backgrounds A to not be all-off-curves, otherwise UFOConverter would be stuck in an infinite loop trying to shuffle points around ;)

madig avatar Dec 01 '18 00:12 madig

There is code for intersection here: https://github.com/trufont/trufont/blob/wx/src/trufont/util/bezierMath.py#L99

adrientetar avatar Dec 01 '18 16:12 adrientetar

Neat! Any reason to have a bezierMath.py in Trufont and tfont?

madig avatar Dec 01 '18 19:12 madig

Ugh. The TruFont function doesn't seem to work (aside from pc0 having a - instead of a + in it) or I'm confused. My trigonometry-fu is very weak. I found https://stackoverflow.com/questions/27664298/calculating-intersection-point-of-quadratic-bezier-curve but the math in there seems to work differently. E.g. in fontTools' solveQuadratic function, it computes DD = b * b - 4.0 * a * c which turns DD negative with the example curve and line and therefore returns no root, whereas the JS example computes DD = b * b - 4.0 * c and leaves out the / a. in the root calculation. Debugging...

madig avatar Dec 01 '18 22:12 madig

Ok, so this is a very rough implementation that works. I don't know why fontTools' solveQuadratic works differently. I'd have to work out the math to avoid the _lerp(). The previous way of computing s0 and s1 looked better.

madig avatar Dec 01 '18 23:12 madig

And for some reason, depending on ufoLib2 does not pull in fontTools[ufo]. Ugh.

madig avatar Dec 01 '18 23:12 madig

Still occasionally get

  File "/home/nikolaus/Entwicklung/tfont/src/tfont/util/bezierMath.py", line 132, in qcurveIntersections
    pc1 = (nx * bx + ny * by) / pc0
ZeroDivisionError: float division by zero

Just catch that and return []?

madig avatar Dec 01 '18 23:12 madig

https://pomax.github.io/bezierinfo/#what-about-curve-line-intersections- https://pomax.github.io/bezierinfo/#aligning

Hm :) Let's see.

madig avatar Dec 02 '18 00:12 madig

I gave up and simply adapted curveIntersections' math for quadratics. It werks! 🎉

madig avatar Dec 02 '18 10:12 madig

splitSegment is tricky I think, as we don't know which subsegment of the qcurve segment the t belongs to :thinking:

madig avatar Dec 02 '18 18:12 madig

I suppose I could change the return value of (q)curveIntersections to include the starting point of the curve the t belongs to, then it's just iterating over the implied subsegments until you hit the right starting point and splitting the subsegment.

madig avatar Dec 05 '18 20:12 madig

Or the index of the segment. then it can be accessed directly https://github.com/trufont/trufont/blob/wx/src/trufont/objects/factories.py#L104

adrientetar avatar Dec 06 '18 07:12 adrientetar

What is the reason cmp is turned off for Point?

madig avatar Dec 22 '18 01:12 madig

What is the reason cmp is turned off for Point?

Comparison is based on identity so two different points with the same coordinates wouldn't hash to the same value.

adrientetar avatar Jan 24 '19 08:01 adrientetar

I find this maddeningly tricky while it looks like there must be an easy solution.

madig avatar Jan 29 '19 00:01 madig

@adrientetar So this mostly works, please advise on the segment list bookkeeping and what to return as newSegment.

I have code like

points_inserted = len(points_to_insert) - 1
segments.insert(index, newSegment)
new_segments = []
index_start = start
for index, point in enumerate(points[start : start + points_inserted]):
    if point.type is not None:
        new_segments.append(Segment(points, index_start, index))
        index_start += index + 1
segments[index:index+1] = new_segments
newSegment = new_segments[0]
for seg in segments[index + 1 :]:
    seg._start += points_inserted
    seg._end += points_inserted

But that likes to delete everything except one point under certain circumstances.

Even with the sledgehammer method in the PR, sometimes I can literally draw a cutting line through a glyph, deleting everything below it, if I cut a glyph just right...

madig avatar Feb 22 '19 00:02 madig

Adding the fs dependency directly is ugly, but specifying fonttools[ufo] instead does not work...

Edit: alternative approach: always depend on fontools[ufo,lxml].

madig avatar Feb 23 '19 16:02 madig