Optional
opt_name: stringname of this Subject
Protected
bods_The RigidBodys in this simulation.
Protected
collisionHow close in space we need to be to a collision, to decide to handle it, as a percentage of the targetGap = distanceTol/2.
Function to print collisions, or null to turn off printing collisions.
Private
compute'C' for ContactSim
Private
contactnumber of recent contacts, for debugging
Private
contactsum of depth of recent contacts, for debugging
Protected
debugFunction 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).
Private
debugtime when last printed number of contacts
Private
extraThe approximate length of a time step, used to find extra acceleration needed to keep contact points at the proper distance apart.
Private
extra_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
Private
forcefor debugging
Private
forcefor debugging
Protected
forceThe ForceLaws in this simulation.
Private
maxthe maximum force calculated between contacts. For testing.
Private
numgives current max size of contact subset, for debugging
Protected
showWhether to add Forces to the SimList so they can be seen.
Protected
simThe SimList holds SimObjects so they can be made visible.
Protected
simRNG_The pseudo random number generator, used in collision handling and computing forces.
Protected
simSuggested size for the SimView. This is mainly for tests to communicate with TestViewerApp.
Protected
varsThe variables that determine the state of the simulation; there are six variables for each RigidBody, plus some others for time, energy, etc.
Static
Readonly
COLLISIONS_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.
Static
Readonly
DEBUG_Show the impulse applied at each collision.
Static
ELASTICITY_Name of event broadcast from setElasticity.
Static
Readonly
SHOW_When true
, write to debug console detail on all contacts found
Static
Readonly
SHOW_When true
, write to debug console number of contacts found
Static
Readonly
SMALL_Impulse smaller than this is not marked as a discontinuous change in the velocity variables of the objects colliding.
Static
SUBSET_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.
Static
Readonly
TINY_Impulse smaller than this is regarded as insignificant at various points in the collision handling algorithm.
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.
RigidBody to add to the simulation
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.
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.
set of Connectors to add
Adds the ForceLaw to the list of ForceLaws operating in this simulation, if it is not already on the list.
the ForceLaw to add
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.
the Observer to add
Adds the Parameter to the list of this Subject's available Parameters.
the Parameter to add
if a Parameter with the same name already exists.
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.
Private
applyApplies 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.
the contact point where the force is to be applied
the magnitude of the normal force
vector of rigid body accelerations
Protected
applyApplies 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.
vector of rigid body accelerations
the Force to be applied
Notifies all Observers that this Subject has changed by calling observe on each Observer.
An Observer may call addObserver or removeObserver during its observe
method.
a SubjectEvent with information relating to the change
Notifies all Observers that the Parameter with the given name has changed by calling observe on each Observer.
the language-independent or English name of the Parameter that has changed
if there is no Parameter with the given name
Private
calcthe current array of state variables (input)
array of change rates for each variable (output)
Private
calculate_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.
(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.
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.
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().
name of the SimObject that is created
center of the circle
radius of the circle
Optional
expireTime: numberthe time when the DisplayObject will be removed; the default expireTime is 'now'.
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.
the current array of state variables (input),
corresponding to the state at getTime() + timeStep
array of change rates for each variable (output), all values are zero on entry.
the current time step (might be zero)
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.
the list of collisions to add to
the current array of state variables
the size of the current time step, in seconds
Returns a RigidBody in this simulation by specifying its name or index in the list of RigidBodys.
index in list of RigidBodys or name of the RigidBody (either the English or language-independent version of the name)
the RigidBody with the given name or at the given position in the list of RigidBodys
if requesting a non-existing body.
Protected
getReturns whether broadcasting is enabled for this Subject. See setBroadcast.
whether broadcasting is enabled for this Subject
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).
the collision accuracy, a fraction between 0 (exclusive) and 1 (inclusive)
Returns the collision handling method being used.
the collision handling method being used
Returns the current EnergyInfo for this system.
an EnergyInfo object representing the current energy of this system.
Returns the method to use for calculating extra acceleration added to eliminate small amount of remaining velocity at a contact.
the method to use for calculating extra acceleration
Returns the ParameterBoolean with the given name.
the language-independent or English name of the ParameterBoolean
the ParameterBoolean with the given name
if there is no ParameterBoolean with the given name
Returns the ParameterNumber with the given name.
the language-independent or English name of the ParameterNumber
the ParameterNumber with the given name
if there is no ParameterNumber with the given name
Returns the ParameterString with the given name.
the language-independent or English name of the ParameterString
the ParameterString with the given name
if there is no ParameterString 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.
the seed of the pseudo random number generator
Returns the suggested size for the SimView. This is mainly for tests to communicate with test/TestViewerApp.TestViewerApp.
suggested size for the SimView
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.
the list of current collisions
Optional
opt_totals: CollisionTotalsCollisionTotals object to update with number of collisions handled
true if was able to handle the collision, changing state of simulation.
Protected
makeReturns 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.
list of RigidBodyCollisions
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.
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'
Removes the RigidBody from the simulation, and any Connectors that were attached to it.
RigidBodys to remove from the simulation
Removes the ForceLaw from the list of ForceLaws operating in this simulation.
the ForceLaw to remove
whether the ForceLaw was removed
Private
removeRemoves imminent collisions from the given set of contacts/collisions.
the set of contacts/collisions to modify
Removes the Observer from this Subject's list of Observers. An Observer may
call removeObserver
during its observe
method.
the Observer to detach from list of Observers
Removes the Parameter from the list of this Subject's available Parameters.
the Parameter to remove
Sets the Simulation back to its initial conditions, see saveInitialState, and calls modifyObjects. Broadcasts event named 'RESET'.
Restores the Simulation state that was saved with saveState.
Saves the current variables and time as the initial state, so that this initial state can be restored with reset. Broadcasts event named 'INITIAL_STATE_SAVED'.
Saves the current state of the Simulation, so that we can back up to this state later on. The state is defined mainly by the set of Simulation variables, see getVarsList, but can include other data. This state is typically used for collision detection as the before collision state, see CollisionSim.findCollisions.
Protected
setSets 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.
whether this Subject should broadcast events
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).
how close in distance to be in order to handle a collision
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);
})
the function to print collisions, or null to turn off printing collisions
Sets the collision handling method to use,
the collision handling method to use
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.
elasticity to set on all RigidBodys, a number from 0 to 1.
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.
the method to use for calculating extra acceleration
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.
the seed of the pseudo random number generator
Sets whether to show collisions visually. Note that setShowForces will also change whether to show collisions.
whether to show collisions visually.
Sets the suggested size for the SimView. This is mainly for tests to communicate with test/TestViewerApp.TestViewerApp.
the suggested size for the SimView
Sets the Terminal object that this simulation can print data into.
the Terminal object that this simulation can print data into.
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'}}
a minimal string representation of this object.
Static
Private
calculate_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.
Generated using TypeDoc
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
EXTRA_ACCEL
, see setExtraAccelSee also the ImpulseSim super class for additional Parameters.
Background and References
See explanations at:
2D Physics Engine Overview
The math and physics underlying RigidBodySim, ImpulseSim and ContactSim are described on the myPhysicsLab website.
ContactSim Math has more details about the math.
The algorithm used here is based on these papers:
David Baraff, Fast Contact Force Computation for Nonpenetrating Rigid Bodies. Computer Graphics Proceedings, Annual Conference Series, 1994; pages 23-34.
David Baraff, An Introduction to Physically Based Modeling: Rigid Body Simulation II—Nonpenetration Constraints Siggraph '97 Course Notes.
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 callfindCollisions()
to find all the contact points, and possibly collisions as well. If we find any actual (penetrating) collisions, thenevaluate()
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 isO(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
where
a =
vector of accelerationsA =
matrix describing how thej
-th contact force affects the acceleration of thei
-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 distanced_i
, find how the acceleration of that contact distanced_i''
is related to the force at thej
-th contact point. The force at thej
-th contact point isf_j N_j
, wheref_j
is a scalar andN_j
is the vector normal. Thea_ij
entry in theA
matrix tells what that relationship is betweenf_j
andd_i''
. Thisa_ij
value is dependent only on the current geometry of how the objects are oriented and touching each other.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:
Consider the first contact at
p1
which is between the ground and body B. The acceleration of the contact distance atp1
is affected by the forces atp1
,p2
, andp3
because all of those forces affect the movement of body B. But the forces atp4
andp5
have no effect, so their entries are zero in the first row of theA
matrix.The first row of the matrix equation can be written out as
That equation says the acceleration of contact distance at point
p1
is equal to a certain linear combination of the contact forcesf1
,f2
,f3
, plus the acceleration due to the external forces which isb1
.The particular values for
a11, a12, a13
are dependent on the geometry of the situation: where the forcesf1
,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 pointp1
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 exceptf5
. Therefore the third row of theA
matrix has four non-zero entries corresponding to the four forces that affect the acceleration atp3
.Constraints On the Solution
Assume we now have the
b
vector of external forces and theA
matrix of dependencies between contact forces and resulting accelerations of different bodies. We solve for thef
vector of contact forces subject to the following constraints: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 separatesNo 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 methodcalculate_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 theevaluate()
method, instead we used the collisions found outside theevaluate()
method duringAdvanceStrategy.advance()
which are based on a complete ODE step. See the git archive.