using System;
using System.Collections;
using System.Drawing;
namespace ParticleSwarm {
// TODO: Collision detection
public class GravityParticles : ParticleSystem {
//public const float GravitationalConstant = 6.672e-11f;
public const float GravitationalConstant = 0.000006672f;
private ParticleComparer pc = new ParticleComparer();
private int accelerationMultiplier = 100;
private bool tracefade = false;
private Rectangle size;
private Bitmap blank;
public GravityParticles() {
// Particle p1 = new Particle(new Vector(350, 350, 0), new Vector(0, 0, 0), 400000, 4, Color.Black);
// Particle p2 = new Particle(new Vector(370, 340, 0), new Vector(-0.01f, 0.01f, 0), 30, 3, Color.Blue);
// Particle p3 = new Particle(new Vector(350, 380, 0), new Vector(0.01f, -0.02f, 0), 2, 2, Color.Red);
// Particle p4 = new Particle(new Vector(450, 330, 0), new Vector(0, 0, 0), 400000, 4, Color.DarkGreen);
//
// particles.AddRange(new Particle[] { p1/*, p2, p3, p4*/ });
// Random r = new Random(Environment.TickCount);
// for (int i = 0; i < 10; i++) {
// Particle p = new Particle(new Vector(r.Next(50, 200), r.Next(50, 200), 0), new Vector(0, 0, 0), r.Next(50, 200), 1, Color.Gray);
// particles.Add(p);
// }
}
private static Color Tint(float ratio, Color c1) {
return Morph(ratio, Color.White, c1);
}
private static Color Morph(float ratio, Color c1, Color c2) {
int r = (int)(c1.R + ratio * (c2.R - c1.R));
int g = (int)(c1.G + ratio * (c2.G - c1.G));
int b = (int)(c1.B + ratio * (c2.B - c1.B));
return Color.FromArgb(r, g, b);
}
private Particle Merge(Particle i, Particle j, Graphics g) {
// if one is bigger, use it's location. otherwise average.
float newX;
float newY;
float newZ;
if (i.Size > j.Size) {
newX = i.Location.X;
newY = i.Location.Y;
newZ = i.Location.Z;
} else if (j.Size > i.Size) {
newX = j.Location.X;
newY = j.Location.Y;
newZ = j.Location.Z;
} else {
newX = (i.Location.X + j.Location.X) / 2f;
newY = (i.Location.Y + j.Location.Y) / 2f;
newZ = (i.Location.Z + j.Location.Z) / 2f;
}
// Conservation of momentum in inelastic collision:
// final velocity = (m1 * v1 + m2 * v2)/(m1 + m2)
Vector v = ((i.Velocity * i.Mass) + (j.Velocity * j.Mass)); // / (i.Mass + j.Mass);
v /= i.Mass + j.Mass;
// v.X /= i.Mass + j.Mass;
// v.Y /= i.Mass + j.Mass;
// v.Z /= i.Mass + j.Mass;
// idea is to grow size slightly, it's not representative anyway.
float newSize;
if (i.Size > j.Size) {
newSize = i.Size + 0.2f; // (j.Size / 10f);
} else if (j.Size > i.Size) {
newSize = j.Size + 0.2f; // + (i.Size / 10f);
} else {
newSize = i.Size + 0.2f; // + (j.Size / 10f);
}
Particle k = new Particle(new Vector(newX, newY, newZ), v, Morph(0.5f, i.Color, j.Color));
k.Mass = i.Mass + j.Mass;
k.Size = newSize;
particles.Remove(i);
particles.Remove(j);
particles.Add(k);
Pen splat = new Pen(new SolidBrush(Color.Red));
float size = k.Size;
if (k.Location.Z > 0) { size += (k.Location.Z * 0.1f); }
if (size < 1) { size = 1; }
float Xmidpoint = k.Location.X + (size/2f);
float Ymidpoint = k.Location.Y + (size/2f);
g.DrawLine(splat, Xmidpoint, Ymidpoint, Xmidpoint, Ymidpoint + size + 5);
g.DrawLine(splat, Xmidpoint, Ymidpoint, Xmidpoint, Ymidpoint - size - 5);
g.DrawLine(splat, Xmidpoint, Ymidpoint, Xmidpoint + size + 5, Ymidpoint);
g.DrawLine(splat, Xmidpoint, Ymidpoint, Xmidpoint - size - 5, Ymidpoint);
g.DrawLine(splat, Xmidpoint, Ymidpoint, Xmidpoint + size + 2, Ymidpoint + size + 2);
g.DrawLine(splat, Xmidpoint, Ymidpoint, Xmidpoint - size - 2, Ymidpoint - size - 2);
g.DrawLine(splat, Xmidpoint, Ymidpoint, Xmidpoint + size + 2, Ymidpoint - size - 2);
g.DrawLine(splat, Xmidpoint, Ymidpoint, Xmidpoint - size - 2, Ymidpoint + size + 2);
return k;
}
public override void Draw(Graphics g, Rectangle bounds) {
// check for collitions
if (base.detectCol) {
if (particles.Count > 1) {
for (int i = 0; i < particles.Count; i++) {
Particle pi = particles[i] as Particle;
Rectangle ri = new Rectangle((int)pi.Location.X, (int)pi.Location.Y, (int)pi.Size, (int)pi.Size);
for (int j = 0; j < particles.Count; j++) {
Particle pj = particles[j] as Particle;
if (object.ReferenceEquals(pi, pj)) { continue; }
Rectangle rj = new Rectangle((int)pj.Location.X, (int)pj.Location.Y, (int)pj.Size, (int)pj.Size);
if (pi.Location.Z - pj.Location.Z < 5
&& pi.Location.Z - pj.Location.Z > -5
&& ri.IntersectsWith(rj)) {
Merge(pi, pj, g);
}
}
}
}
}
// sort by z
particles.Sort(pc);
if (!base.trace) {
g.Clear(backColor);
} else if (tracefade) {
g.Clear(fade);
//if (blank == null || size != bounds) {
// size = bounds;
// blank = new Bitmap(size.Width, size.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
// using (Graphics b = Graphics.FromImage(blank)) {
// //b.FillRectangle(new SolidBrush(fade), size);
// g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
// g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
// g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low;
// g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
// b.Clear(fade);
// }
//}
//g.DrawImageUnscaled(blank, 0, 0);
} else {
g.Clear(backColor);
}
System.Collections.Generic.List<Particle> removes = new System.Collections.Generic.List<Particle>();
foreach (Particle p in particles) {
if (p.Location.X > 10000
|| p.Location.X < -10000
|| p.Location.Y > 10000
|| p.Location.Y < -10000
|| p.Location.Z > 10000
|| p.Location.Z < -10000
) {
removes.Add(p);
}
}
foreach (Particle p in removes) {
particles.Remove(p);
}
foreach (Particle p in particles) {
Vector a = new Vector();
if (particles.Count > 1) {
foreach (Particle p2 in particles) {
if (object.ReferenceEquals(p, p2)) { continue; }
Vector a2 = new Vector();
Vector unit = p2.MidLocation - p.MidLocation;
float magnitude = (float)Math.Sqrt((unit.X * unit.X) + (unit.Y * unit.Y) + (unit.Z * unit.Z));
float factor = (GravitationalConstant * ((p.Mass * p2.Mass) / (magnitude * magnitude * magnitude))) / p.Mass;
unit *= factor;
a2 = unit;
a += a2;
}
p.Velocity += a;
}
p.Acceleration = a;
}
particles.Reverse();
foreach (Particle p in particles) {
float Xmidpoint = p.MidLocation.X; // p.Location.X + (size / 2f);
float Ymidpoint = p.MidLocation.Y; // p.Location.Y + (size / 2f);
p.Update(new PointF(Xmidpoint, Ymidpoint), new PointF(p.Velocity.X * 10, p.Velocity.Y * 10), new PointF(Xmidpoint, Ymidpoint), new PointF(p.Acceleration.X * accelerationMultiplier, p.Acceleration.Y * accelerationMultiplier));
Xmidpoint = p.MidLocation.X; // p.Location.X + (size / 2f);
Ymidpoint = p.MidLocation.Y; // p.Location.Y + (size / 2f);
Color acc = Tint(0.6f, Morph(0.3f, p.Color, Color.Gray));
Pen ac = new Pen(new SolidBrush(acc));
Pen ac2 = new Pen(new SolidBrush(Color.FromArgb(40, acc)));
Color flc = Color.Red; // Tint(0.6f, Morph(0.3f, p.Color, Color.Red));
Pen vl = new Pen(new SolidBrush(flc));
Pen vl2 = new Pen(new SolidBrush(Color.FromArgb(20, flc)));
Brush b = new SolidBrush(p.Color);
Brush f = new SolidBrush(Tint(0.6f, p.Color));
Pen pn = new Pen(b, 1f);
// display size
float size = p.Size + (p.Location.Z * 0.0001f);
if (p.Location.Z > 0) { size += (p.Location.Z * 0.1f); }
if (size < 1) { size = 1; }
if (trace && !tracefade) {
Rectangle box = new Rectangle((int)p.Location.X, (int)p.Location.Y, (int)p.Size, (int)p.Size);
box.Inflate((int)size, (int)size);
g.FillEllipse(new SolidBrush(fade), box);
}
try {
if (base.ShowAccelerationBox) {
g.DrawLine(ac2, Xmidpoint, Ymidpoint, Xmidpoint + (p.Acceleration.X * accelerationMultiplier), Ymidpoint);
g.DrawLine(ac2, Xmidpoint, Ymidpoint, Xmidpoint, Ymidpoint + (p.Acceleration.Y * accelerationMultiplier));
g.DrawLine(ac2, Xmidpoint + (p.Acceleration.X * accelerationMultiplier), Ymidpoint, Xmidpoint + (p.Acceleration.X * accelerationMultiplier), Ymidpoint + (p.Acceleration.Y * accelerationMultiplier));
g.DrawLine(ac2, Xmidpoint, Ymidpoint + (p.Acceleration.Y * accelerationMultiplier), Xmidpoint + (p.Acceleration.X * accelerationMultiplier), Ymidpoint + (p.Acceleration.Y * accelerationMultiplier));
}
if (base.ShowAccelerationVectors) {
g.DrawLine(ac, Xmidpoint, Ymidpoint, Xmidpoint + (p.Acceleration.X * accelerationMultiplier), Ymidpoint + (p.Acceleration.Y * accelerationMultiplier));
}
} catch { }
if (base.ShowVelocityBox) {
g.DrawLine(vl2, Xmidpoint, Ymidpoint, Xmidpoint + (p.Velocity.X * 10), Ymidpoint);
g.DrawLine(vl2, Xmidpoint, Ymidpoint, Xmidpoint, Ymidpoint + (p.Velocity.Y * 10));
g.DrawLine(vl2, Xmidpoint + (p.Velocity.X * 10), Ymidpoint, Xmidpoint + (p.Velocity.X * 10), Ymidpoint + (p.Velocity.Y * 10));
g.DrawLine(vl2, Xmidpoint, Ymidpoint + (p.Velocity.Y * 10), Xmidpoint + (p.Velocity.X * 10), Ymidpoint + (p.Velocity.Y * 10));
}
if (base.ShowVelocityVectors) {
g.DrawLine(vl, Xmidpoint, Ymidpoint, Xmidpoint + (p.Velocity.X * 10), Ymidpoint + (p.Velocity.Y * 10));
}
if (trace && !tracefade) {
Ghost[] ghosts = p.Ghosts.ToArray();
for (int i = 0; i < ghosts.Length; i++) {
try {
if (base.ShowAccelerationBox) {
using (Pen gac2 = new Pen(new SolidBrush(Color.FromArgb(ghosts[i].Color.A, ac2.Color.R, ac2.Color.G, ac2.Color.B)))) {
g.DrawLine(gac2, ghosts[i].Acceleration1.X, ghosts[i].Acceleration1.Y, ghosts[i].Acceleration1.X + ghosts[i].Acceleration2.X, ghosts[i].Acceleration1.Y);
g.DrawLine(gac2, ghosts[i].Acceleration1.X, ghosts[i].Acceleration1.Y, ghosts[i].Acceleration1.X, ghosts[i].Acceleration1.Y + ghosts[i].Acceleration2.Y);
g.DrawLine(gac2, ghosts[i].Acceleration1.X + ghosts[i].Acceleration2.X, ghosts[i].Acceleration1.Y, ghosts[i].Acceleration1.X + ghosts[i].Acceleration2.X, ghosts[i].Acceleration1.Y + ghosts[i].Acceleration2.Y);
g.DrawLine(gac2, ghosts[i].Acceleration1.X, ghosts[i].Acceleration1.Y + ghosts[i].Acceleration2.Y, ghosts[i].Acceleration1.X + ghosts[i].Acceleration2.X, ghosts[i].Acceleration1.Y + ghosts[i].Acceleration2.Y);
}
}
if (base.ShowAccelerationVectors) {
using (Pen gac = new Pen(new SolidBrush(Color.FromArgb(ghosts[i].Color.A, ac.Color.R, ac.Color.G, ac.Color.B)))) {
g.DrawLine(gac, ghosts[i].Acceleration1.X, ghosts[i].Acceleration1.Y, ghosts[i].Acceleration1.X + ghosts[i].Acceleration2.X, ghosts[i].Acceleration1.Y + ghosts[i].Acceleration2.Y);
}
}
} catch { }
if (base.ShowVelocityBox) {
using (Pen gvl2 = new Pen(new SolidBrush(Color.FromArgb(ghosts[i].Color.A, 255, 128, 128)))) {
g.DrawLine(gvl2, ghosts[i].Velocity1.X, ghosts[i].Velocity1.Y, ghosts[i].Velocity1.X + ghosts[i].Velocity2.X, ghosts[i].Velocity1.Y);
g.DrawLine(gvl2, ghosts[i].Velocity1.X, ghosts[i].Velocity1.Y, ghosts[i].Velocity1.X, ghosts[i].Velocity1.Y + ghosts[i].Velocity2.Y);
g.DrawLine(gvl2, ghosts[i].Velocity1.X + ghosts[i].Velocity2.X, ghosts[i].Velocity1.Y, ghosts[i].Velocity1.X + ghosts[i].Velocity2.X, ghosts[i].Velocity1.Y + ghosts[i].Velocity2.Y);
g.DrawLine(gvl2, ghosts[i].Velocity1.X, ghosts[i].Velocity1.Y + ghosts[i].Velocity2.Y, ghosts[i].Velocity1.X + ghosts[i].Velocity2.X, ghosts[i].Velocity1.Y + ghosts[i].Velocity2.Y);
}
}
if (base.ShowVelocityVectors) {
using (Pen gvl = new Pen(new SolidBrush(Color.FromArgb(ghosts[i].Color.A, 255, 128, 128)))) {
g.DrawLine(gvl, ghosts[i].Velocity1.X, ghosts[i].Velocity1.Y, ghosts[i].Velocity1.X + ghosts[i].Velocity2.X, ghosts[i].Velocity1.Y + ghosts[i].Velocity2.Y);
}
}
}
for (int i = 0; i < ghosts.Length; i++) {
Color fill = Tint(0.6f, ghosts[i].Color);
fill = Color.FromArgb(ghosts[i].Color.A, fill.R, fill.G, fill.B);
using (Brush gf = new SolidBrush(fill)) {
using (Brush gb = new SolidBrush(ghosts[i].Color)) {
using (Pen gpn = new Pen(gb, 1f)) {
g.FillEllipse(gf, ghosts[i].Location.X, ghosts[i].Location.Y, size, size);
g.DrawEllipse(gpn, ghosts[i].Location.X, ghosts[i].Location.Y, size, size);
}
}
}
}
}
g.FillEllipse(f, p.Location.X, p.Location.Y, size, size);
g.DrawEllipse(pn, p.Location.X, p.Location.Y, size, size);
}
}
}
}