正弦波レーザーを作りたい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
YYSS
記事: 125
登録日時: 9年前
連絡を取る:

正弦波レーザーを作りたい

#1

投稿記事 by YYSS » 9年前

360度全方向に発射できる正弦波レーザーを作りたいです。
直角方向に発射させることは出来たのですが、斜めの場合はどうしたらいいのかさっぱり分かりません;;

現状の移動ルーチンは

コード:


//sinレーザー作成
//左からXY座標・移動速度・発射角度・振幅幅・位相
CreateSinLaser( &x, &y, speed, angle, amp, phase );


//移動処理
if( angle == 0  ){
   *x += speed;
   *y += sin( phase ) * amp;
}
else if( angle == 180  ){
   *x -= speed;
   *y += sin( phase ) * amp;
}

phase += speed;

この方法だと直角方向しか撃てません;;
アドバイスをいただけると嬉しいです


手書きなので汚いですが、添付画像のようなレーザーがつくりたいのです。

seigenha.png
seigenha.png (11.24 KiB) 閲覧数: 1236 回

アバター
GRAM
記事: 164
登録日時: 10年前
住所: 大阪

Re: 正弦波レーザーを作りたい

#2

投稿記事 by GRAM » 9年前

いまいち仕様がよくわかりませんでしたがこういうことでしょうか?

コード:

#include "DxLib.h"
#include <cmath>
char Key[256];

void CreateSinLaser( double* x, double* y, double speed, double angle, double amp, double phase );


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
        if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //初期化処理
        SetDrawScreen( DX_SCREEN_BACK );        //裏画面に設定
		double x = 100, y = 100, xtemp, ytemp, phase = 0.0;
        while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){
				xtemp = x; ytemp = y;
				CreateSinLaser( &x, &y, 5.0, 1.0, 5.0, phase );
				DrawLine( xtemp , ytemp , x , y , 0xff00ff) ;
				phase += 0.50;

                ScreenFlip();//裏画面を表画面に反映
        }
 
        DxLib_End();
        return 0;
}

void CreateSinLaser( double* x, double* y, double speed, double angle, double amp, double phase ){
	double x_ = speed, y_ = amp;
	y_ *= sin(phase);

	double Sin = sin(angle), Cos = cos(angle);
	double tx = x_, ty = y_;
	x_ = tx*Cos - ty*Sin;
	y_ = tx*Sin + ty*Cos;

	*x += x_;
	*y += y_;

	return;
}
中身は「変換」という概念を用いています。
x方向にa、y方向にbの量を持っているベクトルは角度Θだけ回転するのに


x_ = a*cosΘ - b*sinΘ;
y_ = a*sinΘ + b*cosΘ;

のような計算をすればよいことが分かっています。
(気になるのでしたら実際に証明することもできますが、もし必要ならおっしゃってください。)

アバター
YYSS
記事: 125
登録日時: 9年前
連絡を取る:

Re: 正弦波レーザーを作りたい

#3

投稿記事 by YYSS » 9年前

返答が遅れて申し訳ありません;;
仕事が急に忙しくなって手がつけられませんでした;;


一応、教えてくださったソースを元に作ってみたところ、ちゃんと正弦波の動きは出来たのですが、
位相(変数phase)の指定の仕方がよく分かりません・・・

位相を180度ずらせば、最初に添付した画像のような軌跡を描けると思い、
位相0と位相PI/2(PIは円周率)でやってみたところ、綺麗な形になりません

ソースはこんな感じです

コード:

#define    PI    3.14

 char Key[256];
void CreateSinLaser( double* x, double* y, double speed, double angle, double amp, double phase );
 
 
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
        if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //初期化処理
        SetDrawScreen( DX_SCREEN_BACK );        //裏画面に設定

        double x[10], y[10], xtemp[10], ytemp[10], phase[10];

		x[0] = 100;
		y[0] = 100;
		phase[0] = 0.0;

  		x[1] = 100;
		y[1] = 100;
		phase[1] = PI/2;

		while(!ProcessMessage() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){

			for( int i=0 ; i<2 ; i++ ){
                xtemp[i] = x[i]; ytemp[i] = y[i];
                CreateSinLaser( &x[i], &y[i], 10, 1.0, 10, phase[i] );

				int col	= 0x0000ff;
				if( i==0 ){	col	= 0xff0000;	}

				DrawCircle( xtemp[i] , ytemp[i] , 5, col ) ;
				phase[i] += 0.50;
			}
                ScreenFlip();//裏画面を表画面に反映
        }
 
        DxLib_End();
        return 0;
}
 
void CreateSinLaser( double* x, double* y, double speed, double angle, double amp, double phase ){
    double x_ = speed, y_ = amp;
    y_ *= sin(phase);
 
    double Sin = sin(angle), Cos = cos(angle);
    double tx = x_, ty = y_;
    x_ = tx*Cos - ty*Sin;
    y_ = tx*Sin + ty*Cos;
 
    *x += x_;
    *y += y_;
 
    return;
}
現状が添付画像です。

数学はsinとcosをようやく理解できた程度のレベルなので;;
位相の指定の仕方と、原理?を教えてくださると幸いです


~開発環境~
○Windows 7 Ultimate SP1
○Visual C++ 2010 Express
○DXライブラリ使用
添付ファイル
2011-8-7 23-44-46.png
2011-8-7 23-44-46.png (4.35 KiB) 閲覧数: 1043 回

non
記事: 1097
登録日時: 9年前

Re: 正弦波レーザーを作りたい

#4

投稿記事 by non » 9年前

YYSS さんが書きました:位相を180度ずらせば、最初に添付した画像のような軌跡を描けると思い、
位相0と位相PI/2(PIは円周率)でやってみたところ、綺麗な形になりません
180度はPI/2ではなくPIです。
したがって、

19行は
phase[1] = PI/2;
でなく、
phase[1] = PI;
にします。

さて、それで実行しても思ったようになっていないと思います。これは、元のプログラムが1個前の値に増分を加算する
方法を取っているためです。ちょっと説明がしずらいのですが・・・
数値の変化分は微分値で表すことができます。したがって、yの加算分はsinの微分値になります。
sinの微分はcosですので(、高校3年(数Ⅲ)で習うのかな?) 
42行 y_ *= sin(phase); を
y_ *= cos(phase);
にします。まだ、微分を習っていない方に説明するだけの能力は私にはありませんのでご了承ください。
non

アバター
a5ua
記事: 199
登録日時: 10年前

Re: 正弦波レーザーを作りたい

#5

投稿記事 by a5ua » 9年前

サンプルを作ってみました。参考にどうぞ
方針としては、
レーザーをX軸方向に進むものとして計算しておき、実際に描画するときに回転後の座標を得るようにしています。

コード:

#define _USE_MATH_DEFINES	// VCで、M_PIを使うため
#include <DxLib.h>
#include <math.h>

// (x, y)を座標系の原点を中心に回転させる
void RotateXY(double *x, double *y, double angle)
{
	double x_ = *x;
	double y_ = *y;
	double cos_ = cos(angle);
	double sin_ = sin(angle);

	*x = x_ * cos_ - y_ * sin_;
	*y = x_ * sin_ + y_ * cos_;
}

// (x, y)を平行移動させる
void TranslateXY(double *x, double *y, double tx, double ty)
{
	*x += tx;
	*y += ty;
}

// 正弦波レーザー
struct SinLaser
{
	double x0, y0;		// 発射位置
	double x, y;		// 現在の位置(ただし、回転・平行移動させる前の座標)
	double speed;		// 速度
	double angle;		// 角度
	double amp;			// 振幅
	double period;		// 周期
	double phase;		// 位相
};


// レーザーを作成する
SinLaser MakeLaser(double x, double y, double speed, double angle, double amp, double period, double phase)
{
	SinLaser laser = {x, y, 0, 0, speed, angle, amp, period, phase};
	return laser;
}

// レーザーを移動させる
void MoveLaser(SinLaser *laser)
{
	// 回転を考慮せずに、xを増加させ、対応するyの値を計算する
	laser->x += laser->speed;
	laser->y = laser->amp * sin(2 * M_PI / laser->period * laser->x + laser->phase);
}

// レーザーの実際の位置を得る
void GetLaserPos(const SinLaser *laser, double *x, double *y)
{
	*x = laser->x;
	*y = laser->y;
	
	// 回転後の座標を得る
	RotateXY(x, y, laser->angle);

	// 発射位置に合わせて平行移動させる
	TranslateXY(x, y, laser->x0, laser->y0);
}


void MoveLasers(SinLaser *laser, int n)
{
	for (int i = 0 ; i < n ; ++i) {
		MoveLaser(&laser[i]);
	}
}

void DrawLasers(const SinLaser *laser, int n)
{
	int color[2] = {GetColor(255, 0, 0), GetColor(0, 0, 255)};
	for (int i = 0; i < n; ++i) {
		double x, y;
		GetLaserPos(&laser[i], &x, &y);
		DrawCircle((int)x, (int)y, 5, color[i % 3]);
	}
}

int APIENTRY _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
{
	if (ChangeWindowMode(TRUE) != 0 || DxLib_Init() != 0) {
		return -1;
	}
	SetDrawScreen(DX_SCREEN_BACK);

	char Key[256];
	
	// 右下(45度=π/4ラジアン)に発射される、位相だけが異なる2つのレーザーを作る
	const int N = 2;
	double X = 20;
	double Y = 100;
	double Speed = 5;
	double Angle = M_PI_4;
	double Amp = 30;
	double Period = 4 * Amp;
	
	SinLaser laser[N] = {
		MakeLaser(X, Y, Speed, Angle, Amp, Period, 0), 
		MakeLaser(X, Y, Speed, Angle, Amp, Period, M_PI), 
	};

	while (ProcessMessage() == 0 && GetHitKeyStateAll(Key) == 0 && !Key[KEY_INPUT_ESCAPE]) {
		// 画面クリア
		//ClearDrawScreen();

		// 移動
		MoveLasers(laser, N);

		// 描画
		DrawLasers(laser, N);

		ScreenFlip();
	}

	DxLib_End();

	return 0;
}

アバター
YYSS
記事: 125
登録日時: 9年前
連絡を取る:

Re: 正弦波レーザーを作りたい

#6

投稿記事 by YYSS » 9年前

返答遅れて申し訳ありません;;

a5uaさんやnonさんが教えてくれた通りに組んだら無事に出来ました。

解答してくださった皆さん、ありがとうございました!!

閉鎖

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