Collision Detection between Accelerating Spheres

后端 未结 4 1875
Happy的楠姐
Happy的楠姐 2021-02-09 02:39

I am writing a physics engine/simulator which incorporates 3D space flight, planetary/stellar gravitation, ship thrust and relativistic effects. So far, it is going very well,

4条回答
  •  無奈伤痛
    2021-02-09 03:15

    op asked for time of collision. A slightly different approach will compute it exactly...

    Remember that the position projection equation is:

    NEW_POS=POS+VEL*t+(ACC*t^2)/2

    If we replace POS with D_POS=POS_A-POS_B, VEL with D_VEL=VEL_A-VEL_B, and ACC=ACC_A-ACC_B for objects A and B we get:

    $D_NEW_POS=D_POS+D_VEL*t+(D_ACC*t^2)/2

    This is the formula for vectored distance between the objects. In order to get the squared scalar distance between them, we can take the square of this equation, which after expansion looks like:

    distsq(t) = D_POS^2+2*dot(D_POS,D_VEL)*t + (dot(D_POS, D_ACC)+D_VEL^2)*t^2 + dot(D_VEL,D_ACC)*t^3 + D_ACC^2*t^4/4

    In order to find the time where collision occurs, we can set the equation equal to the square of the sum of radii and solve for t:

    0 = D_POS^2-(r_A+r_B)^2 + 2*dot(D_POS,D_VEL)*t + (dot(D_POS, D_ACC)+D_VEL^2)*t^2 + dot(D_VEL,D_ACC)*t^3 + D_ACC^2*t^4/4

    Now, we can solve for the equation using the quartic formula.

    The quartic formula will yield 4 roots, but we are only interested in real roots. If there is a double real root, then the two objects touch edges at exactly one point in time. If there are two real roots, then the objects continuously overlap between root 1 and root 2 (i.e. root 1 is the time when collision starts and root 2 is the time when collision stops). Four real roots means that the objects collide twice, continuously between root pairs 1,2 and 3,4.

    In R, I used polyroot() to solve as follows:

    # initial positions
    POS_A=matrix(c(0,0),2,1)
    POS_B=matrix(c(2,0),2,1)
    # initial velocities
    VEL_A=matrix(c(sqrt(2)/2,sqrt(2)/2),2,1)
    VEL_B=matrix(c(-sqrt(2)/2,sqrt(2)/2),2,1)
    # acceleration
    ACC_A=matrix(c(sqrt(2)/2,sqrt(2)/2),2,1)
    ACC_B=matrix(c(0,0),2,1)
    # radii
    r_A=.25
    r_B=.25
    # deltas
    D_POS=POS_B-POS_A
    D_VEL=VEL_B-VEL_A
    D_ACC=ACC_B-ACC_A
    
    
    # quartic coefficients
    z=c(t(D_POS)%*%D_POS-r*r, 2*t(D_POS)%*%D_VEL, t(D_VEL)%*%D_VEL+t(D_POS)%*%D_ACC, t(D_ACC)%*%D_VEL, .25*(t(D_ACC)%*%D_ACC))
    # get roots
    roots=polyroot(z)
    # In this case there are only two real roots...
    root1=as.numeric(roots[1])
    root2=as.numeric(roots[2])
    
    # trajectory over time
    pos=function(p,v,a,t){
      T=t(matrix(t,length(t),2))
      return(t(matrix(p,2,length(t))+matrix(v,2,length(t))*T+.5*matrix(a,2,length(t))*T*T))
    }
    
    # plot A in red and B in blue
    t=seq(0,2,by=.1) # from 0 to 2 seconds.
    a1=pos(POS_A,VEL_A,ACC_A,t)
    a2=pos(POS_B,VEL_B,ACC_B,t)
    plot(a1,type='o',col='red')
    lines(a2,type='o',col='blue')
    
    # points of a circle with center 'p' and radius 'r'
    circle=function(p,r,s=36){
      e=matrix(0,s+1,2)
      for(i in 1:s){
        e[i,1]=cos(2*pi*(1/s)*i)*r+p[1]
        e[i,2]=sin(2*pi*(1/s)*i)*r+p[2]
      }
      e[s+1,]=e[1,]
      return(e)
    }
    
    # plot circles with radius r_A and r_B at time of collision start in black
    lines(circle(pos(POS_A,VEL_A,ACC_A,root1),r_A))
    lines(circle(pos(POS_B,VEL_B,ACC_B,root1),r_B))
    # plot circles with radius r_A and r_B at time of collision stop in gray
    lines(circle(pos(POS_A,VEL_A,ACC_A,root2),r_A),col='gray')
    lines(circle(pos(POS_B,VEL_B,ACC_B,root2),r_B),col='gray')
    

    Object A follows the red trajectory from the lower left to the upper right. Object B follows the blue trajectory from the lower right to the upper left. The two objects collide continuously between time 0.9194381 and time 1.167549. The two black circles just touch, showing the beginning of overlap - and overlap continues in time until the objects reach the location of the gray circles.

提交回复
热议问题