CodeZine(コードジン)

特集ページ一覧

Java meets Python - 第0回 Jythonはじめました(前編)

よろずプログラマーのためのPython導入ガイド (1)

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2007/10/09 14:00
目次

例題に学ぶJythonの世界

 先に示したコードの断片は「例題のための例題」であって、それ自身が付加価値を与えるものではありません。そこで、Jythonで広がるJavaプログラミングの可能性を模索するために、小さな付加価値を与える事例として「サイクロイド」を紹介します。

サイクロイドとは

 サイクロイドとは、円を任意の曲線に沿って転がしたとき、その円周上の定点が描く軌跡です。ここでは、最も簡単な事例として、円を直線に沿って転がします。ボタン[animate]を押すと、円周上(青)の定点(黄)が描く軌跡(赤)が描かれます。

おかみさん、数学の時間ですよ

 実際の開発では、要求仕様に記述された内容を理解するのに、(クライアントにとっては自明である)特定の専門知識が必要になることがあります。例えば今回の場合、サイクロイドに関する数学の基礎知識が必要です。そこで、数学の基礎を簡単に復習しておきます。ただし、数学が苦手という皆さんは、ざっと目を通すか、思い切って読み飛ばし、次節に進んでください。それでもかまわない理由は、後で紹介します。

 円を直線に沿って転がすとき、その円周上の点Pが軌跡OPを描くものとします。このとき、X軸と円との接点Qに対して、直線OQと弧PQとの長さが等しくなります。そこで、少しずつ移動する点Pの座標が求まるなら、これらの点を短い直線で連結することで、連続するサイクロイド曲線が描けます。ここで、円の中心からX軸に下ろした垂線と動径rとのなす角度をθします。

 x座標を得るには、点Pから下ろした垂線とX軸との交点Pxを利用します。このとき、2つの線分の長さはOQ = rθおよびPxQ = r sinθとなるので、OPx = OQ-PxQ = rθ-r sinθとなります。

 y座標を得るには、点Pから下ろした垂線とY軸との交点Pyおよび、円の中心点Cから下ろした垂線とY軸との交点Cyを利用します。このとき、2つの線分の長さはOCy = rおよびCyPy = -r cosθとなるので、OPy = OCy+ CyPy = r-r cosθとなります。

付記
 弧の長さがrθとなるのは、弧度法の定義から導かれます。中心角は、円周に対する弧の長さの比率として定義されます。円周の長さ2πrに対して、円周角2πに対する中心角θの比率から、2πの項が約分されて、弧の長さrθが求まります。

アニメーションとは

 アニメーションの原体験は、パラパラ漫画でした。教科書の余白に鉛筆で描いた悪戯書きが、パラパラめくるだけで動いて見える様は、授業中に見つからないかとのスリルも手伝って、感動モノでした。映画では、コマ撮りした連続写真を1秒間に24枚という速度で再生して、実際に動いているように見せます。アニメーションの語源は、ラテン語の霊魂とも言われ、動かないものに命を与えて動かす様を表現しています。

サイクロイドを描くには

 サイクロイドを描くときには、円周上の定点が描く軌跡をアニメーションを使って再現します。ここでは、その準備として、簡単な図形を動かします。今後の連載では、コードの詳細にも触れますが、今はその概要だけを把握してください。

from time import *

x, y, w, h = 10, 10, 40, 40
shape = Rectangle2D.Double(x, y, w, h)

width = 3
def paint(g):
    CanvasPanel.paint(panel, g)
    g.color = Color.yellow
    g.fill(shape)
    stroke = BasicStroke(width)
    g.color = Color.blue
    g.fill(stroke.createStrokedShape(shape))
panel = CanvasPanel()
panel.paint = paint

times, seconds = 100, 0.02
def animate(e):
    for i in range(times):
        sleep(seconds)
        shape.setFrame(x+i, y, w, h)
        bounds = shape.bounds
        bounds.grow(width, width)
        panel.paintImmediately(bounds)

button = JPanel(layout=GridLayout(1, 0))
button.add(JButton("animate", actionPerformed=animate))

frame = JFrame(defaultCloseOperation=JFrame.EXIT_ON_CLOSE,
    size=(160, 110), title="Rectangle & Rectangle2D",
    layout=BorderLayout())
frame.add(panel, BorderLayout.CENTER)
frame.add(button, BorderLayout.SOUTH)
frame.visible = True

 関数animateは、ボタンを押したときに、panel内に図形を描く方法を示します。

 組み込み関数sleep(seconds)は、指定した秒数secondsだけ実行を遅延します。それには、モジュールtimeimportしておく必要があります。

 Javaで記述された関数void paintImmediately(Rectangle r)は、指定した領域r内をすぐに再描画します。ここで、paintを利用したのでは、移動が終了した後に図形が描かれるので、アニメーション効果が得られません。

 図形を描くときには、その外枠の幅だけ領域を拡げる必要があります。そのため、Javaで記述された関数Rectangle getBounds()によって獲得した矩形領域を、Javaで記述された関数void grow(int h,int v)を使って対象領域を拡げます。

 このコードを実行すると、ウィンドウが現われます。ボタン [animate] を押すと、0.02 秒ごとに位置が異なる図形が描かれます。すると、あたかも図形が移動しているように見えます。再びボタンを押すと、2度目以降は、新たな図形が現われてから移動するのが分かります。

次回予告

 前編では、Jythonによって広がる新しいプログラミングの可能性の一端として、サイクロイド曲線をアニメーションで描画するサンプルプログラムを紹介しました。後編では、このプログラムの具体的な解説を進めつつ、今後の連載の概観を示します。



  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:よろずプログラマーのためのPython導入ガイド

もっと読む

著者プロフィール

  • 小泉ひよ子とタマゴ倶楽部(コイズミヒヨコトタマゴクラブ)

    http://tamago-club.cocolog-nifty.com/ 「楽しくなければ仕事じゃない」が私たちのモットー。99%の苦悩の連続も、1%の成功に報われます。だからこそ、この仕事が楽しくて仕方がないのです。楽をするための努力なら惜しみません。何もせず楽をしているのと、努力をしたか...

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5