Diagram.py: fix and simplify drawing polygon fill and stroke
[experiments/RadialSymmetry.git] / RadialSymmetryDiagram.py
1 #!/usr/bin/env python
2 #
3 # A study on radial symmetry based
4 #
5 # Copyright (C) 2015  Antonio Ospite <ao2@ao2.it>
6 #
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20 from math import *
21 import colorsys
22 import Diagram
23
24
25 class RadialSymmetryModel():
26     def __init__(self, base_polygon_sides=6, base_polygon_radius=None,
27                  base_polygon_angle=0, show_base_polygon=False,
28                  element_sides=3, element_radius=None, element_angle_offset=0,
29                  radial_orientation=True, show_elements=True, show_stars=False,
30                  show_labels=False):
31         self.base_polygon_sides = base_polygon_sides
32         self.base_polygon_radius = base_polygon_radius
33         self.base_polygon_angle = base_polygon_angle
34         self.show_base_polygon = show_base_polygon
35         self.element_sides = element_sides
36         self.element_radius = element_radius
37         self.element_angle_offset = element_angle_offset
38         self.radial_orientate = radial_orientation
39         self.show_elements = show_elements
40         self.show_stars = show_stars
41         self.show_labels = show_labels
42
43
44 class RadialSymmetryDiagram(Diagram.Diagram):
45
46     def draw(self, model):
47         cx = self.width / 2.0
48         cy = self.height / 2.0
49
50         # internal radius
51         if model.base_polygon_radius is None:
52             model.base_polygon_radius = min(self.width, self.height) / 4.0
53
54         if model.element_radius is None:
55             model.element_radius = model.base_polygon_radius
56
57         self.clear()
58         self.draw_elements(cx, cy, model)
59
60     def draw_elements(self, cx, cy, model):
61         central_angle = 2 * pi / model.base_polygon_sides
62
63         base_polygon_orientation = central_angle + model.base_polygon_angle
64
65         verts = self.get_regular_polygon(cx, cy, model.base_polygon_sides, model.base_polygon_radius,
66                                          base_polygon_orientation)
67
68         if model.show_base_polygon:
69             self.draw_polygon(verts, None, [0, 0, 0])
70
71         for i, v in enumerate(verts[:]):
72             radial_orientation_angle = (i + 1) * central_angle
73             rotated_radial_orientation_angle = radial_orientation_angle + model.base_polygon_angle
74
75             # the element orientation may depend the base polygon rotation
76             if model.radial_orientate:
77                 element_angle = rotated_radial_orientation_angle
78             else:
79                 element_angle = 2 * pi / model.element_sides
80
81             element_angle += model.element_angle_offset
82
83             # the element color depends oly on the element index
84             a = self.normalized_angle_01(radial_orientation_angle)
85             color = colorsys.hsv_to_rgb(a, 1.0, 1.0)
86
87             self.draw_element(v[0], v[1], model, element_angle, color)
88
89             if model.show_labels:
90                 ta = self.normalized_angle_01(rotated_radial_orientation_angle)
91                 text = ("%.2f" % (ta * 360)).rstrip('0').rstrip('.')
92                 self.draw_centered_text(v[0], v[1], text,
93                                         rotated_radial_orientation_angle, color,
94                                         align_baseline=True)
95
96     def draw_element(self, x, y, model, theta, color=[0, 0, 0]):
97         if model.show_elements:
98             tverts = self.get_regular_polygon(x, y, model.element_sides, model.element_radius, theta)
99             self.draw_polygon(tverts, None, color)
100
101         if model.show_stars:
102             apothem = model.element_radius * cos(pi / model.element_sides)
103             apothem_angle = theta + pi / model.element_sides
104
105             sverts = self.get_regular_polygon(x, y, model.element_sides, apothem,
106                                               apothem_angle)
107             self.draw_star(x, y, sverts, color)
108
109
110 if __name__ == '__main__':
111     h = RadialSymmetryDiagram(800, 600)
112     h.draw(RadialSymmetryModel(base_polygon_sides=10, element_sides=4, show_stars=True, show_labels=False))
113     h.draw(RadialSymmetryModel(base_polygon_sides=31, element_sides=4, show_stars=False, show_labels=False))
114     h.show()
115     h.save_svg("radial_symmetry_test")
116     h.save_png("radial_symmetry_test")