以上のことを考慮して、アプレットに次の修正を加えることにしましょう。
一番目は、物理座標 (xp, yp) からスクリーン座標 (xs, ys) への変換を考えます。図を用いて考えて見ましょう。青色部分がスクリーンだと思ってください。 w は描画領域の横幅、 h は描画領域の高さを表しています。
物理座標とスクリーン座標の違いは、y軸の向きだけなので
となります。このスクリーン座標を「画面中心を原点とするスクリーン座標」にするには、図からもわかるように
(2-2)
となります。
したがって、今回の円運動の式を画面中心を原点とするスクリーン座標で表すと
(2-3)
となります。
以上のことを考慮しながら、アプレットを修正してみましょう。
''CircularMovement02.java"
001|import java.applet.*; 002|import java.awt.*; 003| 004|/* 005| * 質点が円運動する様子を描いたアプレットです。 006| * <applet code="CircularMovement02.class" width="200" height="200"></applet> 007| * 008| */ 009| 010|/** 011| * @author Osamu Koizumi 012| * 013| */ 014|public class CircularMovement02 extends Applet implements Runnable{ 015| /** スレッド */ 016| Thread th; 017| /** 経過時間を保持する変数 */ 018| double t = 0; 019| /** 時間の刻み (ミリ秒単位) */ 020| int dt = 100; 021| 022| /** 円運動の半径 (ピクセル単位) */ 023| double a = 90.0; 024| /** 円運動の周期 (秒単位) */ 025| double T = 2.0; 026| /** 質点の x 座標値を保持する変数 */ 027| double x; 028| /** 質点の y 座標値を保持する変数 */ 029| double y; 030| 031| /** 描画される質点の直径(ピクセル単位) */ 032| int d = 6; 033| 034| /* 035| * このメソッドには初期化処理を記述します。 036| * @see java.applet.Applet#init() 037| */ 038| public void init(){ 039| } 040| 041| /* 042| * アプレットの実行が始まると呼ばれます。 043| * @see java.applet.Applet#init() 044| */ 045| public void start(){ 046| // おまじない 047| if( th == null){ 048| th = new Thread( this); 049| } 050| th.start(); 051| } 052| 053| /* 054| * このメソッドには反復処理を記述します。 055| * @see java.lang.Runnable#run() 056| */ 057| public void run(){ 058| while( th != null){ 059| /* 060| * ここに計算などの処理を記述します。 061| */ 062| // 周期を角振動数に変換する 063| double omega = 2 * Math.PI / T; 064| // 質点の位置を計算する 065| x = a * Math.cos( omega * t) + getWidth()/2.0; 066| y = - a * Math.sin( omega * t) + getHeight()/2.0; 067| // 計算結果を画面に反映させるために再描画する 068| repaint(); 069| 070| // 時間を進める (dt を秒単位に直すために1000で割る) 071| t = t + dt/1000.0; 072| 073| // 刻み時間だけ待つ 074| try{ 075| Thread.sleep( dt); 076| } 077| catch( InterruptedException ex){ 078| } 079| } 080| } 081| 082| /* 083| * このメソッドには描画処理を記述します。 084| * @see java.awt.Component#paint(java.awt.Graphics) 085| */ 086| public void paint( Graphics g){ 087| /* 088| * ここに描画処理を記述します。 089| */ 090| // 描画色を赤色に設定する 091| g.setColor( Color.RED); 092| // 塗りつぶされた円を描く(質点を表す) 093| g.fillOval( (int)(x-d/2), (int)(y-d/2), d, d); 094| // 描画色を灰色に設定する 095| g.setColor( Color.GRAY); 096| // x軸を描く 097| g.drawLine( 0, getHeight()/2, getWidth(), getHeight()/2); 098| // y軸を描く 099| g.drawLine( getWidth()/2, 0, getWidth()/2, getHeight()); 100| } 101| 102| /* 103| * アプレット停止時に呼ばれます。 104| * @see java.applet.Applet#stop() 105| */ 106| public void stop(){ 107| th = null; 108| } 109| 110|}
CircularMovement01.java からの変更箇所を太字で示しました。実行画面は図21のようになります。今度はちゃんとウィンドウの中心を原点として、反時計回りにまわっているはずです。
Fig.21 CircularMovement02.javaの実行結果
それぞれ詳しく説明しましょう。
64. // 質点の位置を計算する 65. x = a * Math.cos( omega * t) + getWidth()/2.0; 66. y = - a * Math.sin( omega * t) + getHeight()/2.0;
65, 66行目は、66ページで解説したように、物理座標で記述されている円運動の式を画面中心を原点とするスクリーン座標に直した式になっています。ここで出てくる getWidth() と getHeight() はそれぞれ、アプレット画面の幅、高さを得るメソッドです。
戻り値 | メソッド | 説明 |
---|---|---|
int | getWidth() | アプレット画面の幅を得ます。 |
int | getHeight() | アプレット画面の高さを得ます。 |
つづいて、描画部分の変更点について説明しましょう。
90. // 描画色を赤色に設定する 91. g.setColor( Color.RED); 92. // 塗りつぶされた円を描く(質点を表す) 93. g.fillOval( (int)(x-d/2), (int)(y-d/2), d, d); 94. // 描画色を灰色に設定する 95. g.setColor( Color.GRAY); 96. // x軸を描く 97. g.drawLine( 0, getHeight()/2, getWidth(), getHeight()/2); 98. // y軸を描く 99. g.drawLine( getWidth()/2, 0, getWidth()/2, getHeight());
92行目から99行目が変更、追加部分です。まずは登場している Graphics クラスのメソッドについて整理しておきます。
戻り値 | メソッド | 説明 |
---|---|---|
int | setColor( Color c) | 描画色を変更します。 |
int | setColor( int r, int g, int b) | 描画色を変更します。 |
int | fillOval( int x, int y, int w, int h) | 塗りつぶされた楕円を描きます。 |
int | drawLine( int xs, int ys, int xf, int yf) | (xs, ys) を始点、(xf, yf) を終点とする線を描きます。 |
表 8: CircularMovement02.java で新たに出てきた Graphics クラスのメソッド
fillOvalの引数、x座標の値とy座標の値がそれぞれ x-(d/2), y-(d/2) というように変更されています。これは、塗りつぶし円の”中心”を質点の位置座標に対応させるためです。改良前は塗りつぶし円を囲う長方形の左上隅が位置座標に対応していました。
図22. 円の中心を位置座標に対応させる
x軸、y軸の描画に関しては特に問題はないと思います。
どうでしたか?思っていたよりも簡単に、円運動をシミュレーションすることができたのではないでしょうか。
最終更新時間:2011年01月08日 17時17分47秒