// from function moveScene(Scene*), MicroTrace.cxx
// collision between spheres
for (unsigned int i=0; i < scene->mSpheres.size(); i++)
{
for (unsigned int j=0; j < scene->mSpheres[i]->primitive.size(); j++)
{
Sphere* sph1 = (Sphere*)(scene->mSpheres[i]->primitive[j]);
// dont compute collision
if (sph1->crashInLastTime > 0)
continue;
// check collision with every other spheres
for (unsigned int k=i; k < scene->mSpheres.size(); k++)
{
unsigned int l; // we calculate only not yet checked pairs
if (k==i) {
l=j;
}
else {
l=0;
}
for (; l < scene->mSpheres[k]->primitive.size(); l++) {
if (i != k || j != l)
{
// other spheres - not i,j sphere
Sphere* sph2 = (Sphere*)(scene->mSpheres[k]->primitive[l]);
intersectionSize = sph1->radius + sph2->radius - (sph1->center - sph2->center).length();
if (intersectionSize > 0)
{
// spheres would be touch - change the direction
Vec2f v1 = Vec2f(sph1->energyVector.x(), sph1->energyVector.z());
Vec2f v2 = Vec2f(sph2->energyVector.x(), sph2->energyVector.z());
getVelocitiesAfterCollision( v1, v2, Vec2f( sph1->center.x(), sph1->center.z()),
Vec2f( sph2->center.x(), sph2->center.z()), sph1->radius + sph2->radius);
sph1->energyVector = Vec3f(v1.x(), 0, v1.y());
sph2->energyVector = Vec3f(v2.x(), 0, v2.y());
// slowdown by crash
sph1->energyVector *= coefSlowDownByCrash;
sph2->energyVector *= coefSlowDownByCrash;
}
}
}
}
}
}
// collision sphere - plane
for (unsigned int i=0; i < scene->mSpheres.size(); i++)
{
for (unsigned int j=0; j < scene->mSpheres[i]->primitive.size(); j++)
{
Sphere* sph = (Sphere*)(scene->mSpheres[i]->primitive[j]);
// dont compute collision
if (sph->crashInLastTime > 0)
continue;
// check collision with every sphere
for (unsigned int k = 0; k < scene->mObjects.size(); k++)
{
for (unsigned int l = 0; l < scene->mObjects[k]->primitive.size(); l++)
{
InfinitePlane* pl = (InfinitePlane*)(scene->mObjects[k]->primitive[l]);
// caluculate the distance of sphere from plane
// d from equation of plane an+bn+cn+d=0
double d = - Dot( pl->origin, pl->normal);
// t of intersection plane with line from centre of sphere
double t = (- d - Dot(sph->center, pl->normal) ) / Dot(pl->normal,pl->normal);
Vec3f intersect = sph->center + t * (-pl->normal);
double lengthEn = sph->energyVector.length();
intersectionSize = sph->radius - (sph->center - intersect).length();
if (intersectionSize > 0)
{
// sphere and plane are intersecting, doesnt look natural - not exactly but good enough for animation
moveBackVector = sph->energyVector;
Normalize(moveBackVector);
sph->center = sph->center - intersectionSize * moveBackVector;
// sphere would be touch the plane - change the direction
sph->energyVector = pl->normal * 2 * (- sph->energyVector.normal().dot(pl->normal)) + sph->energyVector.normal();
sph->energyVector = sph->energyVector.normal() * lengthEn;
sph->energyVector *= coefSlowDownByCrash;
}
}
}
}
}
/* Function compute new velocities of balls after their collision
v1 - velocity - energy vector of the first ball
v2 - velocity - energy vector of the second ball
center1 - center of the first ball
center2 - center of the second ball
sumRadius - sum of radius of these two balls (suppose that they have same radius)
*/
void getVelocitiesAfterCollision(Vec2f &v1, Vec2f &v2, Vec2f center1, Vec2f center2, double sumRadius)
{
double gamaV = atan( (v1.y()-v2.y()) / (v1.x()-v2.x()) );
double gamaXY = atan( (center2.y() - center1.y()) / (center2.x() - center1.x()));
double d = sqrt((center2.x() - center1.x())*(center2.x() - center1.x()) + (center2.y() - center1.y())*(center2.y() - center1.y()));
double alpha = asin( d * sin(gamaXY - gamaV) / sumRadius);
double a = tan(gamaV + alpha);
double delta = 2*(v1.x() - v2.x() + a *(v1.y()-v2.y())) / ((1 + a*a)*2);
// new energies of balls after collision
Vec2f newV2 = Vec2f(v2.x() + delta, v2.y() + a*delta);
Vec2f newV1 = Vec2f(v1.x() - delta, v1.y() - a*delta);
v1 = newV1;
v2 = newV2;
}
// from Sphere.hxx
// Method rotated sphere in actual position in direction (energyX, energyY) -> (energyX,0,energyY)
void Rotate(double energyX, double energyY)
{
double energySize = sqrt(energyX * energyX + energyY * energyY);
if (energySize < Epsilon)
{
// only accumulation error :-/
return;
}
double spherePerimeter = 2 * M_PI * radius;
// compute angle ball rolled by (from 0 to 1)
// minus is for correct rolling direction :-)
double fi = energySize / spherePerimeter;
double sinFi = sin(M_PI * fi);
double cosFi = cos(M_PI * fi);
// move values to unit circle
Vec2f pom(energyX, energyY);
Normalize(pom);
//double cosPsi = - pom.x();
//double sinPsi = pom.y();
double cosPsi = pom.x();
double sinPsi = pom.y();
// compute new northpole using polar coords
// Vec3f newNorth(cosFi * sinPsi, cosFi, sinFi * cosPsi);
Vec3f newNorth(cosPsi, 0, sinPsi);
Vec3f rotationAxis = Cross(newNorth, Vec3f(0,1,0));
Normalize(rotationAxis);
double x = rotationAxis.x();
double y = rotationAxis.y();
double z = rotationAxis.z();
Vec3f Mx(1 + (1-cosFi)*(x*x-1),z*sinFi+(1-cosFi)*x*y,-y*sinFi+(1-cosFi)*x*z);
Vec3f My(-z*sinFi+(1-cosFi)*x*y,1 + (1-cosFi)*(y*y-1),x*sinFi+(1-cosFi)*y*z);
Vec3f Mz(y*sinFi+(1-cosFi)*x*z, -x*sinFi+(1-cosFi)*y*z, 1 + (1-cosFi)*(z*z-1));
// Rotation matrix multiplication...
Vec3f newrotX (
rotX.x() * Mx.x() + rotY.x() * Mx.y() + rotZ.x() * Mx.z(),
rotX.y() * Mx.x() + rotY.y() * Mx.y() + rotZ.y() * Mx.z(),
rotX.z() * Mx.x() + rotY.z() * Mx.y() + rotZ.z() * Mx.z()
);
Vec3f newrotY (
rotX.x() * My.x() + rotY.x() * My.y() + rotZ.x() * My.z(),
rotX.y() * My.x() + rotY.y() * My.y() + rotZ.y() * My.z(),
rotX.z() * My.x() + rotY.z() * My.y() + rotZ.z() * My.z()
);
Vec3f newrotZ (
rotX.x() * Mz.x() + rotY.x() * Mz.y() + rotZ.x() * Mz.z(),
rotX.y() * Mz.x() + rotY.y() * Mz.y() + rotZ.y() * Mz.z(),
rotX.z() * Mz.x() + rotY.z() * Mz.y() + rotZ.z() * Mz.z()
);
rotX = newrotX;
rotY = newrotY;
rotZ = newrotZ;
}