December 28, 2020
Separation algorithms were used to position particles with a smooth motion. similar methods were used for the shells and nucleus with slight variations.
In the actual program a Parallel.For
loop replaces the first for loop to speed up the calculations.
Each particle loops over all PREVIOUS particles and adds equal opposing forces to each.
Protons and Neutrons in the nucleus are all controlled by the same separation algorithm. Every particle in the Nucleus moves towards the center. This force is normalized and then clamped to it’s own magnitude so the particles slow on approach
The particle then checks for overlaps with other particles using the radius distances. If they are overlapping a small separation force is applied. Each particle i only checks particles [0 - i] for overlap, removing duplicate overlap checks.
for (int i = 0, len = particles.Count; i < len; i++)
{
//find the distance from origin
Vector3 diffOrgin = transform.position - particles[i].PhysicsObj.Position;
//calculate the force to center ( clamp is used so particles slow near center
Vector3 forceToCenter = Vector3.ClampMagnitude(diffOrgin.normalized * (PARTICLE_SPEED * scale), diffOrgin.magnitude);
particles[i].PhysicsObj.AddForce(forceToCenter);
for (int j = 0; j < i; j++)
{
//find the distance between particles
Vector3 diffOther = particles[i].PhysicsObj.Position - particles[j].PhysicsObj.Position;
//calculate the amount of overlap
float overlap = diffOther.magnitude - (particles[i].Radius ) - (particles[j].Radius );
//check if actually overlapping
if (overlap < 0)
{
//add force to seperate
Vector3 forceToSeperate = diffOther.normalized * overlap * PARTICLE_SPEED * scale;
//apply forces to the particles
particles[i].PhysicsObj.AddForce(-forceToSeperate);
particles[j].PhysicsObj.AddForce(forceToSeperate);
}
}
}
Similar to the Nucleus separation, except overlap uses a calculated distance to maintain the configuration
Each particle in the shell moves towards the radius distance away from the center.
Using .sqrMagnitude
speeds up the calculation and also creates much larger forces the further away the electron is.
The diffRadius
vector between the particle and center is rotated 90 degrees to become tangent to the circle.
This can then be used to apply a small orbital force to the particle.
Because these particles are moving in 3D space but rotate around a 2D circle a small force is applied to get them aligned on z = 0
Finally, the same method for separation as the Nucleus is used.
seperationDistance = 2 * Radius * Mathf.Sin(Mathf.PI / ElectronCount);
is used as an overlap radius to evenly distribute particles around the circle.
//Euclidean distance between n points on r radius circle (n = ElectronCount, r = Radius)
seperationDistance = 2 * Radius * Mathf.Sin(Mathf.PI / ElectronCount);
for (int i = 0, len = ElectronCount; i < len; i++)
{
//calculate force to get into orbit
Vector2 diffRadius = transform.position - particles[i].PhysicsObj.Position;
Vector2 forceToRadius = diffRadius.normalized * (diffRadius.sqrMagnitude - Radius*Radius) * ALIGNMENT_SPEED;
particles[i].PhysicsObj.AddForce(forceToRadius);
//calculate force to maintain orbit
if (Settings.ORBIT)
{
Vector2 forceToOrbit = new Vector2(-diffRadius.y, diffRadius.x).normalized * ORBIT_SPEED * scale;
particles[i].PhysicsObj.AddForce(forceToOrbit);
}
//calculate force to z = 0;
Vector3 forceToZ = Vector3.back * particles[i].PhysicsObj.Position.z;
particles[i].PhysicsObj.AddForce(forceToZ);
for (int j = 0; j < i; j++)
{
//find the distance between particles
Vector2 diffOther = particles[i].PhysicsObj.Position - particles[j].PhysicsObj.Position;
//rare occurance, but seperate from identical other
if (diffOther.sqrMagnitude < 0.001) { particles[i].PhysicsObj.AddForce(Random.insideUnitSphere); }
//calculate the amount of overlap
float overlap = diffOther.magnitude - seperationDistance;
if (overlap < 0)
{
//add force to seperate
Vector2 forceToSeperate = diffOther.normalized * overlap * SEPERATION_SPEED ;
//apply forces to the particles
particles[i].PhysicsObj.AddForce(-forceToSeperate);
particles[j].PhysicsObj.AddForce(forceToSeperate);
}
}
}
’