見出し画像

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!もう「円」だと言ってもわからんでしょう(笑)

いいなと思ったら応援しよう!