3 # Copyright (C) 2014 Antonio Ospite <ao2@ao2.it>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 def cartesian2polar(x, y, offset_angle=0):
23 """return the polar coordinates relative to a circle
24 centered in (0,0) going counterclockwise.
26 returned angle is in degrees
29 theta = atan2(float(y), float(x)) + offset_angle
31 # report theta in the [0,360) range
32 theta = degrees(theta)
39 def polar2cartesian(r, theta, offset_angle=0):
41 theta expected in degrees
43 theta = radians(theta) - offset_angle
50 class Diagram(object):
52 def __init__(self, filename, width, height):
53 self.filename = filename
57 self.surface = cairo.SVGSurface(filename + '.svg', width, height,
59 cr = self.cr = cairo.Context(self.surface)
64 cr.rectangle(0, 0, width, height)
65 cr.set_source_rgb(1, 1, 1)
69 cr.translate(width/2., height/2.)
72 self.surface.write_to_png(self.filename + '.png')
78 f = StringIO.StringIO()
79 self.surface.write_to_png(f)
84 def draw_line(self, x1, y1, x2, y2, stroke_color=[0, 0, 0, 1]):
90 rf, gf, bf, alpha= stroke_color
91 cr.set_source_rgba(rf, gf, bf, alpha)
94 def draw_circle(self, cx, cy, size=10.0, stroke_color=[0, 0, 0, 1]):
97 cr.arc(cx, cy, size, 0, 2*pi)
99 rf, gf, bf, alpha = stroke_color
100 cr.set_source_rgba(rf, gf, bf, alpha)
104 class PolarGridDiagram(Diagram):
105 def __init__(self, filename, sectors, rings, internal_radius, scale):
106 width = (map_height + internal_radius) * 2 * scale
108 Diagram.__init__(self, filename, width, height)
111 self.sectors = sectors
113 self.internal_radius = internal_radius * scale
114 self.external_radius = width / 2.
115 self.radius = self.external_radius - self.internal_radius
117 def draw_samples(self, stroke_color=[0, 0, 0, 0.5]):
118 for i in range(0, self.rings):
119 for j in range(0, self.sectors):
120 r = self.radius / self.rings * (i + 0.5) + self.internal_radius
121 theta = (360. / self.sectors) * (j + 0.5)
122 x, y = polar2cartesian(r, theta, -pi/2.)
123 self.draw_circle(x, y, 1, stroke_color)
125 def draw_grid(self, stroke_color=[0, 0, 0, 0.5]):
126 line_width = self.cr.get_line_width()
128 for i in range(0, self.rings):
129 self.draw_circle(0, 0, self.radius / self.rings * i + self.internal_radius, stroke_color)
132 self.draw_circle(0, 0, self.external_radius - line_width, stroke_color)
134 min_r = self.internal_radius
135 max_r = self.external_radius - line_width
136 for i in range(0, self.sectors):
137 theta = (360. / self.sectors) * i
138 x1, y1 = polar2cartesian(min_r, theta, -pi/2.)
139 x2, y2 = polar2cartesian(max_r, theta, -pi/2.)
140 self.draw_line(x1, y1, x2, y2, stroke_color)
142 def draw_image(self, image):
144 img = cairo.ImageSurface.create_from_png(image)
145 cr.set_source_surface(img, -self.external_radius, -self.external_radius)
155 if __name__ == '__main__':
157 if len(sys.argv) > 1:
167 grid = PolarGridDiagram('polar_grid', map_width, map_height, internal_radius, scale)