Skip to content

Instantly share code, notes, and snippets.

@andystanton
Last active July 19, 2023 07:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andystanton/c1c314c2d3e67b4130305d76047da5e0 to your computer and use it in GitHub Desktop.
Save andystanton/c1c314c2d3e67b4130305d76047da5e0 to your computer and use it in GitHub Desktop.
Polygon Angle Visualiser in Pythonista

Polygon Angle Visualiser

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())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment