//=========================================================================== // FLOCKING - March 2007 - Version 9 // An option has been added so that the agent will adopt the // average behavior of its neighbors within a given radius. //=========================================================================== // The Leonardo image is 612 by 612 pixels. // The Voyager images are 100 by 44 pixels. //--------------------------------------------------------------------------- #include #include #pragma hdrstop #include "Unit1.h" // The following two lines are needed to enable the randomizer #include "stdlib.h" #include "time.h" #include #define KING 24 #define QUEEN 25 //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { // Double buffering eliminates some screen flicker... DoubleBuffered = true; } //--------------------------------------------------------------------------- //=========================================================================== // GLOBAL VARIABLES //=========================================================================== // ------------------------------------------------- your program begins here // this sets up graphics functions to handle the import of a bitmap image Graphics::TBitmap* b = new Graphics::TBitmap(); RGBTRIPLE* t; // these arrays capture the Red, Green and Blue values of a bitmap image // the .bmp image is used as a geographic map of additional rules int bmpRed[612][612]; int bmpGreen[612][612]; int bmpBlue[612][612]; // this sets up the MIDI functionality int midiport = 0; HMIDIOUT device; union { public: unsigned long word; unsigned char data[4]; } message; int soundType = 0; int instrument; int note; TShape *shape[26] = {0}; // sets up an array of images class anAgent { public: int color; int literacy; int meetKing; int meetQueen; double velocity; double direction; double newDirection; double newDistance; double lastDistance; float x; float y; bool sex; bool flocking; int lastNN; } agent[26]; double vectorD, vectorV, vectorX, vectorY; // average directions & velocities int visibleN; // visible neighbors int increment = 5; double x, y, z; // error if placed in a function double aveDir; bool stop = true; bool wasStopped = false; bool showNNs = false; bool collisions = false; int iterations; int i; int myNeighbor; int kingAgents, queenAgents; int dist; int radius = 30; int chosenAgent; int imageDownX, imageDownY; bool agentWasJustChosen = false; //=========================================================================== // FUNCTIONS //=========================================================================== //-------------------------------------------------- FILL ARRAYS FROM BITMAP // This fills the Red, Green and Blue arrays from the bitmap. // It converts the color values (0-255) to preferences (0-7). // The conversion divides the color values by 35. // With a gray-scale image the Red, Green and Blue values are identical. void bmpToArray(Graphics::TBitmap* bm) { for (int y = 0; y < 612; y++) { t = (RGBTRIPLE*)bm->ScanLine[y]; for (int x = 0; x < 612; x++) { bmpRed[x][y] = t->rgbtRed; // used for preference 0-4 bmpGreen[x][y] = t->rgbtGreen; // used for distance 0-3 bmpBlue[x][y] = t->rgbtBlue; // used for neighborhood 0-2 t++; } } } //------------------------------------------------------------- RENDER BITMAP // This renders the imported bitmap to the screen. // It does not change the values in any of the arrays. // All it does is confirm that the image has been acquired. void renderBMP(Graphics::TBitmap* bm) { for (int y = 0; y < 612; y++) { t = (RGBTRIPLE*)bm->ScanLine[y]; for (int x = 0; x < 612; x++) { Form1->Canvas->Pixels[x][y]= static_cast(RGB(t->rgbtRed, t->rgbtGreen, t->rgbtBlue)); t++; } } } //---------------------------------------------------------------- color ramp int colorRamp(int range, int value) { int pixelDistanceAlongPath = (value * 1792) / range; int red, green, blue; // Which edge of the color cube are we on? if (pixelDistanceAlongPath < 256) { // Edge 1 from BLACK to BLUE red=0; green=0; blue=pixelDistanceAlongPath; } else if (pixelDistanceAlongPath < 512) { // Edge 2 from BLUE to CYAN red =0; green=pixelDistanceAlongPath-256; blue=255; } else if (pixelDistanceAlongPath < 768) { // Edge 3 from CYAN to GREEN red =0; green =255; blue= 255-(pixelDistanceAlongPath-512); } else if (pixelDistanceAlongPath < 1024) { // Edge 4 from GREEN to YELLOW red= (pixelDistanceAlongPath-768); green =255; blue =0; } else if (pixelDistanceAlongPath <1280) { // Edge 5 from YELLOW to RED red =255; green=255-(pixelDistanceAlongPath-1024); blue =0; } else if (pixelDistanceAlongPath < 1536) { // Edge 6 from RED to MAGENTA red =255; green=0; blue=pixelDistanceAlongPath -1280; } else { // Edge 7 from MAGENTA to WHITE red =255; green=pixelDistanceAlongPath-1536; blue =255; } return (RGB(red, green, blue)); } //------------------------------------------------------------------- shuffle void shuffle (void) { for (int i = 0; i < 26; i++) { agent[i].x = random(560) + 30; agent[i].y = random(510) + 50; agent[i].direction = (float(random(1000)) / 500) * M_PI; agent[i].velocity = float(random(1000)) / 1500 + .1; agent[i].flocking = FALSE; if (i % 2 == 0) { agent[i].sex = true; } else agent[i].sex = false; if (i < 24) { shape[i]->Left = agent[i].x - shape[i]->Width / 2; shape[i]->Top = agent[i].y - shape[i]->Height / 2; shape[i]->Brush->Color = clBlack; } if (i == 25) { Form1->ImageKing->Left = agent[i].x - Form1->ImageKing->Width / 2; Form1->ImageKing->Top = agent[i].y - Form1->ImageKing->Height / 2; } if (i == 26) { Form1->ImageQueen->Left = agent[i].x - Form1->ImageQueen->Width / 2; Form1->ImageQueen->Top = agent[i].y - Form1->ImageQueen->Height / 2; } } } //--------------------------------------------------------------------- reset void reset (void) { Form1->Refresh(); iterations = 0; kingAgents = 0; queenAgents=0; Form1->EditIterations->Text = iterations; shuffle(); } //-------------------------------------------------------------------- circle void circle (void) { Form1->Refresh(); for (int i = 0; i < 24; i++) { agent[i].x = 274 + 250 * cos(i * (2 * M_PI / 24)) + 30; agent[i].y = 274 + 250 * sin(i * (2 * M_PI / 24)) + 30; if (i < 24) { shape[i]->Left = agent[i].x - shape[i]->Width / 2; shape[i]->Top = agent[i].y - shape[i]->Height / 2; } if (i == 24) { Form1->ImageKing->Left = agent[i].x - Form1->ImageKing->Width / 2; Form1->ImageKing->Top = agent[i].y - Form1->ImageKing->Height / 2; } if (i == 25) { Form1->ImageQueen->Left = agent[i].x - Form1->ImageQueen->Width / 2; Form1->ImageQueen->Top = agent[i].y - Form1->ImageQueen->Height / 2; } } } //--------------------------------------------------------- nearest neighbors int nearestNeighbor (int me) { vectorD = 0; // directions vectorV = 0; // velocities vectorX = 0; // x component vectorY = 0; // y component visibleN = 0; // number of visible neighbors myNeighbor = 0; // my nearest neighbor dist = 10000; // shortest distance for (int i = 0; i < 26; i++) { if (i == me) continue; x = agent[i].x - agent[me].x; y = agent[i].y - agent[me].y; z = sqrt(x * x + y * y); if (z < dist) { // select nearest neighbor dist = z; myNeighbor = i; } if (z < radius) { // average all visible neighbors visibleN++; vectorY += agent[i].velocity * sin(agent[i].direction); vectorX += agent[i].velocity * cos(agent[i].direction); } } if ((vectorY != 0) && (vectorX != 0) && (visibleN > 0)) { vectorD = atan(vectorY / vectorX); vectorV = sqrt(vectorX * vectorX + vectorY * vectorY) / visibleN; } return myNeighbor; } //----------------------------------------------------- show nearest neighbor void showNearestNeighbor (int me) { Form1->Canvas->Pen->Color = clRed; if (agent[me].sex == true) { // from F Form1->Canvas->MoveTo(agent[me].x - 7, agent[me].y - 17); } else { Form1->Canvas->MoveTo(agent[me].x, // from M agent[me].y - 22); } if (agent[nearestNeighbor(me)].sex == true) { // to F Form1->Canvas->LineTo(agent[nearestNeighbor(me)].x - 7, agent[nearestNeighbor(me)].y - 17); } else { // to M Form1->Canvas->LineTo(agent[nearestNeighbor(me)].x, agent[nearestNeighbor(me)].y - 22); } } //---------------------------------------------------------------------- step void step (void) { Form1->Refresh(); iterations++; Form1->EditIterations->Text = iterations; increment = Form1->TrackBarIncrement->Position; for (i = 0; i < 26; i++) { // calculate agent's new position based on velocity and direction agent[i].x += agent[i].velocity * cos(agent[i].direction) * increment; agent[i].y += agent[i].velocity * sin(agent[i].direction) * increment; // move the visualization on the screen accordingly if (i < 24){ shape[i]->Left = agent[i].x - shape[i]->Width / 2; shape[i]->Top = agent[i].y - shape[i]->Height / 2; } if (i == 24){ Form1->ImageKing->Left = agent[i].x - Form1->ImageKing->Width / 2; Form1->ImageKing->Top = agent[i].y - Form1->ImageKing->Height / 2; } if (i == 25){ Form1->ImageQueen->Left = agent[i].x - Form1->ImageQueen->Width / 2; Form1->ImageQueen->Top = agent[i].y - Form1->ImageQueen->Height / 2; } /////////////////////////////////////////////////////////////////////// ///////////////////// FLOCKING BEHAVIORS BELOW //////////////////////// /////////////////////////////////////////////////////////////////////// // adopt nearest neighbor's direction (problematic with BOUNCE) if (Form1->RadioGroupFlockingBehavior->ItemIndex == 1) { agent[i].direction = agent[nearestNeighbor(i)].direction; } // increment direction by 1/50 your nearest neighbor's if (Form1->RadioGroupFlockingBehavior->ItemIndex == 2) { agent[i].direction += agent[nearestNeighbor(i)].direction / 30; if (agent[i].direction > 2 * M_PI) { // modulo divide agent[i].direction = agent[i].direction - 2 * M_PI; } } // decrement direction by 1/100 your nearest neighbor's if (Form1->RadioGroupFlockingBehavior->ItemIndex == 3) { agent[i].direction -= agent[nearestNeighbor(i)].direction / 100; if (agent[i].direction > 2 * M_PI) { // modulo divide agent[i].direction = agent[i].direction - 2 * M_PI; } } // adopt nearest neighbor's velocity if (Form1->RadioGroupFlockingBehavior->ItemIndex == 4) { agent[i].velocity = agent[nearestNeighbor(i)].velocity; } // increment by half nearest neighbor's velocity if (Form1->RadioGroupFlockingBehavior->ItemIndex == 5) { agent[i].velocity += agent[nearestNeighbor(i)].velocity / 50; } // adopt nearest neighbor's direction and speed if (Form1->RadioGroupFlockingBehavior->ItemIndex == 6) { agent[i].velocity = agent[nearestNeighbor(i)].velocity; agent[i].direction = agent[nearestNeighbor(i)].direction; } // STRAIGHT COUPLES // if same sex: both reverse direction and take random velocities // if opposite sex: both take average direction and NN velocity if (Form1->RadioGroupFlockingBehavior->ItemIndex == 7) { nearestNeighbor(i); if ((dist < radius) && (agent[i].lastNN != myNeighbor)) { if (agent[i].sex == agent[myNeighbor].sex) { // reverse agent[i].direction += M_PI; if (agent[i].direction > 2 * M_PI) { agent[i].direction = agent[i].direction - 2 * M_PI; } agent[myNeighbor].direction += M_PI; if (agent[myNeighbor].direction > 2 * M_PI) { agent[myNeighbor].direction = agent[myNeighbor].direction - 2 * M_PI; } agent[i].velocity = float(random(1000)) / 1500 + .1; agent[myNeighbor].velocity = float(random(1000)) / 1500 + .1; } else { // adopt aveDir = (agent[i].direction + agent[myNeighbor].direction) / 2; agent[i].direction = aveDir; agent[myNeighbor].direction = aveDir; agent[i].velocity = agent[myNeighbor].velocity; } agent[i].lastNN = myNeighbor; } } // GAY/LES COUPLES // if opposite sex: both reverse direction and take random velocities // if same sex: both take average direction and NN velocity if (Form1->RadioGroupFlockingBehavior->ItemIndex == 8) { nearestNeighbor(i); if ((dist < radius) && (agent[i].lastNN != myNeighbor)) { if (agent[i].sex != agent[myNeighbor].sex) { // reverse agent[i].direction += M_PI; if (agent[i].direction > 2 * M_PI) { agent[i].direction = agent[i].direction - 2 * M_PI; } agent[myNeighbor].direction += M_PI; if (agent[myNeighbor].direction > 2 * M_PI) { agent[myNeighbor].direction = agent[myNeighbor].direction - 2 * M_PI; } agent[i].velocity = float(random(1000)) / 1500 + .1; agent[myNeighbor].velocity = float(random(1000)) / 1500 + .1; } else { // adopt aveDir = (agent[i].direction + agent[myNeighbor].direction) / 2; agent[i].direction = aveDir; agent[myNeighbor].direction = aveDir; agent[i].velocity = agent[myNeighbor].velocity; } agent[i].lastNN = myNeighbor; } } // Your direction and velocity are the average of those // you can see within a given radius... if (Form1->RadioGroupFlockingBehavior->ItemIndex == 9) { nearestNeighbor(i); if (vectorV != 0 && vectorD != 0 && visibleN > 1) { agent[i].velocity = vectorV; agent[i].direction = vectorD; agent[i].flocking = TRUE; } else if (agent[i].flocking == TRUE) { agent[i].direction = (float(random(1000)) / 500) * M_PI; agent[i].velocity = float(random(1000)) / 1500 + .1; agent[i].flocking = FALSE; } } // Boriana's Rules if (Form1->RadioGroupFlockingBehavior->ItemIndex == 10) { if (i< 24) { myNeighbor=nearestNeighbor(i); if (myNeighbor == KING) { agent[i].meetKing++; kingAgents++; Form1->EditKingAgents->Text = kingAgents; shape[i]->Brush->Color = clBlue; // shape[i]->Brush->Color = static_cast(colorRamp(24,i)); // shape[i]->Pen->Color = static_cast(colorRamp(24, i)); } if (myNeighbor == QUEEN) { agent[i].meetQueen++; queenAgents ++; Form1->EditQueenAgents->Text = queenAgents; shape[i]->Brush->Color = clRed; } } } /////////////////////////////////////////////////////////////////////// ///////////////////// FLOCKING BEHAVIORS ABOVE /////////////////////// /////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////// BOUNCE if (Form1->RadioGroupBoundary->ItemIndex == 0) { if (agent[i].x > 560) { agent[i].direction = M_PI - agent[i].direction; if (soundType == 1) Beep(196, 50); if (soundType == 2) { PlaySound ("C:\\WINDOWS\\Media\\Windows XP Balloon.wav", "", SND_ASYNC); } if (soundType == 3) { PlaySound ("C:\\Program Files\\Windows NT\\Pinball\\SOUND181.wav", "", SND_ASYNC); } if (soundType == 4) { message.data[0] = 0x90; message.data[1] = 55; message.data[2] = 100; message.data[3] = 0; midiOutShortMsg(device, message.word); } } if (agent[i].y > 560) { agent[i].direction = 2 * M_PI - agent[i].direction; if (soundType == 1) Beep(261, 50); if (soundType == 2) { PlaySound ("C:\\WINDOWS\\Media\\Windows XP pop-up blocked.wav", "", SND_ASYNC); } if (soundType == 3) { PlaySound ("C:\\Program Files\\Windows NT\\Pinball\\SOUND243.wav", "", SND_ASYNC); } if (soundType == 4) { message.data[0] = 0x90; message.data[1] = 60; message.data[2] = 100; message.data[3] = 0; midiOutShortMsg(device, message.word); } } if (agent[i].x < 30) { agent[i].direction = M_PI - agent[i].direction; if (soundType == 1) Beep(330, 50); if (soundType == 2) { PlaySound ("C:\\WINDOWS\\Media\\Windows XP Balloon.wav", "", SND_ASYNC); } if (soundType == 3) { PlaySound ("C:\\Program Files\\Windows NT\\Pinball\\SOUND713.wav", "", SND_ASYNC); } if (soundType == 4) { message.data[0] = 0x90; message.data[1] = 64; message.data[2] = 100; message.data[3] = 0; midiOutShortMsg(device, message.word); } } if (agent[i].y < 50) { agent[i].direction = 2 * M_PI - agent[i].direction; if (soundType == 1) Beep(392, 50); if (soundType == 2) { PlaySound ("C:\\WINDOWS\\Media\\Windows XP pop-up blocked.wav", "", SND_ASYNC); } if (soundType == 3) { PlaySound ("C:\\Program Files\\Windows NT\\Pinball\\SOUND735.wav", "", SND_ASYNC); } if (soundType == 4) { message.data[0] = 0x90; message.data[1] = 67; message.data[2] = 100; message.data[3] = 0; midiOutShortMsg(device, message.word); } } // modular divide direction by one rotation if (agent[i].direction > 2 * M_PI) { agent[i].direction = agent[i].direction - 2 * M_PI; } if (agent[i].direction < 0) { agent[i].direction = agent[i].direction + 2 * M_PI; } } ///////////////////////////////////////////////////////////////// WRAP else { if (agent[i].x > 590) { agent[i].x = 30; shape[i]->Left = agent[i].x - shape[i]->Width / 2; if (soundType == 1) Beep(196, 50); if (soundType == 2) { PlaySound ("C:\\WINDOWS\\Media\\Windows XP Balloon.wav", "", SND_ASYNC); } if (soundType == 3) { PlaySound ("C:\\Program Files\\Windows NT\\Pinball\\SOUND181.wav", "", SND_ASYNC); } if (soundType == 4) { message.data[0] = 0x90; message.data[1] = 55; message.data[2] = 100; message.data[3] = 0; midiOutShortMsg(device, message.word); } } if (agent[i].y > 560) { agent[i].y = 50; shape[i]->Top = agent[i].y - shape[i]->Height / 2; if (soundType == 1) Beep(330, 50); if (soundType == 2) { PlaySound ("C:\\WINDOWS\\Media\\Windows XP Balloon.wav", "", SND_ASYNC); } if (soundType == 3) { PlaySound ("C:\\Program Files\\Windows NT\\Pinball\\SOUND713.wav", "", SND_ASYNC); } if (soundType == 4) { message.data[0] = 0x90; message.data[1] = 64; message.data[2] = 100; message.data[3] = 0; midiOutShortMsg(device, message.word); } } if (agent[i].x < 30) { agent[i].x = 590; shape[i]->Left = agent[i].x - shape[i]->Width / 2; if (soundType == 1) Beep(261, 50); if (soundType == 2) { PlaySound ("C:\\WINDOWS\\Media\\Windows XP pop-up blocked.wav", "", SND_ASYNC); } if (soundType == 3) { PlaySound ("C:\\Program Files\\Windows NT\\Pinball\\SOUND243.wav", "", SND_ASYNC); } if (soundType == 4) { message.data[0] = 0x90; message.data[1] = 60; message.data[2] = 100; message.data[3] = 0; midiOutShortMsg(device, message.word); } } if (agent[i].y < 50) { agent[i].y = 560; shape[i]->Top = agent[i].y - shape[i]->Height / 2; if (soundType == 1) Beep(392, 50); if (soundType == 2) { PlaySound ("C:\\WINDOWS\\Media\\Windows XP pop-up blocked.wav", "", SND_ASYNC); } if (soundType == 3) { PlaySound ("C:\\Program Files\\Windows NT\\Pinball\\SOUND735.wav", "", SND_ASYNC); } if (soundType == 4) { message.data[0] = 0x90; message.data[1] = 67; message.data[2] = 100; message.data[3] = 0; midiOutShortMsg(device, message.word); } } } } } //---------------------------------------------------------------------- Run void run (void) { stop = false; message.data[0] = 0xC0; message.data[1] = 6; message.data[2] = 100; message.data[3] = 0; midiOutShortMsg(device, message.word); while (stop == false) { step(); Application->ProcessMessages(); } if (showNNs) { for (int i = 0; i < 24; i++) { showNearestNeighbor(i); } } showNNs = false; } //=========================================================================== // EVENT HANDLERS //=========================================================================== //------------------------------------------------------------ On Form Create void __fastcall TForm1::FormCreate(TObject *Sender) { midiOutOpen(&device, midiport, 0, 0, CALLBACK_NULL); randomize(); // defines an array of images with properties and events for (int i = 0; i < 24; i++) { shape[i] = new TShape(this); shape[i]->Parent = Form1; shape[i]->Visible = true; shape[i]->OnMouseDown = ShapeMouseDown; shape[i]->OnMouseUp = ShapeMouseUp; shape[i]->OnMouseMove = ShapeMouseMove; shape[i]->Shape = stCircle; shape[i]->Height = 50; shape[i]->Width = 50; shape[i]->Left = 0; shape[i]->Top = 0; shape[i]->Visible = true; shape[i]->Tag = i; } shuffle(); } //------------------------------------------------------- On image Mouse Down // An exception to the rule which says "Let Borland write event handlers." // This one you must type in yourself in addition to a reference to it // in Unit1.h (look at the source code in that unit). void __fastcall TForm1::ShapeMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { TShape *shape = dynamic_cast(Sender); // The following will be used for mouseMove and mouseUp events... // Captures the index number of the image that was clicked chosenAgent = shape->Tag; // remembers is we were stopped or running wasStopped = stop; stop = true; if (Button == 0) { // Begin drag object // Remembers that an image was chosen for mouseMove and mouseUp agentWasJustChosen = true; // Remembers where on the image the mouse was downed imageDownX = X; imageDownY = Y; } else { // Show nearest neighbor showNearestNeighbor(chosenAgent); } } //------------------------------------------------------- On image Mouse Move // An exception to the rule which says "Let Borland write event handlers." // This one you must type in yourself in addition to a reference to it // in Unit1.h (look at the source code in that unit). void __fastcall TForm1::ShapeMouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { TShape *shape = dynamic_cast(Sender); chosenAgent = shape->Tag; if (agentWasJustChosen) { // this drags the image along... shape->Left = shape->Left + X - imageDownX; shape->Top = shape->Top + Y - imageDownY; agent[chosenAgent].x = shape->Left + shape->Width / 2;; agent[chosenAgent].y = shape->Top + shape->Height / 2;; } // When the mouse moves over an image its values are displayed EditAgent->Text = shape->Tag; EditX->Text = int(agent[chosenAgent].x); EditY->Text = int(agent[chosenAgent].y); EditDirection->Text = agent[shape->Tag].direction; EditVelocity->Text = agent[shape->Tag].velocity; if (agent[shape->Tag].sex) { EditSex->Text= "F"; } else EditSex->Text= "M"; EditNN->Text = nearestNeighbor(shape->Tag); } //--------------------------------------------------------- On image Mouse Up // An exception to the rule which says "Let Borland write event handlers." // This one you must type in yourself in addition to a reference to it // in Unit1.h (look at the source code in that unit). void __fastcall TForm1::ShapeMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { TShape *shape = dynamic_cast(Sender); // this is the end of the drag... agentWasJustChosen = false; EditAgent->Text = shape->Tag; // When the mouse moves over an image its values are displayed EditX->Text = int(agent[chosenAgent].x); EditY->Text = int(agent[chosenAgent].y); EditDirection->Text = agent[shape->Tag].direction; EditVelocity->Text = agent[shape->Tag].velocity; // if we were running before the drag, then run... Form1->Refresh(); if (!wasStopped) { run(); } } //---------------------------------------------------------------- run button void __fastcall TForm1::ButtonRunClick(TObject *Sender) { run(); } //--------------------------------------------------------------- step button void __fastcall TForm1::ButtonStepClick(TObject *Sender) { stop = true; step(); } //--------------------------------------------------------------- stop button void __fastcall TForm1::ButtonStopClick(TObject *Sender) { stop = true; } //---------------------------------------------------------- randomize button void __fastcall TForm1::ButtonResetClick(TObject *Sender) { reset(); } //------------------------------------------------------------- circle button void __fastcall TForm1::ButtonCircleClick(TObject *Sender) { circle(); } //------------------------------------------------------ sound type RadioGroup void __fastcall TForm1::RadioGroupSonificationClick(TObject *Sender) { soundType = RadioGroupSonification->ItemIndex; } //--------------------------------------------------------------------------- void __fastcall TForm1::ButtonNNsClick(TObject *Sender) { if (stop) { for (int i = 0; i < 24; i++) { showNearestNeighbor(i); } } else { showNNs = true; stop = true; } } //--------------------------------------------------------------------------- void __fastcall TForm1::TrackBarRadiusChange(TObject *Sender) { radius = TrackBarRadius->Position; Form1->EditRadius->Text = radius; } //--------------------------------------------------------------------------- void __fastcall TForm1::ButtonOpenBMPClick(TObject *Sender) { if (OpenBitMapDialog->Execute() ) b->LoadFromFile(OpenBitMapDialog->FileName); bmpToArray(b); renderBMP(b); } //--------------------------------------------------------------------------- void __fastcall TForm1::ImageKingMouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { chosenAgent = 24; if (agentWasJustChosen) { // this drags the image along... ImageKing->Left = ImageKing->Left + X - imageDownX; ImageKing->Top = ImageKing->Top + Y - imageDownY; agent[chosenAgent].x = ImageKing->Left + ImageKing->Width / 2;; agent[chosenAgent].y = ImageKing->Top + ImageKing->Height / 2;; } // When the mouse moves over an image its values are displayed EditAgent->Text = 24; EditX->Text = int(agent[chosenAgent].x); EditY->Text = int(agent[chosenAgent].y); EditDirection->Text = agent[24].direction; EditVelocity->Text = agent[24].velocity; if (agent[24].sex) { EditSex->Text= "F"; } else EditSex->Text= "M"; EditNN->Text = nearestNeighbor(24); } //--------------------------------------------------------------------------- void __fastcall TForm1::ImageQueenMouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { chosenAgent = 25; if (agentWasJustChosen) { // this drags the image along... ImageQueen->Left = ImageQueen->Left + X - imageDownX; ImageQueen->Top = ImageQueen->Top + Y - imageDownY; agent[chosenAgent].x = ImageQueen->Left + ImageQueen->Width / 2;; agent[chosenAgent].y = ImageQueen->Top + ImageQueen->Height / 2;; } // When the mouse moves over an image its values are displayed EditAgent->Text = 25; EditX->Text = int(agent[chosenAgent].x); EditY->Text = int(agent[chosenAgent].y); EditDirection->Text = agent[25].direction; EditVelocity->Text = agent[25].velocity; if (agent[25].sex) { EditSex->Text= "F"; } else EditSex->Text= "M"; EditNN->Text = nearestNeighbor(25); } //--------------------------------------------------------------------------- void __fastcall TForm1::ImageKingMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { // this is the end of the drag... agentWasJustChosen = false; EditAgent->Text = 24; // When the mouse moves over an image its values are displayed EditX->Text = int(agent[chosenAgent].x); EditY->Text = int(agent[chosenAgent].y); EditDirection->Text = agent[24].direction; EditVelocity->Text = agent[24].velocity; // if we were running before the drag, then run... Form1->Refresh(); if (!wasStopped) { run(); } } //--------------------------------------------------------------------------- void __fastcall TForm1::ImageQueenMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { // this is the end of the drag... agentWasJustChosen = false; EditAgent->Text = 25; // When the mouse moves over an image its values are displayed EditX->Text = int(agent[chosenAgent].x); EditY->Text = int(agent[chosenAgent].y); EditDirection->Text = agent[25].direction; EditVelocity->Text = agent[25].velocity; // if we were running before the drag, then run... Form1->Refresh(); if (!wasStopped) { run(); } } //--------------------------------------------------------------------------- void __fastcall TForm1::ImageKingMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { // The following will be used for mouseMove and mouseUp events... // Captures the index number of the image that was clicked chosenAgent = 24; // remembers is we were stopped or running wasStopped = stop; stop = true; if (Button == 0) { // Begin drag object // Remembers that an image was chosen for mouseMove and mouseUp agentWasJustChosen = true; // Remembers where on the image the mouse was downed imageDownX = X; imageDownY = Y; } else { // Show nearest neighbor showNearestNeighbor(chosenAgent); } } //--------------------------------------------------------------------------- void __fastcall TForm1::ImageQueenMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { // The following will be used for mouseMove and mouseUp events... // Captures the index number of the image that was clicked chosenAgent = 25; // remembers is we were stopped or running wasStopped = stop; stop = true; if (Button == 0) { // Begin drag object // Remembers that an image was chosen for mouseMove and mouseUp agentWasJustChosen = true; // Remembers where on the image the mouse was downed imageDownX = X; imageDownY = Y; } else { // Show nearest neighbor showNearestNeighbor(chosenAgent); } } //---------------------------------------------------------------------------