Physics engine for rigid bodies with contact forces to allow resting contact. The contact forces prevent the bodies from interpenetrating when they are in resting contact. Resting contact means the bodies are not colliding, but have edges and corners that are in continuous contact and exerting force on each other.

The overall idea is to calculate the exact amount of force needed to just barely prevent the objects from penetrating. These contact forces are calculated in the evaluate method, which is called by the DiffEqSolver at the request of the AdvanceStrategy to advance the state of the simulation.

Parameters Created

See also the ImpulseSim super class for additional Parameters.

Background and References

See explanations at:

The algorithm used here is based on these papers:

See also the list of David Baraff's papers.

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

Find External Forces

Within evaluate() we first let the super-class apply the external forces to the RigidBody objects. The external forces include things like gravity, thrust, springs, damping. The external forces result in accelerations of the bodies, so at this point many of the bodies would start to penetrate into each other if we did not find contact forces to prevent that.

Find Contacts

Next in evaluate() we call findCollisions() to find all the contact points, and possibly collisions as well. If we find any actual (penetrating) collisions, then evaluate() returns the set of collisions found, which should then be handled before trying to step forward again, see ImpulseSim.

The criteria for finding a contact is:

  • the corner (or edge) of one body must be very close to the edge of the other body, as specified by getDistanceTol().

  • the bodies must be moving very slowly relative to each other (the normal velocity) at the contact point, as specified by getVelocityTol().

The evaluate() method optionally finds independent subsets of collisions, because that can make the compute_forces algorithm, which is O(n^4), run faster in some cases. See the flag SUBSET_COLLISIONS. Collisions are independent when there is no chain of moveable (finite mass) bodies in common between the collisions.

The Matrix Equation for Contact Forces

Now we have the set of contacts and we know the accelerations of the bodies due to external forces. We set up a matrix equation

a = A f + b

where

  • a = vector of accelerations
  • A = matrix describing how the j-th contact force affects the acceleration of the i-th contact distance (the separation between the bodies)
  • f = vector of contact forces (to be found)
  • b = external forces (gravity, thrust, rubber band, damping)

Set Up the A Matrix

Here is how to set up the A matrix: For each contact distance d_i, find how the acceleration of that contact distance d_i'' is related to the force at the j-th contact point. The force at the j-th contact point is f_j N_j, where f_j is a scalar and N_j is the vector normal. The a_ij entry in the A matrix tells what that relationship is between f_j and d_i''. This a_ij value is dependent only on the current geometry of how the objects are oriented and touching each other.

Baraff Figure 26

For example, consider Figure 26 of [Baraffs Siggraph 97 Course Notes(../Baraff_Siggraph_97_Course_Notes.pdf) shown above. The figure shows two bodies (B,C) resting on the ground, and a third body (A) resting on top of the other two. There are 5 points of contact among the bodies and the ground. Here is how the matrix equation would look for this situation:

a1     a11  a12  a13   0    0     f1     b1
a2     a21  a22  a23   0    0     f2     b2
a3  =  a31  a32  a33  a34   0  *  f3  +  b3
a4      0    0   a43  a44  a45    f4     b4
a5      0    0    0   a54  a55    f5     b5

Consider the first contact at p1 which is between the ground and body B. The acceleration of the contact distance at p1 is affected by the forces at p1, p2, and p3 because all of those forces affect the movement of body B. But the forces at p4 and p5 have no effect, so their entries are zero in the first row of the A matrix.

The first row of the matrix equation can be written out as

a1 = a11*f1 + a12*f2 + a13*f3 + 0*f4 + 0*f5 + b1

That equation says the acceleration of contact distance at point p1 is equal to a certain linear combination of the contact forces f1, f2, f3, plus the acceleration due to the external forces which is b1.

The particular values for a11, a12, a13 are dependent on the geometry of the situation: where the forces f1, f2, f3 are applied on the body; in what direction do the forces act; where is the center of mass of the body; how the force causes the body to accelerate and spin; where is the point p1 is in relation to the center of mass; etc.

The third contact at p3 is more complicated because it is affected by any forces acting on body A or body B. These include all the forces except f5. Therefore the third row of the A matrix has four non-zero entries corresponding to the four forces that affect the acceleration at p3.

Constraints On the Solution

Assume we now have the b vector of external forces and the A matrix of dependencies between contact forces and resulting accelerations of different bodies. We solve for the f vector of contact forces subject to the following constraints:

a >= 0
f >= 0
a.f = 0

The constraints in words are:

  • a >= 0 we require all the relative normal accelerations (between bodies at contact points) to be either zero (remain in contact) or positive (separating).

  • f >= 0 We require contact forces to be zero or positive because they can only push, not pull.

  • a.f = 0 The third constraint is a math way of saying that if there is a force, then acceleration is zero OR if there is acceleration (separation), then there is no force.

Note that for Joints the constraints are different:

  • a == 0 a Joint always remains in resting contact, it never separates

  • No constraint on f because it can push or pull.

Solving For the Contact Forces

The [Baraff 'Fast Contact Force' paper(../Baraff_Fast_Contact_Force_94.pdf) goes into full detail about the algorithm to solve this constraint problem. Here is a quick summary:

  • Start by setting all the forces to zero

  • Add in one force at a time, just enough to maintain the constraints on the points that have been considered so far (ignoring the others), and readjust the other forces as necessary.

  • Continue adding one force at a time, ignoring points that haven't been considered yet.

Suppose that we are working on adding in the third force after already finding the forces for points 1 and 2. The trick is that we only look at the constraints on the first 3 contact points, we ignore the other contact points and other forces. Once we've found the 3rd force (and rebalanced forces 1 and 2 as needed) we then move on to consider the 4th force.

The last step is to apply the contact forces to the bodies, which gives the final set of accelerations that the evaluate() method then returns to the differential equation solver.

Extra Acceleration

The contact forces are calculated so that there is zero acceleration at contact points; but this does not immediately affect the remaining small velocity at a contact point. As a result, objects that are in resting contact will often have some undesirable jittery motion.

One way to deal with this is to request a small amount of additional acceleration which will eliminate that velocity over a few time steps. If the objects are moving towards each other (a small negative velocity) we request a little more acceleration which leads to a little more force being applied there. If the objects are moving apart (a small positive velocity) we request a little less acceleration.

The extra acceleration is added to the b vector in the private method calculate_b_vector. See ExtraAccel enum for explanations of the various options. See setExtraAccel for how to specify the desired ExtraAccel option.

Intermediate Steps During evaluate()

A DiffEqSolver works by 'averaging' several calculated states for each time step; for example ModifiedEuler averages 2 states, and RungeKutta averages 4 states. The collision detection done in evaluate() is based on those intermediate states within a step of the DiffEqSolver, so it is arguable whether that state actually ever occurs.

This point of view argues for only using the collisions detected between full steps of the DiffEqSolver. However, contacts can come and go during these sub-steps so it seems in practice to be more accurate to find the set of contacts anew in each call to evaluate(). Also if a penetrating collision is detected we need to stop the process and handle that collision instead, so it is important to do collision detection for that as well.

Prior to February 2012, there was an experimental option specified by the flag REUSE_COLLISIONS for which we did not find the collisions anew in the evaluate() method, instead we used the collisions found outside the evaluate() method during AdvanceStrategy.advance() which are based on a complete ODE step. See the git archive.

Hierarchy (view full)

Implements

Constructors

Properties

Methods

Constructors

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

computeForces_: ComputeForces

'C' for ContactSim

contactCount_: number = 0

number of recent contacts, for debugging

contactDepth_: number = 0

sum of depth of recent contacts, for debugging

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).

Type declaration

    • (): void
    • Returns void

debugPrintTime_: number = 0

time when last printed number of contacts

extraAccelTimeStep_: number = 0.025

The approximate length of a time step, used to find extra acceleration needed to keep contact points at the proper distance apart.

extra_accel_: ExtraAccel = ExtraAccel.VELOCITY_AND_DISTANCE_JOINTS

the method to use for calculating extra acceleration added to eliminate small amount of remaining velocity at a contact or joint. The option ExtraAccel.VELOCITY_AND_DISTANCE reduces both the distance and velocity at a contact to zero.

NOTE June 26 2014: previously the default was ExtraAccel.VELOCITY Sept 5 2016: previous default was ExtraAccel.VELOCITY_AND_DISTANCE

forceHistoryIndex_: number = 0

for debugging

forceHistory_: number[] = ...

for debugging

forceLaws_: ForceLaw[] = []

The ForceLaws in this simulation.

maxForce_: number = 0

the maximum force calculated between contacts. For testing.

numContacts_: number = 0

gives current max size of contact subset, for debugging

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.

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.

SHOW_CONTACTS: false = false

When true, write to debug console detail on all contacts found

SHOW_NUM_CONTACTS: false = false

When true, write to debug console number of contacts found

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.

SUBSET_COLLISIONS: boolean = true

Find subsets of related contacts to solve each subset separately for contact forces. This feature is useful for cases where there are a lot of contacts that are in separate groups (two piles) because the matrices being solved are smaller. The ComputeForces algorithm is O(n^4). For example suppose there are 40 contact points. The cost of 40^4 = 2,560,000 is far greater than 20^4 + 20^4 = 320,000. There is some overhead to finding the subsets, so this can lose time when there is just a big single pile.

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 a Connector to the list of active Connectors and to the SimList. The RigidBodys of the Connector must already have been added to this ContactSim, unless it is a Scrim. Note that the order of the list of Connectors is significant, see alignConnectors.

    Parameters

    • connector: Connector

      the Connector to add

    • Optional follow: null | Connector

      add new Connector into list after this Connector; if null then add at front of list; if undefined, add at end of list

    Returns void

    Throws

    if RigidBodys of the Connector have not been added to this ContactSim

  • Adds the set of Connectors. Note that the ordering of the Connectors is important because the Connectors are aligned in list order.

    Parameters

    • connectors: Connector[]

      set of Connectors to add

    Returns void

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

    Parameters

    Returns void

    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

    Returns void

  • Aligns all Connectors. This is generally done only during set up of initial conditions of the simulation, or whenever a Connector is being created.

    Note that the order of the bodies within a Joint is significant because Joint.align() usually moves the second body to align with first body. Also, the ordering within the list of Connectors is significant because the Connectors are aligned in list order.

    Returns void

  • Applies a normal force at the contact point. Result is modification of the rigid body accelerations in the change vector. Also the Force objects are added to the SimList for display purposes when the 'show forces' flag is on.

    The impact point(s) given in the contact only affect the angular acceleration of the objects, not the linear acceleration. Curiously, the impact point can be anywhere along the line normal to the impact point with the same result. Because the angular acceleration changes by the cross product of the force and the vector from center of mass to impact point: R x F. If you change R by adding a multiple n of F there is no change: (R + n F) x F = R x F + n F x F = R x F + 0. This is why it doesn't matter which side of the gap that we assign the impact point for the collision.

    We use R vector here, not U vector. The force is applied at the point of contact, not at the center of the circle for a circular edge. The U vector is used for calculating the velocity of the gap distance -- which went into the b-vector, and therefore determined the amount of force. The U vector is also used for calculating the A matrix. We could use the U vector here, but it would give the same result because U = R + n F, see the section Equivalence of Using R or U Vector For Normal Velocity in RigidBodyCollision.

    We entirely skip making (and therefore displaying) the forces for a fixed (infinite mass) body. The reason is that those forces won't affect the simulation because the fixed body cannot move. We could let those forces thru if desired.

    Parameters

    • c: RigidBodyCollision

      the contact point where the force is to be applied

    • f: number

      the magnitude of the normal force

    • change: number[]

      vector of rigid body accelerations

    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

  • Parameters

    • vars: number[]

      the current array of state variables (input)

    • change: number[]

      array of change rates for each variable (output)

    • subset: RigidBodyCollision[]

    Returns void

  • Calculates the b vector which specifies how external forces (like gravity, thrust, etc) affect acceleration of contact points.

    See Calculate the b Vector in the document about ContactSim math.

    Old Notes -- Do Not Trust

    (Sept 2015: don't trust these old notes!)

    New extra acceleration calculation (March 2, 2012). See note below from Nov 2014 about a modification of this calculation.

    let x be the joint gap.  x’ = v, x’’ = a.
    Integrating:  x’ = a t + v_0;   x = a t^2/2 + v_0 t + x_0
    ideally we find accel that both stops velocity and brings the gap to zero:
    0 = a h^2/2 + v_0 h + x_0
    0 = a h + v_0
    we can’t satisfy both those equations, but we can maybe find something
    in the middle?
    we know h, need to find a.
    a = -(v_0 h + x_0)2/h^2
    a = -v_0/h
    what is the average of these?
    -(2 v_0 h + x_0) /h^2
    (note that we put the opposite of this into b vector)
    

    I tested the relationship between the time step h and the divisor q used in finding the extra acceleration a, where a = v / q. (This was October 2011). I found that instability occurs when h > 2 q for Runge Kutta solver, and when h > q for modified Euler solver. This makes sense because RK averages 4 sub-steps and in a sense the time step used is actually h/2. Whereas modified Euler averages 2 sub-steps that are h apart. It also makes sense because the integral above is over a single time step h, so if you are integrating over significantly longer time then you would overshoot and the velocity would be reduced too much.

    Extra acceleration and reusing collisions: It would make more sense to take the velocity at the start of the RK step and use that starting velocity value to calculate an extra acceleration that is used for all the sub-steps of the RK step. Then you would wind up reducing the velocity to zero over that time step. Instead, what we do currently is recalculate the extra acceleration in each sub-step, based on the current simulation state (velocity) in that sub-step. This seems to be less effective in reducing the velocity -- it takes more steps to get to zero velocity. However, I tried an experiment (October 2011) that didn't work out so well. I tried to reuse the collisions, so that the same collision is used for all the RK sub-steps and so have the same velocity used in each sub-step. The results were inconsistent, and re-using the collisions has other effects.

    Note about joints: from doing a quick test with DoublePendulumCompareBuilder it seems that you can get almost as good results for joints by turning off the 'generate tiny collisions at each step' code in CollisionSim and turning on the 'extra acceleration to eliminate velocity' code here for joints. This might be useful if you want to avoid the extra work in each step for handling those tiny collisions. As long as we do the 'tiny collisions for joints', we ensure that velocity at joints is zero, and therefore don't need to do the "extra acceleration to eliminate velocity" kluge for joints.

    Parameters

    Returns number[]

  • 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: number

      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 method to use for calculating extra acceleration added to eliminate small amount of remaining velocity at a contact.

    Returns ExtraAccel

    the method to use for calculating extra acceleration

  • Returns the approximate length of a time step, used to find extra acceleration needed to keep contact points at the proper distance apart.

    Returns number

    the approximate length of a time step

  • For debugging, returns the number of contacts in the biggest subset of contacts that are all interrelated.

    Returns number

    number of contacts in the biggest subset of contacts that are all interrelated

  • 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

  • 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

    Returns boolean

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

  • 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

    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 Connector from the list of active Connectors. If the Connector is also a SimObject, then removes it from the SimList.

    Parameters

    Returns void

  • Removes imminent collisions from the given set of contacts/collisions.

    Parameters

    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

    Returns void

    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 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.

    Returns void

    Throws

    if there are no RigidBodys

  • Sets the method to use for calculating extra acceleration added to eliminate small amount of remaining velocity at a contact.

    Parameters

    • value: ExtraAccel

      the method to use for calculating extra acceleration

    Returns void

  • Sets the approximate length of a time step, used to find extra acceleration needed to keep contact points at the proper distance apart.

    Parameters

    • value: number

      the approximate length of a time step

    Returns void

  • 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 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.

  • Calculates the A matrix which specifies how contact points react to contact forces. Returns a matrix where the (i, j)th entry is how much the relative normal acceleration at contact i will change from a unit force being applied at contact j.

    See Calculate the A Matrix in the document about ContactSim math.

    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 (March 2012) this is the same as ImpulseSim.makeCollisionMatrix, so we need to use just one of these (duplicate code currently). The ImpulseSim version is nicer in how it uses the 'influence' subroutine. However, that version doesn't use the U vector, so need to figure out whether they should both use U vector or not.

    Parameters

    Returns Float64Array[]

Generated using TypeDoc