diff options
Diffstat (limited to 'misc/pylib/fontbuild/convertCurves.py')
-rw-r--r-- | misc/pylib/fontbuild/convertCurves.py | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/misc/pylib/fontbuild/convertCurves.py b/misc/pylib/fontbuild/convertCurves.py new file mode 100644 index 000000000..b6efd5ca2 --- /dev/null +++ b/misc/pylib/fontbuild/convertCurves.py @@ -0,0 +1,102 @@ +#! /usr/bin/env python +# +# Copyright 2015 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Converts a cubic bezier curve to a quadratic spline with +exactly two off curve points. + +""" + +import numpy +from numpy import array,cross,dot +from fontTools.misc import bezierTools +from robofab.objects.objectsRF import RSegment + +def replaceSegments(contour, segments): + while len(contour): + contour.removeSegment(0) + for s in segments: + contour.appendSegment(s.type, [(p.x, p.y) for p in s.points], s.smooth) + +def calcIntersect(a,b,c,d): + numpy.seterr(all='raise') + e = b-a + f = d-c + p = array([-e[1], e[0]]) + try: + h = dot((a-c),p) / dot(f,p) + except: + print a,b,c,d + raise + return c + dot(f,h) + +def simpleConvertToQuadratic(p0,p1,p2,p3): + p = [array(i.x,i.y) for i in [p0,p1,p2,p3]] + off = calcIntersect(p[0],p[1],p[2],p[3]) + +# OFFCURVE_VECTOR_CORRECTION = -.015 +OFFCURVE_VECTOR_CORRECTION = 0 + +def convertToQuadratic(p0,p1,p2,p3): + # TODO: test for accuracy and subdivide further if needed + p = [(i.x,i.y) for i in [p0,p1,p2,p3]] + # if p[0][0] == p[1][0] and p[0][0] == p[2][0] and p[0][0] == p[2][0] and p[0][0] == p[3][0]: + # return (p[0],p[1],p[2],p[3]) + # if p[0][1] == p[1][1] and p[0][1] == p[2][1] and p[0][1] == p[2][1] and p[0][1] == p[3][1]: + # return (p[0],p[1],p[2],p[3]) + seg1,seg2 = bezierTools.splitCubicAtT(p[0], p[1], p[2], p[3], .5) + pts1 = [array([i[0], i[1]]) for i in seg1] + pts2 = [array([i[0], i[1]]) for i in seg2] + on1 = seg1[0] + on2 = seg2[3] + try: + off1 = calcIntersect(pts1[0], pts1[1], pts1[2], pts1[3]) + off2 = calcIntersect(pts2[0], pts2[1], pts2[2], pts2[3]) + except: + return (p[0],p[1],p[2],p[3]) + off1 = (on1 - off1) * OFFCURVE_VECTOR_CORRECTION + off1 + off2 = (on2 - off2) * OFFCURVE_VECTOR_CORRECTION + off2 + return (on1,off1,off2,on2) + +def cubicSegmentToQuadratic(c,sid): + + segment = c[sid] + if (segment.type != "curve"): + print "Segment type not curve" + return + + #pSegment,junk = getPrevAnchor(c,sid) + pSegment = c[sid-1] #assumes that a curve type will always be proceeded by another point on the same contour + points = convertToQuadratic(pSegment.points[-1],segment.points[0], + segment.points[1],segment.points[2]) + return RSegment( + 'qcurve', [[int(i) for i in p] for p in points[1:]], segment.smooth) + +def glyphCurvesToQuadratic(g): + + for c in g: + segments = [] + for i in range(len(c)): + s = c[i] + if s.type == "curve": + try: + segments.append(cubicSegmentToQuadratic(c, i)) + except Exception: + print g.name, i + raise + else: + segments.append(s) + replaceSegments(c, segments) |