123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- #! /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)
|