RigidBodyCollision holds data related to a collision or resting contact between two RigidBodys. The data includes:

  • which RigidBodys are involved,
  • where the collision or contact point is,
  • what is the distance between the RigidBodys (negative means penetration),
  • what is the relative velocity at the collision point,
  • what is the normal vector at the collision point
  • when the collision was detected
  • the estimated time that the collision occurred
  • the force or impulse that is applied

Other data concerns the geometry of the bodies in relation to the collision point – things like the curvature of the an edge, or distance from center of mass to the collision point. Some data exists only for certain sub-classes of RigidBodyCollision.

Most of the data in RigidBodyCollision is filled in after it is created, but some data is updated as the collision handling process proceeds. Many of the fields (properties) of RigidBodyCollision are 'package private' meaning that any code in the myphysicslab.lab.engine2D package can modify the field directly. This avoids having to make dozens of getter/setter methods for those fields.

See explanations at 2D Physics Engine Overview.

Terminology

The two RigidBodys involved in the collision are referred to as follows:

  • the primary body, has either a Vertex or Edge involved in the collision. For a Connector like Joint there is a connection point somewhere on the body instead of at a Vertex or Edge.

  • the normal body, has an Edge which defines the normal vector. For a Connector like Joint, the normal is defined by the Connector not by an Edge.

The normal vector is used to find the distance and velocity of the collision. The distance between the bodies is measured in the direction of the normal vector.

The normal relative velocity is the velocity between the bodies at the point of collision, but only in the direction of the normal vector.

The R vector goes from the center of mass to the impact point, on the primary body. Similarly, the R2 vector is on the normal body from its center of mass to the impact point.

Distance of Collision

The point of collision, or 'impact point', is where the two bodies are touching or penetrating. This 'point' is actually two different points, one on the primary body and one on the normal body. Ideally at the moment of collision these are at the same point in space, but in practice they are always somewhat apart.

The distance between the two bodies is the distance between the two impact points in the direction of the normal vector. Mathematically we can define the distance as follows:

p_a = point of impact on primary body
p_b = point of impact on normal body
n = vector normal to edge at impact point
distance = n . (p_a - p_b)

If distance is positive there is a gap between the objects. If distance is negative, then the objects are interpenetrating.

Target Gap

When bodies are interpenetrating, the physics engine gets 'stuck'. To prevent this, we aim to back up in time to a moment just before the collision when the objects are separated by a small distance called the target gap. See Seek to Half-Gap Distance for the full explanation.

The Collision.closeEnough method returns true when the collision distance is close to the target gap distance, within the tolerance given by RigidBody.getAccuracy.

Collision Handling Notes TO BE EDITTED

The following is actually super useful for reading the collision handling code

A colliding contact that might be handled comes in several flavors. Any contact exists in one of these zones, depending on its distance

0. out of range.
   distanceTol
1. not yet in target accuracy zone.
   targetGap+accuracy
2. in target accuracy zone
   targetGap-accuracy
3. past target accuracy zone but not penetrating
   zero distance
4. penetrating (illegal)

> contact: 1, 2, 3;  small velocity
> isTouching(): 1, 2, 3;  any velocity
>closeEnough(false): 2;  any velocity
> closeEnough(true): 2 or 3;  any velocity
> isColliding() 3 or 4 for large negative velocity;  4 for large positive velocity
> illegalState(): 4  any velocity

I also have some diagrams from around May 16, 2016 that makes the above very clear.

Update State After Backing Up In Time

The collision handling scheme used by CollisionAdvance results in backing up in time from the post-collision state to the pre-collision state. This is done to avoid having RigidBodys being in an ambiguous illegal interpenetrating state.

A consequence of this is that the RigidBodyCollision we are handling will have its data from the near-future post-collision state. The method updateCollision updates the RigidBodyCollision to reflect the current pre-collision state after backing up in time.

The mustHandle flag remembers those RigidBodyCollisions that were penetrating in the post-collision state, before the backup in time occurred. This is needed because those RigidBodyCollisions might otherwise indicate that they do not need to be handled: they have negative distance (penetrating) in the post-collision state, but positive distance (non-penetrating) in the pre-collision state.

The U Vector

When a RigidBody has a curved edge involved in the collision, the U vector is vector from body's center of mass to center of the circular edge. For the primary body this is called the U vector, for the normal body it is called the U2 vector.

For curved edges we use the U and U2 vectors instead of the R and R2 vectors.

The U and U2 vectors are used in finding the contact force needed because a smooth curved edge works differently than a sharp pointed corner. The normal distance (and therefore normal velocity) between a straight edge and a circle is related to the movement of the circle's center – rotation of the circle about the center is irrelevant. This is different to a sharp corner where the movement of the point of the corner is what is important.

This is relevant for finding contact forces which are applied over time. For an instantaneous collision impulse this is not important because the bodies immediately move apart.

See the paper Curved Edge Physics paper by Erik Neumann for modifications to contact forces when curved edges are involved.

Equivalence of Using R or U Vector For Normal Velocity

Here we show that you get the same result whether using the R or U vector in getNormalVelocity.

Suppose you have a circular body striking a horizontal infinite mass floor; let the circle have an offset center of mass, so that U and R are different.

vab = relative velocity of contact points (vpa, vpb) on bodies
vab = (vpa - vpb)
vpa = va + wa x ra = velocity of contact point
vab = va + wa x ra - vb - wb x rb
// vab.n = (va + wa x ra - vb - wb x rb) . n
// cross product: w x r = (0,0,w) x (rx, ry, 0) = (-w*ry, w*rx, 0)
dx = vax + wa*(-ray) - vbx - wb*(-rby);
dy = vay + wa*(rax) - vby - wb*(rbx);
nv = nx*dx + ny*dy;
but with n = (0, 1) we have
nv = 0*dx + 1*dy = dy
and because body b is infinite mass, we have vbx = vby = wb = 0, so
dy = vay + wa*(rax)
dy = vay + wa*(uax)   // when using U instead of R

In the picture, you can see that rax = uax, because the normal at the impact point goes thru the center of the circle, and so both U and R have the same x component. The situation would be the same when the normal is not (0, 1). In the general case, you are finding the length of R (or U) that is orthogonal to the normal, and again these are the same for U and R because the normal at the impact point goes right thru the center of the circle.

TO DO guess: the only things really needed are normal and impact point (plus of course the two bodies). Wait, also things like ballObject, ballNormal.

TO DO guess: some things like r1, r2, u1, u2, radius1, radius2 can all be calculated; they are only stored in the RBC for convenience to avoid re-calculating. (would it be better to do that calculating in one place?)

Hierarchy (view full)

Implements

Constructors

  • Parameters

    • body: RigidBody

      the 'primary' body which typically has a Vertex or Edge involved in the collision

    • normalBody: RigidBody

      the 'normal' body which typically has an Edge involved in the collision that defines the normal vector for the collision

    • joint: boolean

      whether this is a bilateral constraint which can both push and pull.

    Returns RigidBodyCollision

Properties

accuracy_: number

Collision distance accuracy: when the collision distance is within accuracy of the target gap distance, then the collision is close enough to be able to handle it (apply an impulse).

ballNormal: boolean = false

true if the normal object's edge is curved

ballObject: boolean = false

true if the 'primary' object's edge is curved

creator: string = ''

for debugging, unique code tells where this was generated

detectedDistance_: number = NaN

distance between objects when first detected, pre-backup

detectedTime_: number = NaN

simulation time that collision was detected

detectedVelocity_: number = NaN

normal velocity when collision was detected, pre-backup.

distance: number = NaN

distance between objects; negative = penetration

distanceTol_: number

distance tolerance is used to decide when bodies are touching.

elasticity_: number

elasticity of this collision, from 0 to 1.

estimate_: number = NaN

estimate of time when half-gap distance happens

force: number = NaN

amount of force applied at a contact point

impact1: Vector = Vector.ORIGIN

point of impact, in global coords

impact2: null | Vector = null

second impact point needed for Rope because the impact points are far apart. OPTIONAL point of impact on normalBody, in global coords

impulse: number = NaN

amount of impulse applied during collision

joint: boolean

whether this is a bilateral constraint which can both push and pull

mustHandle_: boolean = false

Indicates this is a collision that needs to be handled

normal: Vector = Vector.NORTH

normal pointing outward from normalObj, in world coords

normalBody: RigidBody

object corresponding to the normal (its edge defines the normal vector)

normalFixed: boolean

true = normal is constant

normalVelocity_: number = NaN

relative normal velocity at impact point; negative=colliding, positive = separating. Cached value: it is invalid when NaN.

normal_dt: null | Vector = null

derivative of normal vector with respect to time

primaryBody: RigidBody

'primary' object whose corner or edge is colliding

radius1: number = NaN

radius of curvature at impact1, for primary body; negative means concave

radius2: number = NaN

radius of curvature at impact1, for normal body; negative means concave

targetGap_: number

desired target gap where collision is handled (we try to back up to time when collision distance is this amount). Can be zero for joints.

updateTime_: number = NaN

time corresponding to last update

velocityTol_: number

velocity tolerance used to determine if an object is in contact with another object. See ImpulseSim.getVelocityTol.

Methods

  • Returns true if this represents a bilateral constraint which can both push and pull; for example a Joint between two objects.

    Returns boolean

    true if this is a bilateral constraint

  • Whether close enough to the point when this Collision can be handled. The allowTiny parameter exists because of cases where a small distance collision cannot be backed-up in time to get near to the preferred target 'half gap' distance.

    Parameters

    • allowTiny: boolean

      regard as 'close enough' Collisions that have smaller distance than distance accuracy would normally allow

    Returns boolean

    true if close enough to the point when this Collision can be handled.

  • Returns distance to the target 'half gap' distance. We aim to handle a collision when the distance is 'half gap', which is when this returns zero.

    Returns number

    distance to the target 'half gap' distance.

  • Returns the relative acceleration between the two contact points.

    Parameters

    • change: number[]

      array of change rates for each variable

    Returns Vector

    the relative acceleration between the two contact points

  • Returns the Connector that generated this collision, or null if this collision was not generated by a Connector.

    Returns null | Connector

    the Connector that generated this collision, or null

  • Returns the elasticity used when calculating collisions; a value of 1.0 means perfect elasticity where the kinetic energy after collision is the same as before (extremely bouncy), while a value of 0 means no elasticity (no bounce). A collision uses the lesser elasticity value of the two bodies involved.

    Returns number

    elasticity used when calculating collisions, a number from 0 to 1.

  • Returns the estimated time when this Collision should be handled by firing an impulse.

    Returns number

    the estimated time when this Collision should be handled or NaN if unknown.

  • Returns point of impact on normal body, in global coords. For example, this is needed for Rope because the impact points are far apart. Often null when only Vertex.isEndPoint is needed.

    Returns null | Vector

    point of impact on normal body, in global coords, or null

  • Returns size of impulse (change in momentum) that was applied to this Collision.

    Returns number

    size of impulse that was applied to this Collision, or NaN if no impulse applied.

  • The lateral velocity (sideways to normal) between the two bodies at the point of contact.

    Returns number

    the lateral velocity (sideways to normal) between the two bodies at the point of contact.

  • Returns the normal body involved in the collision, which defines the normal vector. The classic situation is that a vertex on the primary body is colliding into an edge on the normal body, but there are many variations on this.

    Returns RigidBody

    the normal body involved in the collision

  • Returns the relative normal velocity based on current velocity of the bodies. Negative velocity means the objects moving towards each other, positive velocity means they are moving apart.

    Returns number

    relative normal velocity between the two bodies at the point of contact.

  • Returns vector perpendicular to normal vector. This is tangent to the normal body edge.

    Returns Vector

    vector perpendicular to normal vector, in world coords

  • Returns the primary body involved in the collision. The primary body does not define the normal. The classic situation is that a vertex on the primary body is colliding into an edge on the normal body, but there are many variations on this.

    Returns RigidBody

    the primary body involved in the collision

  • Returns vector from center of mass of primary body to point of impact, in world coords.

    Returns Vector

    vector from center of mass of primary body to point of impact, in world coords

  • Returns vector from center of mass of normal body to point of impact, in world coords. Uses the second impact point if appropriate.

    Returns Vector

    vector from center of mass of normal body to point of impact, in world coords

  • Returns the difference in velocity of the two impact points of the collision based on current velocity of the bodies.

    let V = velocity of center of mass (CM);
    let R = distance vector CM to contact point
    let w = angular velocity
    w x R = (0, 0, w) x (Rx, Ry, 0) = (-w Ry, w Rx, 0)
    velocity of corner = V + w x R = (Vx - w Ry, Vy + w Rx, 0)
    relative velocity = Vab = Va + wa x Ra - Vb - wb x Rb
    

    For curved edge we use the U vector (from center of mass to edge's circle center) instead of R vector (from center of mass to point of impact). Because what matters is not the motion of the individual point but instead the entire curved edge. Consider that for a ball with center of mass at center of the circle, rotation doesn't change the distance at all.

    Returns Vector

    the velocity vector of this collision

  • Returns vector from center of mass of primary body to either point of impact or to center of circular edge in world coords.

    Returns Vector

    vector from center of mass of primary body to either point of impact or to center of circular edge in world coords

  • Returns vector from center of mass of normal body to either point of impact or to center of circular edge in world coords. Uses the second impact point if appropriate.

    Returns Vector

    vector from center of mass of normal body to either point of impact or to center of circular edge, in world coords

  • Returns the relative normal velocity between the two collision points. Negative velocity means the objects are colliding, positive means they are separating.

    Returns number

    relative normal velocity between the two collision points, negative means colliding

  • Whether this collision involves the given RigidBody

    Parameters

    Returns boolean

    whether collision involves the given RigidBody

  • Whether this collision involves the given edge. If given edge is null, then always returns false.

    Parameters

    • edge: null | Edge

      the Edge of interest

    Returns boolean

    whether collision involves the given Edge

  • Whether this collision involves the given vertex

    Parameters

    • v: Vertex

      the Vertex of interest

    Returns boolean

    whether collision involves the given Vertex

  • Returns true if this represents an illegal state, typically because objects are interpenetrating.

    Returns boolean

    true if this represents an illegal state

  • Returns true if this represents a collision state, generally when two objects are interpenetrating. The collision search mechanism implemented by AdvanceStrategy.advance operates to set the simulation at a time very close to but just before any Collision is happening, see getEstimatedTime.

    Returns boolean

    true if this represents a collision state

  • Whether the distance is small enough that the objects are touching each other so that impulses can be transmitted.

    Returns boolean

    whether the objects are touching each other

  • Returns true if this Collision needs to be resolved, such as by applying an impulse to reverse the velocities of the objects. This remains true even after backing up in time.

    Returns boolean

    true if this Collision needs to be resolved

  • Stores the time when this collision was detected, stores the current distance and velocity as the detected distance and detected velocity, and estimates when the collision occurred.

    Parameters

    • time: number

      when this collision is detected

    Returns void

    Throws

    if the detected time has been previously set

  • Mark this Collision as one that needs handling because it is has caused the collision engine to backup in time in order to resolve this Collision. This is useful because after backing up in time, a Collision may no longer report itself as isColliding.

    Parameters

    • needsHandling: boolean

      true if this Collision needs to be resolved

    Returns void

  • Returns whether this collision could be the same as another collision. Often there are several collisions found at a single location by the various collision detection mechanisms, and this is used when deciding which collision of those to keep.

    Parameters

    Returns boolean

    true if the two collisions are possibly the same collision

  • Updates the information in the collision to reflect current position and velocity of bodies. Changes the impact point to be the nearest point between the bodies (as long as this point is reasonably close to the original impact point). Then update the normal, R vectors, etc.

    This is used when handling collisions because the collisions are found post-collision, but are handled pre-collision. Therefore, we need to update the information to correspond to the pre-collision arrangement of the bodies.

    Doing this fixes inaccurate collisions; for example, a ball that hits a wall at an angle would wrongly acquire spin if the collision were not updated to the current pre-collision information.

    Assumes that the bodies have been updated for their current location, by for example RigidBodySim.modifyObjects.

    Parameters

    • time: number

      the current simulation time

    Returns void

  • Update the estimated time of collision using both pre-backup and post-backup information and a calculus model of constant acceleration.

    Derivation of the estimate:
    t1 = time after backup
    t2 = time before backup
    time interval of h = t2 - t1
    d1 = distance at t1 = distance
    v1 = velocity at t1 = normalVelocity
    d2 = distance at t2 = detectedDistance_
    v2 = velocity at t2 = detectedVelocity_
    assume constant acceleration of a = (v2 - v1)/h
    In the following, t is 0 at t1.
    velocity v(t) = integral(a dt) = v1 + a t
    distance d(t) = integral(v1 + a t dt) = d1 + v1 t + a t^2/2
    Now, find time corresponding to distance = targetGap
    targetGap = d1 + v1 t + (a/2) t^2
    Quadratic equation in t
    0 = (d1 - targetGap) + v1 t + (a/2) t^2
    t = [-v1 +/- sqrt(v1^2 - 4 (a/2) (d1 - targetGap)) ]/(2 a/2)
    t = [-v1 +/- sqrt(v1^2 - 2 a (d1 - targetGap)) ]/a
    

    Parameters

    • time: number
    • doUpdate: boolean

    Returns void

Generated using TypeDoc