C言語でのリサージュ曲線軌跡の描き方

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Hajime

C言語でのリサージュ曲線軌跡の描き方

#1

投稿記事 by Hajime » 17年前

こんにちは。

このたび学校でC言語を勉強することになり、自主的に本を購入して勉強していたのですが、わからない点があるので質問させていただきます。独習している書籍は、高橋麻奈氏の「やさしいC」と、大槻有一郎氏の「14歳からはじめるリアルに動く!ゲーム物理プログラミング教室」です。

このうち後者のものにそってプログラムを組んでいたのですが、100ページほど済んだところで自分でそれを改造し、動画サイトに投稿されていた数学の動画において曲線の美しさに気付いたこともあり、画面に表示された円がリサージュ曲線の軌跡を描くようなプログラムを作りたくなりました。

-----------------------------------------
#include "DxLib.h"
#include "math.h"

double posx, posy;

void PhysicsDraw(){
	for(int x=40; x<640; x=x+40) DrawLine(x,0,x,480, GetColor(64,64,64));
	for(int y=40; y<480; y=y+40) DrawLine(0,y,640,y, GetColor(64,64,64));
	DrawCircle(posx-10,posy-10,2, GetColor(255,200,200), FALSE);
	DrawCircle(posx-5,posy-5,2, GetColor(255,100,00), FALSE);
	DrawCircle(posx,posy,2, GetColor(255,0,0), FALSE);
	posx = posx + 1;
	posy = posy + 1;
}

int WINAPI WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR lpc, int nc){
	ChangeWindowMode(TRUE);
	if(DxLib_Init() == -1) return(-1);

	SetDrawScreen(DX_SCREEN_BACK);
	while(ProcessMessage()==0 && CheckHitKey(KEY_INPUT_ESCAPE)==0){
		ClsDrawScreen();
		PhysicsDraw();
		ScreenFlip();
	}

	DxLib_End();			
	return(0);		
}
-----------------------------------------

これではDXライブラリを使用して、直線をなぞっていくように円を表示しているだけなのですが、ここからどうやってリサージュ曲線の数式を使用した軌跡を描くように発展させていくことができるのか、まったく想像がつかない状況です。三角関数を使用してみようともしましたが、うまくいきません。詳しい解説と具体的なソースを示していただけないでしょうか?

OSはXPでVisualC++ExpressEditionを使用しています。当方の経験といたしましては、どのようにプログラムを学んでいけばよいのか学校の他教科と違いすぎてまったくわからない、といったものです。

木霊

Re:C言語でのリサージュ曲線軌跡の描き方

#2

投稿記事 by 木霊 » 17年前

一応、C++で作ってみました。
今回gdgdなのですみません・・・
リサージュ曲線の説明はこちら
http://ja.wikipedia.org/wiki/%E3%83%AA% ... 3%E5%BD%A2

---------- ここから ----------
#include "DxLib.h"
#include <math.h>
const double PI = 3.14159265358979323846;
inline double Get_Angle_To_Radian ( double Temp_Angle ) { return Temp_Angle /180.0 *PI; }
void Draw_Grid ( void );
void Draw_Lissajous ( double Alpha, double Beta, double Delta, double Radius );

int WINAPI WinMain( HINSTANCE hInstance, 
     HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
    ChangeWindowMode ( TRUE ) ;
    if ( DxLib_Init () == -1 ) { return -1; }
    SetDrawScreen ( DX_SCREEN_BACK );
    while ( ProcessMessage () == 0 ) {		// ------------------ ループ開始
	ClearDrawScreen ();

	Draw_Grid ();
	Draw_Lissajous ( 1.0, 2.0, -PI/4.0, 100.0 );

	ScreenFlip ();
	if ( CheckHitKey ( KEY_INPUT_ESCAPE ) == 1 ) { break; }
    }
    DxLib_End();
    return 0;
}
void Draw_Grid ( void )
{
    int Cr = GetColor ( 128, 128, 128 );
    for ( int X = 0; X < 640; X += 16 ) { DrawLine ( X, 0, X, 480, Cr ); }
    for ( int Y = 0; Y < 480; Y += 16 ) { DrawLine ( 0, Y, 640, Y, Cr ); }
    DrawLine ( 320, 0, 320, 480, GetColor ( 0, 0, 255 ) );
    DrawLine ( 0, 240, 640, 240, GetColor ( 0, 0, 255 ) );
    return;
}
void Draw_Lissajous ( double Alpha, double Beta, double Delta, double Radius )
{
    int Cr = GetColor ( 255, 255, 255 );
    for ( int T = 0; T < 360; T += 3 ) {
	DrawCircle ( 320 +cos ( Get_Angle_To_Radian ( Alpha *T ) )*Radius,
		240 -sin ( Get_Angle_To_Radian ( Beta *T ) +Delta )*Radius,
		5, Cr, FALSE );
    }
    return;
}
---------- ここまで ----------

本当にすみません・・・リンク先を見て、数式を当てはめただけです・・・
なので解説と言うほどのものも無いような・・・
「320」「240」という値は「とりあえずの画面中心の座標」です。
またRadiusは Alpha=1.0; Beta=1.0; Delta=0.0; 時に描かれる円の半径で、この値が小さいと画面中央に
白い塊が出来るだけです。
あと、T は1周描画する分の値です。T += 3 なのは++ T だと隙間がなく、白く塗りつぶしたようになるので
適当に設定した値です。
Y座標の所で、240 -sin・・・と符号が逆になっているのは、グラフの正負と画面の座標の正負が逆だからです。

プログラム的には、
1・定数でないグローバル変数は極力使わないように
2・関数は機能別に(今回は「グリッドの描画」と「リサージュ曲線の描画」)
を心がけると変更しやすいプログラムを書けると思います。

最後に、今回は変数の範囲チェックをしていません。
エラーは出ないと思いますが、必要と思うなら付けてみてください。

おやすみなさい。

Hajime

Re:C言語でのリサージュ曲線軌跡の描き方

#3

投稿記事 by Hajime » 17年前

回答していただきましてありがとうございます。印刷してひとつひとつ検討させていただきます。
おそらく、またわからない点が出てくることになると思いますから、このトピックは残させていただきます。

Hajime

Re:C言語でのリサージュ曲線軌跡の描き方

#4

投稿記事 by Hajime » 17年前

なんとかプログラムの仕組みを理解できたのですが、改造しようとするとうまくいきません。
Alpha Beta Delta Radiusの各値をキーの組み合わせで変更しさらにその状態で曲線を再表示するようにしたいのです。今回 // ------------------ ループ開始 このループ内を書き換えていきました。

Draw_Lissajous ( 1.0, 2.0, -PI/4.0, 100.0 );
私にはこの命令で各値が決定されてしまうような気がするのですが・・・

表示に関してもループ内でキーを設定しましたが、キーを押している間しかコマンドが反映されなくなりました(曲線が表示されつづけないです)。どうも混乱している感じです・・・ご助力お願いします。

木霊

Re:C言語でのリサージュ曲線軌跡の描き方

#5

投稿記事 by 木霊 » 17年前

>Draw_Lissajous ( 1.0, 2.0, -PI/4.0, 100.0 );
>私にはこの命令で各値が決定されてしまうような気がするのですが・・・
その通りです。
Hajimeさんのソースが分からないので推測になりますが、関数Draw_Lissajous内を改造してませんか?
この関数の引数を変えるようにして下さい。

// ループの外で変数を定義
double ALPHA = 1.0, BETA = 1.0, DELTA = 4.0, RADIUS = 100.0;
・・・
// ループの中で値を変更して関数を呼び出し
/* Hajimeさんの改造部分で各値を変更 */
Draw_Lissajous ( ALPHA, BETA, -PI /DELTA, RADIUS );
・・・

引数の値を使って計算をしているので、関数の呼び出しの際に引数の値を変えないと同じ結果になってしまいます。

送信した後に気付いたのですが、Radiusは数式内のラージAとラージBにあたるので2つ用意した方が、いいかも知れません。(引数を一つ増やす)
X = A *cos ( a *t ), Y = B *sin ( ( b *t ) -δ)

Hajime

Re:C言語でのリサージュ曲線軌跡の描き方

#6

投稿記事 by Hajime » 17年前

そのとおりにループ内外を改造することと、キー操作関数を新たに作ることでうまく反映されるようになりました。また別種の曲線を描かせることも出来ました。
初心モノに教授してくださって本当にありがとうございました。解決とさせていただきます。

閉鎖

“C言語何でも質問掲示板” へ戻る