見出し画像

PythonでCanvas使ってみる(4)うねうねアニメ

(末尾にアニメーションのvimeo動画があります。是非「動画」としてご覧ください)
一週間ほど前

「アニメーション」はおそらく使いそうもない
などと書いていましたが、前回完成した、スピログラフアプリ

をいじっているうちに、「うねうね」させたくなってきました(笑)

何を言っているかというと、例えば

とパラメータsを「連続的に」振ることで図形が「連続的に」変化していくわけですが、これをアニメーションにしたら面白いんじゃないかな?と思ったわけです。

要は
・ある画面の表示をする。
・連続的な変化がある次の画面表示へ移る
というのを繰り返せばいい。

こういうのこそ、(スピログラフの「定規」だけでは絶対できない)プログラミングならではの優位性じゃないですかね。

UdemyTkinter教材のアニメーションの回では
windowやフレームのafterメソッド(指定時間後に関数呼び出し)に
・after(ミリ秒,呼び出す関数)
についての説明がありました。これを使いましょう。

やってみます

(抜粋)
    # うねうね
    def mycommand2(self):
        # 画面クリア
        self.canvas.delete("all")

        # 刻み度数
        self.ddeg = float(self.ctkentry_刻み.get())

        # 外側の歯数
        self.gearl = int(self.ctkentry_外歯車.get())

        # 内側の歯数
        self.gears = int(self.ctkentry_内歯車.get())

        # うねる回数
        self.unekaisu = int(self.ctkentry_うねる回数.get())
        # アニメ描画
        self.sratio = 0

        self.unediff = 0.01

        self.spiro_ani()

    def spiro_ani(self):
        if self.unekaisu > 0:
            if ((self.sratio < 1.0) and (self.unediff > 0)) or (
                (self.sratio > 0.0) and (self.unediff < 0)
            ):
                self.spiro(self.ddeg, self.gearl, self.gears, self.sratio)
                self.sratio += self.unediff
                self.after(10, self.spiro_ani)
            else:
                self.unediff *= -1.0
                self.unekaisu -= 1
                self.spiro_ani()  # 再帰呼び出し

    # spiro一枚描き上げ
    def spiro(self, ddeg, gearl, gears, sratio):

        # 画面クリア
        self.canvas.delete("all")

        # ギア比
        r = gears / gearl

        # ぶん回す回数
        w = math.lcm(gearl, gears) / gearl

        s = r * sratio

        for deg in np.arange(0, 360 * w, ddeg):
            self.penline(deg, ddeg, r, s)

    # 内接円の中心位置 thetaはラジアン
    def circle_s_center(self, theta, r):
        return (1 - r) * math.cos(theta), (1 - r) * math.sin(theta)

    # 内接円の中心から見たペン先位置
    def rel_pen(self, theta, r, s):
        return s * math.cos(-theta * (1.0 / r - 1)), s * math.sin(
            -theta * (1.0 / r - 1)
        )

    def abs_pen(self, theta, r, s):
        cx, cy = self.circle_s_center(theta, r)
        rpx, rpy = self.rel_pen(theta, r, s)
        return cx + rpx, cy + rpy

    def penline(self, deg, ddeg, r, s):
        theta_rad1 = math.radians(deg)
        theta_rad2 = math.radians(deg + ddeg)
        x1, y1 = self.abs_pen(theta_rad1, r, s)
        x2, y2 = self.abs_pen(theta_rad2, r, s)
        self.canvas.create_line(
            self.tfm.transform(x1, y1),
            self.tfm.transform(x2, y2),
            fill="white",
            width=1,
        )

こんな感じに書いてmycommand2 を実行したら・・
(Vimeoの動画です是非「動かして」ご覧ください)

うねってます(笑)
動きがあると俄然面白くなりますね。

この記事が気に入ったらサポートをしてみませんか?