ページ 11

物体の中心の軌跡を残すには

Posted: 2011年12月15日(木) 10:25
by 混沌の従者
自由落下した物体の跳ね返り運動を、横軸を時間軸として表すプログラムを作っています。
一応それらしいものは出来たのですが、どうしても物体の中心の軌跡がいちいち途切れてしまいます。
この中心の軌跡をずっと残すためにはどうすればいいのでしょうか。
初めて間もない新参者ですが、よろしくお願いします。

コード:

 #pragma once
#include "windows.h"
#include "math.h"
#include "stdio.h"
#pragma warning(disable : 4244)

namespace test1 {

	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;

	/// <summary>
	/// Form1 の概要
	///
	/// 警告: このクラスの名前を変更する場合、このクラスが依存するすべての .resx ファイルに関連付けられた
	///          マネージ リソース コンパイラ ツールに対して 'Resource File Name' プロパティを
	///          変更する必要があります。この変更を行わないと、
	///          デザイナと、このフォームに関連付けられたローカライズ済みリソースとが、
	///          正しく相互に利用できなくなります。
	/// </summary>
	public ref class Form1 : public System::Windows::Forms::Form
	{
	public:
		Form1(void)
		{
			InitializeComponent();
			//
			//TODO: ここにコンストラクタ コードを追加します
			//
		}

	protected:
		/// <summary>
		/// 使用中のリソースをすべてクリーンアップします。
		/// </summary>
		~Form1()
		{
			if (components)
			{
				delete components;
			}
		}
	private: System::Windows::Forms::PictureBox^  pictureBox1;
	private: System::Windows::Forms::TextBox^  textBox1;
	protected: 

	private:
		/// <summary>
		/// 必要なデザイナ変数です。
		/// </summary>
		System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
		/// <summary>
		/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
		/// コード エディタで変更しないでください。
		/// </summary>
		void InitializeComponent(void)
		{
			this->pictureBox1 = (gcnew System::Windows::Forms::PictureBox());
			this->textBox1 = (gcnew System::Windows::Forms::TextBox());
			(cli::safe_cast<System::ComponentModel::ISupportInitialize^  >(this->pictureBox1))->BeginInit();
			this->SuspendLayout();
			// 
			// pictureBox1
			// 
			this->pictureBox1->Location = System::Drawing::Point(74, -2);
			this->pictureBox1->Name = L"pictureBox1";
			this->pictureBox1->Size = System::Drawing::Size(1192, 616);
			this->pictureBox1->TabIndex = 0;
			this->pictureBox1->TabStop = false;
			this->pictureBox1->Click += gcnew System::EventHandler(this, &Form1::pictureBox1_Click);
			// 
			// textBox1
			// 
			this->textBox1->Location = System::Drawing::Point(2, 61);
			this->textBox1->Name = L"textBox1";
			this->textBox1->Size = System::Drawing::Size(66, 19);
			this->textBox1->TabIndex = 1;
			// 
			// Form1
			// 
			this->AutoScaleDimensions = System::Drawing::SizeF(6, 12);
			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			this->ClientSize = System::Drawing::Size(1028, 578);
			this->Controls->Add(this->textBox1);
			this->Controls->Add(this->pictureBox1);
			this->Name = L"Form1";
			this->Text = L"Form1";
			(cli::safe_cast<System::ComponentModel::ISupportInitialize^  >(this->pictureBox1))->EndInit();
			this->ResumeLayout(false);
			this->PerformLayout();

		}
#pragma endregion
double E;


	private: System::Void pictureBox1_Click(System::Object^  sender, System::EventArgs^  e) {
				 E=double::Parse(textBox1->Text);

//ピクチャボックスと同じ大きさのBitmapを作成
Bitmap^ bmp = gcnew Bitmap(pictureBox1->Width, pictureBox1->Height);

pictureBox1->Image = bmp;
   
//ピクチャボックスからGraphicsの作成
Graphics^ G = Graphics::FromImage(pictureBox1->Image);



//自由落下//

double t0; //自由落下してからの時間(物体)//
double u0; //自由落下してからの時間(物体の中心)//

double g=9.81; //重力加速度//
double H=500; //最初に自由落下をする高さ//
double T0=sqrt(2*H/g); //物体が自由落下してから地面に当たるまでの時間//

double A=0.1; //時間の刻み//

for (t0 = 0; t0 <= T0 ; t0=t0+A ){;

double y0=0.5*g*t0*t0; //物体が地面に着くまでの変位//
double X0=10*t0;
double y1=0.5*g*(t0-A)*(t0-A);
double X1=10*(t0-A);

//物体の描画//
G->FillEllipse(Brushes::Red, 35+X0, 45+y0, 30, 30 );

pictureBox1->Refresh();



//ピクチャボックスの背景色でクリアする。
G->Clear(pictureBox1->BackColor);


//物体の中心・軌跡//

for(u0=0;u0<=t0;u0=u0+A){
   
	double y0=0.5*g*u0*u0; //物体が地面に着くまでの変位//
    double X0=10*u0;
    double y1=0.5*g*(u0-A)*(u0-A);
    double X1=10*(u0-A);


//物体の中心の軌跡の描画
G->DrawEllipse(Pens::Black, 50+X0, 60+y0, 1, 1 );


Sleep(0.001);

//線を引く//
G->DrawLine(Pens::Black, 50, 60,1200,60 ); //H//
G->DrawLine(Pens::Black, 50, 185,1200,185 ); //3/4H//
G->DrawLine(Pens::Black, 50, 310,1200,310 ); //1/2H//
G->DrawLine(Pens::Black, 50, 435,1200,435 ); //1/4H//
G->DrawLine(Pens::Red, 50, 555,1200,555 ); //1/100H//
G->DrawLine(Pens::Black, 50, 560,1200,560 ); //H=0//
G->DrawLine(Pens::Black, 50, 575,1200,575 ); //地面//
G->DrawLine(Pens::Black, 50, 30,50,575 ); //縦線//




}



} //for (t0 = 0; t0 <= T0 ; t0=t0+0.1 ){;//





//跳ね返り//

double t; //跳ね返った後の時間(物体)//
double u; //跳ね返った後の時間(物体の中心)//
int n=0; //跳ね返りの回数//

double v0=sqrt(2*H*g); //最初の自由落下で地面に当たる時の速度//




while (1) {; //無限に繰返しをする//

if (pow(E,n*2) <= 0.01){; //Eの2乗が1/100以下なら繰返しをやめる//

break;

}

 n=n+1; //跳ね返る回数の加算//


double vn=pow(E,n)*v0; //n回目に跳ね返った時の速度//

double T=2*vn/g; //n回目に跳ね返り、地面に当たる時までの時間//

double Tn=v0/g*(1+(2-pow(E,n)*2)/(1-E)); //物体がn回はねて着地するまでの時間//

for (t = 0; t <= T;t=t+A){; 

double X=10*t; //跳ね返りの間のx座標の方向の変位//
double Xn=10*Tn; //物体がn回はねて着地するまでの時間の変位//
double X2=2*v0/g*10;////

double y=0.5*g*t*t-vn*t; //n回目に跳ね返り、地面に当たる時までの変位//

double X3=10*(t-A);
double y2=0.5*g*(t-A)*(t-A)-vn*(t-A);

//物体の描画//
G->FillEllipse(Brushes::Red, 35+X+Xn-X2, 545+y, 30, 30 );

Sleep(0.001);
pictureBox1->Refresh();


//ピクチャボックスの背景色でクリアする。
G->Clear(pictureBox1->BackColor);


//物体の中心・軌跡//
for (u = 0; u <= t;u=u+A){; 

double X=10*u; //跳ね返りの間のx座標の方向の変位//
double Xn=10*Tn; //物体がn回はねて着地するまでの時間の変位//
double X2=2*v0/g*10;////

double y=0.5*g*u*u-vn*u; //n回目に跳ね返り、地面に当たる時までの変位//

double X3=10*(u-A);
double y2=0.5*g*(u-A)*(u-A)-vn*(u-A);


//物体の中心の軌跡の描画
G->DrawEllipse(Pens::Black, 50+X+Xn-X2, 560+y, 1, 1 );

Sleep(0.001);


//線を引く//
G->DrawLine(Pens::Black, 50, 60,1200,60 ); //H//
G->DrawLine(Pens::Black, 50, 185,1200,185 ); //3/4H//
G->DrawLine(Pens::Black, 50, 310,1200,310 ); //1/2H//
G->DrawLine(Pens::Black, 50, 435,1200,435 ); //1/4H//
G->DrawLine(Pens::Red, 50, 555,1200,555 ); //1/100H//
G->DrawLine(Pens::Black, 50, 560,1200,560 ); //H=0//
G->DrawLine(Pens::Black, 50, 575,1200,575 ); //地面//
G->DrawLine(Pens::Black, 50, 30,50,575 ); //縦線//

}

} //for (t = 0; t <= T;t=t+0.1){;//

} //for (n = 1; n <= 7 ; n++){;//




}
};
}

Re: 物体の中心の軌跡を残すには

Posted: 2011年12月15日(木) 10:58
by softya(ソフト屋)
えーと、これはC++/CLI(Windows フォーム)ですね? C++/CLIは決して初心者向きとは言えないですが参考サイトとか見つけられていますか? 私もC++はあってもC++/CLIでは組んだ事が無いので全部に答えれるか不安ですが。

とりあえず非常に乱れたインデントを修正して下さい。インデントの意味がわからなければ聞いて下さい。
「mixcpp/投稿前チェックリスト - PukiWiki」 (beatleさん作成)
http://uchan.net/w/index.php?mixcpp%2F% ... 5%B9%A5%C8

あと、このプログラムの動作のさせ方を教えて下さい。

Re: 物体の中心の軌跡を残すには

Posted: 2011年12月15日(木) 11:13
by 混沌の従う
回答になっているかわかりませんが、こちらはVisual C++ 2008 Express Editionを公式ページから
ダウンロードして使っています。

上のやつをそのままForm1のところに貼り付ければ、ピクチャーボックスに表示されると思うんですが…

インデントについては……よくわかりません。

Re: 物体の中心の軌跡を残すには

Posted: 2011年12月15日(木) 11:30
by softya(ソフト屋)
>回答になっているかわかりませんが、こちらはVisual C++ 2008 Express Editionを公式ページからダウンロードして使っています。

いえ、そちらではなくC++/CLIや.NetFrameWorkライブラリのリファレンスや入門サイト、入門書のことです。
入門者向けのものが殆ど無いと思いますが見つけられていますか?
なぜ、このようなことを聞くかというと情報が少ない上に文法が複雑なので初心者はC++/CLIを使うべきではないと思っているからです。

>上のやつをそのままForm1のところに貼り付ければ、ピクチャーボックスに表示されると思うんですが…

残念ですが動きませんでした。もう少し調べてみます。

>インデントについては……よくわかりません。

先程はリンクを張り損ないましたのでもう一度。
「mixcpp/投稿前チェックリスト - PukiWiki」 (beatleさん作成)
http://uchan.net/w/index.php?mixcpp%2F% ... 5%B9%A5%C8

Re: 物体の中心の軌跡を残すには

Posted: 2011年12月15日(木) 11:43
by 混沌の従者
>いえ、そちらではなくC++/CLIや.NetFrameWorkライブラリのリファレンスや入門サイト、入門書のことです。
>入門者向けのものが殆ど無いと思いますが見つけられていますか?

おっしゃる通り、ネットや地元の本屋などを漁ってみましたが、参考になるものはほとんど
見つかりませんでした。

参考になったといえば下のサイトくらいでしょうか。
http://imagingsolution.blog107.fc2.com/ ... y-123.html


あとは自分で色々試してみたりして、どうにかそれっぽい形にはなった、というのが現状です。

Re: 物体の中心の軌跡を残すには

Posted: 2011年12月15日(木) 11:53
by softya(ソフト屋)
分かりました。クリックすると動くのですね。

で、問題点が沢山あります。

(1)クリックイベントで描画している。
Windowsアプリの記述の方法として間違っています。
描画関数で描画して下さい。

(2)描画したままイベント処理を終了しない。
タイマーイベントなどを起動するにとどめてすぐに抜けて下さい。
描画ループすることはウィンドウアプリとして禁止されています。 → 応答しないプログラムとみなされます。
目安は数ms程度。sleepするのはもっての外です。

(3)数値の入力をチェックしていない。
未入力だとエラーになります。

以上です。
Windowsフォームに詳しくないので参考サイトは書けませんが、C/C++で組むならWin32APIの方が面倒ですが資料が多いと思います。

>おっしゃる通り、ネットや地元の本屋などを漁ってみましたが、参考になるものはほとんど
>見つかりませんでした。

そういう意味と言語の分かりやすさからはC#の方をお勧めしたいです。

[追記]
解決策を書き忘れました。
中心点を線で結べば解決すると思います。

Re: 物体の中心の軌跡を残すには

Posted: 2011年12月15日(木) 12:18
by 混沌の従者
>(1)クリックイベントで描画している。
>Windowsアプリの記述の方法として間違っています。
>描画関数で描画して下さい。

プログラムを実行するときにクリックなしで描画させるようにする、ということでしょうか。

>(2)描画したままイベント処理を終了しない。
>タイマーイベントなどを起動するにとどめてすぐに抜けて下さい。
>描画ループすることはウィンドウアプリとして禁止されています。 → 応答しないプログラムとみなされます。
>目安は数ms程度。sleepするのはもっての外です。

すみません……よく意味がわかりません(´; ω ;`)


>(3)数値の入力をチェックしていない。
>未入力だとエラーになります。

数値の入力に関しては全く説明してませんでしたね……本当に申し訳ない。
数値は床の弾性係数で、その値によってバウンドに変化を出させるようにしたものです。

数値の入力をチェックしていない、というのは、数字を入力しなかった場合「数値を入力してください」
というようなウィンドウを表示させる、ということでしょうか。



……アンポンタンな質問かもしれませんが、よろしくお願いします。

Re: 物体の中心の軌跡を残すには

Posted: 2011年12月15日(木) 12:25
by softya(ソフト屋)
根本的なところなのですが、基本としてウィンドウアプリは1/100秒程度の時間で処理を終わらないと行けないことになっています。
クリックされたら、すぐに終わる必要があると言うことです。

今の処理はクリックされたら延々と描画を続けていますのでウィンドウアプリの基本原則に違反していることになります。
解決策としては、描画処理を作りそちらに描画させる必要と一定時間ごとに更新するのはタイマーイベントのイベント処理で行う必要があります。
どちらもsleepのあるループはせずすぐに終了させます。

[参考]
「タイマにより一定時間間隔で処理を行うには?(Windowsタイマ編) - @IT」
http://www.atmarkit.co.jp/fdotnet/dotne ... timer.html
C#とVBの例です。C++/CLIは見つけられませんでした。

>数値の入力をチェックしていない、というのは、数字を入力しなかった場合「数値を入力してください」
>というようなウィンドウを表示させる、ということでしょうか。

そういう事ですね。

Re: 物体の中心の軌跡を残すには

Posted: 2011年12月15日(木) 12:42
by 混沌の従者
なるほど…… ...Φ(。。 )
確かにクリックしてもその場で止まりませんね。

中心点を線で結ぶというのは、時間経過による中心点の座標をDrawLineで結んで、
それをfor文で繰り返していく……ということでよろしいのでしょうか??

Re: 物体の中心の軌跡を残すには

Posted: 2011年12月15日(木) 12:54
by softya(ソフト屋)
混沌の従者 さんが書きました:なるほど…… ...Φ(。。 )
確かにクリックしてもその場で止まりませんね。

中心点を線で結ぶというのは、時間経過による中心点の座標をDrawLineで結んで、
それをfor文で繰り返していく……ということでよろしいのでしょうか??
それだとループ処理になりませんか?
処理の仕方次第ですが、一回のタイマイベント処理毎にDrawLineで結んでいくだけで良い気がします。

VBにおける一定周期の描画の例ですがC++/CLIも同様な方法を取り必要があります。
「VB キャラクターの出現と移動 - ゲーム講座, Visual Basic 中学校」
http://rucio.o.oo7.jp/VBGame/VBGameD01.htm

Re: 物体の中心の軌跡を残すには

Posted: 2011年12月15日(木) 13:05
by 混沌の従者
わかりました。こちらで色々取り組んでみたいと思います。

親切に教えていただいて、本当にありがとうございました。
また何かあったら来ます。