PythonでCanvas使ってみる(2)
前回、
Canvasに線を描くことができ。座標変換のクラスも準備しました。
Canvasの図形描画にはcreate_line()以外にもcreate_rectangle()、create_arc()、create_oval()、create_polygon()など様々な関数が用意されているわけで、「それ使えばいい」ところですけど、まずは、create_line()でいろいろ描いてみようと思います。
やりたいこと
前にも少し書きましたが、自分はいつかそのうち、これ「スピログラフ」
のお絵描きを自作アプリ上でやらせてみたいと思っています。
自分が小学生の頃の記憶。これを「ぐるぐる」描いていくと、必ずどこかでガタっと歯車が食い違って「失敗」してしまう。ごく簡単な図形以外では最後まで成功した(描き上げた)記憶が無いんです。うん十年ぶりにリベンジしたい(笑)
三角関数
三角関数はなにかと必要ですね。
mathをインポートして
import math
rad=math.radians(deg)
deg=math.degrees(rad)
math.cos(rad)
math.sin(rad)
これらは頻繁に使いそうです。
円を多角形で描いてみる
簡単のために単位円(XY座標の原点を中心として半径1の円)を多角形で描いていきます。角度 degから角度deg+ddegまでの弧を線分で描いてddegを小さくしていく。
角度degのときの座標は(cos(radians(deg)), sin(radians(deg)))
角度deg+ddegの座標は(cos(radians(deg+ddeg)), sin(radians(deg+ddeg)))
この2点をつなぐ線分を描く。
これをdeg=0からはじめて、degをddegずつ増やしながら360度まで一回りすると、多角形ができている。という発想
import math
import customtkinter as ctk
from mytool_lib import CoordinateTransformer
class App(ctk.CTk):
def __init__(self, title):
# main window
super().__init__()
self.title(title)
# widget配置
self.canvas = ctk.CTkCanvas(self, width=800, height=600, bg="black")
self.canvas.pack()
self.entry = ctk.CTkEntry(self)
self.entry.pack(anchor="e")
self.button1 = ctk.CTkButton(self, text="コマンド1", command=self.mycommand1)
self.button1.pack(anchor="e")
# 座標変換クラス (-2, -1.5) -> (0, 600), (2, 1.5) -> (800, 0) の変換
self.tfm = CoordinateTransformer(-2, -1.5, 0, 600, 2, 1.5, 800, 0)
# mainloop
self.mainloop()
def mycommand1(self):
self.canvas.delete("all")
ddeg = int(self.entry.get())
for deg in range(0, 360, ddeg):
self.arcline(deg, ddeg)
def arcline(self, deg, ddeg):
rad1 = math.radians(deg)
rad2 = math.radians(deg + ddeg)
self.canvas.create_line(
self.tfm.transform(math.cos(rad1), math.sin(rad1)),
self.tfm.transform(math.cos(rad2), math.sin(rad2)),
fill="white",
width=2,
)
App("My First polygon")
ddeg=120°(正三角形)
ddeg=90°(正方形)
ddeg=60°(正六角形)
ddeg=45°(正八角形)
ddeg=30°(正十二角形)
ddeg=5°(正72角形)
ddeg=1°(正360角形)
バグ発見
もっと細かく刻もうと0.5と入れたら
ddeg = int(self.entry.get())
^^^^^^^^^^^^^^^^^^^^^
ValueError: invalid literal for int() with base 10: '0.5'
でエラーになりました。
floatにしたら
for deg in range(0, 360, ddeg):
^^^^^^^^^^^^^^^^^^^
TypeError: 'float' object cannot be interpreted as an integer
というエラーになりました。Copilot先生に丸投げ。
修正後のコード
import math
import customtkinter as ctk
import numpy as np
from mytool_lib import CoordinateTransformer
class App(ctk.CTk):
def __init__(self, title):
# main window
super().__init__()
self.title(title)
# widget配置
self.canvas = ctk.CTkCanvas(self, width=800, height=600, bg="black")
self.canvas.pack()
self.entry = ctk.CTkEntry(self)
self.entry.pack(anchor="e")
self.button1 = ctk.CTkButton(self, text="コマンド1", command=self.mycommand1)
self.button1.pack(anchor="e")
# 座標変換クラス (-2, -1.5) -> (0, 600), (2, 1.5) -> (800, 0) の変換
self.tfm = CoordinateTransformer(-2, -1.5, 0, 600, 2, 1.5, 800, 0)
# mainloop
self.mainloop()
def mycommand1(self):
self.canvas.delete("all")
ddeg = float(self.entry.get())
for deg in np.arange(0, 360, ddeg):
self.arcline(deg, ddeg)
def arcline(self, deg, ddeg):
rad1 = math.radians(deg)
rad2 = math.radians(deg + ddeg)
self.canvas.create_line(
self.tfm.transform(math.cos(rad1), math.sin(rad1)),
self.tfm.transform(math.cos(rad2), math.sin(rad2)),
fill="white",
width=2,
)
App("My First polygon")
ddeg=0.5°(正720角形)
OK!もう「円」だと言ってもわからんでしょう(笑)