Up

速さの錯視

 

対象間の間隔によって速さの知覚が異なる(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++プログラミング入門」勁草書房>で説明している。

 

Up