[qu2cu] Optimize using a forced set of oncurve points

Speeds up benchmark 12x.
This commit is contained in:
Behdad Esfahbod 2023-02-20 18:04:19 -07:00
parent a4f4cd078c
commit 710232f1d0

View File

@ -24,6 +24,7 @@ except ImportError:
from fontTools.misc.bezierTools import splitCubicAtTC from fontTools.misc.bezierTools import splitCubicAtTC
from collections import namedtuple from collections import namedtuple
import math
from typing import ( from typing import (
List, List,
Tuple, Tuple,
@ -249,6 +250,7 @@ Solution = namedtuple("Solution", ["num_points", "error", "start_index", "is_cub
i=cython.int, i=cython.int,
j=cython.int, j=cython.int,
k=cython.int, k=cython.int,
start=cython.int,
i_sol_count=cython.int, i_sol_count=cython.int,
j_sol_count=cython.int, j_sol_count=cython.int,
this_sol_count=cython.int, this_sol_count=cython.int,
@ -284,13 +286,23 @@ def spline_to_curves(q, costs, tolerance=0.5, all_cubic=False):
elevate_quadratic(*q[i : i + 3]) for i in range(0, len(q) - 2, 2) elevate_quadratic(*q[i : i + 3]) for i in range(0, len(q) - 2, 2)
] ]
# Find sharp corners; the have to be oncurves for sure.
forced = {0}
for i in range(1, len(elevated_quadratics)):
p0 = elevated_quadratics[i - 1][2]
p1 = elevated_quadratics[i][0]
p2 = elevated_quadratics[i][1]
if abs(p1 - p0) + abs(p2 - p1) > tolerance + abs(p2 - p0):
forced.add(i)
# Dynamic-Programming to find the solution with fewest number of # Dynamic-Programming to find the solution with fewest number of
# cubic curves, and within those the one with smallest error. # cubic curves, and within those the one with smallest error.
sols = [Solution(0, 0, 0, False)] sols = [Solution(0, 0, 0, False)]
impossible = Solution(len(elevated_quadratics) * 3 + 1, 0, 1, False) impossible = Solution(len(elevated_quadratics) * 3 + 1, 0, 1, False)
start = 0
for i in range(1, len(elevated_quadratics) + 1): for i in range(1, len(elevated_quadratics) + 1):
best_sol = impossible best_sol = impossible
for j in range(0, i): for j in range(start, i):
j_sol_count, j_sol_error = sols[j].num_points, sols[j].error j_sol_count, j_sol_error = sols[j].num_points, sols[j].error
@ -354,6 +366,8 @@ def spline_to_curves(q, costs, tolerance=0.5, all_cubic=False):
break break
sols.append(best_sol) sols.append(best_sol)
if i in forced:
start = i
# Reconstruct solution # Reconstruct solution
splits = [] splits = []