Subscribe to Stuck in an Infiniteloop        RSS Feed
-----

Detecting Collision Between Two Spheres

Icon Leave Comment
This blog post is going to be more code then text as the code has plenty of comments and typing it again would be overly redundant. To determine collision between two spheres in a given time step we calculate the "next" position of each spheres and pass both of them in addition to the "current" position of the sphere to the function. With that we have the following algorithm:

bool Vector::hasCollision(Vector* oneStart, Vector* oneEnd, Vector* twoStart, Vector* twoEnd)
{
	/*A simple way to check for collision between two spheres given the start and end position for a given time frame
	  is to see the smallest distance between them--ever
		  d^2 = a^2-(A*B)^2/b^2
	  lower case letters are the magnitude of each vector where the upper case are the actual vectors

	  Given two spheres P and Q with two points P1, Q1, etc... we have two vectors A and B where
	  A = P1-Q1
	  B = (P2-P1)-(Q2-Q1)

	  if distance < (rp+rq)^2, there is a collision (r is the radius of each respective sphere)
	  */
	double distance, t = 0;
	double rOne = 10, rTwo = 15; //example radii, most likely will be passed as parameters
	Vector* A = new Vector();
	Vector* B = new Vector();
	//Calculate  A and B vectors
	*A = *oneStart - *twoStart;
	*B = (*oneEnd - *oneStart)-(*twoEnd - *twoStart);
	
	distance = pow(A->getMagnitude(), 2.0) - ((pow(A->numericalDotProduct(B),2.0))/pow(B->getMagnitude(),2.0));

	//get time (collision between t0 and t1 timesteps):
	//quadratic equation equivalent if t is between 0 and 1 that is collision time within the timestamp
	t = -(A->numericalDotProduct(B));
	cout << "t: " << t << endl;
	t -= sqrt((pow(A->numericalDotProduct(B),2.0)) - ((pow(B->getMagnitude(),2.0))*(pow(A->getMagnitude(),2.0)-(pow(rOne+rTwo,2.0)))));
	cout << "t: " << t << endl;
	t/= pow(B->getMagnitude(),2.0);
	cout << "t: " << t << endl;

	//clean up
	delete A, B;

	if (distance < pow(rOne + rTwo, 2.0))
		return true;
	else
		return false;


}




This snippet relies on quite a bit of framework, namely the Vector class, here it is:

#ifndef VECTOR_H
#define VECTOR_H
#include <iostream>
using std::ostream;

class Vector {
private:
	double x, y, z;
public:
	Vector()										{ x = y = z = 0; };
	Vector(double pX, double pY, double pZ)			{ x = pX; y = pY; z = pZ; };
	~Vector() {};
	void setX(double pX)							{ x = pX; };
	void setY(double pY)							{ y = pY; };
	void setZ(double pZ)							{ z = pZ; };
	double getX()									{ return x; };
	double getY()									{ return y; };
	double getZ()									{ return z; };
	double getMagnitude(); 
	Vector normalize();
	Vector crossProduct(Vector*, Vector*);
	Vector dotProduct(Vector*);
	double numericalDotProduct(Vector*);
	Vector scalarMultiplication(double);
	void gravitationalAcceleration(Vector*);
	bool hasCollision(Vector*, Vector*, Vector*, Vector*);
	Vector operator+(Vector&);
	Vector operator-(Vector&);
	Vector operator=(Vector&);
	friend ostream& operator<< (ostream& os, Vector& vect)
	{
		os << "[" << vect.getX() << ", " << vect.getY() << ", " << 
			vect.getZ() << "]";
		return os;
	}
};
#endif


//corresponding cpp file:
#include <iostream>
#include <cmath>
#include "Vector.h"
using namespace std;

double Vector::getMagnitude()
{
	double magnitude = sqrt(x*x+y*y+z*z);
	return magnitude;
}

Vector Vector::normalize()
{
	double length = this->getMagnitude();
	Vector temp;
	temp.setX(this->getX()/length);
	temp.setY(this->getY()/length);
	temp.setZ(this->getZ()/length);
	return temp;
}

Vector Vector::crossProduct(Vector* vectOne, Vector* vectTwo)
{
	Vector temp;
	temp.setX(vectOne->getY()*vectTwo->getZ()-vectOne->getZ()*vectTwo->getY());
	temp.setY(vectOne->getZ()*vectTwo->getX()-vectOne->getX()*vectTwo->getZ());
	temp.setZ(vectOne->getX()*vectTwo->getY()-vectOne->getY()*vectTwo->getX());
	return temp;
}

Vector Vector::dotProduct(Vector* vectTwo)
{
	Vector temp;
	temp.setX(this->getX()*vectTwo->getX());
	temp.setY(this->getY()*vectTwo->getY());
	temp.setZ(this->getZ()*vectTwo->getZ());
	return temp;
}

double Vector::numericalDotProduct(Vector* vectTwo)
{
	double temp = 0;
	temp = this->getX()*vectTwo->getX()+ this->getY()*vectTwo->getY()+ this->getZ()*vectTwo->getZ();
	return temp;
}

Vector Vector::scalarMultiplication(double num)
{
	Vector temp;
	temp.setX(this->getX()*num);
	temp.setY(this->getY()*num);
	temp.setZ(this->getZ()*num);

	return temp;
}

void Vector::gravitationalAcceleration(Vector* vInit)
{
	//given the gravity vector Earth [0, 0, -9.81] and the particle initial position (the vector itself)
	// and the velocity desired we can calculate where it moves in 't' timesteps, a second for example
	//as long as the velocity is not parallel to the gravity, the result will be parabolic


	//*************Equation*******************
   //  p(t) = pInit + vInit*(t-tInit) + (1/2)*gravity*(t-tInit)^2
   //****************************************
	//This example assumes a start time of 0, so we begin with the position at t = 1

	Vector* curPosition = new Vector();
	Vector* gravity = new Vector(0, 0, -9.81);
	for(int i = 1; i <= 10; i++) //10 moments in time
	{
		*curPosition = *this + vInit->scalarMultiplication(i);
		*curPosition = *curPosition + gravity->scalarMultiplication(0.5*(pow(i,2.0)));
		cout << *curPosition << endl;
	}

	delete curPosition, gravity;
}

bool Vector::hasCollision(Vector* oneStart, Vector* oneEnd, Vector* twoStart, Vector* twoEnd)
{
	/*A simple way to check for collision between two spheres given the start and end position for a given time frame
	  is to see the smallest distance between them--ever
		  d^2 = a^2-(A*B)^2/b^2
	  lower case letters are the magnitude of each vector where the upper case are the actual vectors

	  Given two spheres P and Q with two points P1, Q1, etc... we have two vectors A and B where
	  A = P1-Q1
	  B = (P2-P1)-(Q2-Q1)

	  if distance < (rp+rq)^2, there is a collision (r is the radius of each respective sphere)
	  */
	double distance, t = 0;
	double rOne = 10, rTwo = 15; //example radii, most likely will be passed as parameters
	Vector* A = new Vector();
	Vector* B = new Vector();
	//Calculate  A and B vectors
	*A = *oneStart - *twoStart;
	*B = (*oneEnd - *oneStart)-(*twoEnd - *twoStart);
	
	distance = pow(A->getMagnitude(), 2.0) - ((pow(A->numericalDotProduct(B),2.0))/pow(B->getMagnitude(),2.0));

	//get time (coliision between t0 and t1 timesteps):
	//quadratic equation equivalent if t is between 0 and 1 that is collision tiem within the timestamp
	t = -(A->numericalDotProduct(B));
	cout << "t: " << t << endl;
	t -= sqrt((pow(A->numericalDotProduct(B),2.0)) - ((pow(B->getMagnitude(),2.0))*(pow(A->getMagnitude(),2.0)-(pow(rOne+rTwo,2.0)))));
	cout << "t: " << t << endl;
	t/= pow(B->getMagnitude(),2.0);
	cout << "t: " << t << endl;

	//clean up
	delete A, B;

	if (distance < pow(rOne + rTwo, 2.0))
		return true;
	else
		return false;


}

Vector Vector::operator+(Vector& rhs)
{
		Vector temp;
		temp.setX(this->getX() + rhs.getX());
		temp.setY(this->getY() + rhs.getY());
		temp.setZ(this->getZ() + rhs.getZ());
		return temp;
}

Vector Vector::operator-(Vector& rhs)
{
		Vector temp;
		temp.setX(this->getX() - rhs.getX());
		temp.setY(this->getY() - rhs.getY());
		temp.setZ(this->getZ() - rhs.getZ());
		return temp;
}

Vector Vector::operator=(Vector& rhs)
{
	this->setX(rhs.getX());
	this->setY(rhs.getY());
	this->setZ(rhs.getZ());

	return *this;
}



Create four Vector position pointers (which represent the beginning and ending positions of two spheres) and pass them to the function to determine if the two spheres will collide during their movement in that "timestep". Thanks for reading. Feel free to ask questions, offer guidance, pointers, criticisms, etc...

--KYA

0 Comments On This Entry

 

January 2022

S M T W T F S
      1
2345678
9101112131415
161718192021 22
23242526272829
3031     

Tags

    Recent Entries

    Recent Comments

    Search My Blog

    19 user(s) viewing

    19 Guests
    0 member(s)
    0 anonymous member(s)