//=========================================================================== // 1000 CANVAS RENDERED AGENTS // Version 4 - Higher Definition // 23 March 2010 // // This is the beginning of a new foundation. // Illustrating class construction, a great deal of code // has been added to the class declaration and definition. // // Note: The Canvas->Rectangle method runs ABOUT 10 times faster // than the Canvas->Ellipse method and about 100 times faster // than moving TImages around the screen. // Use Canvas->Polyline or Canvas->Polygon to vary the visualization. // Trials runs 5-10 times faster than no trails. //=========================================================================== #include #include #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; #define POP 1000 // ====================================================== VARIABLES & CLASSES bool stop = true; bool move = false; bool flock=false; bool anAgentHasBeenChosen = false; // for throwing an agent double downX, downY; double upX, upY; double downUpX, downUpY; double timeUp, timeDown; double timeDownUp; int delay = 0; TColor back = 0X79BBD7; TColor fore = 0X4080FF; int i; int dist, chosen; TColor color = 0X4080FF; int XM=0; int YM=0; //--------------------------------------------------- Color Ramp Version 2008 TColor colorRamp(int part, int whole) { if (whole == 0) whole++; // prevent divide by zero int pixelDistanceAlongEdges = (part * 1792) / whole; int red, green, blue; // Which edge of the color cube are we on? if (pixelDistanceAlongEdges < 256) { // from BLACK to BLUE red = 0; green = 0; blue = pixelDistanceAlongEdges; } else if (pixelDistanceAlongEdges < 512) { // from BLUE to CYAN red = 0; green = pixelDistanceAlongEdges - 256; blue = 255; } else if (pixelDistanceAlongEdges < 768) { // from CYAN to GREEN red = 0; green = 255; blue = 255 - (pixelDistanceAlongEdges - 512); } else if (pixelDistanceAlongEdges < 1024) { // from GREEN to YELLOW red = (pixelDistanceAlongEdges - 768); green = 255; blue = 0; } else if (pixelDistanceAlongEdges < 1280) { // from YELLOW to RED red = 255; green= 255-(pixelDistanceAlongEdges - 1024); blue = 0; } else if (pixelDistanceAlongEdges < 1536) { // from RED to MAGENTA red = 255; green= 0; blue = pixelDistanceAlongEdges - 1280; } else { // from MAGENTA to WHITE red = 255; green = pixelDistanceAlongEdges - 1537; blue = 255; } return static_cast(RGB(red, green, blue)); } // this is a description of an abstract class called "agents" class agents { public: double x, y ; double direction; double dx, dy; TPoint points[6]; double life; TColor color; float height, width; double change; void erase (void) { points[0].x = x + dx * 10; points[0].y = y + dy * 10; points[1].x = x - dx * 10 + 4 * dy; points[1].y = y - dy * 10 - 4 * dx; points[2].x = x - dx * 10 - 4 * dy; points[2].y = y - dy * 10 + 4 * dx; Form1->PaintBox1->Canvas->Pen->Color = back; Form1->PaintBox1->Canvas->Brush->Color = back; //Form1->PaintBox1->Canvas->Pixels[x][y] = back; // check for center Form1->PaintBox1->Canvas->Polygon(points, 2); // Form1->PaintBox1->Canvas->Rectangle // (x - width / 2, y - height / 2, x + width / 2, y + height / 2); } void draw (void) { points[0].x = x + dx * 10; points[0].y = y + dy * 10; points[1].x = x - dx * 10 + 4 * dy; points[1].y = y - dy * 10 - 4 * dx; points[2].x = x - dx * 10 - 4 * dy; points[2].y = y - dy * 10 + 4 * dx; // Form1->PaintBox1->Canvas->Pen->Color = clBlack; if (Form1->RadioGroupColor->ItemIndex == 0) { // your color Form1->PaintBox1->Canvas->Brush->Color = color; Form1->PaintBox1->Canvas->Pen->Color = color; if(life==255){change=-0.5; } if (life==0) {change=0.5; } Form1->PaintBox1->Canvas->Brush->Color = colorRamp(life,255); Form1->PaintBox1->Canvas->Pen->Color = colorRamp(life,255); life=life+change; } if (Form1->RadioGroupColor->ItemIndex == 1) { Form1->PaintBox1->Canvas->Brush->Color = (dx + dy) * 4194303; Form1->PaintBox1->Canvas->Pen->Color = (dx + dy) * 4194303; } if (Form1->RadioGroupColor->ItemIndex == 2) { Form1->PaintBox1->Canvas->Brush->Color = dx * dy * 4194303; Form1->PaintBox1->Canvas->Pen->Color = dx * dy * 4194303; } if (Form1->RadioGroupColor->ItemIndex == 3) { Form1->PaintBox1->Canvas->Brush->Color = (x + y) * 63200; Form1->PaintBox1->Canvas->Pen->Color = (x + y) * 63200; } Form1->PaintBox1->Canvas->Polygon(points, 2); //Form1->PaintBox1->Canvas->Pixels[x][y] = clBlack; check for center // Form1->PaintBox1->Canvas->Rectangle // (x - width / 2, y - height / 2, x + width / 2, y + height / 2); } void drawChosen (void) { points[0].x = x + dx * 10; points[0].y = y + dy * 10; points[1].x = x - dx * 10 + 4 * dy; points[1].y = y - dy * 10 - 4 * dx; points[2].x = x - dx * 10 - 4 * dy; points[2].y = y - dy * 10 + 4 * dx; Form1->PaintBox1->Canvas->Brush->Color = color; Form1->PaintBox1->Canvas->Pen->Color = color; Form1->PaintBox1->Canvas->Polygon(points, 2); } void shrink (void) { // only works with Canvas->Rectangle erase(); height *= .9; width *= .9; draw(); } void grow (void) { // only works with Canvas->Rectangle erase(); height *= 1.1; width *= 1.1; draw(); } void move (void) { if (Form1->RadioGroupTrail->ItemIndex == 0) { erase(); } x += dx; y += dy; if (Form1->RadioGroupSpace->ItemIndex == 0) { // Bounce if (x > 895 || x < 5) { dx = -dx; } if (y > 895 || y < 5) { dy = -dy; } } else { // Wrap if (x > 895 ) x = 5; if (x < 5) x = 895; if (y > 895) y = 5; if (y < 5) y = 895; } draw(); } void moveChosen (void) { if (Form1->RadioGroupTrail->ItemIndex == 0) { erase(); } x += dx; y += dy; if (Form1->RadioGroupSpace->ItemIndex == 0) { // Bounce if (x > 895 || x < 5) { dx = -dx; } if (y > 895 || y < 5) { dy = -dy; } } else { // Wrap if (x > 895 ) x = 5; if (x < 5) x = 895; if (y > 895) y = 5; if (y < 5) y = 895; } drawChosen(); } void moveToMouse(void){ if (Form1->RadioGroupTrail->ItemIndex == 0) { erase(); } //int multiplier=3; float mag=sqrt(pow(dx,2)+pow(dy,2)); if(XM-x==0){ dx=0; dy=0; } else if(XM-x<0){ dx=-mag*cos(atan((YM-y)/(XM-x))); dy=-mag*sin(atan((YM-y)/(XM-x))); } else{ dx=mag*cos(atan((YM-y)/(XM-x))); dy=mag*sin(atan((YM-y)/(XM-x))); } // if (Form1->RadioGroupSpace->ItemIndex == 0) { // Bounce // if (x > 895 || x < 5) { // dx = -dx; // } // if (y > 895 || y < 5) { // dy = -dy; // } // } // else { // Wrap // if (x > 895 ) x = 5; // if (x < 5) x = 895; // if (y > 895) y = 5; // if (y < 5) y = 895; // } y+=dy; x+=dx; draw(); } void rotateAboutMouse(void){ if (Form1->RadioGroupTrail->ItemIndex == 0) { erase(); } float mag=sqrt(pow(dx,2)+pow(dy,2)); float distance=sqrt(pow((XM-x),2)+pow((YM-y),2)); float slope; float angle; if(YM-y==0) slope=-(XM-x)*99999; else slope=-((XM-x)/(YM-y)); if(slope==0) angle=0; else angle=atan(1/slope); dx=mag*sin(angle); dy=mag*cos(angle); if(XM-x==0){ dx=0; dy=0; } if(XM-x<0){ dx=-dx; dy=-dy; } if (Form1->RadioGroupSpace->ItemIndex == 0) { // Bounce if (x > 895 || x < 5) { dx = -dx; } if (y > 895 || y < 5) { dy = -dy; } } else { // Wrap if (x > 895 ) x = 5; if (x < 5) x = 895; if (y > 895) y = 5; if (y < 5) y = 895; } y+=dy; x+=dx; draw(); } void rotateAboutMouse2(void){ if (Form1->RadioGroupTrail->ItemIndex == 0) { erase(); } // float mag=sqrt(pow(dx,2)+pow(dy,2)); float distance=sqrt(pow((XM-x),2)+pow((YM-y),2)); float mag=100/distance; float slope; float angle; if(YM-y==0) slope=-(XM-x)*99999; else slope=-((XM-x)/(YM-y)); if(slope==0) angle=0; else angle=atan(1/slope); dx=mag*sin(angle); dy=mag*cos(angle); if(XM-x==0){ dx=0; dy=0; } if(XM-x<0){ dx=-dx; dy=-dy; } if (Form1->RadioGroupSpace->ItemIndex == 0) { // Bounce if (x > 895 || x < 5) { dx = -dx; } if (y > 895 || y < 5) { dy = -dy; } } else { // Wrap if (x > 895 ) x = 5; if (x < 5) x = 895; if (y > 895) y = 5; if (y < 5) y = 895; } y+=dy; x+=dx; draw(); } void rotate2(void){ if (Form1->RadioGroupTrail->ItemIndex == 0) { erase(); } float mag=sqrt(pow(dx,2)+pow(dy,2)); float distance=sqrt(pow((XM-x),2)+pow((YM-y),2)); dx=mag*cos(direction); dy=mag*sin(direction); y+=dy; x+=dx; direction+=1*(atan(mag/distance)); draw(); } }; agents agent[POP]; // we now create an array "agent" of type "agents" // ================================================================ FUNCTIONS void initialize (void) { for (int i = 0; i < POP; i++) { agent[i].erase(); agent[i].height = 10; agent[i].width = 10; agent[i].color = 0X4080FF; agent[i].life=0; agent[i].direction = double(i) / 3; agent[i].x = random(890) + 5; // in a 900 x 900 world agent[i].y = random(890) + 5; // in a 900 x 900 world agent[i].dy = double(random(100) - 50) / 25.00; // -2 to +2 agent[i].dx = double(random(100) - 50) / 25.00; // -2 to +2 agent[i].draw(); } Form1->TrackBarDelay->Position = Form1->TrackBarDelay->Max; } void step (void) { if(Form1->RadioGroupTarget->ItemIndex==1){ XM=agent[chosen].x; YM=agent[chosen].y; flock=true; } if (flock==true) { for (int i = 0; i < POP; i++) { if(i==chosen) agent[i].moveChosen(); else{ if(Form1->RadioGroupBehavior->ItemIndex==0) agent[i].move(); if(Form1->RadioGroupBehavior->ItemIndex==1) agent[i].moveToMouse(); if(Form1->RadioGroupBehavior->ItemIndex==2) agent[i].rotateAboutMouse(); if(Form1->RadioGroupBehavior->ItemIndex==3) agent[i].rotateAboutMouse2(); if(Form1->RadioGroupBehavior->ItemIndex==4) agent[i].rotate2(); } } } else{ for (int i = 0; i < POP; i++) { agent[i].move(); } } Sleep(delay); } void refresh (void) { for (int i = 0; i < POP; i++) { agent[i].draw(); } } // =========================================================== EVENT HANDLERS //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { DoubleBuffered = true; randomize(); initialize(); } //--------------------------------------------------------------------------- void __fastcall TForm1::ButtonShrinkClick(TObject *Sender) { for (int i = 0; i < POP; i++) { agent[i].shrink(); } } //--------------------------------------------------------------------------- void __fastcall TForm1::ButtonGrowClick(TObject *Sender) { for (int i = 0; i < POP; i++) { agent[i].grow(); } } //--------------------------------------------------------------------------- void __fastcall TForm1::RadioGroupTrailClick(TObject *Sender) { Form1->Refresh(); } //--------------------------------------------------------------------------- void __fastcall TForm1::ButtonStepClick(TObject *Sender) { stop = true; step(); } //--------------------------------------------------------------------------- void __fastcall TForm1::ButtonRunClick(TObject *Sender) { stop = false; while (stop == false) { Application->ProcessMessages(); step(); } } //--------------------------------------------------------------------------- void __fastcall TForm1::ButtonStopClick(TObject *Sender) { stop = true; } //--------------------------------------------------------------------------- void __fastcall TForm1::ButtonResetClick(TObject *Sender) { initialize(); Form1->Paint(); } //--------------------------------------------------------------------------- void __fastcall TForm1::PaintBox1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { // a chosen agent is the nearest agent no farther away from its radius dist = 1000; for (i = 0; i < POP; i++) { if (abs(X - agent[i].x) + abs(Y - agent[i].y) < dist) { dist = abs(X - agent[i].x) + abs(Y - agent[i].y); chosen = i; } } if (dist < agent[chosen].width / 2) { anAgentHasBeenChosen = true; } else anAgentHasBeenChosen = false; // left click to throw if (Button == 0 && anAgentHasBeenChosen) { move = true; timeDown = Now(); downX = X; downY = Y; } // right click to color if (Button == 1 && anAgentHasBeenChosen) { move = false; agent[chosen].color = color; agent[chosen].draw(); } } //--------------------------------------------------------------------------- void __fastcall TForm1::PaintBox1MouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { if (move == true && anAgentHasBeenChosen) { agent[chosen].erase(); agent[chosen].x = X; agent[chosen].y = Y; timeUp = Now(); agent[chosen].draw(); refresh(); } if (Form1->RadioGroupTarget->ItemIndex==0) { XM=X; YM=Y; } } //--------------------------------------------------------------------------- void __fastcall TForm1::PaintBox1MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { if (move == true && anAgentHasBeenChosen) { timeUp = Now(); upX = X; upY = Y; downUpX = downX - upX; downUpY = downY - upY; timeDownUp = timeDown - timeUp; agent[chosen].dx = downUpX / timeDownUp / 5000000; agent[chosen].dy = downUpY / timeDownUp / 5000000; move = false; } } //--------------------------------------------------------------------------- void __fastcall TForm1::FormShow(TObject *Sender) { refresh(); } //--------------------------------------------------------------------------- void __fastcall TForm1::PaintBox1Paint(TObject *Sender) { refresh(); } //--------------------------------------------------------------------------- void __fastcall TForm1::ButtonSelectColorClick(TObject *Sender) { if(Form1->ColorDialog1->Execute()) { color = ColorDialog1->Color; Form1->ShapeColor->Brush->Color = color; } } //--------------------------------------------------------------------------- void __fastcall TForm1::TrackBarDelayChange(TObject *Sender) { delay = TrackBarDelay->Max - TrackBarDelay->Position; } //--------------------------------------------------------------------------- void __fastcall TForm1::PaintBox1MouseEnter(TObject *Sender) { if (Form1->RadioGroupTarget->ItemIndex==0) flock=true; } //--------------------------------------------------------------------------- void __fastcall TForm1::PaintBox1MouseLeave(TObject *Sender) { if (Form1->RadioGroupTarget->ItemIndex==0) flock=false; } //---------------------------------------------------------------------------