diff options
author | Rasmus Andersson <rasmus@notion.se> | 2017-08-22 10:05:20 +0300 |
---|---|---|
committer | Rasmus Andersson <rasmus@notion.se> | 2017-08-22 12:23:08 +0300 |
commit | 3b1fffade1473f20f2558733fbd218f4580fc7c3 (patch) | |
tree | ea4f80b43b08744d493bb86ab646444ec04ddc7f /misc/pylib/fontbuild/mitreGlyph.py | |
download | inter-3b1fffade1473f20f2558733fbd218f4580fc7c3.tar.xz |
Initial public commitv1.0
Diffstat (limited to 'misc/pylib/fontbuild/mitreGlyph.py')
-rw-r--r-- | misc/pylib/fontbuild/mitreGlyph.py | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/misc/pylib/fontbuild/mitreGlyph.py b/misc/pylib/fontbuild/mitreGlyph.py new file mode 100644 index 000000000..d0834ed84 --- /dev/null +++ b/misc/pylib/fontbuild/mitreGlyph.py @@ -0,0 +1,111 @@ +# 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. + + +"""Mitre Glyph: + +mitreSize : Length of the segment created by the mitre. The default is 4. +maxAngle : Maximum angle in radians at which segments will be mitred. The default is .9 (about 50 degrees). + Works for both inside and outside angles + +""" + +import math +from robofab.objects.objectsRF import RPoint, RSegment +from fontbuild.convertCurves import replaceSegments + +def getTangents(contours): + tmap = [] + for c in contours: + clen = len(c) + for i in range(clen): + s = c[i] + p = s.points[-1] + ns = c[(i + 1) % clen] + ps = c[(clen + i - 1) % clen] + np = ns.points[1] if ns.type == 'curve' else ns.points[-1] + pp = s.points[2] if s.type == 'curve' else ps.points[-1] + tmap.append((pp - p, np - p)) + return tmap + +def normalizeVector(p): + m = getMagnitude(p); + if m != 0: + return p*(1/m) + else: + return RPoint(0,0) + +def getMagnitude(p): + return math.sqrt(p.x*p.x + p.y*p.y) + +def getDistance(v1,v2): + return getMagnitude(RPoint(v1.x - v2.x, v1.y - v2.y)) + +def getAngle(v1,v2): + angle = math.atan2(v1.y,v1.x) - math.atan2(v2.y,v2.x) + return (angle + (2*math.pi)) % (2*math.pi) + +def angleDiff(a,b): + return math.pi - abs((abs(a - b) % (math.pi*2)) - math.pi) + +def getAngle2(v1,v2): + return abs(angleDiff(math.atan2(v1.y, v1.x), math.atan2(v2.y, v2.x))) + +def getMitreOffset(n,v1,v2,mitreSize=4,maxAngle=.9): + + # dont mitre if segment is too short + if abs(getMagnitude(v1)) < mitreSize * 2 or abs(getMagnitude(v2)) < mitreSize * 2: + return + angle = getAngle2(v2,v1) + v1 = normalizeVector(v1) + v2 = normalizeVector(v2) + if v1.x == v2.x and v1.y == v2.y: + return + + + # only mitre corners sharper than maxAngle + if angle > maxAngle: + return + + radius = mitreSize / abs(getDistance(v1,v2)) + offset1 = RPoint(round(v1.x * radius), round(v1.y * radius)) + offset2 = RPoint(round(v2.x * radius), round(v2.y * radius)) + return offset1, offset2 + +def mitreGlyph(g,mitreSize,maxAngle): + if g == None: + return + + tangents = getTangents(g.contours) + sid = -1 + for c in g.contours: + segments = [] + needsMitring = False + for s in c: + sid += 1 + v1, v2 = tangents[sid] + off = getMitreOffset(s,v1,v2,mitreSize,maxAngle) + s1 = s.copy() + if off != None: + offset1, offset2 = off + p2 = s.points[-1] + offset2 + s2 = RSegment('line', [(p2.x, p2.y)]) + s1.points[0] += offset1 + segments.append(s1) + segments.append(s2) + needsMitring = True + else: + segments.append(s1) + if needsMitring: + replaceSegments(c, segments) |