2 # Copyright (C) 2000-2005 by Yasushi Saito (yasushi.saito@gmail.com)
4 # Jockey is free software; you can redistribute it and/or modify it
5 # under the terms of the GNU General Public License as published by the
6 # Free Software Foundation; either version 2, or (at your option) any
9 # Jockey is distributed in the hope that it will be useful, but WITHOUT
10 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 from pychart_types import *
27 Arrow is an optional component of a chart that draws line segments with
28 an arrowhead. To draw an arrow, one creates an arrow.T object, and calls
29 its "draw" method usually after area.draw() is called (otherwise, area.draw()
30 may overwrite the arrow). For example, the below code draws an arrow
31 from (10,10) to (20,30).
34 a = arrow.T(head_style = 1)
36 a.draw([(10,10), (20,30)])
39 def draw_arrowhead(can, tailx, taily, tipx, tipy, thickness, head_len, style):
40 can.comment("ARROWHEAD tail=(%d,%d) tip=(%d,%d)\n"
41 % (tailx, taily, tipx, tipy))
43 halfthickness = thickness/2.0
46 arrow_len = math.sqrt(dx*dx + dy*dy)
47 angle = math.atan2(dy, dx) * 360 / (2*math.pi)
48 base = arrow_len - head_len
49 can.push_transformation((tailx, taily), None, angle)
53 can.moveto(base, - halfthickness)
54 can.lineto(base, halfthickness)
55 can.lineto(arrow_len, 0)
58 depth = head_len / 2.5
59 can.moveto(base - depth, -halfthickness)
61 can.lineto(base - depth, halfthickness)
62 can.lineto(arrow_len, 0)
65 can.moveto(base + head_len/2.0, 0)
66 can.path_arc(base + head_len / 2.0, 0, head_len / 2.0, 1.0, 0, 400)
69 can.lineto(base + head_len/2.0, -halfthickness)
70 can.lineto(arrow_len, 0)
71 can.lineto(base + head_len/2.0, halfthickness)
74 raise Exception, "Arrow style must be a number between 0 and 3."
76 can.pop_transformation()
77 can.comment("end ARROWHEAD.\n")
79 def draw_arrowbody(can, tailx, taily, tipx, tipy, head_len):
82 arrow_len = math.sqrt(dx*dx + dy*dy)
83 angle = math.atan2(dy, dx) * 360 / (2*math.pi)
84 base = arrow_len - head_len
85 can.push_transformation((tailx, taily), None, angle)
87 can.lineto(base+head_len*0.1, 0)
89 can.pop_transformation()
92 class T(chart_object.T):
93 __doc__ = arrow_doc.doc
95 "thickness" : (UnitType, 4,
96 "The width of the arrow head."),
97 "head_len": (UnitType, 8,
98 "The length of the arrow head."),
99 "head_color": (color.T, color.default,
100 "The color of the arrow head."),
101 "line_style": (line_style.T, line_style.default,
103 "head_style": (IntType, 1,
104 "The value of 0 draws a triangular arrow head. The value of 1 draws a swallow-tail arrow head. The value of 2 draws a circular head. The value of 3 draws a diamond-shaped head.")
106 ##AUTOMATICALLY GENERATED
108 ##END AUTOMATICALLY GENERATED
109 def draw(self, points, can = None):
110 """Parameter <points> specifies the
111 list of points the arrow traverses through.
112 It should contain at least two points, i.e.,
113 the tail and tip. Parameter
114 <can> is an optional parameter that specifies the output.
117 if can == None: can = canvas.default_canvas()
122 xtail = points[-2][0]
123 ytail = points[-2][1]
126 can.set_line_style(self.line_style)
128 can.moveto(points[0][0], points[0][1])
129 for i in range(1, len(points)-1):
130 can.lineto(points[i][0], points[i][1])
132 draw_arrowbody(can, xscale(xtail), yscale(ytail),
133 yscale(xtip), yscale(ytip),
134 nscale(self.head_len))
136 can.set_fill_color(self.head_color)
137 draw_arrowhead(can, xscale(xtail), yscale(ytail),
138 xscale(xtip), yscale(ytip),
139 nscale(self.thickness),
140 nscale(self.head_len),
143 can.setbb(xtail, ytail)
144 can.setbb(xtip, ytip)
146 standards = object_set.T()
152 a0 = _intern(T(head_style=0))
153 a1 = _intern(T(head_style=1))
154 a2 = _intern(T(head_style=2))
155 a3 = _intern(T(head_style=3))
156 gray0 = _intern(T(head_style=0, head_color = color.gray50,
157 line_style=line_style.T(color=color.gray50)))
158 gray1 = _intern(T(head_style=1, head_color = color.gray50,
159 line_style=line_style.T(color=color.gray50)))
160 gray2 = _intern(T(head_style=2, head_color = color.gray50,
161 line_style=line_style.T(color=color.gray50)))
162 gray3 = _intern(T(head_style=3, head_color = color.gray50,
163 line_style=line_style.T(color=color.gray50)))
165 fat0 = _intern(T(head_style=0, head_len=12, thickness=10, line_style=line_style.T(width=2)))
166 fat1 = _intern(T(head_style=1, head_len=12, thickness=10, line_style=line_style.T(width=2)))
167 fat2 = _intern(T(head_style=2, head_len=12, thickness=10, line_style=line_style.T(width=2)))
168 fat3 = _intern(T(head_style=3, head_len=12, thickness=10, line_style=line_style.T(width=2)))
169 fatgray0 = _intern(T(head_style=0, head_len=12, thickness=10,
170 head_color = color.gray50,
171 line_style=line_style.T(width=2, color=color.gray50)))
172 fatgray1 = _intern(T(head_style=1, head_len=12, thickness=10,
173 head_color = color.gray50,
174 line_style=line_style.T(width=2, color=color.gray50)))
175 fatgray2 = _intern(T(head_style=2, head_len=12, thickness=10,
176 head_color = color.gray50,
177 line_style=line_style.T(width=2, color=color.gray50)))
178 fatgray3 = _intern(T(head_style=3, head_len=12, thickness=10,
179 head_color = color.gray50,
180 line_style=line_style.T(width=2, color=color.gray50)))