//=========================================================================== // INTERACTION FLOCKING - Version 21 // AutoRun with Multiple Timers // 23 March 2012 // // EVERYTHING RUNS MORE SLOWLY IN WINDOWS 7 // // This application automatically expands to the size of the display: // Form1->AutoSize = false; // Form1->BorderStyle = bsNone; // Form1 and PaintBox1 sizes are set to MonitorHeight and MonitorWidth. // // Since the standard Windows controls do not appear: // A label [X] when clicked executes Form1->Close(). // A PopUp Menu is used to show abbreviated controls. // // To make the application run with continuously varying parameters: // More than 13 timers control various parameters. // Directions are in Radians as follows: // // North // pi/2 // (-1.57) // // West East // pi + 0 // +/-3.14 0 // // South // -pi/2 // (+1.57) // ========================================================================== // ====================================================== VARIABLES & CLASSES // ========================================================================== //------------------------ declaration of an abstract class called agentClass class agentClass { public: long double x, y, z ; long double dx, dy, dz; long double dxx, dyy, dzz; TPoint twoDPoints[3]; TPoint threeDPoints[3]; TColor color; float height, width; int tag; int seeking; void erase (void) { // size is dependent upon speed if (anaglyph) { // 3d Form1->PaintBox1->Canvas->Pen->Color = back; Form1->PaintBox1->Canvas->Brush->Color = back; Form1->PaintBox1->Canvas->Brush->Style = bsSolid; //bsClear; Form1->PaintBox1->Canvas->Polygon(twoDPoints, 2); Form1->PaintBox1->Canvas->Polygon(threeDPoints, 2); } else { // 2d Form1->PaintBox1->Canvas->Pen->Color = back; Form1->PaintBox1->Canvas->Brush->Color = back; Form1->PaintBox1->Canvas->Brush->Style = bsSolid; Form1->PaintBox1->Canvas->Polygon(twoDPoints, 2); } } void draw (void) { // trackbar determines size twoDPoints[0].x = x + dx * size; twoDPoints[0].y = y + dy * size; twoDPoints[1].x = x - dx * size + size / 2 * dy; twoDPoints[1].y = y - dy * size - size / 2 * dx; twoDPoints[2].x = x - dx * size - size / 2 * dy; twoDPoints[2].y = y - dy * size + size / 2 * dx; if (!anaglyph) { // 2D COLORING BY // agent-specific colors if (Form1->RadioGroupColor->ItemIndex == 0) { dynaColor = color; } // speed in colors if (Form1->RadioGroupColor->ItemIndex == 1) { dynaColor = colorRamp(getVelocity() * 300, 1000); } // speed in grays if (Form1->RadioGroupColor->ItemIndex == 2) { dynaColor = grayRamp(getVelocity() * 300, 1000); } // iterations in colors synchronous if (Form1->RadioGroupColor->ItemIndex == 3) { dynaColor = colorRamp(iterations + 10, 3000); } // iterations in grays synchronous if (Form1->RadioGroupColor->ItemIndex == 4) { dynaColor = grayRamp(iterations + 10, 3000); } // iterations in colors asynchronous if (Form1->RadioGroupColor->ItemIndex == 5) { dynaColor = colorRamp(iterations + 5*tag, 5 * pop); } // iterations in grays asynchronous if (Form1->RadioGroupColor->ItemIndex == 6) { dynaColor = grayRamp(iterations + 5*tag, 5 * pop); } // direction in colors if (Form1->RadioGroupColor->ItemIndex == 7) { dynaColor = colorRamp((getDirection() + 3) * 100, 628); } // direction in grays if (Form1->RadioGroupColor->ItemIndex == 8) { dynaColor = grayRamp((getDirection() + 3) * 100, 628); } // neighbors in colors if (Form1->RadioGroupColor->ItemIndex == 9) { dynaColor = colorRamp(neighbors + 5, maxNeighbors); } // neighbors in grays if (Form1->RadioGroupColor->ItemIndex == 10) { dynaColor = grayRamp(neighbors + 5, maxNeighbors); } // color trails and outline in black if (Form1->RadioGroupTrail->ItemIndex == 1) { Form1->PaintBox1->Canvas->Pen->Color = clBlack; } // color trails and outline in opposite color // Why, sincd dynaColor is used for both Brush and Pen? if (Form1->RadioGroupTrail->ItemIndex == 2) { Form1->PaintBox1->Canvas->Pen->Color = lastDynaColor; } // color trails and outline in same color if (Form1->RadioGroupTrail->ItemIndex == 3) { Form1->PaintBox1->Canvas->Pen->Color = dynaColor; } lastDynaColor = dynaColor; // remember color of last Brush Form1->PaintBox1->Canvas->Brush->Color = dynaColor; if (tag == chosen || tag == lastChosen) { Form1->PaintBox1->Canvas->Brush->Color = clWhite; } Form1->PaintBox1->Canvas->Polygon(twoDPoints, 2); } else { // RED is twoDPoints and is OK Form1->PaintBox1->Canvas->Pen->Color = clRed; Form1->PaintBox1->Canvas->Brush->Style = bsClear; Form1->PaintBox1->Canvas->Polygon(twoDPoints, 2); // 3D COLORING // compute CYAN threeDPoints[0].x = x + dx * size + (monitorHeight / 2 - z) / depth;; threeDPoints[0].y = y + dy * size; threeDPoints[1].x = x - dx * size + size / 2 * dy + (monitorHeight / 2 - z) / depth; threeDPoints[1].y = y - dy * size - size / 2 * dx; threeDPoints[2].x = x - dx * size - size / 2 * dy + (monitorHeight / 2 - z) / depth; threeDPoints[2].y = y - dy * size + size / 2 * dx; // CYAN is threeDPoints and OK Form1->PaintBox1->Canvas->Pen->Color = cyanColor; Form1->PaintBox1->Canvas->Brush->Style = bsClear; Form1->PaintBox1->Canvas->Polygon(threeDPoints, 2); } Application->ProcessMessages(); } void move (void) { x += dx; y += dy; if (anaglyph) z += dz; if (Form1->RadioGroupSpace->ItemIndex == 0) { // Bounce if ((x > monitorWidth) || (x < 0)) { // was 885, 155 dx = -dx; } if ((y > monitorHeight) || (y < 0)) { dy = -dy; } if (anaglyph && (z > monitorHeight || z < 0)) { dz = -dz; } } else { // Wrap if (x > monitorWidth) x = 0; // was 895, 5 if (x < 0) x = monitorWidth; if (y > monitorHeight) y = 0; if (y < 0) y = monitorHeight; if (anaglyph && (z > monitorHeight)) z = 0; if (anaglyph && (z < 0)) z = monitorHeight; } draw(); } long double getDirection (void) { // ok if (dx == 0) dx = .000000001; return atan2(dy, dx); } long double getVelocity (void) { // ok double velo = sqrtl(pow(dx, 2.0) + pow(dy, 2.0)); //if (anaglyph) velo = sqrt(pow(velo, 2) + pow(dz, 2)); return velo; } // velocities skew towards minimal at +/- pi/2 and // continue to shrink void setDirection (long double dir) { dx = getVelocity() * cos(dir); dy = getVelocity() * sin(dir); } // directions skew towards the horizontal w/ large velocities void setVelocity (long double vel) { dx = vel * cos(getDirection()); dy = vel * sin(getDirection()); } }; agentClass agent[POP]; // creates an array "agent" of type "agentClass" agentClass circles[4]; agentClass cursor; // ========================================================================== // ================================================================ FUNCTIONS // ========================================================================== // ===================================================================== STEP void step (void) { iterations ++; lastMaxNeighbors = maxNeighbors; maxNeighbors = 0; for (int i = 0; i < pop; i++) { if (neighbors > maxNeighbors) maxNeighbors = neighbors; // draw trails or not if (Form1->RadioGroupTrail->ItemIndex == 0) { agent[i].erase(); } if (colorChoice == 9 || colorChoice == 10) averageInRadius(i); // does this slow things too much? //######################### beginning of rules ################## //######################### beginning of rules ################## // ####################################################### RULE 1 if (rule == 1) { // adopt nearest neighbors direction and speed agent[i].dx = agent[nneighbor(i)].dx; agent[i].dy = agent[nneighbor(i)].dy; } // ####################################################### RULE 2 // adopt weighted average direction and speed of those // within a square radius if (rule == 2) { averageInRadius(i); // look around // add all x & y components weightedAveSumXdistances = (independence * agent[i].dx + sumXdistancesFromMe) / (neighbors + independence); weightedAveSumYdistances = (independence * agent[i].dy + sumYdistancesFromMe) / (neighbors + independence); weightedAveSumZdistances = (independence * agent[i].dz + sumZdistancesFromMe) / (neighbors + independence); if (weightedAveSumXdistances == 0) weightedAveSumXdistances = .00001; if (weightedAveSumYdistances == 0) weightedAveSumYdistances = .00001; if (weightedAveSumZdistances == 0) weightedAveSumZdistances = .00001; // compute noise directionVariance = 0.001 * ((random(variance + 1)) - 0.5 * variance); weightedAveDirection = atan2(weightedAveSumYdistances, weightedAveSumXdistances) + directionVariance; my_H = agent[i].getVelocity(); weightedAveVelocity = (independence * my_H + sum_dH) / (neighbors + independence); agent[i].dx = my_H * cos(weightedAveDirection); agent[i].dy = my_H * sin(weightedAveDirection); } // ####################################################### RULE 3 if (rule == 3) { // flock to cursor sumXdistancesFromMe = cursorX - agent[i].x; sumYdistancesFromMe = cursorY - agent[i].y; sumZdistancesFromMe = cursorZ - agent[i].z; weightedAveSumXdistances = (independence * agent[i].dx + sumXdistancesFromMe) / (independence); weightedAveSumYdistances = (independence * agent[i].dy + sumYdistancesFromMe) / (independence); weightedAveSumZdistances = (independence * agent[i].dz + sumZdistancesFromMe) / (independence); if (weightedAveSumXdistances == 0) weightedAveSumXdistances = .00001; if (weightedAveSumYdistances == 0) weightedAveSumYdistances = .00001; if (weightedAveSumZdistances == 0) weightedAveSumZdistances = .00001; // compute noise directionVariance = 0.001 * ((random(variance + 1)) - 0.5 * variance); weightedAveDirection = atan2(weightedAveSumYdistances, weightedAveSumXdistances) + directionVariance; my_H = agent[i].getVelocity(); weightedAveVelocity = (independence * my_H + sum_dH) / (neighbors + independence); agent[i].dx = my_H * cos(weightedAveDirection); agent[i].dy = my_H * sin(weightedAveDirection); } // ####################################################### RULE 4 if (rule == 4) { // flee from cursor sumXdistancesFromMe = agent[i].x - cursorX; sumYdistancesFromMe = agent[i].y - cursorY; sumYdistancesFromMe = agent[i].z - cursorZ; weightedAveSumXdistances = (independence * agent[i].dx + sumXdistancesFromMe) / (independence); weightedAveSumYdistances = (independence * agent[i].dy + sumYdistancesFromMe) / (independence); weightedAveSumZdistances = (independence * agent[i].dz + sumZdistancesFromMe) / (independence); if (weightedAveSumXdistances == 0) weightedAveSumXdistances = .00001; if (weightedAveSumYdistances == 0) weightedAveSumYdistances = .00001; if (weightedAveSumZdistances == 0) weightedAveSumZdistances = .00001; // compute noise directionVariance = 0.001 * ((random(variance + 1)) - 0.5 * variance); weightedAveDirection = atan2(weightedAveSumYdistances, weightedAveSumXdistances) + directionVariance; my_H = agent[i].getVelocity(); weightedAveVelocity = (independence * my_H + sum_dH) / (neighbors + independence); agent[i].dx = my_H * cos(weightedAveDirection); agent[i].dy = my_H * sin(weightedAveDirection); } // ####################################################### RULE 5 if (rule == 5) { // assimilate to nearest neighbor's color agent[i].color = agent[nneighbor(i)].color; } // ####################################################### RULE 6 if (rule == 6) { // seek assigned random individual sumXdistancesFromMe = agent[agent[i].seeking].x - agent[i].x; sumYdistancesFromMe = agent[agent[i].seeking].y - agent[i].y; sumZdistancesFromMe = agent[agent[i].seeking].z - agent[i].z; weightedAveSumXdistances = (independence * agent[i].dx + sumXdistancesFromMe) / (independence); weightedAveSumYdistances = (independence * agent[i].dy + sumYdistancesFromMe) / (independence); weightedAveSumZdistances = (independence * agent[i].dz + sumZdistancesFromMe) / (independence); if (weightedAveSumXdistances == 0) weightedAveSumXdistances = .00001; if (weightedAveSumYdistances == 0) weightedAveSumYdistances = .00001; if (weightedAveSumZdistances == 0) weightedAveSumZdistances = .00001; // compute noise directionVariance = 0.001 * ((random(variance + 1)) - 0.5 * variance); weightedAveDirection = atan2(weightedAveSumYdistances, weightedAveSumXdistances) + directionVariance; my_H = agent[i].getVelocity(); weightedAveVelocity = (independence * my_H + sum_dH) / (neighbors + independence); agent[i].dx = my_H * cos(weightedAveDirection); agent[i].dy = my_H * sin(weightedAveDirection); } // ####################################################### RULE 7 if (rule == 7) { // follow in line, seek in order sumXdistancesFromMe = agent[mv(i+1)].x - agent[i].x; sumYdistancesFromMe = agent[mv(i+1)].y - agent[i].y; sumZdistancesFromMe = agent[mv(i+1)].z - agent[i].z; weightedAveSumXdistances = (independence * agent[i].dx + sumXdistancesFromMe) / (independence); weightedAveSumYdistances = (independence * agent[i].dy + sumYdistancesFromMe) / (independence); weightedAveSumZdistances = (independence * agent[i].dz + sumZdistancesFromMe) / (independence); if (weightedAveSumXdistances == 0) weightedAveSumXdistances = .00001; if (weightedAveSumYdistances == 0) weightedAveSumYdistances = .00001; if (weightedAveSumZdistances == 0) weightedAveSumZdistances = .00001; // compute noise directionVariance = 0.001 * ((random(variance + 1)) - 0.5 * variance); weightedAveDirection = atan2(weightedAveSumYdistances, weightedAveSumXdistances) + directionVariance; my_H = agent[i].getVelocity(); weightedAveVelocity = (independence * my_H + sum_dH) / (neighbors + independence); agent[i].dx = my_H * cos(weightedAveDirection); agent[i].dy = my_H * sin(weightedAveDirection); } // ####################################################### RULE 8 if(rule == 8) { // Seek nearest neighbor sumXdistancesFromMe = agent[nneighbor(i)].x - agent[i].x; sumYdistancesFromMe = agent[nneighbor(i)].y - agent[i].y; sumZdistancesFromMe = agent[nneighbor(i)].z - agent[i].z; weightedAveSumXdistances = (independence * agent[i].dx + sumXdistancesFromMe) / (independence); weightedAveSumYdistances = (independence * agent[i].dy + sumYdistancesFromMe) / (independence); weightedAveSumZdistances = (independence * agent[i].dz + sumZdistancesFromMe) / (independence); if (weightedAveSumXdistances == 0) weightedAveSumXdistances = .00001; if (weightedAveSumYdistances == 0) weightedAveSumYdistances = .00001; if (weightedAveSumZdistances == 0) weightedAveSumZdistances = .00001; // compute noise directionVariance = 0.001 * ((random(variance + 1)) - 0.5 * variance); weightedAveDirection = atan2(weightedAveSumYdistances, weightedAveSumXdistances) + directionVariance; my_H = agent[i].getVelocity(); weightedAveVelocity = (independence * my_H + sum_dH) / (neighbors + independence); agent[i].dx = my_H * cos(weightedAveDirection); agent[i].dy = my_H * sin(weightedAveDirection); } // ####################################################### RULE 9 if (rule == 9) { //flee nearest neighbor nneighbor(i); sumXdistancesFromMe = agent[i].x - agent[nn].x; sumYdistancesFromMe = agent[i].y - agent[nn].y; weightedAveSumXdistances = (independence * agent[i].dx + sumXdistancesFromMe) / (independence); weightedAveSumYdistances = (independence * agent[i].dy + sumYdistancesFromMe) / (independence); if (weightedAveSumXdistances == 0) weightedAveSumXdistances = .00001; if (weightedAveSumYdistances == 0) weightedAveSumYdistances = .00001; // compute noise directionVariance = 0.001 * ((random(variance + 1)) - 0.5 * variance); weightedAveDirection = atan2(weightedAveSumYdistances, weightedAveSumXdistances) + directionVariance; my_H = agent[i].getVelocity(); weightedAveVelocity = (independence * my_H + sum_dH) / (neighbors + independence); agent[i].dx = my_H * cos(weightedAveDirection); agent[i].dy = my_H * sin(weightedAveDirection); } // ###################################################### RULE 10 if (rule == 10) { // Odd (.y and .x switched from seek cursor) sumXdistancesFromMe = cursorX - agent[i].y; sumYdistancesFromMe = cursorY - agent[i].x; sumZdistancesFromMe = cursorZ - agent[i].z; weightedAveSumXdistances = (independence * agent[i].dx + sumXdistancesFromMe) / (independence); weightedAveSumYdistances = (independence * agent[i].dy + sumYdistancesFromMe) / (independence); weightedAveSumZdistances = (independence * agent[i].dz + sumZdistancesFromMe) / (independence); if (weightedAveSumXdistances == 0) weightedAveSumXdistances = .00001; if (weightedAveSumYdistances == 0) weightedAveSumYdistances = .00001; if (weightedAveSumZdistances == 0) weightedAveSumZdistances = .00001; // compute noise directionVariance = 0.001 * ((random(variance + 1)) - 0.5 * variance); weightedAveDirection = atan2(weightedAveSumYdistances, weightedAveSumXdistances) + directionVariance; my_H = agent[i].getVelocity(); weightedAveVelocity = (independence * my_H + sum_dH) / (neighbors + independence); agent[i].dx = my_H * cos(weightedAveDirection); agent[i].dy = my_H * sin(weightedAveDirection); } // ###################################################### RULE 11 if (rule == 11) { // Sarah Van Name's Four Corners //if (fixCursorXY == false) { if (agent[i].x < 840 && agent[i].y < 525) { sumXdistancesFromMe = 420 - agent[i].x; sumYdistancesFromMe = 262.5 - agent[i].y; sumZdistancesFromMe = 100 - agent[i].z; } if (agent[i].x < 840 && agent[i].y > 525) { sumXdistancesFromMe = 420 - agent[i].x; sumYdistancesFromMe = 787.5 - agent[i].y; sumZdistancesFromMe = 100 - agent[i].z; } if (agent[i].x > 840 && agent[i].y < 525) { sumXdistancesFromMe = 1260 - agent[i].x; sumYdistancesFromMe = 262.5 - agent[i].y; sumZdistancesFromMe = 100 - agent[i].z; } if (agent[i].x > 840 && agent[i].y > 525) { sumXdistancesFromMe = 1260 - agent[i].x; sumYdistancesFromMe = 787.5 - agent[i].y; sumZdistancesFromMe = 100 - agent[i].z; } dynaColor = colorRamp(125, 255); weightedAveSumXdistances = (independence * agent[i].dx + sumXdistancesFromMe) / (independence); weightedAveSumYdistances = (independence * agent[i].dy + sumYdistancesFromMe) / (independence); weightedAveSumZdistances = (independence * agent[i].dz + sumZdistancesFromMe) / (independence); if (weightedAveSumXdistances == 0) weightedAveSumXdistances = .00001; if (weightedAveSumYdistances == 0) weightedAveSumYdistances = .00001; if (weightedAveSumZdistances == 0) weightedAveSumZdistances = .00001; // compute noise directionVariance = 0.001 * ((random(variance + 1)) - 0.5 * variance); weightedAveDirection = atan2(weightedAveSumYdistances, weightedAveSumXdistances) + directionVariance; my_H = agent[i].getVelocity(); weightedAveVelocity = (independence * my_H + sum_dH) / (neighbors + independence); agent[i].dx = my_H * cos(weightedAveDirection); agent[i].dy = my_H * sin(weightedAveDirection); } // ###################################################### RULE 12 if (rule == 12) { // Seek hierarchically sumXdistancesFromMe = agent[agent[i].seeking].x - agent[i].x; sumYdistancesFromMe = agent[agent[i].seeking].y - agent[i].y; sumZdistancesFromMe = agent[agent[i].seeking].z - agent[i].z; if (i == 0) { sumXdistancesFromMe = cursorX - agent[i].x; sumYdistancesFromMe = cursorY - agent[i].y; sumZdistancesFromMe = cursorZ - agent[i].z; } weightedAveSumXdistances = (independence * agent[i].dx + sumXdistancesFromMe) / (independence); weightedAveSumYdistances = (independence * agent[i].dy + sumYdistancesFromMe) / (independence); weightedAveSumZdistances = (independence * agent[i].dz + sumZdistancesFromMe) / (independence); if (weightedAveSumXdistances == 0) weightedAveSumXdistances = .00001; if (weightedAveSumYdistances == 0) weightedAveSumYdistances = .00001; if (weightedAveSumZdistances == 0) weightedAveSumZdistances = .00001; // compute noise directionVariance = 0.001 * ((random(variance + 1)) - 0.5 * variance); weightedAveDirection = atan2(weightedAveSumYdistances, weightedAveSumXdistances) + directionVariance; my_H = agent[i].getVelocity(); weightedAveVelocity = (independence * my_H + sum_dH) / (neighbors + independence); agent[i].dx = my_H * cos(weightedAveDirection); agent[i].dy = my_H * sin(weightedAveDirection); } // ###################################################### RULE 13 if (rule == 13) { // Sarah Van Name's Lissajou Figure agent[mv(i+1)].x = 840 + .45 * tan(i * 20) *512; agent[mv(i+1)].y = 525 + 0.3 * sin(i* 20) *512; sumXdistancesFromMe = agent[mv(i+1)].x - agent[i].x; sumYdistancesFromMe = agent[mv(i+1)].y - agent[i].y; sumZdistancesFromMe = agent[mv(i+1)].z - agent[i].z; weightedAveSumXdistances = (independence * agent[i].dx + sumXdistancesFromMe) / (independence); weightedAveSumYdistances = (independence * agent[i].dy + sumYdistancesFromMe) / (independence); weightedAveSumZdistances = (independence * agent[i].dz + sumZdistancesFromMe) / (independence); if (weightedAveSumXdistances == 0) weightedAveSumXdistances = .00001; if (weightedAveSumYdistances == 0) weightedAveSumYdistances = .00001; if (weightedAveSumZdistances == 0) weightedAveSumZdistances = .00001; // compute noise directionVariance = 0.001 * ((random(variance + 1)) - 0.5 * variance); weightedAveDirection = atan2(weightedAveSumYdistances, weightedAveSumXdistances) + directionVariance; my_H = agent[i].getVelocity(); weightedAveVelocity = (independence * my_H + sum_dH) / (neighbors + independence); agent[i].dx = my_H * cos(weightedAveDirection); agent[i].dy = my_H * sin(weightedAveDirection); } // ###################################################### RULE 14 if(rule == 14) { // Flee Larger, Seek Smaller if(agent[nneighbor(i)].getVelocity() > agent[i].getVelocity()) { sumXdistancesFromMe = -1 * (agent[nneighbor(i)].x - agent[i].x); sumYdistancesFromMe = -1 * (agent[nneighbor(i)].y - agent[i].y); sumZdistancesFromMe = -1 * (agent[nneighbor(i)].z - agent[i].z); } else { sumXdistancesFromMe = agent[nneighbor(i)].x - agent[i].x; sumYdistancesFromMe = agent[nneighbor(i)].y - agent[i].y; sumZdistancesFromMe = agent[nneighbor(i)].z - agent[i].z; } weightedAveSumXdistances = (independence * agent[i].dx + sumXdistancesFromMe) / (independence); weightedAveSumYdistances = (independence * agent[i].dy + sumYdistancesFromMe) / (independence); weightedAveSumZdistances = (independence * agent[i].dz + sumZdistancesFromMe) / (independence); if (weightedAveSumXdistances == 0) weightedAveSumXdistances = .00001; if (weightedAveSumYdistances == 0) weightedAveSumYdistances = .00001; if (weightedAveSumZdistances == 0) weightedAveSumZdistances = .00001; // compute noise directionVariance = 0.001 * ((random(variance + 1)) - 0.5 * variance); weightedAveDirection = atan2(weightedAveSumYdistances, weightedAveSumXdistances) + directionVariance; my_H = agent[i].getVelocity(); weightedAveVelocity = (independence * my_H + sum_dH) / (neighbors + independence); agent[i].dx = my_H * cos(weightedAveDirection); agent[i].dy = my_H * sin(weightedAveDirection); } // ###################################################### RULE 15 if (rule == 15) { // circle: seek radius from cursor if (distanceToCursor(i) < 10 * radius) { // flee sumXdistancesFromMe = agent[i].x - cursorX; sumYdistancesFromMe = agent[i].y - cursorY; weightedAveSumXdistances = (independence * agent[i].dx + sumXdistancesFromMe) / (independence); weightedAveSumYdistances = (independence * agent[i].dy + sumYdistancesFromMe) / (independence); if (weightedAveSumXdistances == 0) weightedAveSumXdistances = .00001; if (weightedAveSumYdistances == 0) weightedAveSumYdistances = .00001; // compute noise directionVariance = 0.001 * ((random(variance + 1)) - 0.5 * variance); weightedAveDirection = atan2(weightedAveSumYdistances, weightedAveSumXdistances) + directionVariance; my_H = agent[i].getVelocity(); weightedAveVelocity = (independence * my_H + sum_dH) / (neighbors + independence); agent[i].dx = my_H * cos(weightedAveDirection); agent[i].dy = my_H * sin(weightedAveDirection); } else { // flock sumXdistancesFromMe = cursorX - agent[i].x; sumYdistancesFromMe = cursorY - agent[i].y; weightedAveSumXdistances = (independence * agent[i].dx + sumXdistancesFromMe) / (independence); weightedAveSumYdistances = (independence * agent[i].dy + sumYdistancesFromMe) / (independence); if (weightedAveSumXdistances == 0) weightedAveSumXdistances = .00001; if (weightedAveSumYdistances == 0) weightedAveSumYdistances = .00001; // compute noise directionVariance = 0.001 * ((random(variance + 1)) - 0.5 * variance); weightedAveDirection = atan2(weightedAveSumYdistances, weightedAveSumXdistances) + directionVariance; my_H = agent[i].getVelocity(); weightedAveVelocity = (independence * my_H + sum_dH) / (neighbors + independence); agent[i].dx = my_H * cos(weightedAveDirection); agent[i].dy = my_H * sin(weightedAveDirection); } } //############################### end of rules ################## //############################### end of rules ################## // ========================================================================== // =========================================================== EVENT HANDLERS // ========================================================================== //------------------------------------------------------ PAINT BOX MOUSE DOWN void __fastcall TForm1::PaintBox1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { int shft = Shift.ToInt(); // shft values: | Left Right Wheel // -------------------------------------------------------------- // no key | 8 cursor 16 popup 32 // Shift | 9 musicians 17 33 probe // Alt | 10 color 18 34 // Ctrl | 12 obstacles 20 36 // -------------------------------------------------------------- // Left button #0 to set and unset, cursor X and Y // Clicks alternate between a fixed & moving cursor if (shft == 8) { fixCursorXY = !fixCursorXY; if (fixCursorXY == true) { cursorX = X; cursorY = Y; cursorZ = monitorHeight / 2; } } // Right Button #1 (shft 16) is reserved for the Popup Menu // Shift left button to set the nearest agent as a musician // Two musical agents will be colored white if (shft == 9) { int shortestDistance = 1000; lastLastChosen = lastChosen; lastChosen = chosen; for (i = 0; i < pop; i++) { int distance = abs(X - agent[i].x) + abs(Y - agent[i].y); if (distance < shortestDistance) { shortestDistance = distance; chosen = i; } } agent[lastLastChosen].draw(); agent[chosen].draw(); } // Alt left button to color the nearest agent // This only shows with color rule 0, "color by agent color" if (shft == 10) { int shortestDistance = 1000; for (i = 0; i < pop; i++) { int distance = abs(X - agent[i].x) + abs(Y - agent[i].y); if (distance < shortestDistance) { shortestDistance = distance; who = i; } } agent[who].color = userColor; agent[who].draw(); } // Control Left Click to enter obstacles in order // Obstacles must be enabled if (shft == 12) { leftClick = leftClick % 4; circles[leftClick].x = X; circles[leftClick].y = Y; if (leftClick == 0) { Form1->Shape1->Left = X - 15; Form1->Shape1->Top = Y - 15; Form1->Shape1->Visible = true; } if (leftClick == 1) { Form1->Shape2->Left = X - 15; Form1->Shape2->Top = Y - 15; Form1->Shape2->Visible = true; } if (leftClick == 2) { Form1->Shape3->Left = X - 15; Form1->Shape3->Top = Y - 15; Form1->Shape3->Visible = true; } if (leftClick == 3) { Form1->Shape1->Visible = false; Form1->Shape2->Visible = false; Form1->Shape3->Visible = false; } leftClick++; } // Shift Wheel Click to probe nearest agent if (shft == 33) { int shortestDistance = 1000; for (i = 0; i < pop; i++) { int distance = abs(X - agent[i].x) + abs(Y - agent[i].y); if (distance < shortestDistance) { shortestDistance = distance; who = i; } } // Edit->Text cannot convert a long double to a string double tempDX = agent[who].dx; double tempDY = agent[who].dy; Form1->EditWho->Text = agent[who].tag; Form1->EditDX->Text = tempDX; Form1->EditDY->Text = tempDY; double tempDirection = agent[who].getDirection(); double tempVelocity = agent[who].getVelocity(); Form1->EditDir->Text = tempDirection; Form1->EditVel->Text = tempVelocity; } } //------------------------------------------------------ PAINT BOX MOUSE MOVE void __fastcall TForm1::PaintBox1MouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { if (fixCursorXY == false) { cursorX = X; // useful for some rules cursorY = Y; } }