pbox2d 0.6.0-java → 0.8.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.mvn/extensions.xml +8 -0
- data/.mvn/wrapper/maven-wrapper.properties +1 -0
- data/.travis.yml +23 -0
- data/CHANGELOG.md +8 -0
- data/README.md +7 -7
- data/Rakefile +1 -2
- data/lib/box2d.jar +0 -0
- data/lib/pbox2d/version.rb +1 -1
- data/lib/pbox2d.rb +1 -0
- data/pbox2d.gemspec +6 -11
- data/pom.rb +59 -0
- data/pom.xml +82 -73
- data/src/org/jbox2d/JBox2D.gwt.xml +12 -0
- data/src/org/jbox2d/callbacks/ContactAdaptor.java +27 -0
- data/src/org/jbox2d/callbacks/ContactFilter.java +59 -0
- data/src/org/jbox2d/callbacks/ContactImpulse.java +42 -0
- data/src/org/jbox2d/callbacks/ContactListener.java +87 -0
- data/src/org/jbox2d/callbacks/DebugDraw.java +297 -0
- data/src/org/jbox2d/callbacks/DestructionListener.java +53 -0
- data/src/org/jbox2d/callbacks/PairCallback.java +29 -0
- data/src/org/jbox2d/callbacks/ParticleDestructionListener.java +20 -0
- data/src/org/jbox2d/callbacks/ParticleQueryCallback.java +19 -0
- data/src/org/jbox2d/callbacks/ParticleRaycastCallback.java +19 -0
- data/src/org/jbox2d/callbacks/QueryCallback.java +45 -0
- data/src/org/jbox2d/callbacks/RayCastCallback.java +55 -0
- data/src/org/jbox2d/callbacks/TreeCallback.java +42 -0
- data/src/org/jbox2d/callbacks/TreeRayCastCallback.java +44 -0
- data/src/org/jbox2d/collision/AABB.java +338 -0
- data/src/org/jbox2d/collision/Collision.java +1444 -0
- data/src/org/jbox2d/collision/ContactID.java +106 -0
- data/src/org/jbox2d/collision/Distance.java +773 -0
- data/src/org/jbox2d/collision/DistanceInput.java +41 -0
- data/src/org/jbox2d/collision/DistanceOutput.java +43 -0
- data/src/org/jbox2d/collision/Manifold.java +116 -0
- data/src/org/jbox2d/collision/ManifoldPoint.java +104 -0
- data/src/org/jbox2d/collision/RayCastInput.java +47 -0
- data/src/org/jbox2d/collision/RayCastOutput.java +46 -0
- data/src/org/jbox2d/collision/TimeOfImpact.java +526 -0
- data/src/org/jbox2d/collision/WorldManifold.java +200 -0
- data/src/org/jbox2d/collision/broadphase/BroadPhase.java +92 -0
- data/src/org/jbox2d/collision/broadphase/BroadPhaseStrategy.java +88 -0
- data/src/org/jbox2d/collision/broadphase/DefaultBroadPhaseBuffer.java +268 -0
- data/src/org/jbox2d/collision/broadphase/DynamicTree.java +883 -0
- data/src/org/jbox2d/collision/broadphase/DynamicTreeFlatNodes.java +873 -0
- data/src/org/jbox2d/collision/broadphase/DynamicTreeNode.java +54 -0
- data/src/org/jbox2d/collision/broadphase/Pair.java +46 -0
- data/src/org/jbox2d/collision/shapes/ChainShape.java +264 -0
- data/src/org/jbox2d/collision/shapes/CircleShape.java +207 -0
- data/src/org/jbox2d/collision/shapes/EdgeShape.java +254 -0
- data/src/org/jbox2d/collision/shapes/MassData.java +105 -0
- data/src/org/jbox2d/collision/shapes/PolygonShape.java +718 -0
- data/src/org/jbox2d/collision/shapes/Shape.java +136 -0
- data/src/org/jbox2d/collision/shapes/ShapeType.java +32 -0
- data/src/org/jbox2d/common/BufferUtils.java +209 -0
- data/src/org/jbox2d/common/Color3f.java +88 -0
- data/src/org/jbox2d/common/IViewportTransform.java +133 -0
- data/src/org/jbox2d/common/Mat22.java +609 -0
- data/src/org/jbox2d/common/Mat33.java +290 -0
- data/src/org/jbox2d/common/MathUtils.java +335 -0
- data/src/org/jbox2d/common/OBBViewportTransform.java +174 -0
- data/src/org/jbox2d/common/PlatformMathUtils.java +46 -0
- data/src/org/jbox2d/common/RaycastResult.java +37 -0
- data/src/org/jbox2d/common/Rot.java +150 -0
- data/src/org/jbox2d/common/Settings.java +246 -0
- data/src/org/jbox2d/common/Sweep.java +116 -0
- data/src/org/jbox2d/common/Timer.java +46 -0
- data/src/org/jbox2d/common/Transform.java +203 -0
- data/src/org/jbox2d/common/Vec2.java +388 -0
- data/src/org/jbox2d/common/Vec3.java +170 -0
- data/src/org/jbox2d/dynamics/Body.java +1246 -0
- data/src/org/jbox2d/dynamics/BodyDef.java +382 -0
- data/src/org/jbox2d/dynamics/BodyType.java +41 -0
- data/src/org/jbox2d/dynamics/ContactManager.java +293 -0
- data/src/org/jbox2d/dynamics/Filter.java +62 -0
- data/src/org/jbox2d/dynamics/Fixture.java +454 -0
- data/src/org/jbox2d/dynamics/FixtureDef.java +214 -0
- data/src/org/jbox2d/dynamics/FixtureProxy.java +38 -0
- data/src/org/jbox2d/dynamics/Island.java +602 -0
- data/src/org/jbox2d/dynamics/Profile.java +97 -0
- data/src/org/jbox2d/dynamics/SolverData.java +33 -0
- data/src/org/jbox2d/dynamics/TimeStep.java +46 -0
- data/src/org/jbox2d/dynamics/World.java +2075 -0
- data/src/org/jbox2d/dynamics/contacts/ChainAndCircleContact.java +57 -0
- data/src/org/jbox2d/dynamics/contacts/ChainAndPolygonContact.java +57 -0
- data/src/org/jbox2d/dynamics/contacts/CircleContact.java +50 -0
- data/src/org/jbox2d/dynamics/contacts/Contact.java +365 -0
- data/src/org/jbox2d/dynamics/contacts/ContactCreator.java +35 -0
- data/src/org/jbox2d/dynamics/contacts/ContactEdge.java +56 -0
- data/src/org/jbox2d/dynamics/contacts/ContactPositionConstraint.java +49 -0
- data/src/org/jbox2d/dynamics/contacts/ContactRegister.java +31 -0
- data/src/org/jbox2d/dynamics/contacts/ContactSolver.java +1104 -0
- data/src/org/jbox2d/dynamics/contacts/ContactVelocityConstraint.java +60 -0
- data/src/org/jbox2d/dynamics/contacts/EdgeAndCircleContact.java +52 -0
- data/src/org/jbox2d/dynamics/contacts/EdgeAndPolygonContact.java +52 -0
- data/src/org/jbox2d/dynamics/contacts/PolygonAndCircleContact.java +51 -0
- data/src/org/jbox2d/dynamics/contacts/PolygonContact.java +50 -0
- data/src/org/jbox2d/dynamics/contacts/Position.java +31 -0
- data/src/org/jbox2d/dynamics/contacts/Velocity.java +31 -0
- data/src/org/jbox2d/dynamics/joints/ConstantVolumeJoint.java +258 -0
- data/src/org/jbox2d/dynamics/joints/ConstantVolumeJointDef.java +75 -0
- data/src/org/jbox2d/dynamics/joints/DistanceJoint.java +356 -0
- data/src/org/jbox2d/dynamics/joints/DistanceJointDef.java +106 -0
- data/src/org/jbox2d/dynamics/joints/FrictionJoint.java +294 -0
- data/src/org/jbox2d/dynamics/joints/FrictionJointDef.java +78 -0
- data/src/org/jbox2d/dynamics/joints/GearJoint.java +520 -0
- data/src/org/jbox2d/dynamics/joints/GearJointDef.java +58 -0
- data/src/org/jbox2d/dynamics/joints/Jacobian.java +32 -0
- data/src/org/jbox2d/dynamics/joints/Joint.java +235 -0
- data/src/org/jbox2d/dynamics/joints/JointDef.java +65 -0
- data/src/org/jbox2d/dynamics/joints/JointEdge.java +57 -0
- data/src/org/jbox2d/dynamics/joints/JointType.java +28 -0
- data/src/org/jbox2d/dynamics/joints/LimitState.java +28 -0
- data/src/org/jbox2d/dynamics/joints/MotorJoint.java +339 -0
- data/src/org/jbox2d/dynamics/joints/MotorJointDef.java +55 -0
- data/src/org/jbox2d/dynamics/joints/MouseJoint.java +262 -0
- data/src/org/jbox2d/dynamics/joints/MouseJointDef.java +62 -0
- data/src/org/jbox2d/dynamics/joints/PrismaticJoint.java +808 -0
- data/src/org/jbox2d/dynamics/joints/PrismaticJointDef.java +120 -0
- data/src/org/jbox2d/dynamics/joints/PulleyJoint.java +393 -0
- data/src/org/jbox2d/dynamics/joints/PulleyJointDef.java +105 -0
- data/src/org/jbox2d/dynamics/joints/RevoluteJoint.java +554 -0
- data/src/org/jbox2d/dynamics/joints/RevoluteJointDef.java +137 -0
- data/src/org/jbox2d/dynamics/joints/RopeJoint.java +276 -0
- data/src/org/jbox2d/dynamics/joints/RopeJointDef.java +34 -0
- data/src/org/jbox2d/dynamics/joints/WeldJoint.java +424 -0
- data/src/org/jbox2d/dynamics/joints/WeldJointDef.java +85 -0
- data/src/org/jbox2d/dynamics/joints/WheelJoint.java +498 -0
- data/src/org/jbox2d/dynamics/joints/WheelJointDef.java +98 -0
- data/src/org/jbox2d/particle/ParticleBodyContact.java +17 -0
- data/src/org/jbox2d/particle/ParticleColor.java +52 -0
- data/src/org/jbox2d/particle/ParticleContact.java +14 -0
- data/src/org/jbox2d/particle/ParticleDef.java +24 -0
- data/src/org/jbox2d/particle/ParticleGroup.java +154 -0
- data/src/org/jbox2d/particle/ParticleGroupDef.java +62 -0
- data/src/org/jbox2d/particle/ParticleGroupType.java +8 -0
- data/src/org/jbox2d/particle/ParticleSystem.java +2172 -0
- data/src/org/jbox2d/particle/ParticleType.java +28 -0
- data/src/org/jbox2d/particle/StackQueue.java +44 -0
- data/src/org/jbox2d/particle/VoronoiDiagram.java +209 -0
- data/src/org/jbox2d/pooling/IDynamicStack.java +47 -0
- data/src/org/jbox2d/pooling/IOrderedStack.java +57 -0
- data/src/org/jbox2d/pooling/IWorldPool.java +101 -0
- data/src/org/jbox2d/pooling/arrays/FloatArray.java +50 -0
- data/src/org/jbox2d/pooling/arrays/GeneratorArray.java +33 -0
- data/src/org/jbox2d/pooling/arrays/IntArray.java +53 -0
- data/src/org/jbox2d/pooling/arrays/Vec2Array.java +57 -0
- data/src/org/jbox2d/pooling/normal/CircleStack.java +77 -0
- data/src/org/jbox2d/pooling/normal/DefaultWorldPool.java +331 -0
- data/src/org/jbox2d/pooling/normal/MutableStack.java +72 -0
- data/src/org/jbox2d/pooling/normal/OrderedStack.java +73 -0
- data/src/org/jbox2d/pooling/stacks/DynamicIntStack.java +60 -0
- metadata +161 -14
- data/lib/jbox2d-library-2.3.1-SNAPSHOT.jar +0 -0
@@ -0,0 +1,602 @@
|
|
1
|
+
/*******************************************************************************
|
2
|
+
* Copyright (c) 2013, Daniel Murphy
|
3
|
+
* All rights reserved.
|
4
|
+
*
|
5
|
+
* Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
* are permitted provided that the following conditions are met:
|
7
|
+
* * Redistributions of source code must retain the above copyright notice,
|
8
|
+
* this list of conditions and the following disclaimer.
|
9
|
+
* * Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
* this list of conditions and the following disclaimer in the documentation
|
11
|
+
* and/or other materials provided with the distribution.
|
12
|
+
*
|
13
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
14
|
+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
15
|
+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
16
|
+
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
17
|
+
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
18
|
+
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
19
|
+
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
20
|
+
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
21
|
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
22
|
+
* POSSIBILITY OF SUCH DAMAGE.
|
23
|
+
******************************************************************************/
|
24
|
+
package org.jbox2d.dynamics;
|
25
|
+
|
26
|
+
import org.jbox2d.callbacks.ContactImpulse;
|
27
|
+
import org.jbox2d.callbacks.ContactListener;
|
28
|
+
import org.jbox2d.common.MathUtils;
|
29
|
+
import org.jbox2d.common.Settings;
|
30
|
+
import org.jbox2d.common.Sweep;
|
31
|
+
import org.jbox2d.common.Timer;
|
32
|
+
import org.jbox2d.common.Vec2;
|
33
|
+
import org.jbox2d.dynamics.contacts.Contact;
|
34
|
+
import org.jbox2d.dynamics.contacts.ContactSolver;
|
35
|
+
import org.jbox2d.dynamics.contacts.ContactSolver.ContactSolverDef;
|
36
|
+
import org.jbox2d.dynamics.contacts.ContactVelocityConstraint;
|
37
|
+
import org.jbox2d.dynamics.contacts.Position;
|
38
|
+
import org.jbox2d.dynamics.contacts.Velocity;
|
39
|
+
import org.jbox2d.dynamics.joints.Joint;
|
40
|
+
|
41
|
+
/*
|
42
|
+
Position Correction Notes
|
43
|
+
=========================
|
44
|
+
I tried the several algorithms for position correction of the 2D revolute joint.
|
45
|
+
I looked at these systems:
|
46
|
+
- simple pendulum (1m diameter sphere on massless 5m stick) with initial angular velocity of 100 rad/s.
|
47
|
+
- suspension bridge with 30 1m long planks of length 1m.
|
48
|
+
- multi-link chain with 30 1m long links.
|
49
|
+
|
50
|
+
Here are the algorithms:
|
51
|
+
|
52
|
+
Baumgarte - A fraction of the position error is added to the velocity error. There is no
|
53
|
+
separate position solver.
|
54
|
+
|
55
|
+
Pseudo Velocities - After the velocity solver and position integration,
|
56
|
+
the position error, Jacobian, and effective mass are recomputed. Then
|
57
|
+
the velocity constraints are solved with pseudo velocities and a fraction
|
58
|
+
of the position error is added to the pseudo velocity error. The pseudo
|
59
|
+
velocities are initialized to zero and there is no warm-starting. After
|
60
|
+
the position solver, the pseudo velocities are added to the positions.
|
61
|
+
This is also called the First Order World method or the Position LCP method.
|
62
|
+
|
63
|
+
Modified Nonlinear Gauss-Seidel (NGS) - Like Pseudo Velocities except the
|
64
|
+
position error is re-computed for each raint and the positions are updated
|
65
|
+
after the raint is solved. The radius vectors (aka Jacobians) are
|
66
|
+
re-computed too (otherwise the algorithm has horrible instability). The pseudo
|
67
|
+
velocity states are not needed because they are effectively zero at the beginning
|
68
|
+
of each iteration. Since we have the current position error, we allow the
|
69
|
+
iterations to terminate early if the error becomes smaller than Settings.linearSlop.
|
70
|
+
|
71
|
+
Full NGS or just NGS - Like Modified NGS except the effective mass are re-computed
|
72
|
+
each time a raint is solved.
|
73
|
+
|
74
|
+
Here are the results:
|
75
|
+
Baumgarte - this is the cheapest algorithm but it has some stability problems,
|
76
|
+
especially with the bridge. The chain links separate easily close to the root
|
77
|
+
and they jitter as they struggle to pull together. This is one of the most common
|
78
|
+
methods in the field. The big drawback is that the position correction artificially
|
79
|
+
affects the momentum, thus leading to instabilities and false bounce. I used a
|
80
|
+
bias factor of 0.2. A larger bias factor makes the bridge less stable, a smaller
|
81
|
+
factor makes joints and contacts more spongy.
|
82
|
+
|
83
|
+
Pseudo Velocities - the is more stable than the Baumgarte method. The bridge is
|
84
|
+
stable. However, joints still separate with large angular velocities. Drag the
|
85
|
+
simple pendulum in a circle quickly and the joint will separate. The chain separates
|
86
|
+
easily and does not recover. I used a bias factor of 0.2. A larger value lead to
|
87
|
+
the bridge collapsing when a heavy cube drops on it.
|
88
|
+
|
89
|
+
Modified NGS - this algorithm is better in some ways than Baumgarte and Pseudo
|
90
|
+
Velocities, but in other ways it is worse. The bridge and chain are much more
|
91
|
+
stable, but the simple pendulum goes unstable at high angular velocities.
|
92
|
+
|
93
|
+
Full NGS - stable in all tests. The joints display good stiffness. The bridge
|
94
|
+
still sags, but this is better than infinite forces.
|
95
|
+
|
96
|
+
Recommendations
|
97
|
+
Pseudo Velocities are not really worthwhile because the bridge and chain cannot
|
98
|
+
recover from joint separation. In other cases the benefit over Baumgarte is small.
|
99
|
+
|
100
|
+
Modified NGS is not a robust method for the revolute joint due to the violent
|
101
|
+
instability seen in the simple pendulum. Perhaps it is viable with other raint
|
102
|
+
types, especially scalar constraints where the effective mass is a scalar.
|
103
|
+
|
104
|
+
This leaves Baumgarte and Full NGS. Baumgarte has small, but manageable instabilities
|
105
|
+
and is very fast. I don't think we can escape Baumgarte, especially in highly
|
106
|
+
demanding cases where high raint fidelity is not needed.
|
107
|
+
|
108
|
+
Full NGS is robust and easy on the eyes. I recommend this as an option for
|
109
|
+
higher fidelity simulation and certainly for suspension bridges and long chains.
|
110
|
+
Full NGS might be a good choice for ragdolls, especially motorized ragdolls where
|
111
|
+
joint separation can be problematic. The number of NGS iterations can be reduced
|
112
|
+
for better performance without harming robustness much.
|
113
|
+
|
114
|
+
Each joint in a can be handled differently in the position solver. So I recommend
|
115
|
+
a system where the user can select the algorithm on a per joint basis. I would
|
116
|
+
probably default to the slower Full NGS and let the user select the faster
|
117
|
+
Baumgarte method in performance critical scenarios.
|
118
|
+
*/
|
119
|
+
|
120
|
+
/*
|
121
|
+
Cache Performance
|
122
|
+
|
123
|
+
The Box2D solvers are dominated by cache misses. Data structures are designed
|
124
|
+
to increase the number of cache hits. Much of misses are due to random access
|
125
|
+
to body data. The raint structures are iterated over linearly, which leads
|
126
|
+
to few cache misses.
|
127
|
+
|
128
|
+
The bodies are not accessed during iteration. Instead read only data, such as
|
129
|
+
the mass values are stored with the constraints. The mutable data are the raint
|
130
|
+
impulses and the bodies velocities/positions. The impulses are held inside the
|
131
|
+
raint structures. The body velocities/positions are held in compact, temporary
|
132
|
+
arrays to increase the number of cache hits. Linear and angular velocity are
|
133
|
+
stored in a single array since multiple arrays lead to multiple misses.
|
134
|
+
*/
|
135
|
+
|
136
|
+
/*
|
137
|
+
2D Rotation
|
138
|
+
|
139
|
+
R = [cos(theta) -sin(theta)]
|
140
|
+
[sin(theta) cos(theta) ]
|
141
|
+
|
142
|
+
thetaDot = omega
|
143
|
+
|
144
|
+
Let q1 = cos(theta), q2 = sin(theta).
|
145
|
+
R = [q1 -q2]
|
146
|
+
[q2 q1]
|
147
|
+
|
148
|
+
q1Dot = -thetaDot * q2
|
149
|
+
q2Dot = thetaDot * q1
|
150
|
+
|
151
|
+
q1_new = q1_old - dt * w * q2
|
152
|
+
q2_new = q2_old + dt * w * q1
|
153
|
+
then normalize.
|
154
|
+
|
155
|
+
This might be faster than computing sin+cos.
|
156
|
+
However, we can compute sin+cos of the same angle fast.
|
157
|
+
*/
|
158
|
+
|
159
|
+
/**
|
160
|
+
* This is an internal class.
|
161
|
+
*
|
162
|
+
* @author Daniel Murphy
|
163
|
+
*/
|
164
|
+
public class Island {
|
165
|
+
|
166
|
+
public ContactListener m_listener;
|
167
|
+
|
168
|
+
public Body[] m_bodies;
|
169
|
+
public Contact[] m_contacts;
|
170
|
+
public Joint[] m_joints;
|
171
|
+
|
172
|
+
public Position[] m_positions;
|
173
|
+
public Velocity[] m_velocities;
|
174
|
+
|
175
|
+
public int m_bodyCount;
|
176
|
+
public int m_jointCount;
|
177
|
+
public int m_contactCount;
|
178
|
+
|
179
|
+
public int m_bodyCapacity;
|
180
|
+
public int m_contactCapacity;
|
181
|
+
public int m_jointCapacity;
|
182
|
+
|
183
|
+
public Island() {
|
184
|
+
|
185
|
+
}
|
186
|
+
|
187
|
+
public void init(int bodyCapacity, int contactCapacity, int jointCapacity,
|
188
|
+
ContactListener listener) {
|
189
|
+
// System.out.println("Initializing Island");
|
190
|
+
m_bodyCapacity = bodyCapacity;
|
191
|
+
m_contactCapacity = contactCapacity;
|
192
|
+
m_jointCapacity = jointCapacity;
|
193
|
+
m_bodyCount = 0;
|
194
|
+
m_contactCount = 0;
|
195
|
+
m_jointCount = 0;
|
196
|
+
|
197
|
+
m_listener = listener;
|
198
|
+
|
199
|
+
if (m_bodies == null || m_bodyCapacity > m_bodies.length) {
|
200
|
+
m_bodies = new Body[m_bodyCapacity];
|
201
|
+
}
|
202
|
+
if (m_joints == null || m_jointCapacity > m_joints.length) {
|
203
|
+
m_joints = new Joint[m_jointCapacity];
|
204
|
+
}
|
205
|
+
if (m_contacts == null || m_contactCapacity > m_contacts.length) {
|
206
|
+
m_contacts = new Contact[m_contactCapacity];
|
207
|
+
}
|
208
|
+
|
209
|
+
// dynamic array
|
210
|
+
if (m_velocities == null || m_bodyCapacity > m_velocities.length) {
|
211
|
+
final Velocity[] old = m_velocities == null ? new Velocity[0] : m_velocities;
|
212
|
+
m_velocities = new Velocity[m_bodyCapacity];
|
213
|
+
System.arraycopy(old, 0, m_velocities, 0, old.length);
|
214
|
+
for (int i = old.length; i < m_velocities.length; i++) {
|
215
|
+
m_velocities[i] = new Velocity();
|
216
|
+
}
|
217
|
+
}
|
218
|
+
|
219
|
+
// dynamic array
|
220
|
+
if (m_positions == null || m_bodyCapacity > m_positions.length) {
|
221
|
+
final Position[] old = m_positions == null ? new Position[0] : m_positions;
|
222
|
+
m_positions = new Position[m_bodyCapacity];
|
223
|
+
System.arraycopy(old, 0, m_positions, 0, old.length);
|
224
|
+
for (int i = old.length; i < m_positions.length; i++) {
|
225
|
+
m_positions[i] = new Position();
|
226
|
+
}
|
227
|
+
}
|
228
|
+
}
|
229
|
+
|
230
|
+
public void clear() {
|
231
|
+
m_bodyCount = 0;
|
232
|
+
m_contactCount = 0;
|
233
|
+
m_jointCount = 0;
|
234
|
+
}
|
235
|
+
|
236
|
+
private final ContactSolver contactSolver = new ContactSolver();
|
237
|
+
private final Timer timer = new Timer();
|
238
|
+
private final SolverData solverData = new SolverData();
|
239
|
+
private final ContactSolverDef solverDef = new ContactSolverDef();
|
240
|
+
|
241
|
+
public void solve(Profile profile, TimeStep step, Vec2 gravity, boolean allowSleep) {
|
242
|
+
|
243
|
+
// System.out.println("Solving Island");
|
244
|
+
float h = step.dt;
|
245
|
+
|
246
|
+
// Integrate velocities and apply damping. Initialize the body state.
|
247
|
+
for (int i = 0; i < m_bodyCount; ++i) {
|
248
|
+
final Body b = m_bodies[i];
|
249
|
+
final Sweep bm_sweep = b.m_sweep;
|
250
|
+
final Vec2 c = bm_sweep.c;
|
251
|
+
float a = bm_sweep.a;
|
252
|
+
final Vec2 v = b.m_linearVelocity;
|
253
|
+
float w = b.m_angularVelocity;
|
254
|
+
|
255
|
+
// Store positions for continuous collision.
|
256
|
+
bm_sweep.c0.set(bm_sweep.c);
|
257
|
+
bm_sweep.a0 = bm_sweep.a;
|
258
|
+
|
259
|
+
if (b.m_type == BodyType.DYNAMIC) {
|
260
|
+
// Integrate velocities.
|
261
|
+
// v += h * (b.m_gravityScale * gravity + b.m_invMass * b.m_force);
|
262
|
+
v.x += h * (b.m_gravityScale * gravity.x + b.m_invMass * b.m_force.x);
|
263
|
+
v.y += h * (b.m_gravityScale * gravity.y + b.m_invMass * b.m_force.y);
|
264
|
+
w += h * b.m_invI * b.m_torque;
|
265
|
+
|
266
|
+
// Apply damping.
|
267
|
+
// ODE: dv/dt + c * v = 0
|
268
|
+
// Solution: v(t) = v0 * exp(-c * t)
|
269
|
+
// Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v *
|
270
|
+
// exp(-c * dt)
|
271
|
+
// v2 = exp(-c * dt) * v1
|
272
|
+
// Pade approximation:
|
273
|
+
// v2 = v1 * 1 / (1 + c * dt)
|
274
|
+
v.x *= 1.0f / (1.0f + h * b.m_linearDamping);
|
275
|
+
v.y *= 1.0f / (1.0f + h * b.m_linearDamping);
|
276
|
+
w *= 1.0f / (1.0f + h * b.m_angularDamping);
|
277
|
+
}
|
278
|
+
|
279
|
+
m_positions[i].c.x = c.x;
|
280
|
+
m_positions[i].c.y = c.y;
|
281
|
+
m_positions[i].a = a;
|
282
|
+
m_velocities[i].v.x = v.x;
|
283
|
+
m_velocities[i].v.y = v.y;
|
284
|
+
m_velocities[i].w = w;
|
285
|
+
}
|
286
|
+
|
287
|
+
timer.reset();
|
288
|
+
|
289
|
+
// Solver data
|
290
|
+
solverData.step = step;
|
291
|
+
solverData.positions = m_positions;
|
292
|
+
solverData.velocities = m_velocities;
|
293
|
+
|
294
|
+
// Initialize velocity constraints.
|
295
|
+
solverDef.step = step;
|
296
|
+
solverDef.contacts = m_contacts;
|
297
|
+
solverDef.count = m_contactCount;
|
298
|
+
solverDef.positions = m_positions;
|
299
|
+
solverDef.velocities = m_velocities;
|
300
|
+
|
301
|
+
contactSolver.init(solverDef);
|
302
|
+
// System.out.println("island init vel");
|
303
|
+
contactSolver.initializeVelocityConstraints();
|
304
|
+
|
305
|
+
if (step.warmStarting) {
|
306
|
+
// System.out.println("island warm start");
|
307
|
+
contactSolver.warmStart();
|
308
|
+
}
|
309
|
+
|
310
|
+
for (int i = 0; i < m_jointCount; ++i) {
|
311
|
+
m_joints[i].initVelocityConstraints(solverData);
|
312
|
+
}
|
313
|
+
|
314
|
+
profile.solveInit.accum(timer.getMilliseconds());
|
315
|
+
|
316
|
+
// Solve velocity constraints
|
317
|
+
timer.reset();
|
318
|
+
// System.out.println("island solving velocities");
|
319
|
+
for (int i = 0; i < step.velocityIterations; ++i) {
|
320
|
+
for (int j = 0; j < m_jointCount; ++j) {
|
321
|
+
m_joints[j].solveVelocityConstraints(solverData);
|
322
|
+
}
|
323
|
+
|
324
|
+
contactSolver.solveVelocityConstraints();
|
325
|
+
}
|
326
|
+
|
327
|
+
// Store impulses for warm starting
|
328
|
+
contactSolver.storeImpulses();
|
329
|
+
profile.solveVelocity.accum(timer.getMilliseconds());
|
330
|
+
|
331
|
+
// Integrate positions
|
332
|
+
for (int i = 0; i < m_bodyCount; ++i) {
|
333
|
+
final Vec2 c = m_positions[i].c;
|
334
|
+
float a = m_positions[i].a;
|
335
|
+
final Vec2 v = m_velocities[i].v;
|
336
|
+
float w = m_velocities[i].w;
|
337
|
+
|
338
|
+
// Check for large velocities
|
339
|
+
float translationx = v.x * h;
|
340
|
+
float translationy = v.y * h;
|
341
|
+
|
342
|
+
if (translationx * translationx + translationy * translationy > Settings.maxTranslationSquared) {
|
343
|
+
float ratio = Settings.maxTranslation
|
344
|
+
/ MathUtils.sqrt(translationx * translationx + translationy * translationy);
|
345
|
+
v.x *= ratio;
|
346
|
+
v.y *= ratio;
|
347
|
+
}
|
348
|
+
|
349
|
+
float rotation = h * w;
|
350
|
+
if (rotation * rotation > Settings.maxRotationSquared) {
|
351
|
+
float ratio = Settings.maxRotation / MathUtils.abs(rotation);
|
352
|
+
w *= ratio;
|
353
|
+
}
|
354
|
+
|
355
|
+
// Integrate
|
356
|
+
c.x += h * v.x;
|
357
|
+
c.y += h * v.y;
|
358
|
+
a += h * w;
|
359
|
+
|
360
|
+
m_positions[i].a = a;
|
361
|
+
m_velocities[i].w = w;
|
362
|
+
}
|
363
|
+
|
364
|
+
// Solve position constraints
|
365
|
+
timer.reset();
|
366
|
+
boolean positionSolved = false;
|
367
|
+
for (int i = 0; i < step.positionIterations; ++i) {
|
368
|
+
boolean contactsOkay = contactSolver.solvePositionConstraints();
|
369
|
+
|
370
|
+
boolean jointsOkay = true;
|
371
|
+
for (int j = 0; j < m_jointCount; ++j) {
|
372
|
+
boolean jointOkay = m_joints[j].solvePositionConstraints(solverData);
|
373
|
+
jointsOkay = jointsOkay && jointOkay;
|
374
|
+
}
|
375
|
+
|
376
|
+
if (contactsOkay && jointsOkay) {
|
377
|
+
// Exit early if the position errors are small.
|
378
|
+
positionSolved = true;
|
379
|
+
break;
|
380
|
+
}
|
381
|
+
}
|
382
|
+
|
383
|
+
// Copy state buffers back to the bodies
|
384
|
+
for (int i = 0; i < m_bodyCount; ++i) {
|
385
|
+
Body body = m_bodies[i];
|
386
|
+
body.m_sweep.c.x = m_positions[i].c.x;
|
387
|
+
body.m_sweep.c.y = m_positions[i].c.y;
|
388
|
+
body.m_sweep.a = m_positions[i].a;
|
389
|
+
body.m_linearVelocity.x = m_velocities[i].v.x;
|
390
|
+
body.m_linearVelocity.y = m_velocities[i].v.y;
|
391
|
+
body.m_angularVelocity = m_velocities[i].w;
|
392
|
+
body.synchronizeTransform();
|
393
|
+
}
|
394
|
+
|
395
|
+
profile.solvePosition.accum(timer.getMilliseconds());
|
396
|
+
|
397
|
+
report(contactSolver.m_velocityConstraints);
|
398
|
+
|
399
|
+
if (allowSleep) {
|
400
|
+
float minSleepTime = Float.MAX_VALUE;
|
401
|
+
|
402
|
+
final float linTolSqr = Settings.linearSleepTolerance * Settings.linearSleepTolerance;
|
403
|
+
final float angTolSqr = Settings.angularSleepTolerance * Settings.angularSleepTolerance;
|
404
|
+
|
405
|
+
for (int i = 0; i < m_bodyCount; ++i) {
|
406
|
+
Body b = m_bodies[i];
|
407
|
+
if (b.getType() == BodyType.STATIC) {
|
408
|
+
continue;
|
409
|
+
}
|
410
|
+
|
411
|
+
if ((b.m_flags & Body.E_AUTO_SLEEP_FLAG) == 0
|
412
|
+
|| b.m_angularVelocity * b.m_angularVelocity > angTolSqr
|
413
|
+
|| Vec2.dot(b.m_linearVelocity, b.m_linearVelocity) > linTolSqr) {
|
414
|
+
b.m_sleepTime = 0.0f;
|
415
|
+
minSleepTime = 0.0f;
|
416
|
+
} else {
|
417
|
+
b.m_sleepTime += h;
|
418
|
+
minSleepTime = MathUtils.min(minSleepTime, b.m_sleepTime);
|
419
|
+
}
|
420
|
+
}
|
421
|
+
|
422
|
+
if (minSleepTime >= Settings.timeToSleep && positionSolved) {
|
423
|
+
for (int i = 0; i < m_bodyCount; ++i) {
|
424
|
+
Body b = m_bodies[i];
|
425
|
+
b.setAwake(false);
|
426
|
+
}
|
427
|
+
}
|
428
|
+
}
|
429
|
+
}
|
430
|
+
|
431
|
+
private final ContactSolver toiContactSolver = new ContactSolver();
|
432
|
+
private final ContactSolverDef toiSolverDef = new ContactSolverDef();
|
433
|
+
|
434
|
+
public void solveTOI(TimeStep subStep, int toiIndexA, int toiIndexB) {
|
435
|
+
assert (toiIndexA < m_bodyCount);
|
436
|
+
assert (toiIndexB < m_bodyCount);
|
437
|
+
|
438
|
+
// Initialize the body state.
|
439
|
+
for (int i = 0; i < m_bodyCount; ++i) {
|
440
|
+
m_positions[i].c.x = m_bodies[i].m_sweep.c.x;
|
441
|
+
m_positions[i].c.y = m_bodies[i].m_sweep.c.y;
|
442
|
+
m_positions[i].a = m_bodies[i].m_sweep.a;
|
443
|
+
m_velocities[i].v.x = m_bodies[i].m_linearVelocity.x;
|
444
|
+
m_velocities[i].v.y = m_bodies[i].m_linearVelocity.y;
|
445
|
+
m_velocities[i].w = m_bodies[i].m_angularVelocity;
|
446
|
+
}
|
447
|
+
|
448
|
+
toiSolverDef.contacts = m_contacts;
|
449
|
+
toiSolverDef.count = m_contactCount;
|
450
|
+
toiSolverDef.step = subStep;
|
451
|
+
toiSolverDef.positions = m_positions;
|
452
|
+
toiSolverDef.velocities = m_velocities;
|
453
|
+
toiContactSolver.init(toiSolverDef);
|
454
|
+
|
455
|
+
// Solve position constraints.
|
456
|
+
for (int i = 0; i < subStep.positionIterations; ++i) {
|
457
|
+
boolean contactsOkay = toiContactSolver.solveTOIPositionConstraints(toiIndexA, toiIndexB);
|
458
|
+
if (contactsOkay) {
|
459
|
+
break;
|
460
|
+
}
|
461
|
+
}
|
462
|
+
// #if 0
|
463
|
+
// // Is the new position really safe?
|
464
|
+
// for (int i = 0; i < m_contactCount; ++i)
|
465
|
+
// {
|
466
|
+
// Contact* c = m_contacts[i];
|
467
|
+
// Fixture* fA = c.GetFixtureA();
|
468
|
+
// Fixture* fB = c.GetFixtureB();
|
469
|
+
//
|
470
|
+
// Body bA = fA.GetBody();
|
471
|
+
// Body bB = fB.GetBody();
|
472
|
+
//
|
473
|
+
// int indexA = c.GetChildIndexA();
|
474
|
+
// int indexB = c.GetChildIndexB();
|
475
|
+
//
|
476
|
+
// DistanceInput input;
|
477
|
+
// input.proxyA.Set(fA.GetShape(), indexA);
|
478
|
+
// input.proxyB.Set(fB.GetShape(), indexB);
|
479
|
+
// input.transformA = bA.GetTransform();
|
480
|
+
// input.transformB = bB.GetTransform();
|
481
|
+
// input.useRadii = false;
|
482
|
+
//
|
483
|
+
// DistanceOutput output;
|
484
|
+
// SimplexCache cache;
|
485
|
+
// cache.count = 0;
|
486
|
+
// Distance(&output, &cache, &input);
|
487
|
+
//
|
488
|
+
// if (output.distance == 0 || cache.count == 3)
|
489
|
+
// {
|
490
|
+
// cache.count += 0;
|
491
|
+
// }
|
492
|
+
// }
|
493
|
+
// #endif
|
494
|
+
|
495
|
+
// Leap of faith to new safe state.
|
496
|
+
m_bodies[toiIndexA].m_sweep.c0.x = m_positions[toiIndexA].c.x;
|
497
|
+
m_bodies[toiIndexA].m_sweep.c0.y = m_positions[toiIndexA].c.y;
|
498
|
+
m_bodies[toiIndexA].m_sweep.a0 = m_positions[toiIndexA].a;
|
499
|
+
m_bodies[toiIndexB].m_sweep.c0.set(m_positions[toiIndexB].c);
|
500
|
+
m_bodies[toiIndexB].m_sweep.a0 = m_positions[toiIndexB].a;
|
501
|
+
|
502
|
+
// No warm starting is needed for TOI events because warm
|
503
|
+
// starting impulses were applied in the discrete solver.
|
504
|
+
toiContactSolver.initializeVelocityConstraints();
|
505
|
+
|
506
|
+
// Solve velocity constraints.
|
507
|
+
for (int i = 0; i < subStep.velocityIterations; ++i) {
|
508
|
+
toiContactSolver.solveVelocityConstraints();
|
509
|
+
}
|
510
|
+
|
511
|
+
// Don't store the TOI contact forces for warm starting
|
512
|
+
// because they can be quite large.
|
513
|
+
|
514
|
+
float h = subStep.dt;
|
515
|
+
|
516
|
+
// Integrate positions
|
517
|
+
for (int i = 0; i < m_bodyCount; ++i) {
|
518
|
+
Vec2 c = m_positions[i].c;
|
519
|
+
float a = m_positions[i].a;
|
520
|
+
Vec2 v = m_velocities[i].v;
|
521
|
+
float w = m_velocities[i].w;
|
522
|
+
|
523
|
+
// Check for large velocities
|
524
|
+
float translationx = v.x * h;
|
525
|
+
float translationy = v.y * h;
|
526
|
+
if (translationx * translationx + translationy * translationy > Settings.maxTranslationSquared) {
|
527
|
+
float ratio =
|
528
|
+
Settings.maxTranslation
|
529
|
+
/ MathUtils.sqrt(translationx * translationx + translationy * translationy);
|
530
|
+
v.mulLocal(ratio);
|
531
|
+
}
|
532
|
+
|
533
|
+
float rotation = h * w;
|
534
|
+
if (rotation * rotation > Settings.maxRotationSquared) {
|
535
|
+
float ratio = Settings.maxRotation / MathUtils.abs(rotation);
|
536
|
+
w *= ratio;
|
537
|
+
}
|
538
|
+
|
539
|
+
// Integrate
|
540
|
+
c.x += v.x * h;
|
541
|
+
c.y += v.y * h;
|
542
|
+
a += h * w;
|
543
|
+
|
544
|
+
m_positions[i].c.x = c.x;
|
545
|
+
m_positions[i].c.y = c.y;
|
546
|
+
m_positions[i].a = a;
|
547
|
+
m_velocities[i].v.x = v.x;
|
548
|
+
m_velocities[i].v.y = v.y;
|
549
|
+
m_velocities[i].w = w;
|
550
|
+
|
551
|
+
// Sync bodies
|
552
|
+
Body body = m_bodies[i];
|
553
|
+
body.m_sweep.c.x = c.x;
|
554
|
+
body.m_sweep.c.y = c.y;
|
555
|
+
body.m_sweep.a = a;
|
556
|
+
body.m_linearVelocity.x = v.x;
|
557
|
+
body.m_linearVelocity.y = v.y;
|
558
|
+
body.m_angularVelocity = w;
|
559
|
+
body.synchronizeTransform();
|
560
|
+
}
|
561
|
+
|
562
|
+
report(toiContactSolver.m_velocityConstraints);
|
563
|
+
}
|
564
|
+
|
565
|
+
public void add(Body body) {
|
566
|
+
assert (m_bodyCount < m_bodyCapacity);
|
567
|
+
body.m_islandIndex = m_bodyCount;
|
568
|
+
m_bodies[m_bodyCount] = body;
|
569
|
+
++m_bodyCount;
|
570
|
+
}
|
571
|
+
|
572
|
+
public void add(Contact contact) {
|
573
|
+
assert (m_contactCount < m_contactCapacity);
|
574
|
+
m_contacts[m_contactCount++] = contact;
|
575
|
+
}
|
576
|
+
|
577
|
+
public void add(Joint joint) {
|
578
|
+
assert (m_jointCount < m_jointCapacity);
|
579
|
+
m_joints[m_jointCount++] = joint;
|
580
|
+
}
|
581
|
+
|
582
|
+
private final ContactImpulse impulse = new ContactImpulse();
|
583
|
+
|
584
|
+
public void report(ContactVelocityConstraint[] constraints) {
|
585
|
+
if (m_listener == null) {
|
586
|
+
return;
|
587
|
+
}
|
588
|
+
|
589
|
+
for (int i = 0; i < m_contactCount; ++i) {
|
590
|
+
Contact c = m_contacts[i];
|
591
|
+
|
592
|
+
ContactVelocityConstraint vc = constraints[i];
|
593
|
+
impulse.count = vc.pointCount;
|
594
|
+
for (int j = 0; j < vc.pointCount; ++j) {
|
595
|
+
impulse.normalImpulses[j] = vc.points[j].normalImpulse;
|
596
|
+
impulse.tangentImpulses[j] = vc.points[j].tangentImpulse;
|
597
|
+
}
|
598
|
+
|
599
|
+
m_listener.postSolve(c, impulse);
|
600
|
+
}
|
601
|
+
}
|
602
|
+
}
|
@@ -0,0 +1,97 @@
|
|
1
|
+
/*******************************************************************************
|
2
|
+
* Copyright (c) 2013, Daniel Murphy
|
3
|
+
* All rights reserved.
|
4
|
+
*
|
5
|
+
* Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
* are permitted provided that the following conditions are met:
|
7
|
+
* * Redistributions of source code must retain the above copyright notice,
|
8
|
+
* this list of conditions and the following disclaimer.
|
9
|
+
* * Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
* this list of conditions and the following disclaimer in the documentation
|
11
|
+
* and/or other materials provided with the distribution.
|
12
|
+
*
|
13
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
14
|
+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
15
|
+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
16
|
+
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
17
|
+
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
18
|
+
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
19
|
+
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
20
|
+
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
21
|
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
22
|
+
* POSSIBILITY OF SUCH DAMAGE.
|
23
|
+
******************************************************************************/
|
24
|
+
package org.jbox2d.dynamics;
|
25
|
+
|
26
|
+
import java.util.List;
|
27
|
+
|
28
|
+
import org.jbox2d.common.MathUtils;
|
29
|
+
|
30
|
+
public class Profile {
|
31
|
+
private static final int LONG_AVG_NUMS = 20;
|
32
|
+
private static final float LONG_FRACTION = 1f / LONG_AVG_NUMS;
|
33
|
+
private static final int SHORT_AVG_NUMS = 5;
|
34
|
+
private static final float SHORT_FRACTION = 1f / SHORT_AVG_NUMS;
|
35
|
+
|
36
|
+
public static class ProfileEntry {
|
37
|
+
float longAvg;
|
38
|
+
float shortAvg;
|
39
|
+
float min;
|
40
|
+
float max;
|
41
|
+
float accum;
|
42
|
+
|
43
|
+
public ProfileEntry() {
|
44
|
+
min = Float.MAX_VALUE;
|
45
|
+
max = -Float.MAX_VALUE;
|
46
|
+
}
|
47
|
+
|
48
|
+
public void record(float value) {
|
49
|
+
longAvg = longAvg * (1 - LONG_FRACTION) + value * LONG_FRACTION;
|
50
|
+
shortAvg = shortAvg * (1 - SHORT_FRACTION) + value * SHORT_FRACTION;
|
51
|
+
min = MathUtils.min(value, min);
|
52
|
+
max = MathUtils.max(value, max);
|
53
|
+
}
|
54
|
+
|
55
|
+
public void startAccum() {
|
56
|
+
accum = 0;
|
57
|
+
}
|
58
|
+
|
59
|
+
public void accum(float value) {
|
60
|
+
accum += value;
|
61
|
+
}
|
62
|
+
|
63
|
+
public void endAccum() {
|
64
|
+
record(accum);
|
65
|
+
}
|
66
|
+
|
67
|
+
@Override
|
68
|
+
public String toString() {
|
69
|
+
return String.format("%.2f (%.2f) [%.2f,%.2f]", shortAvg, longAvg, min, max);
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
public final ProfileEntry step = new ProfileEntry();
|
74
|
+
public final ProfileEntry stepInit = new ProfileEntry();
|
75
|
+
public final ProfileEntry collide = new ProfileEntry();
|
76
|
+
public final ProfileEntry solveParticleSystem = new ProfileEntry();
|
77
|
+
public final ProfileEntry solve = new ProfileEntry();
|
78
|
+
public final ProfileEntry solveInit = new ProfileEntry();
|
79
|
+
public final ProfileEntry solveVelocity = new ProfileEntry();
|
80
|
+
public final ProfileEntry solvePosition = new ProfileEntry();
|
81
|
+
public final ProfileEntry broadphase = new ProfileEntry();
|
82
|
+
public final ProfileEntry solveTOI = new ProfileEntry();
|
83
|
+
|
84
|
+
public void toDebugStrings(List<String> strings) {
|
85
|
+
strings.add("Profile:");
|
86
|
+
strings.add(" step: " + step);
|
87
|
+
strings.add(" init: " + stepInit);
|
88
|
+
strings.add(" collide: " + collide);
|
89
|
+
strings.add(" particles: " + solveParticleSystem);
|
90
|
+
strings.add(" solve: " + solve);
|
91
|
+
strings.add(" solveInit: " + solveInit);
|
92
|
+
strings.add(" solveVelocity: " + solveVelocity);
|
93
|
+
strings.add(" solvePosition: " + solvePosition);
|
94
|
+
strings.add(" broadphase: " + broadphase);
|
95
|
+
strings.add(" solveTOI: " + solveTOI);
|
96
|
+
}
|
97
|
+
}
|