A Pythonista script that displays a polygon and its internal angle.
Swiping left and right causes the number of sides to increase or decrease.
from scene import * | |
from math import pi, sin, cos | |
from datetime import datetime | |
class PolygonAngleVisualiser(Scene): | |
def setup(self): | |
self.touch_start = Point(0, 0) | |
self.min_side_count = 3 | |
self.max_side_count = 36 | |
self.side_count = 4 | |
self.res_scale = 1 | |
self.fade_instruction_time = None | |
# arbitrary scaling to handle the difference between iPad & iPhone resolutions & ratio | |
self.res_scale = (max(self.size.w, self.size.h) / 812) | |
def touch_began(self, touch): | |
self.touch_start = touch.location | |
def touch_moved(self, touch): | |
if not self.fade_instruction_time: | |
self.fade_instruction_time = datetime.now() | |
touch_distance = touch.location - self.touch_start | |
movement_threshold = self.size.w / 12 | |
new_side_count = self.side_count | |
if abs(touch_distance.x) > movement_threshold: | |
swipe_direction = -int(touch_distance.x / abs(touch_distance.x)) | |
new_side_count = new_side_count + swipe_direction | |
if self.min_side_count <= new_side_count <= self.max_side_count and new_side_count != self.side_count: | |
self.side_count = new_side_count | |
self.touch_start = touch.location | |
def draw(self): | |
background(0.7, 0.7, 0.7) | |
external_angle = 2 * pi / self.side_count | |
internal_angle = pi - external_angle | |
radius = 100 * self.res_scale | |
angle_length = radius | |
padding = 20 * self.res_scale | |
left_margin = self.size.w / 2 - radius - radius - padding | |
if left_margin < 20: | |
left_margin = 20 | |
top_margin = self.size.h / 2 - radius - radius - 2 * padding | |
if top_margin < 20: | |
top_margin = 20 | |
stroke(0.4, 0.4, 1, 1) | |
stroke_weight(4) | |
angle_start = Point(left_margin, self.size.h - top_margin - angle_length) | |
polygon_start = self.size / 2 | |
if self.size.h > self.size.w: | |
polygon_start.y -= 75 * self.res_scale | |
else: | |
polygon_start.y -= 30 * self.res_scale | |
# angle | |
line( | |
*(angle_start + Point(0, angle_length)), | |
*(angle_start)) | |
line( | |
*(angle_start), | |
*(angle_start + Point( | |
angle_length * sin(internal_angle), | |
angle_length * cos(internal_angle)))) | |
# angle line | |
if self.side_count == 4: | |
line( | |
*(angle_start + Point(0, angle_length / 2)), | |
*(angle_start + Point(angle_length / 2, angle_length / 2))) | |
line( | |
*(angle_start + Point(angle_length / 2, angle_length / 2)), | |
*(angle_start + Point(angle_length / 2, 0))) | |
else: | |
sub_angle_divisions = 16 | |
sub_angle = internal_angle / sub_angle_divisions | |
for i in range(0, sub_angle_divisions): | |
line( | |
*(angle_start + Point( | |
angle_length / 2 * sin(sub_angle * i), | |
angle_length / 2 * cos(sub_angle * i))), | |
*(angle_start + Point( | |
angle_length / 2 * sin(sub_angle * (i + 1)), | |
angle_length / 2 * cos(sub_angle * (i + 1))))) | |
# angle text | |
angle_in_degrees = round((internal_angle / (2 * pi)) * 360) | |
text( | |
"{:0.0f}°".format(angle_in_degrees), | |
'Futura', | |
20 * self.res_scale, | |
*(angle_start + Point(1.5 * padding, angle_length / 2 + padding))) | |
# polygon | |
for i in range(0, self.side_count): | |
start_angle = external_angle * i | |
end_angle = external_angle * (i + 1) | |
# rotate the square to align with axes | |
if self.side_count == 4: | |
start_angle = external_angle * i + external_angle / 2 | |
end_angle = external_angle * (i + 1) + external_angle / 2 | |
line_start = polygon_start + radius * Point(sin(start_angle), cos(start_angle)) | |
line_end = polygon_start + radius * Point(sin(end_angle), cos(end_angle)) | |
line(*line_start, *line_end) | |
# side count text | |
text(str(self.side_count), 'Futura', 40 * self.res_scale, *polygon_start) | |
# instructions | |
fade_out_time = 1500 | |
text_alpha = 1 | |
if self.fade_instruction_time: | |
elapsed_time = (datetime.now().timestamp() - self.fade_instruction_time.timestamp()) * 1000 | |
if elapsed_time < fade_out_time: | |
text_alpha = 1 - (elapsed_time / fade_out_time) | |
else: | |
text_alpha = 0 | |
tint(1, 1, 1, text_alpha) | |
if polygon_start.y - radius * 1.2 < radius: | |
text("Swipe to change shape", 'Futura', 2 * padding, *(polygon_start - Point(0, radius * 1.2))) | |
else: | |
text("Swipe to", 'Futura', 2 * padding, *(polygon_start - Point(0, radius * 1.2))) | |
text("change shape", 'Futura', 2 * padding, *(polygon_start - Point(0, radius * 1.2) - Point(0, 2.5 * padding))) | |
run(PolygonAngleVisualiser()) |