Fortran Program Code for 3D Elastic and Inelastic Collision of 2 Balls

Copy and Paste from Browser

      
c******************************************************************************
c   This program is a 'remote' 3D-collision detector for two balls on linear
c   trajectories and returns, if applicable, the location of the collision for 
c   both balls as well as the new velocity vectors (assuming a partially elastic
c   collision as defined by the restitution coefficient).
c   The equations on which the code is based have been derived at
c   http://www.plasmaphysics.org.uk/collision3d.htm
c
c   All variables apart from 'error' are of Double Precision Floating Point type.
c
c   The Parameters are:
c 
c    R    (restitution coefficient)  between 0 and 1 (1=perfectly elastic collision)                                   
c    m1    (mass of ball 1)
c    m2    (mass of ball 2)
c    r1    (radius of ball 1)
c    r2    (radius of ball 2)
c  * x1    (x-coordinate of ball 1) 
c  * y1    (y-coordinate of ball 1)          
c  * z1    (z-coordinate of ball 1)  
c  * x2    (x-coordinate of ball 2)          
c  * y2    (y-coordinate of ball 2)         
c  * z2    (z-coordinate of ball 2)         
c  * vx1   (velocity x-component of ball 1) 
c  * vy1   (velocity y-component of ball 1)
c  * vz1   (velocity z-component of ball 1)          
c  * vx2   (velocity x-component of ball 2)         
c  * vy2   (velocity y-component of ball 2)
c  * vz2   (velocity z-component of ball 2)
c  * error (Integer*2) (0: no error 
c                      1: balls do not collide 
c                      2: initial positions impossible (balls overlap)
c
c   In the calling program, the arguments corresponding to the parameters
c   with an asterisk (*) will be updated (the positions and velocities however
c   only if 'error'=0).
c   All variables should have the same data types in the calling program
c   and all should be initialized before calling the subroutine.
c
c   This program is free to use for everybody. However, you use it at your own
c   risk and I do not accept any liability resulting from incorrect behaviour.
c   I have tested the program for numerous cases and I could not see anything 
c   wrong with it but I can not guarantee that it is bug-free under any 
c   circumstances. 
c   I do in general not recommend the use of single precision because for
c   iterative computations the rounding errors can accumulate and render the
c   result useless if there are not enough decimal places; however for uncritical
c   applications or if speed is of paramount importance, you can change the 
c   program to single precision by changing the variable declaration to REAL*4
c   and remove the 'D' in front of the mathematical function names.
c
c
c   I would appreciate if you could report any problems to me
c   (for contact details see  http://www.plasmaphysics.org.uk/feedback.htm ).
c
c   Thomas Smid   February 2004
c                 December 2005 (a few minor changes to improve speed)
c                 December 2009 (generalization to partially inelastic collisions)
c                 July     2011 (fix for possible rounding errors)
c*******************************************************************************
                       
                              
 
       SUBROUTINE collision3D(R,m1,m2,r1,r2,
     &   x1,y1,z1,x2,y2,z2,vx1,vy1,vz1,vx2,vy2,vz2,error)
   
       IMPLICIT REAL*8 (A-Z)
       INTEGER*2 error
       
c      **** initialize some variables ****
       pi=DACOS(-1.0D0)  
       error=0
       r12=r1+r2
       m21=m2/m1
       x21=x2-x1
       y21=y2-y1
       z21=z2-z1
       vx21=vx2-vx1
       vy21=vy2-vy1
       vz21=vz2-vz1

       vx_cm = (m1*vx1+m2*vx2)/(m1+m2) 
       vy_cm = (m1*vy1+m2*vy2)/(m1+m2) 
       vz_cm = (m1*vz1+m2*vz2)/(m1+m2) 
       
             
c      **** calculate relative distance and relative speed ***      
       d=DSQRT(x21*x21 +y21*y21 +z21*z21)
       v=DSQRT(vx21*vx21 +vy21*vy21 +vz21*vz21)
       
c      **** return if distance between balls smaller than sum of radii ****
       IF (d .LT. r12) THEN
       error=2
       RETURN
       END IF
       
c      **** return if relative speed = 0 ****
       IF (v .EQ. 0) THEN
       error=1
       RETURN
       END IF       
       

c      **** shift coordinate system so that ball 1 is at the origin ***       
       x2=x21
       y2=y21
       z2=z21
       
c      **** boost coordinate system so that ball 2 is resting ***    
       vx1=-vx21
       vy1=-vy21
       vz1=-vz21

c      **** find the polar coordinates of the location of ball 2 ***    
       theta2=DACOS(z2/d)
       IF (x2 .EQ. 0 .AND. y2 .EQ. 0) THEN
       phi2=0
       ELSE
       phi2=DATAN2(y2,x2)
       END IF   
       st=DSIN(theta2)							
       ct=DCOS(theta2)							
       sp=DSIN(phi2)							
       cp=DCOS(phi2) 							


c      **** express the velocity vector of ball 1 in a rotated coordinate
c           system where ball 2 lies on the z-axis ******   
       vx1r=ct*cp*vx1+ct*sp*vy1-st*vz1 					
       vy1r=cp*vy1-sp*vx1 				
       vz1r=st*cp*vx1+st*sp*vy1+ct*vz1
	   fvz1r=vz1r/v
c      **** fix for possible rounding errors ****
       IF (fvz1r .GT. 1) THEN
       fvz1r=1
       ELSE 
         IF (fvz1r .LT. -1) THEN
         fvz1r=-1
         END IF
       END IF		  
c      **** End 'fix for possible rounding errors' ****	   
       thetav=DACOS(fvz1r)
       IF (vx1r .EQ. 0 .AND. vy1r .EQ. 0) THEN
       phiv=0
       ELSE
       phiv=DATAN2(vy1r,vx1r)
       END IF   

        						
c      **** calculate the normalized impact parameter ***    
       dr=d*DSIN(thetav)/r12


c      **** return old positions and velocities if balls do not collide ***
       IF (thetav .GT. pi/2 .OR. DABS(dr) .GT. 1) THEN
       x2=x2+x1
       y2=y2+y1
       z2=z2+z1
       vx1=vx1+vx2
       vy1=vy1+vy2
       vz1=vz1+vz2
       error=1
       RETURN
       END IF
       
c      **** calculate impact angles if balls do collide ***      
       alpha=DASIN(-dr)
       beta=phiv
       sbeta=DSIN(beta)
       cbeta=DCOS(beta)
        
       
c      **** calculate time to collision ***      
       t=(d*DCOS(thetav) -r12*DSQRT(1-dr**2))/v
     
c      **** update positions and reverse the coordinate shift *** 
       x2=x2+vx2*t +x1
       y2=y2+vy2*t +y1
       z2=z2+vz2*t +z1
       x1=(vx1+vx2)*t +x1
       y1=(vy1+vy2)*t +y1
       z1=(vz1+vz2)*t +z1
        
 
       
c  ***  update velocities ***

       a=DTAN(thetav+alpha)

       dvz2=2*(vz1r+a*(cbeta*vx1r+sbeta*vy1r))/((1+a**2)*(1+m21))
       
       vz2r=dvz2
       vx2r=a*cbeta*dvz2
       vy2r=a*sbeta*dvz2
       vz1r=vz1r-m21*vz2r
       vx1r=vx1r-m21*vx2r
       vy1r=vy1r-m21*vy2r

       
c      **** rotate the velocity vectors back and add the initial velocity
c            vector of ball 2 to retrieve the original coordinate system ****
                     
       vx1=ct*cp*vx1r-sp*vy1r+st*cp*vz1r +vx2 						
       vy1=ct*sp*vx1r+cp*vy1r+st*sp*vz1r +vy2 					
       vz1=ct*vz1r-st*vx1r               +vz2
       vx2=ct*cp*vx2r-sp*vy2r+st*cp*vz2r +vx2 						
       vy2=ct*sp*vx2r+cp*vy2r+st*sp*vz2r +vy2 					
       vz2=ct*vz2r-st*vx2r               +vz2  
       

c     ***  velocity correction for inelastic collisions ***

       vx1=(vx1-vx_cm)*R + vx_cm;
       vy1=(vy1-vy_cm)*R + vy_cm;
       vz1=(vz1-vz_cm)*R + vz_cm;
       vx2=(vx2-vx_cm)*R + vx_cm;
       vy2=(vy2-vy_cm)*R + vy_cm;
       vz2=(vz2-vz_cm)*R + vz_cm;  
       
       RETURN
       END


C++ Code

(Back To) Description