速さの錯視
対象間の間隔によって速さの知覚が異なる(Scientific American: MIND, MAY/JUNE 2014, p. 69. “More legs move faster?”)ことのデモンストレーションプログラムをVisual C++/.NET 2013で作成してみた。
プログラムillusionSpeed.exeをダウンロード・実行すると図1のフォームが表示される。
図1
うまくダウンロード・実行できないときは
<WindowsにおけるEXEファイルのダウンロード・実行>
を参照されたい。
図1のフォームで「GO」ボタンをクリックすると図2の画面になり、2つの大きい円の周りを小さい円が回転する。
図2
左右、同じ速さで回転しているが、小円の数の多い右側の方が速く回転しているように見える。回転の速さは「Step Size」の値によって変わる。値を大きくすると速くなる。
もし、小円の動きがあまり滑らかでないときは、図2のフォームを小さくして画像の処理時間を短くしたプログラムillusionSpeed_S.exeも用意したので試すことができる。
プログラムのソースコードファイルなどは圧縮ファイルillusionSpeed.zipにまとめた。クリックしてダウンロード解凍すれば、Visual Studio 2013 for Windows Desktopで開くことができる。
フォームを小さくしたプログラムのソースコードファイルなどをまとめた圧縮ファイルillusionSpeed_S.zipも用意した。クリックしてダウンロード解凍してVisual Studio 2013 for Windows Desktopで開くことができる。
プログラムのメインの部分は以下のようになっている。
#pragma
once
namespace
illusionSpeed {
・
・
・
この部分は、Visual
Studioによって勝手に作成される。
・
・
・
#pragma
endregion
private:
System::Void buttonClose_Click(System::Object^ sender, System::EventArgs^ e) {
Close();
}
int pw, ph;
double StepSize,
StepPos;
private:
System::Void buttonGO_Click(System::Object^ sender, System::EventArgs^ e) {
//
// フォームの準備
//
timer1->Enabled
= false;
this->WindowState = FormWindowState::Maximized;
this->Update();
pictureBox1->Left
= 0;
pictureBox1->Top
= buttonClose->Height + 1;
pictureBox1->Width
= this->ClientSize.Width;
pictureBox1->Height
= this->ClientSize.Height - pictureBox1->Top;
pw
= pictureBox1->Width;
ph = pictureBox1->Height;
pictureBox1->Image
= gcnew Bitmap(pw, ph);
Graphics
^g = Graphics::FromImage(pictureBox1->Image);
Brush
^ BshWt = gcnew SolidBrush(Color::White);
g->FillRectangle(BshWt, 0, 0, pw, ph);
StepSize = double::Parse(textBox1->Text);
StepPos = 0.0;
timer1->Interval
= 1;
timer1->Enabled
= true;
}
private:
System::Void timer1_Tick(System::Object^
sender, System::EventArgs^ e) {
timer1->Enabled
= false;
Bitmap
^ bm = gcnew Bitmap(pw, ph);
Graphics
^g = Graphics::FromImage(bm);
//
// 全体を白で塗り潰す
//
Brush
^ BshWt = gcnew SolidBrush(Color::White);
g->FillRectangle(BshWt, 0, 0, pw, ph);
//
// 大きな2つの円の描画
//
double
C_L_left = pw * (0.5 - 0.25);
double
C_L_right = pw * (0.5 + 0.25);
double
r_L = pw / 8.0;
double
r_S = pw / 48.0;
Brush
^ BshBl = gcnew SolidBrush(Color::Blue);
g->FillEllipse(BshBl, int(C_L_left - r_L), int(ph
/ 2 - r_L), int(2 * r_L), int(2 * r_L));
g->FillEllipse(BshBl, int(C_L_right - r_L), int(ph
/ 2 - r_L), int(2 * r_L), int(2 * r_L));
//
// 小さい円の描画
//
Brush
^ BshOr = gcnew SolidBrush(Color::Orange);
for (int i = 0; i
< 2; i++){
double
theta = Math::PI * (StepPos + i);
double
x_pos = C_L_left + (r_L + r_S * 1.1) *
Math::Cos(theta);
double
y_pos = ph / 2.0 - (r_L + r_S * 1.1) *
Math::Sin(theta);
g->FillEllipse(BshOr, int(x_pos - r_S),
int(y_pos - r_S), int(2.0 * r_S), int(2.0 * r_S));
}
for (int i = 0; i
< 16; i++){
double
theta = Math::PI * (StepPos + i
/ 8.0);
double
x_pos = C_L_right + (r_L + r_S * 1.1) *
Math::Cos(theta);
double
y_pos = ph / 2.0 - (r_L + r_S * 1.1) *
Math::Sin(theta);
g->FillEllipse(BshOr, int(x_pos - r_S),
int(y_pos - r_S), int(2.0 * r_S), int(2.0 * r_S));
}
delete
g;
StepPos += StepSize;
if (StepPos > 2.0) StepPos -= 2.0;
Graphics
^g1 = Graphics::FromImage(pictureBox1->Image);
g1->DrawImage(bm, 0, 0); // ビットマップに描いた画像の転送
pictureBox1->Image
= pictureBox1->Image; // 描画結果を表示する。
delete
bm;
delete
BshBl;
delete
BshWt;
delete
BshOr;
delete
g1;
timer1->Enabled
= true;
}
private:
System::Void textBox1_TextChanged(System::Object^ sender, System::EventArgs^ e) {
timer1->Enabled
= false;
}
};
}
Visual C++/.NETプログラミングについては<岡本安晴「大学生のための心理学VC++プログラミング入門」勁草書房>で説明している。