1 # -*- coding: utf-8 -*-
3 # Copyright (C) 2000-2005 by Yasushi Saito (yasushi.saito@gmail.com)
5 # Jockey is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by the
7 # Free Software Foundation; either version 2, or (at your option) any
10 # Jockey is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 from pychart_types import *
28 Arrow is an optional component of a chart that draws line segments with
29 an arrowhead. To draw an arrow, one creates an arrow.T object, and calls
30 its "draw" method usually after area.draw() is called (otherwise, area.draw()
31 may overwrite the arrow). For example, the below code draws an arrow
32 from (10,10) to (20,30).
35 a = arrow.T(head_style = 1)
37 a.draw([(10,10), (20,30)])
40 def draw_arrowhead(can, tailx, taily, tipx, tipy, thickness, head_len, style):
41 can.comment("ARROWHEAD tail=(%d,%d) tip=(%d,%d)\n"
42 % (tailx, taily, tipx, tipy))
44 halfthickness = thickness/2.0
47 arrow_len = math.sqrt(dx*dx + dy*dy)
48 angle = math.atan2(dy, dx) * 360 / (2*math.pi)
49 base = arrow_len - head_len
50 can.push_transformation((tailx, taily), None, angle)
54 can.moveto(base, - halfthickness)
55 can.lineto(base, halfthickness)
56 can.lineto(arrow_len, 0)
59 depth = head_len / 2.5
60 can.moveto(base - depth, -halfthickness)
62 can.lineto(base - depth, halfthickness)
63 can.lineto(arrow_len, 0)
66 can.moveto(base + head_len/2.0, 0)
67 can.path_arc(base + head_len / 2.0, 0, head_len / 2.0, 1.0, 0, 400)
70 can.lineto(base + head_len/2.0, -halfthickness)
71 can.lineto(arrow_len, 0)
72 can.lineto(base + head_len/2.0, halfthickness)
75 raise Exception, "Arrow style must be a number between 0 and 3."
77 can.pop_transformation()
78 can.comment("end ARROWHEAD.\n")
80 def draw_arrowbody(can, tailx, taily, tipx, tipy, head_len):
83 arrow_len = math.sqrt(dx*dx + dy*dy)
84 angle = math.atan2(dy, dx) * 360 / (2*math.pi)
85 base = arrow_len - head_len
86 can.push_transformation((tailx, taily), None, angle)
88 can.lineto(base+head_len*0.1, 0)
90 can.pop_transformation()
93 class T(chart_object.T):
94 __doc__ = arrow_doc.doc
96 "thickness" : (UnitType, 4,
97 "The width of the arrow head."),
98 "head_len": (UnitType, 8,
99 "The length of the arrow head."),
100 "head_color": (color.T, color.default,
101 "The color of the arrow head."),
102 "line_style": (line_style.T, line_style.default,
104 "head_style": (IntType, 1,
105 "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.")
107 ##AUTOMATICALLY GENERATED
109 ##END AUTOMATICALLY GENERATED
110 def draw(self, points, can = None):
111 """Parameter <points> specifies the
112 list of points the arrow traverses through.
113 It should contain at least two points, i.e.,
114 the tail and tip. Parameter
115 <can> is an optional parameter that specifies the output.
118 if can == None: can = canvas.default_canvas()
123 xtail = points[-2][0]
124 ytail = points[-2][1]
127 can.set_line_style(self.line_style)
129 can.moveto(points[0][0], points[0][1])
130 for i in range(1, len(points)-1):
131 can.lineto(points[i][0], points[i][1])
133 draw_arrowbody(can, xscale(xtail), yscale(ytail),
134 yscale(xtip), yscale(ytip),
135 nscale(self.head_len))
137 can.set_fill_color(self.head_color)
138 draw_arrowhead(can, xscale(xtail), yscale(ytail),
139 xscale(xtip), yscale(ytip),
140 nscale(self.thickness),
141 nscale(self.head_len),
144 can.setbb(xtail, ytail)
145 can.setbb(xtip, ytip)
147 standards = object_set.T()
153 a0 = _intern(T(head_style=0))
154 a1 = _intern(T(head_style=1))
155 a2 = _intern(T(head_style=2))
156 a3 = _intern(T(head_style=3))
157 gray0 = _intern(T(head_style=0, head_color = color.gray50,
158 line_style=line_style.T(color=color.gray50)))
159 gray1 = _intern(T(head_style=1, head_color = color.gray50,
160 line_style=line_style.T(color=color.gray50)))
161 gray2 = _intern(T(head_style=2, head_color = color.gray50,
162 line_style=line_style.T(color=color.gray50)))
163 gray3 = _intern(T(head_style=3, head_color = color.gray50,
164 line_style=line_style.T(color=color.gray50)))
166 fat0 = _intern(T(head_style=0, head_len=12, thickness=10, line_style=line_style.T(width=2)))
167 fat1 = _intern(T(head_style=1, head_len=12, thickness=10, line_style=line_style.T(width=2)))
168 fat2 = _intern(T(head_style=2, head_len=12, thickness=10, line_style=line_style.T(width=2)))
169 fat3 = _intern(T(head_style=3, head_len=12, thickness=10, line_style=line_style.T(width=2)))
170 fatgray0 = _intern(T(head_style=0, head_len=12, thickness=10,
171 head_color = color.gray50,
172 line_style=line_style.T(width=2, color=color.gray50)))
173 fatgray1 = _intern(T(head_style=1, head_len=12, thickness=10,
174 head_color = color.gray50,
175 line_style=line_style.T(width=2, color=color.gray50)))
176 fatgray2 = _intern(T(head_style=2, head_len=12, thickness=10,
177 head_color = color.gray50,
178 line_style=line_style.T(width=2, color=color.gray50)))
179 fatgray3 = _intern(T(head_style=3, head_len=12, thickness=10,
180 head_color = color.gray50,
181 line_style=line_style.T(width=2, color=color.gray50)))