Class ImpulseSim

Simulation of RigidBody movement with collisions. ImpulseSim adds methods for collision detection and collision handling to the superclass RigidBodySim.

The overall collision handling algorithm is implemented in CollisionAdvance. The two main methods that CollisionAdvance asks ImpulseSim to perform are:

• findCollisions Returns the current set of collisions and also contacts. Checks each corner and edge of each body to see if it is penetrating into another body (or nearby for a contact). Creates a RigidBodyCollision corresponding to each collision (or contact) found and returns them in an array.

• handleCollisions For each collision, calculates and applies the appropriate impulse to handle the collision.

Collision Handling Options

There are several different collision handling options available. See the section on Multiple Simultaneous Collisions and the CollisionHandling enum.

Contacts During Collision Handling

Resting contacts, joints, and imminent collisions are involved in the collision handling mechanism, as part of a multiple simultaneous collision. The handleCollisions method can calculate the impulse needed at each point, which can be a big performance win.

Consider for example a situation where there are 2 or more bodies in resting contact, and a third body collides into one of the resting bodies. The result will be a complex series of ricochet collisions back and forth until finally all the bodies are either separating or in resting contact.

If you calculate such a scenario by considering only one collision at a time, then after each collision we would step forward in time, find collisions, back up to where we were, handle the collision, and do that over and over for each ricochet. This would take far more compute time than doing the equivalent inside of `handleCollisions`.

Finding the Collision Impulse

This reviews some of the math involved in handleCollisions.

Define these symbols

``````v_i = initial velocity (vector, length n)
v_f = final velocity (vector, length n)
A = n x n matrix giving change in velocity for impulse at each contact
j = impulses at each contact (vector, length n)
n = number of contacts
e = elasticity
``````

Then we have

``````v_f = A j + v_i
``````

We also have

``````v_f = -e v_i
``````

therefore

``````0 = A j + (1+e) v_i
``````

this corresponds to the equation in ComputeForces

``````0 = A f + b
``````

so we put the `(1+e) v_i` factor into the `b` vector when passing to ComputeForces.

On the myPhysicsLab Rigid Body Collisions web page is a derivation of the following equation which gives the value of `j` for a single collision.

``````ma = mass of body A
n = normal vector pointing out from body A (length 1 here)
j = impulse scalar
jn = impulse vector
va = old linear velocity of cm for body A
va2 = new linear velocity of cm
wa = old angular velocity for body A
wa2 = new angular velocity
ra = vector from body A cm to point of impact = (rax, ray)
Ia = moment of inertia of body A about center of mass
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
cross product: w x r = (0,0,w) x (rx, ry, 0) = (-w*ry, w*rx, 0)

-(1 + elasticity) vab.n
j = -------------------------------------
1     1     (ra x n)^2    (rb x n)^2
(--- + ---) + ---------  + ---------
Ma   Mb        Ia           Ib
``````

In an earlier version of `handleCollisions`, the above equation was used directly. Now we use ComputeForces because there might be multiple simultaneous collisions, but it amounts to the same equation. If there is only a single collision, then the above equation still exists in the following pieces:

• the `(1+e) v_i` factor is in the `b` vector (`v_i` is the same as `vab` above).

• the denominator is the `A` matrix

This corresponds to solving for `j` as

``````0 = A j + (1+e) v_i
j = -(1 + e) v_i / A
``````

This only works when A is a scalar value not a matrix. Otherwise you would left-multiply by the inverse of the A matrix.

TO DO use UtilCollision.subsetCollisions1 to arrange collisions into separate groups, so that contacts are handled with zero elasticity more often. Currently, when contacts are handled simultaneously with a high-velocity collision, we use the non-zero elasticity on the contacts also, even if they are not connected to the collision.

TO DO the momentum stuff was pretty klugey and ugly; I'm commenting it out Dec 2009; the text info might be useful, but it needs to be made prettier. The 'momentum arrows' didn't seem to add much insight.

TO DO the distance and velocity tolerance is stored on the RigidBody and also here; this is confusing and error prone; and if they are different then you might see the wrong value in the user control; could it be useful to have different distance/velocity tolerance on different bodies? If not, perhaps we can find a better way to communicate the distance/velocity tolerance to the RigidBody.

TO DO collision impact: make these into a SimObject, similar to Force, and add to SimList; then user can decide how to represent them

TO DO The method findCollisions is doing twice as much work as it needs to: once you check if body A collides with body B, you don't have to check if body B collides with body A.

Properties

bods_: RigidBody[] = []

The RigidBodys in this simulation.

collisionAccuracy_: number = 0.6

How close in space we need to be to a collision, to decide to handle it, as a percentage of the targetGap = distanceTol/2.

collisionFunction_: null | ((c, t) => void) = null

Function to print collisions, or null to turn off printing collisions.

Type declaration

• (c, t): void

Returns void

computeImpacts_: ComputeForces = ...

'I' for ImpulseSim

debugPaint_: null | (() => void) = null

Function to paint canvases, for debugging. If defined, this will be called within `moveObjects()` so you can see the simulation state after each time step (you will need to arrange your debugger to pause after each invocation of debugPaint_ to see the state).

• (): void
• Returns void

distanceTol_: number = 0.01

Distance tolerance, for determining if RigidBody is in contact with another RigidBody. Contact point must have relative normal distance less than this.

forceLaws_: ForceLaw[] = []

The ForceLaws in this simulation.

showForces_: boolean = false

Whether to add Forces to the SimList so they can be seen.

simList_: SimList = ...

The SimList holds SimObjects so they can be made visible.

simRNG_: Random = ...

The pseudo random number generator, used in collision handling and computing forces.

simRect_: null | DoubleRect = null

Suggested size for the SimView. This is mainly for tests to communicate with TestViewerApp.

varsList_: VarsList

The variables that determine the state of the simulation; there are six variables for each RigidBody, plus some others for time, energy, etc.

velocityTol_: number = 0.5

Velocity tolerance, for determining if RigidBody is in contact with another RigidBody. Contact point must have relative normal velocity smaller than this.

warningTime_: number = 0

for warning that proximity test is off

COLLISIONS_DISABLED: false = false

For debugging, this allows code to look for collisions, but does not actually return them. This allows to debug code for finding nearest point between objects.

DEBUG_IMPULSE: false = false

Show the impulse applied at each collision.

ELASTICITY_SET: string = 'ELASTICITY_SET'

Name of event broadcast from setElasticity.

SMALL_IMPULSE: 0.0001 = 1E-4

Impulse smaller than this is not marked as a discontinuous change in the velocity variables of the objects colliding.

TINY_IMPULSE: 1e-12 = 1E-12

Impulse smaller than this is regarded as insignificant at various points in the collision handling algorithm.

Methods

• Add the RigidBody to the simulation and SimList, and add a set of 6 variables for the RigidBody to the VarsList.

Using FunctionVariable's ensures that the variables on the VarsList have the same values as the RigidBody's (because the FunctionVariables retrieve and store their values in the RigidBody's). There is no need for a separate step to coordinate between the VarsList and the RigidBody's, they are automatically in sync.

Parameters

• body: RigidBody

RigidBody to add to the simulation

Returns void

• Adds the ForceLaw to the list of ForceLaws operating in this simulation, if it is not already on the list.

Parameters

• forceLaw: ForceLaw

the ForceLaw to add

Throws

if adding a second DampingLaw or GravityLaw

• Adds the given Observer to this Subject's list of Observers, so that the Observer will be notified of changes in this Subject. An Observer may call `Subject.addObserver` during its `observe` method.

Parameters

• observer: Observer

the Observer to add

Returns void

• Adds the Parameter to the list of this Subject's available Parameters.

Parameters

• parameter: Parameter

the Parameter to add

Throws

if a Parameter with the same name already exists.

• Applies the given impulse to the objects involved in the given collision, at the impact point of the collision.

Parameters

• cd: RigidBodyCollision

collision where the impulse should be applied

• j: number

magnitude of impulse to apply

Returns void

• Applies the Force by modifying the array representing rate of change of each variable. The Force specifies which RigidBody it works on so we can figure out which variable rates to modify. If showForces_ is `true`, adds the Force to the SimList with an immediate expiration time.

Parameters

• change: number[]

vector of rigid body accelerations

• force: Force

the Force to be applied

Returns void

• Applies the impulse by modifying the simulation variables.

Returns void

• Notifies all Observers that the Parameter with the given name has changed by calling observe on each Observer.

Parameters

• name: string

the language-independent or English name of the Parameter that has changed

Throws

if there is no Parameter with the given name

• Check that infinite mass object remain at rest.

Throws

if an infinite mass object has non-zero velocity

• Removes all RigidBodys, ForceLaws, most Variables, and clears the SimList. This is used in applications to build a new configuration of RigidBodys. This should give essentially the same state that you would get from making a new RigidBodySim, except for parameters (like gravity) that may have been changed.

The alternative is to create a new RigidBodySim; that would be 'cleaner' but then you must unhook the old RigidBodySim from all the various user controls and graph and such, and hook up the new one.

Returns void

• Creates a PointMass which is displayed as a circle, and adds it to the SimList, for debugging only. The expiration time on temporary SimObjects is set to 'now', so that they are removed right away during the next call to advance().

Parameters

• name: string

name of the SimObject that is created

• center: GenericVector

center of the circle

radius of the circle

• `Optional`expireTime: number

the time when the DisplayObject will be removed; the default expireTime is 'now'.

Returns void

• Creates a ConcreteLine and adds it to the SimList, for debugging only. The expiration time on temporary SimObjects is set to 'now', so that they are removed right away during the next call to advance().

Parameters

• name: string

name of the SimObject that is created

• pa: Vector

starting point of the line

• pb: Vector

ending point of the line

• `Optional`expireTime: number

the time when the DisplayObject will be removed; the default expireTime is 'now'.

Returns void

• Defines the differential equations of this ODESim; for an input set of variables, returns the current rate of change for each variable (the first derivative of each variable with respect to time).

The `timeStep` is the time since the state variables were last fully calculated, which can be and often is zero. The current time can be regarded as `getTime() + timeStep`. The input variables correspond to the Simulation state at that time. Note that `timeStep` is different from the time step used to advance the Simulation (as in AdvanceStrategy.advance). The `timeStep` is typically used when finding collisions in CollisionSim.findCollisions.

Parameters

• vars: number[]

the current array of state variables (input), corresponding to the state at `getTime() + timeStep`

• change: number[]

array of change rates for each variable (output), all values are zero on entry.

• _timeStep: number

the current time step (might be zero)

Returns null | object

`null` if the evaluation succeeds, otherwise an object relating to the error that occurred. The `change` array contains the output results.

• Finds collisions based on the passed in state variables. Can rely on modifyObjects having been called prior, with this set of state variables. Uses the state saved by saveState as the 'before' state for comparison.

The list of collisions that are passed in can potentially have collisions from the near future that were found previously. The CollisionSim should avoid adding collisions that are duplicates of those already on the list.

Parameters

• collisions: RigidBodyCollision[]

the list of collisions to add to

• vars: number[]

the current array of state variables

• stepSize: number

the size of the current time step, in seconds

Returns void

• Returns a RigidBody in this simulation by specifying its name or index in the list of RigidBodys.

Parameters

• numOrName: string | number

index in list of RigidBodys or name of the RigidBody (either the English or language-independent version of the name)

Returns RigidBody

the RigidBody with the given name or at the given position in the list of RigidBodys

Throws

if requesting a non-existing body.

• Returns the collision distance accuracy, a fraction between zero and one; when the collision distance is within `accuracy * targetGap` of the target gap distance, then the collision is considered close enough to handle (apply an impulse).

Returns number

the collision accuracy, a fraction between 0 (exclusive) and 1 (inclusive)

• Returns distance tolerance used to determine if an object is in contact with another object

Returns number

distance tolerance used to determine if an object is in contact with another object

• Returns the Parameter with the given name.

Parameters

• name: string

the language-independent or English name of the Parameter

Returns Parameter

the Parameter with the given name

Throws

if there is no Parameter with the given name

• Returns the seed of the pseudo random number generator (RNG) used in this simulation. The RNG is used during collision handling and contact force calculation. To get reproducible results, set this seed at the start of a simulation, and the RNG will then always give the same sequence of random numbers.

Returns number

the seed of the pseudo random number generator

• Whether to to show collisions visually.

Returns boolean

whether to show collisions visually.

• Returns velocity tolerance used to determine if an object is in contact with another object

Returns number

velocity tolerance used to determine if an object is in contact with another object

• Adjusts the simulation state based on the given Collisions. For example, this might reverse the velocities of objects colliding against a wall. The simulation state is contained in the `vars` array of state variables from getVarsList.

Note that these Collisions will typically be from the very near future; CollisionAdvance backs up to just before the moment of collision before handling Collisions.

Parameters

• rbcs: RigidBodyCollision[]

the list of current collisions

• `Optional`opt_totals: CollisionTotals

CollisionTotals object to update with number of collisions handled

Returns boolean

true if was able to handle the collision, changing state of simulation.

• Handles a set of collisions using the serial collision handling method. We keep handling collisions at random until we reach a state where there is no collision. Note that this can take many times thru the loop, up to thousands of times.

The idea is that multiple collisions can be simulated as a rapid series of instantaneous collisions as objects collide and ricochet against each other many times until they finally separate or the energy of the collisions is absorbed by the sequence of inelastic collisions. It is as though the objects are all separated by a tiny gap, so that when object A is struck, it then collides with object B, and then object B collides with object C and so forth. But this gap is so tiny that no time passes, and we can calculate the results of all these collisions here very quickly.

Each time thru the loop, we pick a single focus collision to resolve. If there are no joints, then we simply resolve that single collision. If there are joints on either body involved in the chosen focus collision, we find all the joints that are connected via other joints (for example, a chain would include all the joints in the chain). We then do a simultaneous type calculation for that set of original focus collision plus connected joints. Because we must maintain the velocity of the joint contact at zero (which means elasticity is zero), we can include the joints in the calculation and maintain the integrity of the joints.

The order of processing contacts is determined by the randomInts function. It is important to use randomInts here to ensure that we get an even distribution of integers each time thru the loop. For example if the same sequence were used every time thru the loop, then the contacts at the start of the sequence would be processed much more frequently, and the algorithm would be much less efficient.

To provide a non-random option you can use the setRandomSeed method to set the seed used by the random number generator. This will provide a reproducible series of random numbers. This is done when running tests.

Turn on the `showVelo` flag to show visually the velocity at each contact point and get a sense of how this algorithm works. See setDebugPaint for additional steps needed to have the contact forces drawn while stepping thru this method.

The `hybrid` option uses the following policy: Each time thru the loop, we focus on the collision with the largest velocity, and we include the set of 'active' collisions (non-joint and non-contact) that are happening on either body involved in the initial focus collision; we then do simultaneous type collision handling on this set of collisions.

An example where hybrid option makes a difference: a block falling onto the ground so that both its corners hit simultaneously -- with hybrid option the block bounces straight up without spinning, because both collisions are treated simultaneously. Hybrid works more correctly than simultaneous in cases like the 'one hits two' scenario, or in Newton's Cradle. See test/MultipleCollisionTest.MultipleCollisionTest for other examples.

Contacts are treated with elasticity zero when there are only contacts in the set of collisions. This is to reduce the 'jitter' at contacts, stopping residual velocity at contact points. But when there is a large velocity collision in the set, then contacts are treated with the same elasticity as other collisions, as given by `getElasticity()`.

We continue handling collisions until all collision velocities are smaller than `small_velocity`.

1. For joints: Math.abs(velocity) < small_velocity

2. For non-joints: velocity > -small_velocity (i.e. positive or small negative)

About doPanic: It seems to save only about 10 percent on the number of times thru the loop, but more important is that it might occasionally allow finding a solution versus being in an infinite loop here.

Algorithm

The concept here is to consider one 'focus' collision at a time.

Find the set of contacts/joints that are directly involved in that focus collision

1. For the pure serial method, only look at the focus collision and attached joints

2. For the hybrid method, look at focus and joints, plus other collisions involving either body of the focus collision

Find the impulse that reverses the velocity at each collision involved This step uses the simultaneous type of calculation for the set of collisions under consideration during each step.

Find the new collision velocities, given all the impulses found so far; continue the above until there are no collisions remaining.

This is like dealing with collisions serially, except we do it all here, and so avoid going back to the (slow) collision detection loop until we see that all collision points are separating or in contact.

TO DO when only a single collision is being processed, we could avoid a lot of code here and perhaps save time. Ie. don't need to set up a sub-matrix, or even call compute_forces.

TO DO make the exception thrown more informational: is it because accuracy in the solution is poor, or some other reason.

Parameters

• collisions: RigidBodyCollision[]

the set of collisions to handle

• hybrid: boolean

true means use a hybrid collision handling method that uses the 'simultaneous' method in some cases

• `Optional`opt_totals: CollisionTotals

CollisionTotals object to update with number of collisions handled

• `Optional`grouped: boolean

treat joints connected to focus collision simultaneously with the focus collision and with zero elasticity at the joint.

• `Optional`lastPass: boolean

do a final 'pass' on all collisions with zero elasticity to ensure that each collision has non-negative velocity. This pass only happens at end once all collisions are smaller than the small_velocity.

• `Optional`small_velocity: number

handle collisions until they are this small

• `Optional`doPanic: boolean

true means that the velocity tolerance is loosened when there are many successive collisions

Returns boolean

whether any change was made to the collisions

• Handles a set of collisions using the 'simultaneous' collision handling method. Finds impulses so that every collision has a change in velocity given by the initial velocity and the elasticity.

Parameters

• collisions: RigidBodyCollision[]

list of RigidBodyCollisions

• `Optional`opt_totals: CollisionTotals

CollisionTotals object to update with number of collisions handled

Returns boolean

whether any change was made to the collisions

• Pick a collision to focus on, either randomly or the 'biggest'. When we reach a point where there are no more collisions, then `focus = -1`. Part of the `handleCollisionsSerial` process.

Parameters

• _debugHCS: boolean

turns on debug messages

• small_velocity: number

only handle collisions bigger than this

• _loopCtr: number

loop counter, number of times this method has been called

• joint: boolean[]

which contacts are joints

• b: number[]

normal velocity at each contact

Returns number

index of focus collision, or -1 when all collisions are small

• Handles one focus collision within the handleCollisionsSerial process. Modifies the velocity and impulse for that focus collision, and also adjusts connected collisions (if any).

Parameters

• hybrid: boolean

use hybrid 'simultaneous and serial' collision handling

• grouped: boolean

treat joints connected to focus collision

• debugHCS: boolean

turns on debug messages

• small_velocity: number

only handle collisions bigger than this

• loopCtr: number

loop counter, number of times this method has been called

• focus: number

index of the collision to handle

• joint: boolean[]

which contacts are joints

• e: number[]

elasticity at each contact

• b: number[]

normal velocity at each contact (updated by this method)

• j2: number[]

cumulative impulse (updated by this method)

• collisions: RigidBodyCollision[]

the set of collisions being treated

• A: Float64Array[]

the matrix that says how collisions affect each other

Returns void

• Returns the change in relative normal velocity at collision ci resulting from a unit impulse on the given body at collision cj.

We have two collision points, ci and cj. How much does a unit impulse at cj on the given body affect the relative normal velocity at ci?

To have a direct effect, the body must be directly involved in both collisions. Let the notation c(a,b) mean that collision c is between bodies a and b. Then for the pair of collisions

``````ci(0,1), cj(1, 2)
``````

we know that the impulse at cj directly affects the velocity of body 1, which in turn affects the velocity at ci.

On the other hand, if there is no common body in the two collisions, then there is no direct effect. For example:

``````ci(0, 1), cj(2, 3)
``````

Suppose there is an additional contact/collision c(1,2). Still, the impulse at cj(2,3) only affects bodies 2 and 3, which has no direct effect at the contact ci(0,1) between bodies 1 and 2. Indirectly, you can get an effect. While the matrix entry (see makeCollisionMatrix for the above combo would be zero, you would have non-zero entries for:

``````ci(0,1), cj(1, 2)
ci(1,2), cj(2, 3)
``````

Therefore, you would get an indirect effect between ci(0,1) and cj(2,3) thru the various matrix entries. In solving for the correct amount of impulse at each collision, the matrix solver will adjust for indirect connections like this. Because pushing at c(2,3) affects c(1,2), so you may need to adjust the impulse at c(1,2), which in turn will affect whatâ€™s happening at c(0,1).

So, again, the question here is to find the direct effect of a unit impulse at cj on the given body for the relative normal velocity at ci.

A unit impulse at cj(1,2) has a certain effect on body 1; the effect is a change in the velocity (all 3 velocities: horizontal, vertical, rotational) which is calculated by the size of the impulse (assumed to be 1 here), the direction of the impulse (either the normal of cj or opposite of the normal), and the vector from the cm (center of mass) of body 1 to cj; this vector is either R or R2 of cj depending on whether body 1 is the normal body or primary body in collision cj.

The change in normal velocity at ci(0,1) depends on: the change in velocity of body 1, and the vector from cm of body 1 to ci; this vector is either R or R2 of ci depending on whether body 1 is the normal body or primary body in collision ci.

The relative normal velocity, vi, at ci(a,b) is given by:

``````vi = ni . (va + wa x rai - (vb + wb x rbi))
ni is the normal at collision ci
va, vb is the translational velocity of body a or b respectively
wa, wb is the rotational velocity of body a or b respectively
rai, rbi is the vector from body a or b's cm to collision ci.
``````

The change in velocity of body a from impulse fj at collision cj is:

``````change in translational velocity =  âˆ†va = fj nj / ma
change in rotational velocity = âˆ†wa = (raj x fj nj) / Ia
ma is the mass of body a
Ia is the rotational inertia of body a
nj is the normal at collision cj
raj is the vector from body a's cm to collision cj.
``````

Therefore, the change in vi from impulse fj at cj on body a is:

``````âˆ†vi = ni . (âˆ†va + âˆ†wa x rai)
= ni . ( fj nj/ ma + (raj x fj nj) x rai / Ia)
``````

Note that the change in vi from the impulse fj at cj on body b is not considered here. Here is how the vector cross product is calculated:

``````(rj x n) x ri = [0, 0, rjx ny - rjy nx] x ri
= [-riy(rjx ny - rjy nx), rix(rjx ny - rjy nx), 0]
``````

Returns number

the change in relative normal velocity at collision ci resulting from a unit impulse on the given body at collision cj.

• Returns a matrix where the `(i, j)`th entry is how much the relative normal velocity at collision `i` will change from a unit impulse being applied at collision `j`.

TO DO it is a symmetric matrix, so we could save time by only calculating upper triangle and then copying to lower triangle.

TO DO this is the same as ContactSim.calculate_a_matrix, so we need to use just one of these (duplicate code currently). March 2012.

Parameters

• collisions: RigidBodyCollision[]

list of RigidBodyCollisions

Returns Float64Array[]

matrix that tells how much impulse at collision point `i` affects relative normal velocity at collision point `j`

• Prints the message to console, preceded by the current simulation time. Draws the time in green, the message in black; you can add colors in the message by adding more '%c' symbols in the message string and pass additional colors.

Parameters

• message: string

message to print, optionally with '%c' where color changes are desired

• `Rest`...colors: string[]

CSS color or background strings, to change the color in the message at points in the message marked by the string '%c'

Returns void

• Removes the RigidBody from the simulation and SimList, and removes the corresponding variables from the VarsList.

Parameters

• body: RigidBody

RigidBody to remove from the simulation

Returns void

• Removes the ForceLaw from the list of ForceLaws operating in this simulation.

Parameters

• forceLaw: ForceLaw

the ForceLaw to remove

Returns boolean

whether the ForceLaw was removed

• Removes the Observer from this Subject's list of Observers. An Observer may call `removeObserver` during its `observe` method.

Parameters

• observer: Observer

the Observer to detach from list of Observers

Returns void

• Removes the Parameter from the list of this Subject's available Parameters.

Parameters

• parameter: Parameter

the Parameter to remove

Returns void

• Sets whether this Subject will broadcast events, typically used to temporarily disable broadcasting. Intended to be used in situations where a subclass overrides a method that broadcasts an event. This allows the subclass to prevent the superclass broadcasting that event, so that the subclass can broadcast the event when the method is completed.

Parameters

• value: boolean

whether this Subject should broadcast events

Returns boolean

the previous value

• Sets the collision distance accuracy, a fraction between zero and one; when the collision distance is within `accuracy * targetGap` of the target gap distance, then the collision is considered close enough to handle (apply an impulse).

Parameters

• value: number

how close in distance to be in order to handle a collision

Throws

if value is out of the range 0 to 1, or is exactly zero

• Sets a function for printing collisions. The function is called for each collision that occurs. The function takes two variables: a RigidBodyCollision and a Terminal. This can be defined from within the Terminal by the user. Here is an example function (FastBallApp is a good place to try it).

``````sim.setCollisionFunction(function(c,t) {const s = c.getDetectedTime().toFixed(2)+"\t"  +c.getImpulse().toFixed(2)+"\t"  +c.getPrimaryBody().getName()+"\t"  +c.getNormalBody().getName();t.println(s);})
``````

Parameters

• f: null | ((c, t) => void)

the function to print collisions, or null to turn off printing collisions

Returns void

• Sets the collision handling method to use,

Parameters

• value: CollisionHandling

the collision handling method to use

Returns void

• For debugging, specify a function that will paint canvases, so that you can see the simulation while stepping thru with debugger.

Parameters

• fn: null | (() => void)

function that will paint canvases

Returns void

• Sets distance tolerance to use to determine if an object is in contact with another object

Parameters

• value: number

distance tolerance to use to determine if an object is in contact with another object

Returns void

• Sets the elasticity of all RigidBodys to this value. Elasticity is used when calculating collisions; a value of 1.0 means perfectly elastic where the kinetic energy after collision is the same as before (extremely bouncy), while a value of 0 means no elasticity (no bounce).

Broadcasts an 'ELASTICITY_SET' event.

Parameters

• value: number

elasticity to set on all RigidBodys, a number from 0 to 1.

Throws

if there are no RigidBodys

• Sets the seed of the pseudo random number generator (RNG) used in this simulation. The RNG is used during collision handling and contact force calculation. To get reproducible results, set this seed at the start of a simulation, and the RNG will then always give the same sequence of random numbers.

Parameters

• value: number

the seed of the pseudo random number generator

Returns void

• Sets whether to show collisions visually. Note that setShowForces will also change whether to show collisions.

Parameters

• value: boolean

whether to show collisions visually.

Returns void

• Sets whether to add Forces to the SimList so they can be seen.

Parameters

• value: boolean

whether to add Forces to the SimList so they can be seen

Returns void

• Sets velocity tolerance to use to determine if an object is in contact with another object

Parameters

• value: number

velocity tolerance to use to determine if an object is in contact with another object

Returns void

• Returns a minimal string representation of this object, usually giving just identity information like the class name and name of the object.

For an object whose main purpose is to represent another Printable object, it is recommended to include the result of calling `toStringShort` on that other object. For example, calling `toStringShort()` on a DisplayShape might return something like this:

``````DisplayShape{polygon:Polygon{'chain3'}}
``````

Returns string

a minimal string representation of this object.

• Returns size of 'largest' velocity among the set of velocities. Here 'largest' means either:

1. most negative, for regular collisions; or
2. largest in absolute value, for joints

Parameters

• joint: boolean[]

which contacts are joints

• b: number[]

normal velocity at each contact

Returns number

size of largest velocity

Generated using TypeDoc