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,883 @@
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.collision.broadphase;
25
+
26
+ import org.jbox2d.callbacks.DebugDraw;
27
+ import org.jbox2d.callbacks.TreeCallback;
28
+ import org.jbox2d.callbacks.TreeRayCastCallback;
29
+ import org.jbox2d.collision.AABB;
30
+ import org.jbox2d.collision.RayCastInput;
31
+ import org.jbox2d.common.Color3f;
32
+ import org.jbox2d.common.MathUtils;
33
+ import org.jbox2d.common.Settings;
34
+ import org.jbox2d.common.Vec2;
35
+
36
+ /**
37
+ * A dynamic tree arranges data in a binary tree to accelerate queries such as volume queries and
38
+ * ray casts. Leafs are proxies with an AABB. In the tree we expand the proxy AABB by _fatAABBFactor
39
+ * so that the proxy AABB is bigger than the client object. This allows the client object to move by
40
+ * small amounts without triggering a tree update.
41
+ *
42
+ * @author daniel
43
+ */
44
+ public class DynamicTree implements BroadPhaseStrategy {
45
+ public static final int MAX_STACK_SIZE = 64;
46
+ public static final int NULL_NODE = -1;
47
+
48
+ private DynamicTreeNode m_root;
49
+ private DynamicTreeNode[] m_nodes;
50
+ private int m_nodeCount;
51
+ private int m_nodeCapacity;
52
+
53
+ private int m_freeList;
54
+
55
+ private final Vec2[] drawVecs = new Vec2[4];
56
+ private DynamicTreeNode[] nodeStack = new DynamicTreeNode[20];
57
+ private int nodeStackIndex = 0;
58
+
59
+ public DynamicTree() {
60
+ m_root = null;
61
+ m_nodeCount = 0;
62
+ m_nodeCapacity = 16;
63
+ m_nodes = new DynamicTreeNode[16];
64
+
65
+ // Build a linked list for the free list.
66
+ for (int i = m_nodeCapacity - 1; i >= 0; i--) {
67
+ m_nodes[i] = new DynamicTreeNode(i);
68
+ m_nodes[i].parent = (i == m_nodeCapacity - 1) ? null : m_nodes[i + 1];
69
+ m_nodes[i].height = -1;
70
+ }
71
+ m_freeList = 0;
72
+
73
+ for (int i = 0; i < drawVecs.length; i++) {
74
+ drawVecs[i] = new Vec2();
75
+ }
76
+ }
77
+
78
+ @Override
79
+ public final int createProxy(final AABB aabb, Object userData) {
80
+ assert(aabb.isValid());
81
+ final DynamicTreeNode node = allocateNode();
82
+ int proxyId = node.id;
83
+ // Fatten the aabb
84
+ final AABB nodeAABB = node.aabb;
85
+ nodeAABB.lowerBound.x = aabb.lowerBound.x - Settings.aabbExtension;
86
+ nodeAABB.lowerBound.y = aabb.lowerBound.y - Settings.aabbExtension;
87
+ nodeAABB.upperBound.x = aabb.upperBound.x + Settings.aabbExtension;
88
+ nodeAABB.upperBound.y = aabb.upperBound.y + Settings.aabbExtension;
89
+ node.userData = userData;
90
+
91
+ insertLeaf(proxyId);
92
+
93
+ return proxyId;
94
+ }
95
+
96
+ @Override
97
+ public final void destroyProxy(int proxyId) {
98
+ assert (0 <= proxyId && proxyId < m_nodeCapacity);
99
+ DynamicTreeNode node = m_nodes[proxyId];
100
+ assert (node.child1 == null);
101
+
102
+ removeLeaf(node);
103
+ freeNode(node);
104
+ }
105
+
106
+ @Override
107
+ public final boolean moveProxy(int proxyId, final AABB aabb, Vec2 displacement) {
108
+ assert(aabb.isValid());
109
+ assert (0 <= proxyId && proxyId < m_nodeCapacity);
110
+ final DynamicTreeNode node = m_nodes[proxyId];
111
+ assert (node.child1 == null);
112
+
113
+ final AABB nodeAABB = node.aabb;
114
+ // if (nodeAABB.contains(aabb)) {
115
+ if (nodeAABB.lowerBound.x <= aabb.lowerBound.x && nodeAABB.lowerBound.y <= aabb.lowerBound.y
116
+ && aabb.upperBound.x <= nodeAABB.upperBound.x && aabb.upperBound.y <= nodeAABB.upperBound.y) {
117
+ return false;
118
+ }
119
+
120
+ removeLeaf(node);
121
+
122
+ // Extend AABB
123
+ final Vec2 lowerBound = nodeAABB.lowerBound;
124
+ final Vec2 upperBound = nodeAABB.upperBound;
125
+ lowerBound.x = aabb.lowerBound.x - Settings.aabbExtension;
126
+ lowerBound.y = aabb.lowerBound.y - Settings.aabbExtension;
127
+ upperBound.x = aabb.upperBound.x + Settings.aabbExtension;
128
+ upperBound.y = aabb.upperBound.y + Settings.aabbExtension;
129
+
130
+ // Predict AABB displacement.
131
+ final float dx = displacement.x * Settings.aabbMultiplier;
132
+ final float dy = displacement.y * Settings.aabbMultiplier;
133
+ if (dx < 0.0f) {
134
+ lowerBound.x += dx;
135
+ } else {
136
+ upperBound.x += dx;
137
+ }
138
+
139
+ if (dy < 0.0f) {
140
+ lowerBound.y += dy;
141
+ } else {
142
+ upperBound.y += dy;
143
+ }
144
+
145
+ insertLeaf(proxyId);
146
+ return true;
147
+ }
148
+
149
+ @Override
150
+ public final Object getUserData(int proxyId) {
151
+ assert (0 <= proxyId && proxyId < m_nodeCapacity);
152
+ return m_nodes[proxyId].userData;
153
+ }
154
+
155
+ @Override
156
+ public final AABB getFatAABB(int proxyId) {
157
+ assert (0 <= proxyId && proxyId < m_nodeCapacity);
158
+ return m_nodes[proxyId].aabb;
159
+ }
160
+
161
+ @Override
162
+ public final void query(TreeCallback callback, AABB aabb) {
163
+ assert(aabb.isValid());
164
+ nodeStackIndex = 0;
165
+ nodeStack[nodeStackIndex++] = m_root;
166
+
167
+ while (nodeStackIndex > 0) {
168
+ DynamicTreeNode node = nodeStack[--nodeStackIndex];
169
+ if (node == null) {
170
+ continue;
171
+ }
172
+
173
+ if (AABB.testOverlap(node.aabb, aabb)) {
174
+ if (node.child1 == null) {
175
+ boolean proceed = callback.treeCallback(node.id);
176
+ if (!proceed) {
177
+ return;
178
+ }
179
+ } else {
180
+ if (nodeStack.length - nodeStackIndex - 2 <= 0) {
181
+ DynamicTreeNode[] newBuffer = new DynamicTreeNode[nodeStack.length * 2];
182
+ System.arraycopy(nodeStack, 0, newBuffer, 0, nodeStack.length);
183
+ nodeStack = newBuffer;
184
+ }
185
+ nodeStack[nodeStackIndex++] = node.child1;
186
+ nodeStack[nodeStackIndex++] = node.child2;
187
+ }
188
+ }
189
+ }
190
+ }
191
+
192
+ private final Vec2 r = new Vec2();
193
+ private final AABB aabb = new AABB();
194
+ private final RayCastInput subInput = new RayCastInput();
195
+
196
+ @Override
197
+ public void raycast(TreeRayCastCallback callback, RayCastInput input) {
198
+ final Vec2 p1 = input.p1;
199
+ final Vec2 p2 = input.p2;
200
+ float p1x = p1.x, p2x = p2.x, p1y = p1.y, p2y = p2.y;
201
+ float vx, vy;
202
+ float rx, ry;
203
+ float absVx, absVy;
204
+ float cx, cy;
205
+ float hx, hy;
206
+ float tempx, tempy;
207
+ r.x = p2x - p1x;
208
+ r.y = p2y - p1y;
209
+ assert ((r.x * r.x + r.y * r.y) > 0f);
210
+ r.normalize();
211
+ rx = r.x;
212
+ ry = r.y;
213
+
214
+ // v is perpendicular to the segment.
215
+ vx = -1f * ry;
216
+ vy = 1f * rx;
217
+ absVx = MathUtils.abs(vx);
218
+ absVy = MathUtils.abs(vy);
219
+
220
+ // Separating axis for segment (Gino, p80).
221
+ // |dot(v, p1 - c)| > dot(|v|, h)
222
+
223
+ float maxFraction = input.maxFraction;
224
+
225
+ // Build a bounding box for the segment.
226
+ final AABB segAABB = aabb;
227
+ // Vec2 t = p1 + maxFraction * (p2 - p1);
228
+ // before inline
229
+ // temp.set(p2).subLocal(p1).mulLocal(maxFraction).addLocal(p1);
230
+ // Vec2.minToOut(p1, temp, segAABB.lowerBound);
231
+ // Vec2.maxToOut(p1, temp, segAABB.upperBound);
232
+ tempx = (p2x - p1x) * maxFraction + p1x;
233
+ tempy = (p2y - p1y) * maxFraction + p1y;
234
+ segAABB.lowerBound.x = p1x < tempx ? p1x : tempx;
235
+ segAABB.lowerBound.y = p1y < tempy ? p1y : tempy;
236
+ segAABB.upperBound.x = p1x > tempx ? p1x : tempx;
237
+ segAABB.upperBound.y = p1y > tempy ? p1y : tempy;
238
+ // end inline
239
+
240
+ nodeStackIndex = 0;
241
+ nodeStack[nodeStackIndex++] = m_root;
242
+ while (nodeStackIndex > 0) {
243
+ final DynamicTreeNode node = nodeStack[--nodeStackIndex];
244
+ if (node == null) {
245
+ continue;
246
+ }
247
+
248
+ final AABB nodeAABB = node.aabb;
249
+ if (!AABB.testOverlap(nodeAABB, segAABB)) {
250
+ continue;
251
+ }
252
+
253
+ // Separating axis for segment (Gino, p80).
254
+ // |dot(v, p1 - c)| > dot(|v|, h)
255
+ // node.aabb.getCenterToOut(c);
256
+ // node.aabb.getExtentsToOut(h);
257
+ cx = (nodeAABB.lowerBound.x + nodeAABB.upperBound.x) * .5f;
258
+ cy = (nodeAABB.lowerBound.y + nodeAABB.upperBound.y) * .5f;
259
+ hx = (nodeAABB.upperBound.x - nodeAABB.lowerBound.x) * .5f;
260
+ hy = (nodeAABB.upperBound.y - nodeAABB.lowerBound.y) * .5f;
261
+ tempx = p1x - cx;
262
+ tempy = p1y - cy;
263
+ float separation = MathUtils.abs(vx * tempx + vy * tempy) - (absVx * hx + absVy * hy);
264
+ if (separation > 0.0f) {
265
+ continue;
266
+ }
267
+
268
+ if (node.child1 == null) {
269
+ subInput.p1.x = p1x;
270
+ subInput.p1.y = p1y;
271
+ subInput.p2.x = p2x;
272
+ subInput.p2.y = p2y;
273
+ subInput.maxFraction = maxFraction;
274
+
275
+ float value = callback.raycastCallback(subInput, node.id);
276
+
277
+ if (value == 0.0f) {
278
+ // The client has terminated the ray cast.
279
+ return;
280
+ }
281
+
282
+ if (value > 0.0f) {
283
+ // Update segment bounding box.
284
+ maxFraction = value;
285
+ // temp.set(p2).subLocal(p1).mulLocal(maxFraction).addLocal(p1);
286
+ // Vec2.minToOut(p1, temp, segAABB.lowerBound);
287
+ // Vec2.maxToOut(p1, temp, segAABB.upperBound);
288
+ tempx = (p2x - p1x) * maxFraction + p1x;
289
+ tempy = (p2y - p1y) * maxFraction + p1y;
290
+ segAABB.lowerBound.x = p1x < tempx ? p1x : tempx;
291
+ segAABB.lowerBound.y = p1y < tempy ? p1y : tempy;
292
+ segAABB.upperBound.x = p1x > tempx ? p1x : tempx;
293
+ segAABB.upperBound.y = p1y > tempy ? p1y : tempy;
294
+ }
295
+ } else {
296
+ if (nodeStack.length - nodeStackIndex - 2 <= 0) {
297
+ DynamicTreeNode[] newBuffer = new DynamicTreeNode[nodeStack.length * 2];
298
+ System.arraycopy(nodeStack, 0, newBuffer, 0, nodeStack.length);
299
+ nodeStack = newBuffer;
300
+ }
301
+ nodeStack[nodeStackIndex++] = node.child1;
302
+ nodeStack[nodeStackIndex++] = node.child2;
303
+ }
304
+ }
305
+ }
306
+
307
+ @Override
308
+ public final int computeHeight() {
309
+ return computeHeight(m_root);
310
+ }
311
+
312
+ private final int computeHeight(DynamicTreeNode node) {
313
+ assert (0 <= node.id && node.id < m_nodeCapacity);
314
+
315
+ if (node.child1 == null) {
316
+ return 0;
317
+ }
318
+ int height1 = computeHeight(node.child1);
319
+ int height2 = computeHeight(node.child2);
320
+ return 1 + MathUtils.max(height1, height2);
321
+ }
322
+
323
+ /**
324
+ * Validate this tree. For testing.
325
+ */
326
+ public void validate() {
327
+ validateStructure(m_root);
328
+ validateMetrics(m_root);
329
+
330
+ int freeCount = 0;
331
+ DynamicTreeNode freeNode = m_freeList != NULL_NODE ? m_nodes[m_freeList] : null;
332
+ while (freeNode != null) {
333
+ assert (0 <= freeNode.id && freeNode.id < m_nodeCapacity);
334
+ assert (freeNode == m_nodes[freeNode.id]);
335
+ freeNode = freeNode.parent;
336
+ ++freeCount;
337
+ }
338
+
339
+ assert (getHeight() == computeHeight());
340
+
341
+ assert (m_nodeCount + freeCount == m_nodeCapacity);
342
+ }
343
+
344
+ @Override
345
+ public int getHeight() {
346
+ if (m_root == null) {
347
+ return 0;
348
+ }
349
+ return m_root.height;
350
+ }
351
+
352
+ @Override
353
+ public int getMaxBalance() {
354
+ int maxBalance = 0;
355
+ for (int i = 0; i < m_nodeCapacity; ++i) {
356
+ final DynamicTreeNode node = m_nodes[i];
357
+ if (node.height <= 1) {
358
+ continue;
359
+ }
360
+
361
+ assert (node.child1 == null == false);
362
+
363
+ DynamicTreeNode child1 = node.child1;
364
+ DynamicTreeNode child2 = node.child2;
365
+ int balance = MathUtils.abs(child2.height - child1.height);
366
+ maxBalance = MathUtils.max(maxBalance, balance);
367
+ }
368
+
369
+ return maxBalance;
370
+ }
371
+
372
+ @Override
373
+ public float getAreaRatio() {
374
+ if (m_root == null) {
375
+ return 0.0f;
376
+ }
377
+
378
+ final DynamicTreeNode root = m_root;
379
+ float rootArea = root.aabb.getPerimeter();
380
+
381
+ float totalArea = 0.0f;
382
+ for (int i = 0; i < m_nodeCapacity; ++i) {
383
+ final DynamicTreeNode node = m_nodes[i];
384
+ if (node.height < 0) {
385
+ // Free node in pool
386
+ continue;
387
+ }
388
+
389
+ totalArea += node.aabb.getPerimeter();
390
+ }
391
+
392
+ return totalArea / rootArea;
393
+ }
394
+
395
+ /**
396
+ * Build an optimal tree. Very expensive. For testing.
397
+ */
398
+ public void rebuildBottomUp() {
399
+ int[] nodes = new int[m_nodeCount];
400
+ int count = 0;
401
+
402
+ // Build array of leaves. Free the rest.
403
+ for (int i = 0; i < m_nodeCapacity; ++i) {
404
+ if (m_nodes[i].height < 0) {
405
+ // free node in pool
406
+ continue;
407
+ }
408
+
409
+ DynamicTreeNode node = m_nodes[i];
410
+ if (node.child1 == null) {
411
+ node.parent = null;
412
+ nodes[count] = i;
413
+ ++count;
414
+ } else {
415
+ freeNode(node);
416
+ }
417
+ }
418
+
419
+ AABB b = new AABB();
420
+ while (count > 1) {
421
+ float minCost = Float.MAX_VALUE;
422
+ int iMin = -1, jMin = -1;
423
+ for (int i = 0; i < count; ++i) {
424
+ AABB aabbi = m_nodes[nodes[i]].aabb;
425
+
426
+ for (int j = i + 1; j < count; ++j) {
427
+ AABB aabbj = m_nodes[nodes[j]].aabb;
428
+ b.combine(aabbi, aabbj);
429
+ float cost = b.getPerimeter();
430
+ if (cost < minCost) {
431
+ iMin = i;
432
+ jMin = j;
433
+ minCost = cost;
434
+ }
435
+ }
436
+ }
437
+
438
+ int index1 = nodes[iMin];
439
+ int index2 = nodes[jMin];
440
+ DynamicTreeNode child1 = m_nodes[index1];
441
+ DynamicTreeNode child2 = m_nodes[index2];
442
+
443
+ DynamicTreeNode parent = allocateNode();
444
+ parent.child1 = child1;
445
+ parent.child2 = child2;
446
+ parent.height = 1 + MathUtils.max(child1.height, child2.height);
447
+ parent.aabb.combine(child1.aabb, child2.aabb);
448
+ parent.parent = null;
449
+
450
+ child1.parent = parent;
451
+ child2.parent = parent;
452
+
453
+ nodes[jMin] = nodes[count - 1];
454
+ nodes[iMin] = parent.id;
455
+ --count;
456
+ }
457
+
458
+ m_root = m_nodes[nodes[0]];
459
+
460
+ validate();
461
+ }
462
+
463
+ private final DynamicTreeNode allocateNode() {
464
+ if (m_freeList == NULL_NODE) {
465
+ assert (m_nodeCount == m_nodeCapacity);
466
+
467
+ DynamicTreeNode[] old = m_nodes;
468
+ m_nodeCapacity *= 2;
469
+ m_nodes = new DynamicTreeNode[m_nodeCapacity];
470
+ System.arraycopy(old, 0, m_nodes, 0, old.length);
471
+
472
+ // Build a linked list for the free list.
473
+ for (int i = m_nodeCapacity - 1; i >= m_nodeCount; i--) {
474
+ m_nodes[i] = new DynamicTreeNode(i);
475
+ m_nodes[i].parent = (i == m_nodeCapacity - 1) ? null : m_nodes[i + 1];
476
+ m_nodes[i].height = -1;
477
+ }
478
+ m_freeList = m_nodeCount;
479
+ }
480
+ int nodeId = m_freeList;
481
+ final DynamicTreeNode treeNode = m_nodes[nodeId];
482
+ m_freeList = treeNode.parent != null ? treeNode.parent.id : NULL_NODE;
483
+
484
+ treeNode.parent = null;
485
+ treeNode.child1 = null;
486
+ treeNode.child2 = null;
487
+ treeNode.height = 0;
488
+ treeNode.userData = null;
489
+ ++m_nodeCount;
490
+ return treeNode;
491
+ }
492
+
493
+ /**
494
+ * returns a node to the pool
495
+ */
496
+ private final void freeNode(DynamicTreeNode node) {
497
+ assert (node != null);
498
+ assert (0 < m_nodeCount);
499
+ node.parent = m_freeList != NULL_NODE ? m_nodes[m_freeList] : null;
500
+ node.height = -1;
501
+ m_freeList = node.id;
502
+ m_nodeCount--;
503
+ }
504
+
505
+ private final AABB combinedAABB = new AABB();
506
+
507
+ private final void insertLeaf(int leaf_index) {
508
+ DynamicTreeNode leaf = m_nodes[leaf_index];
509
+ if (m_root == null) {
510
+ m_root = leaf;
511
+ m_root.parent = null;
512
+ return;
513
+ }
514
+
515
+ // find the best sibling
516
+ AABB leafAABB = leaf.aabb;
517
+ DynamicTreeNode index = m_root;
518
+ while (index.child1 != null) {
519
+ final DynamicTreeNode node = index;
520
+ DynamicTreeNode child1 = node.child1;
521
+ DynamicTreeNode child2 = node.child2;
522
+
523
+ float area = node.aabb.getPerimeter();
524
+
525
+ combinedAABB.combine(node.aabb, leafAABB);
526
+ float combinedArea = combinedAABB.getPerimeter();
527
+
528
+ // Cost of creating a new parent for this node and the new leaf
529
+ float cost = 2.0f * combinedArea;
530
+
531
+ // Minimum cost of pushing the leaf further down the tree
532
+ float inheritanceCost = 2.0f * (combinedArea - area);
533
+
534
+ // Cost of descending into child1
535
+ float cost1;
536
+ if (child1.child1 == null) {
537
+ combinedAABB.combine(leafAABB, child1.aabb);
538
+ cost1 = combinedAABB.getPerimeter() + inheritanceCost;
539
+ } else {
540
+ combinedAABB.combine(leafAABB, child1.aabb);
541
+ float oldArea = child1.aabb.getPerimeter();
542
+ float newArea = combinedAABB.getPerimeter();
543
+ cost1 = (newArea - oldArea) + inheritanceCost;
544
+ }
545
+
546
+ // Cost of descending into child2
547
+ float cost2;
548
+ if (child2.child1 == null) {
549
+ combinedAABB.combine(leafAABB, child2.aabb);
550
+ cost2 = combinedAABB.getPerimeter() + inheritanceCost;
551
+ } else {
552
+ combinedAABB.combine(leafAABB, child2.aabb);
553
+ float oldArea = child2.aabb.getPerimeter();
554
+ float newArea = combinedAABB.getPerimeter();
555
+ cost2 = newArea - oldArea + inheritanceCost;
556
+ }
557
+
558
+ // Descend according to the minimum cost.
559
+ if (cost < cost1 && cost < cost2) {
560
+ break;
561
+ }
562
+
563
+ // Descend
564
+ if (cost1 < cost2) {
565
+ index = child1;
566
+ } else {
567
+ index = child2;
568
+ }
569
+ }
570
+
571
+ DynamicTreeNode sibling = index;
572
+ DynamicTreeNode oldParent = m_nodes[sibling.id].parent;
573
+ final DynamicTreeNode newParent = allocateNode();
574
+ newParent.parent = oldParent;
575
+ newParent.userData = null;
576
+ newParent.aabb.combine(leafAABB, sibling.aabb);
577
+ newParent.height = sibling.height + 1;
578
+
579
+ if (oldParent != null) {
580
+ // The sibling was not the root.
581
+ if (oldParent.child1 == sibling) {
582
+ oldParent.child1 = newParent;
583
+ } else {
584
+ oldParent.child2 = newParent;
585
+ }
586
+
587
+ newParent.child1 = sibling;
588
+ newParent.child2 = leaf;
589
+ sibling.parent = newParent;
590
+ leaf.parent = newParent;
591
+ } else {
592
+ // The sibling was the root.
593
+ newParent.child1 = sibling;
594
+ newParent.child2 = leaf;
595
+ sibling.parent = newParent;
596
+ leaf.parent = newParent;
597
+ m_root = newParent;
598
+ }
599
+
600
+ // Walk back up the tree fixing heights and AABBs
601
+ index = leaf.parent;
602
+ while (index != null) {
603
+ index = balance(index);
604
+
605
+ DynamicTreeNode child1 = index.child1;
606
+ DynamicTreeNode child2 = index.child2;
607
+
608
+ assert (child1 != null);
609
+ assert (child2 != null);
610
+
611
+ index.height = 1 + MathUtils.max(child1.height, child2.height);
612
+ index.aabb.combine(child1.aabb, child2.aabb);
613
+
614
+ index = index.parent;
615
+ }
616
+ // validate();
617
+ }
618
+
619
+ private final void removeLeaf(DynamicTreeNode leaf) {
620
+ if (leaf == m_root) {
621
+ m_root = null;
622
+ return;
623
+ }
624
+
625
+ DynamicTreeNode parent = leaf.parent;
626
+ DynamicTreeNode grandParent = parent.parent;
627
+ DynamicTreeNode sibling;
628
+ if (parent.child1 == leaf) {
629
+ sibling = parent.child2;
630
+ } else {
631
+ sibling = parent.child1;
632
+ }
633
+
634
+ if (grandParent != null) {
635
+ // Destroy parent and connect sibling to grandParent.
636
+ if (grandParent.child1 == parent) {
637
+ grandParent.child1 = sibling;
638
+ } else {
639
+ grandParent.child2 = sibling;
640
+ }
641
+ sibling.parent = grandParent;
642
+ freeNode(parent);
643
+
644
+ // Adjust ancestor bounds.
645
+ DynamicTreeNode index = grandParent;
646
+ while (index != null) {
647
+ index = balance(index);
648
+
649
+ DynamicTreeNode child1 = index.child1;
650
+ DynamicTreeNode child2 = index.child2;
651
+
652
+ index.aabb.combine(child1.aabb, child2.aabb);
653
+ index.height = 1 + MathUtils.max(child1.height, child2.height);
654
+
655
+ index = index.parent;
656
+ }
657
+ } else {
658
+ m_root = sibling;
659
+ sibling.parent = null;
660
+ freeNode(parent);
661
+ }
662
+
663
+ // validate();
664
+ }
665
+
666
+ // Perform a left or right rotation if node A is imbalanced.
667
+ // Returns the new root index.
668
+ private DynamicTreeNode balance(DynamicTreeNode iA) {
669
+ assert (iA != null);
670
+
671
+ DynamicTreeNode A = iA;
672
+ if (A.child1 == null || A.height < 2) {
673
+ return iA;
674
+ }
675
+
676
+ DynamicTreeNode iB = A.child1;
677
+ DynamicTreeNode iC = A.child2;
678
+ assert (0 <= iB.id && iB.id < m_nodeCapacity);
679
+ assert (0 <= iC.id && iC.id < m_nodeCapacity);
680
+
681
+ DynamicTreeNode B = iB;
682
+ DynamicTreeNode C = iC;
683
+
684
+ int balance = C.height - B.height;
685
+
686
+ // Rotate C up
687
+ if (balance > 1) {
688
+ DynamicTreeNode iF = C.child1;
689
+ DynamicTreeNode iG = C.child2;
690
+ DynamicTreeNode F = iF;
691
+ DynamicTreeNode G = iG;
692
+ assert (F != null);
693
+ assert (G != null);
694
+ assert (0 <= iF.id && iF.id < m_nodeCapacity);
695
+ assert (0 <= iG.id && iG.id < m_nodeCapacity);
696
+
697
+ // Swap A and C
698
+ C.child1 = iA;
699
+ C.parent = A.parent;
700
+ A.parent = iC;
701
+
702
+ // A's old parent should point to C
703
+ if (C.parent != null) {
704
+ if (C.parent.child1 == iA) {
705
+ C.parent.child1 = iC;
706
+ } else {
707
+ assert (C.parent.child2 == iA);
708
+ C.parent.child2 = iC;
709
+ }
710
+ } else {
711
+ m_root = iC;
712
+ }
713
+
714
+ // Rotate
715
+ if (F.height > G.height) {
716
+ C.child2 = iF;
717
+ A.child2 = iG;
718
+ G.parent = iA;
719
+ A.aabb.combine(B.aabb, G.aabb);
720
+ C.aabb.combine(A.aabb, F.aabb);
721
+
722
+ A.height = 1 + MathUtils.max(B.height, G.height);
723
+ C.height = 1 + MathUtils.max(A.height, F.height);
724
+ } else {
725
+ C.child2 = iG;
726
+ A.child2 = iF;
727
+ F.parent = iA;
728
+ A.aabb.combine(B.aabb, F.aabb);
729
+ C.aabb.combine(A.aabb, G.aabb);
730
+
731
+ A.height = 1 + MathUtils.max(B.height, F.height);
732
+ C.height = 1 + MathUtils.max(A.height, G.height);
733
+ }
734
+
735
+ return iC;
736
+ }
737
+
738
+ // Rotate B up
739
+ if (balance < -1) {
740
+ DynamicTreeNode iD = B.child1;
741
+ DynamicTreeNode iE = B.child2;
742
+ DynamicTreeNode D = iD;
743
+ DynamicTreeNode E = iE;
744
+ assert (0 <= iD.id && iD.id < m_nodeCapacity);
745
+ assert (0 <= iE.id && iE.id < m_nodeCapacity);
746
+
747
+ // Swap A and B
748
+ B.child1 = iA;
749
+ B.parent = A.parent;
750
+ A.parent = iB;
751
+
752
+ // A's old parent should point to B
753
+ if (B.parent != null) {
754
+ if (B.parent.child1 == iA) {
755
+ B.parent.child1 = iB;
756
+ } else {
757
+ assert (B.parent.child2 == iA);
758
+ B.parent.child2 = iB;
759
+ }
760
+ } else {
761
+ m_root = iB;
762
+ }
763
+
764
+ // Rotate
765
+ if (D.height > E.height) {
766
+ B.child2 = iD;
767
+ A.child1 = iE;
768
+ E.parent = iA;
769
+ A.aabb.combine(C.aabb, E.aabb);
770
+ B.aabb.combine(A.aabb, D.aabb);
771
+
772
+ A.height = 1 + MathUtils.max(C.height, E.height);
773
+ B.height = 1 + MathUtils.max(A.height, D.height);
774
+ } else {
775
+ B.child2 = iE;
776
+ A.child1 = iD;
777
+ D.parent = iA;
778
+ A.aabb.combine(C.aabb, D.aabb);
779
+ B.aabb.combine(A.aabb, E.aabb);
780
+
781
+ A.height = 1 + MathUtils.max(C.height, D.height);
782
+ B.height = 1 + MathUtils.max(A.height, E.height);
783
+ }
784
+
785
+ return iB;
786
+ }
787
+
788
+ return iA;
789
+ }
790
+
791
+ private void validateStructure(DynamicTreeNode node) {
792
+ if (node == null) {
793
+ return;
794
+ }
795
+ assert (node == m_nodes[node.id]);
796
+
797
+ if (node == m_root) {
798
+ assert (node.parent == null);
799
+ }
800
+
801
+ DynamicTreeNode child1 = node.child1;
802
+ DynamicTreeNode child2 = node.child2;
803
+
804
+ if (node.child1 == null) {
805
+ assert (child1 == null);
806
+ assert (child2 == null);
807
+ assert (node.height == 0);
808
+ return;
809
+ }
810
+
811
+ assert (child1 != null && 0 <= child1.id && child1.id < m_nodeCapacity);
812
+ assert (child2 != null && 0 <= child2.id && child2.id < m_nodeCapacity);
813
+
814
+ assert (child1.parent == node);
815
+ assert (child2.parent == node);
816
+
817
+ validateStructure(child1);
818
+ validateStructure(child2);
819
+ }
820
+
821
+ private void validateMetrics(DynamicTreeNode node) {
822
+ if (node == null) {
823
+ return;
824
+ }
825
+
826
+ DynamicTreeNode child1 = node.child1;
827
+ DynamicTreeNode child2 = node.child2;
828
+
829
+ if (node.child1 == null) {
830
+ assert (child1 == null);
831
+ assert (child2 == null);
832
+ assert (node.height == 0);
833
+ return;
834
+ }
835
+
836
+ assert (child1 != null && 0 <= child1.id && child1.id < m_nodeCapacity);
837
+ assert (child2 != null && 0 <= child2.id && child2.id < m_nodeCapacity);
838
+
839
+ int height1 = child1.height;
840
+ int height2 = child2.height;
841
+ int height;
842
+ height = 1 + MathUtils.max(height1, height2);
843
+ assert (node.height == height);
844
+
845
+ AABB aabb = new AABB();
846
+ aabb.combine(child1.aabb, child2.aabb);
847
+
848
+ assert (aabb.lowerBound.equals(node.aabb.lowerBound));
849
+ assert (aabb.upperBound.equals(node.aabb.upperBound));
850
+
851
+ validateMetrics(child1);
852
+ validateMetrics(child2);
853
+ }
854
+
855
+ @Override
856
+ public void drawTree(DebugDraw argDraw) {
857
+ if (m_root == null) {
858
+ return;
859
+ }
860
+ int height = computeHeight();
861
+ drawTree(argDraw, m_root, 0, height);
862
+ }
863
+
864
+ private final Color3f color = new Color3f();
865
+ private final Vec2 textVec = new Vec2();
866
+
867
+ public void drawTree(DebugDraw argDraw, DynamicTreeNode node, int spot, int height) {
868
+ node.aabb.getVertices(drawVecs);
869
+
870
+ color.set(1, (height - spot) * 1f / height, (height - spot) * 1f / height);
871
+ argDraw.drawPolygon(drawVecs, 4, color);
872
+
873
+ argDraw.getViewportTranform().getWorldToScreen(node.aabb.upperBound, textVec);
874
+ argDraw.drawString(textVec.x, textVec.y, node.id + "-" + (spot + 1) + "/" + height, color);
875
+
876
+ if (node.child1 != null) {
877
+ drawTree(argDraw, node.child1, spot + 1, height);
878
+ }
879
+ if (node.child2 != null) {
880
+ drawTree(argDraw, node.child2, spot + 1, height);
881
+ }
882
+ }
883
+ }