3 # A class to draw tetraflexagons
5 # Copyright (C) 2018 Antonio Ospite <ao2@ao2.it>
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.
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.
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/>.
20 from .tritetraflexagon import TriTetraflexagon
23 class TetraflexagonDiagram(object):
24 def __init__(self, x_border, backend=None):
25 self.x_border = x_border
26 self.backend = backend
28 self.tetraflexagon = TriTetraflexagon()
30 num_squares = len(self.tetraflexagon.squares)
31 self.square_side = (self.backend.height - (x_border * 3)) / (num_squares)
32 self.square_radius = self.square_side / 2
33 self.tile_side = self.square_radius
34 self.tile_radius = self.tile_side / 2
38 # draw the plan centered wrt. the squares
39 self.plan_origin = ((self.backend.width - self.tile_side * 5) / 2,
42 self.squares_color_map = [(1, 0, 0), (0, 1, 0), (0, 0, 1)]
44 def _init_centers(self):
45 # Preallocate the lists to be able to access them by indices in the
47 self.squares_centers = [None for h in self.tetraflexagon.squares]
48 self.tiles_centers = [[None for t in h.tiles] for h in self.tetraflexagon.squares]
50 cy = self.backend.height - (self.square_radius + self.x_border)
51 for square in self.tetraflexagon.squares:
52 cx = self.x_border + (2 * self.square_radius + self.x_border) * (square.index + 1)
53 self.squares_centers[square.index] = (cx, cy)
55 for tile in square.tiles:
56 # offset by 1 or -1 times the tile radius
57 tile_cx = cx + self.tile_radius * ((tile.index % 2) * 2 - 1)
58 tile_cy = cy + self.tile_radius * ((tile.index > 1) * 2 - 1)
59 self.tiles_centers[square.index][tile.index] = (tile_cx, tile_cy)
61 def get_square_center(self, square):
62 return self.squares_centers[square.index]
64 def get_tile_center(self, tile):
65 return self.tiles_centers[tile.square.index][tile.index]
67 def get_tile_center_in_plan(self, tile):
68 x0, y0 = self.plan_origin
69 i, j = self.tetraflexagon.get_tile_plan_position(tile)
70 x, y = tile.calc_plan_coordinates(self.tile_side, i, j)
73 def get_tile_transform(self, tile):
74 """Calculate the transformation matrix from a tile in an square to
75 the correspondent tile in the plan.
77 Return the matrix as a list of values sorted in row-major order."""
79 src_x, src_y = self.get_tile_center(tile)
80 dest_x, dest_y = self.get_tile_center_in_plan(tile)
82 i, j = self.tetraflexagon.get_tile_plan_position(tile)
83 theta = tile.calc_angle_in_plan(i, j)
85 return self.backend.calc_rotate_translate_transform(src_x, src_y,
86 dest_x, dest_y, theta)
88 def draw_square_template(self, square):
89 for tile in square.tiles:
90 cx, cy = self.get_tile_center(tile)
91 self.draw_tile_template(tile, cx, cy, 0)
93 def draw_tile_template(self, tile, cx, cy, theta):
95 color = self.squares_color_map[tile.square.index]
97 self.backend.draw_rect_from_center(cx, cy, side, side, theta,
101 corners_labels = "ABC"
102 corner_text = corners_labels[tile.square.index] + str(tile.index + 1)
103 self.backend.draw_centered_text(cx, cy, corner_text, 0, color)
105 def draw_plan_template(self):
106 x0, y0 = self.plan_origin
107 for square in self.tetraflexagon.squares:
108 for tile in square.tiles:
109 i, j = self.tetraflexagon.get_tile_plan_position(tile)
110 x, y = tile.calc_plan_coordinates(self.tile_radius, i, j)
111 theta = tile.get_angle_in_plan(i, j)
112 self.draw_tile_template(tile, x0 + x, y0 + y, theta)
114 def draw_template(self):
115 for square in self.tetraflexagon.squares:
116 self.draw_square_template(square)
118 self.draw_plan_template()