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.
Files changed (154) hide show
  1. checksums.yaml +4 -4
  2. data/.mvn/extensions.xml +8 -0
  3. data/.mvn/wrapper/maven-wrapper.properties +1 -0
  4. data/.travis.yml +23 -0
  5. data/CHANGELOG.md +8 -0
  6. data/README.md +7 -7
  7. data/Rakefile +1 -2
  8. data/lib/box2d.jar +0 -0
  9. data/lib/pbox2d/version.rb +1 -1
  10. data/lib/pbox2d.rb +1 -0
  11. data/pbox2d.gemspec +6 -11
  12. data/pom.rb +59 -0
  13. data/pom.xml +82 -73
  14. data/src/org/jbox2d/JBox2D.gwt.xml +12 -0
  15. data/src/org/jbox2d/callbacks/ContactAdaptor.java +27 -0
  16. data/src/org/jbox2d/callbacks/ContactFilter.java +59 -0
  17. data/src/org/jbox2d/callbacks/ContactImpulse.java +42 -0
  18. data/src/org/jbox2d/callbacks/ContactListener.java +87 -0
  19. data/src/org/jbox2d/callbacks/DebugDraw.java +297 -0
  20. data/src/org/jbox2d/callbacks/DestructionListener.java +53 -0
  21. data/src/org/jbox2d/callbacks/PairCallback.java +29 -0
  22. data/src/org/jbox2d/callbacks/ParticleDestructionListener.java +20 -0
  23. data/src/org/jbox2d/callbacks/ParticleQueryCallback.java +19 -0
  24. data/src/org/jbox2d/callbacks/ParticleRaycastCallback.java +19 -0
  25. data/src/org/jbox2d/callbacks/QueryCallback.java +45 -0
  26. data/src/org/jbox2d/callbacks/RayCastCallback.java +55 -0
  27. data/src/org/jbox2d/callbacks/TreeCallback.java +42 -0
  28. data/src/org/jbox2d/callbacks/TreeRayCastCallback.java +44 -0
  29. data/src/org/jbox2d/collision/AABB.java +338 -0
  30. data/src/org/jbox2d/collision/Collision.java +1444 -0
  31. data/src/org/jbox2d/collision/ContactID.java +106 -0
  32. data/src/org/jbox2d/collision/Distance.java +773 -0
  33. data/src/org/jbox2d/collision/DistanceInput.java +41 -0
  34. data/src/org/jbox2d/collision/DistanceOutput.java +43 -0
  35. data/src/org/jbox2d/collision/Manifold.java +116 -0
  36. data/src/org/jbox2d/collision/ManifoldPoint.java +104 -0
  37. data/src/org/jbox2d/collision/RayCastInput.java +47 -0
  38. data/src/org/jbox2d/collision/RayCastOutput.java +46 -0
  39. data/src/org/jbox2d/collision/TimeOfImpact.java +526 -0
  40. data/src/org/jbox2d/collision/WorldManifold.java +200 -0
  41. data/src/org/jbox2d/collision/broadphase/BroadPhase.java +92 -0
  42. data/src/org/jbox2d/collision/broadphase/BroadPhaseStrategy.java +88 -0
  43. data/src/org/jbox2d/collision/broadphase/DefaultBroadPhaseBuffer.java +268 -0
  44. data/src/org/jbox2d/collision/broadphase/DynamicTree.java +883 -0
  45. data/src/org/jbox2d/collision/broadphase/DynamicTreeFlatNodes.java +873 -0
  46. data/src/org/jbox2d/collision/broadphase/DynamicTreeNode.java +54 -0
  47. data/src/org/jbox2d/collision/broadphase/Pair.java +46 -0
  48. data/src/org/jbox2d/collision/shapes/ChainShape.java +264 -0
  49. data/src/org/jbox2d/collision/shapes/CircleShape.java +207 -0
  50. data/src/org/jbox2d/collision/shapes/EdgeShape.java +254 -0
  51. data/src/org/jbox2d/collision/shapes/MassData.java +105 -0
  52. data/src/org/jbox2d/collision/shapes/PolygonShape.java +718 -0
  53. data/src/org/jbox2d/collision/shapes/Shape.java +136 -0
  54. data/src/org/jbox2d/collision/shapes/ShapeType.java +32 -0
  55. data/src/org/jbox2d/common/BufferUtils.java +209 -0
  56. data/src/org/jbox2d/common/Color3f.java +88 -0
  57. data/src/org/jbox2d/common/IViewportTransform.java +133 -0
  58. data/src/org/jbox2d/common/Mat22.java +609 -0
  59. data/src/org/jbox2d/common/Mat33.java +290 -0
  60. data/src/org/jbox2d/common/MathUtils.java +335 -0
  61. data/src/org/jbox2d/common/OBBViewportTransform.java +174 -0
  62. data/src/org/jbox2d/common/PlatformMathUtils.java +46 -0
  63. data/src/org/jbox2d/common/RaycastResult.java +37 -0
  64. data/src/org/jbox2d/common/Rot.java +150 -0
  65. data/src/org/jbox2d/common/Settings.java +246 -0
  66. data/src/org/jbox2d/common/Sweep.java +116 -0
  67. data/src/org/jbox2d/common/Timer.java +46 -0
  68. data/src/org/jbox2d/common/Transform.java +203 -0
  69. data/src/org/jbox2d/common/Vec2.java +388 -0
  70. data/src/org/jbox2d/common/Vec3.java +170 -0
  71. data/src/org/jbox2d/dynamics/Body.java +1246 -0
  72. data/src/org/jbox2d/dynamics/BodyDef.java +382 -0
  73. data/src/org/jbox2d/dynamics/BodyType.java +41 -0
  74. data/src/org/jbox2d/dynamics/ContactManager.java +293 -0
  75. data/src/org/jbox2d/dynamics/Filter.java +62 -0
  76. data/src/org/jbox2d/dynamics/Fixture.java +454 -0
  77. data/src/org/jbox2d/dynamics/FixtureDef.java +214 -0
  78. data/src/org/jbox2d/dynamics/FixtureProxy.java +38 -0
  79. data/src/org/jbox2d/dynamics/Island.java +602 -0
  80. data/src/org/jbox2d/dynamics/Profile.java +97 -0
  81. data/src/org/jbox2d/dynamics/SolverData.java +33 -0
  82. data/src/org/jbox2d/dynamics/TimeStep.java +46 -0
  83. data/src/org/jbox2d/dynamics/World.java +2075 -0
  84. data/src/org/jbox2d/dynamics/contacts/ChainAndCircleContact.java +57 -0
  85. data/src/org/jbox2d/dynamics/contacts/ChainAndPolygonContact.java +57 -0
  86. data/src/org/jbox2d/dynamics/contacts/CircleContact.java +50 -0
  87. data/src/org/jbox2d/dynamics/contacts/Contact.java +365 -0
  88. data/src/org/jbox2d/dynamics/contacts/ContactCreator.java +35 -0
  89. data/src/org/jbox2d/dynamics/contacts/ContactEdge.java +56 -0
  90. data/src/org/jbox2d/dynamics/contacts/ContactPositionConstraint.java +49 -0
  91. data/src/org/jbox2d/dynamics/contacts/ContactRegister.java +31 -0
  92. data/src/org/jbox2d/dynamics/contacts/ContactSolver.java +1104 -0
  93. data/src/org/jbox2d/dynamics/contacts/ContactVelocityConstraint.java +60 -0
  94. data/src/org/jbox2d/dynamics/contacts/EdgeAndCircleContact.java +52 -0
  95. data/src/org/jbox2d/dynamics/contacts/EdgeAndPolygonContact.java +52 -0
  96. data/src/org/jbox2d/dynamics/contacts/PolygonAndCircleContact.java +51 -0
  97. data/src/org/jbox2d/dynamics/contacts/PolygonContact.java +50 -0
  98. data/src/org/jbox2d/dynamics/contacts/Position.java +31 -0
  99. data/src/org/jbox2d/dynamics/contacts/Velocity.java +31 -0
  100. data/src/org/jbox2d/dynamics/joints/ConstantVolumeJoint.java +258 -0
  101. data/src/org/jbox2d/dynamics/joints/ConstantVolumeJointDef.java +75 -0
  102. data/src/org/jbox2d/dynamics/joints/DistanceJoint.java +356 -0
  103. data/src/org/jbox2d/dynamics/joints/DistanceJointDef.java +106 -0
  104. data/src/org/jbox2d/dynamics/joints/FrictionJoint.java +294 -0
  105. data/src/org/jbox2d/dynamics/joints/FrictionJointDef.java +78 -0
  106. data/src/org/jbox2d/dynamics/joints/GearJoint.java +520 -0
  107. data/src/org/jbox2d/dynamics/joints/GearJointDef.java +58 -0
  108. data/src/org/jbox2d/dynamics/joints/Jacobian.java +32 -0
  109. data/src/org/jbox2d/dynamics/joints/Joint.java +235 -0
  110. data/src/org/jbox2d/dynamics/joints/JointDef.java +65 -0
  111. data/src/org/jbox2d/dynamics/joints/JointEdge.java +57 -0
  112. data/src/org/jbox2d/dynamics/joints/JointType.java +28 -0
  113. data/src/org/jbox2d/dynamics/joints/LimitState.java +28 -0
  114. data/src/org/jbox2d/dynamics/joints/MotorJoint.java +339 -0
  115. data/src/org/jbox2d/dynamics/joints/MotorJointDef.java +55 -0
  116. data/src/org/jbox2d/dynamics/joints/MouseJoint.java +262 -0
  117. data/src/org/jbox2d/dynamics/joints/MouseJointDef.java +62 -0
  118. data/src/org/jbox2d/dynamics/joints/PrismaticJoint.java +808 -0
  119. data/src/org/jbox2d/dynamics/joints/PrismaticJointDef.java +120 -0
  120. data/src/org/jbox2d/dynamics/joints/PulleyJoint.java +393 -0
  121. data/src/org/jbox2d/dynamics/joints/PulleyJointDef.java +105 -0
  122. data/src/org/jbox2d/dynamics/joints/RevoluteJoint.java +554 -0
  123. data/src/org/jbox2d/dynamics/joints/RevoluteJointDef.java +137 -0
  124. data/src/org/jbox2d/dynamics/joints/RopeJoint.java +276 -0
  125. data/src/org/jbox2d/dynamics/joints/RopeJointDef.java +34 -0
  126. data/src/org/jbox2d/dynamics/joints/WeldJoint.java +424 -0
  127. data/src/org/jbox2d/dynamics/joints/WeldJointDef.java +85 -0
  128. data/src/org/jbox2d/dynamics/joints/WheelJoint.java +498 -0
  129. data/src/org/jbox2d/dynamics/joints/WheelJointDef.java +98 -0
  130. data/src/org/jbox2d/particle/ParticleBodyContact.java +17 -0
  131. data/src/org/jbox2d/particle/ParticleColor.java +52 -0
  132. data/src/org/jbox2d/particle/ParticleContact.java +14 -0
  133. data/src/org/jbox2d/particle/ParticleDef.java +24 -0
  134. data/src/org/jbox2d/particle/ParticleGroup.java +154 -0
  135. data/src/org/jbox2d/particle/ParticleGroupDef.java +62 -0
  136. data/src/org/jbox2d/particle/ParticleGroupType.java +8 -0
  137. data/src/org/jbox2d/particle/ParticleSystem.java +2172 -0
  138. data/src/org/jbox2d/particle/ParticleType.java +28 -0
  139. data/src/org/jbox2d/particle/StackQueue.java +44 -0
  140. data/src/org/jbox2d/particle/VoronoiDiagram.java +209 -0
  141. data/src/org/jbox2d/pooling/IDynamicStack.java +47 -0
  142. data/src/org/jbox2d/pooling/IOrderedStack.java +57 -0
  143. data/src/org/jbox2d/pooling/IWorldPool.java +101 -0
  144. data/src/org/jbox2d/pooling/arrays/FloatArray.java +50 -0
  145. data/src/org/jbox2d/pooling/arrays/GeneratorArray.java +33 -0
  146. data/src/org/jbox2d/pooling/arrays/IntArray.java +53 -0
  147. data/src/org/jbox2d/pooling/arrays/Vec2Array.java +57 -0
  148. data/src/org/jbox2d/pooling/normal/CircleStack.java +77 -0
  149. data/src/org/jbox2d/pooling/normal/DefaultWorldPool.java +331 -0
  150. data/src/org/jbox2d/pooling/normal/MutableStack.java +72 -0
  151. data/src/org/jbox2d/pooling/normal/OrderedStack.java +73 -0
  152. data/src/org/jbox2d/pooling/stacks/DynamicIntStack.java +60 -0
  153. metadata +161 -14
  154. 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
+ }