1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
"""Mitre Glyph:
mitreSize : Length of the segment created by the mitre. The default is 4.
maxAngle : Maximum angle in radians at which nodes will be mitred. The default is .9 (about 50 degrees).
Works for both inside and outside angles
"""
from FL import *
import math
def getContours(g):
nLength = len(g.nodes)
contours = []
cid = -1
for i in range(nLength):
n = g.nodes[i]
if n.type == nMOVE:
cid += 1
contours.append([])
contours[cid].append(n)
return contours
def getTangents(contours):
tmap = []
for c in contours:
clen = len(c)
for i in range(clen):
n = c[i]
p = Point(n.x, n.y)
nn = c[(i + 1) % clen]
pn = c[(clen + i - 1) % clen]
if nn.type == nCURVE:
np = Point(nn[1].x,nn[1].y)
else:
np = Point(nn.x,nn.y)
if n.type == nCURVE:
pp = Point(n[2].x,n[2].y)
else:
pp = Point(pn.x,pn.y)
nVect = Point(-p.x + np.x, -p.y + np.y)
pVect = Point(-p.x + pp.x, -p.y + pp.y)
tmap.append((pVect,nVect))
return tmap
def normalizeVector(p):
m = getMagnitude(p);
if m != 0:
return p*(1/m)
else:
return Point(0,0)
def getMagnitude(p):
return math.sqrt(p.x*p.x + p.y*p.y)
def getDistance(v1,v2):
return getMagnitude(Point(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 = Point(round(v1.x * radius), round(v1.y * radius))
offset2 = Point(round(v2.x * radius), round(v2.y * radius))
return offset1, offset2
def mitreGlyph(g,mitreSize,maxAngle):
if g == None:
return
contours = getContours(g)
tangents = getTangents(contours)
nodes = []
needsMitring = False
nid = -1
for c in contours:
for n in c:
nid += 1
v1, v2 = tangents[nid]
off = getMitreOffset(n,v1,v2,mitreSize,maxAngle)
n1 = Node(n)
if off != None:
offset1, offset2 = off
n2 = Node(nLINE, Point(n.x + offset2.x, n.y + offset2.y))
n1[0].x += offset1.x
n1[0].y += offset1.y
nodes.append(n1)
nodes.append(n2)
needsMitring = True
else:
nodes.append(n1)
if needsMitring:
g.Clear()
g.Insert(nodes)
fl.SetUndo()
mitreGlyph(fl.glyph,8.,.9)
fl.UpdateGlyph()
|