e6bc38363c0cb67a14316993d2d1c98055a28fa6
[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 __init__(self, width, height, background=[1, 1, 1]):
47         Diagram.Diagram.__init__(self, width, height, background)
48
49     def draw(self, model):
50         cx = self.width / 2.0
51         cy = self.height / 2.0
52
53         # internal radius
54         if model.base_polygon_radius is None:
55             model.base_polygon_radius = min(self.width, self.height) / 4.0
56
57         if model.element_radius is None:
58             model.element_radius = model.base_polygon_radius
59
60         self.clear()
61         self.draw_elements(cx, cy, model)
62
63     def draw_elements(self, cx, cy, model):
64         central_angle = 2 * pi / model.base_polygon_sides
65
66         base_polygon_orientation = central_angle + model.base_polygon_angle
67
68         verts = self.get_regular_polygon(cx, cy, model.base_polygon_sides, model.base_polygon_radius,
69                                          base_polygon_orientation)
70
71         if model.show_base_polygon:
72             self.draw_polygon(verts, [0, 0, 0])
73
74         for i, v in enumerate(verts[:]):
75             radial_orientation_angle = (i + 1) * central_angle
76             rotated_radial_orientation_angle = radial_orientation_angle + model.base_polygon_angle
77
78             # the element orientation may depend the base polygon rotation
79             if model.radial_orientate:
80                 element_angle = rotated_radial_orientation_angle
81             else:
82                 element_angle = 2 * pi / model.element_sides
83
84             element_angle += model.element_angle_offset
85
86             # the element color depends oly on the element index
87             a = self.normalized_angle_01(radial_orientation_angle)
88             color = colorsys.hsv_to_rgb(a, 1.0, 1.0)
89
90             self.draw_element(v[0], v[1], model, element_angle, color)
91
92             if model.show_labels:
93                 ta = self.normalized_angle_01(rotated_radial_orientation_angle)
94                 text = ("%.2f" % (ta * 360)).rstrip('0').rstrip('.')
95                 color = colorsys.hsv_to_rgb(a, 1.0, 1.0)
96                 self.draw_centered_text(v[0], v[1], text,
97                                         rotated_radial_orientation_angle, color)
98
99     def draw_element(self, x, y, model, theta, color=[0, 0, 0]):
100         if model.show_elements:
101             tverts = self.get_regular_polygon(x, y, model.element_sides, model.element_radius, theta)
102             self.draw_polygon(tverts, color)
103
104         if model.show_stars:
105             apothem = model.element_radius * cos(pi / model.element_sides)
106             apothem_angle = theta + pi / model.element_sides
107
108             sverts = self.get_regular_polygon(x, y, model.element_sides, apothem,
109                                               apothem_angle)
110             self.draw_star(x, y, sverts, color)
111
112
113 if __name__ == '__main__':
114     h = RadialSymmetryDiagram(800, 600)
115     h.draw(RadialSymmetryModel(base_polygon_sides=10, element_sides=4, show_stars=True, show_labels=False))
116     h.draw(RadialSymmetryModel(base_polygon_sides=31, element_sides=4, show_stars=False, show_labels=False))
117     h.show()
118     h.save_svg("radial_symmetry_test")
119     h.save_png("radial_symmetry_test")