Skip to content

Commit 8027cbd

Browse files
Fix DynamicTree Clear (space-wizards#6651)
1 parent 38a8e32 commit 8027cbd

5 files changed

Lines changed: 96 additions & 28 deletions

File tree

RELEASE-NOTES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ END TEMPLATE-->
4343

4444
### Bugfixes
4545

46+
* Fix DynamicTree.Clear not removing node references.
4647
* Reverted validation for `UiBox2i` `ctor`s as it was causing regressions in debug UIs.
4748

4849
### Other

Robust.Shared.Tests/Physics/B2DynamicTree_Test.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,39 @@ public void AddAndQuery()
6666
}
6767
});
6868
}
69+
70+
[Test]
71+
public void RebuildFullPreservesQueries()
72+
{
73+
var dt = new B2DynamicTree<int>();
74+
75+
for (var i = 0; i < aabbs1.Length; ++i)
76+
{
77+
dt.CreateProxy(aabbs1[i], uint.MaxValue, i);
78+
}
79+
80+
dt.Rebuild(true);
81+
82+
var point = new Vector2(0, 0);
83+
var box = Box2.CenteredAround(point, new Vector2(0.1f, 0.1f));
84+
var results = new HashSet<int>();
85+
86+
dt.Query(proxy =>
87+
{
88+
results.Add(dt.GetUserData(proxy));
89+
return true;
90+
}, box);
91+
92+
Assert.Multiple(() =>
93+
{
94+
for (var i = 0; i < aabbs1.Length; i++)
95+
{
96+
if (aabbs1[i].Intersects(box))
97+
{
98+
Assert.That(results, Does.Contain(i));
99+
}
100+
}
101+
});
102+
}
69103
}
70104
}

Robust.Shared.Tests/Physics/DynamicTree_Test.cs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,12 @@ internal sealed class DynamicTree_Test
6060
[Test]
6161
public void AddAndGrow()
6262
{
63-
var dt = new DynamicTree<int>((in int x) => aabbs1[x], capacity: 16, growthFunc: x => x += 2);
63+
const int proxyCapacity = 16;
64+
var dt = new DynamicTree<int>((in int x) => aabbs1[x], capacity: proxyCapacity, growthFunc: x => x += 2);
6465

6566
var initCap = dt.Capacity;
6667

67-
Assert.That(initCap, Is.EqualTo(16));
68+
Assert.That(initCap, Is.EqualTo(2 * proxyCapacity - 1));
6869

6970
Assert.Multiple(() =>
7071
{
@@ -194,6 +195,38 @@ public void AddThenRemove()
194195
});
195196
}
196197

198+
[Test]
199+
public void ClearRemovesAllEntries()
200+
{
201+
var aabbs = new[]
202+
{
203+
((Box2) default).Enlarged(1),
204+
new Box2(float.NaN, float.NaN, float.NaN, float.NaN),
205+
};
206+
207+
var dt = new DynamicTree<int>((in int x) => aabbs[x], capacity: 16, growthFunc: x => x += 2);
208+
209+
Assert.That(dt.Add(0), Is.True);
210+
Assert.That(dt.Add(1), Is.True);
211+
Assert.That(dt.Count, Is.EqualTo(2));
212+
213+
dt.Clear();
214+
215+
Assert.Multiple(() =>
216+
{
217+
Assert.That(dt.Count, Is.Zero);
218+
Assert.That(dt.Contains(0), Is.False);
219+
Assert.That(dt.Contains(1), Is.False);
220+
Assert.That(dt, Is.Empty);
221+
});
222+
223+
Assert.Multiple(() =>
224+
{
225+
Assert.That(dt.Add(0), Is.True);
226+
Assert.That(dt.Add(1), Is.True);
227+
});
228+
}
229+
197230
[Test]
198231
public void AddAndQuery() {
199232
var dt = new DynamicTree<int>((in int x) => aabbs1[x], capacity: 16, growthFunc: x => x += 2);

Robust.Shared/Physics/B2DynamicTree.cs

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,8 @@ public B2DynamicTree(float aabbExtendSize = 1f / 32, int capacity = 256, Func<in
251251
capacity = Math.Max(MinimumCapacity, capacity);
252252

253253
_root = Proxy.Free;
254-
_nodes = new Node[capacity];
254+
// Maximum node count for a full binary tree is 2 * leafCount - 1.
255+
_nodes = new Node[2 * capacity - 1];
255256

256257
// Build a linked list for the free list.
257258
ref var node = ref _nodes[0];
@@ -294,6 +295,10 @@ private ref Node AllocateNode(out Proxy proxy)
294295
_freeList = allocNode.Next;
295296
Assert(_freeList == -1 || _nodes[_freeList].IsFree);
296297
allocNode = default;
298+
allocNode.Parent = Proxy.Free;
299+
allocNode.Next = Proxy.Free;
300+
allocNode.Child1 = Proxy.Free;
301+
allocNode.Child2 = Proxy.Free;
297302
++NodeCount;
298303
proxy = alloc;
299304
return ref allocNode;
@@ -1897,7 +1902,7 @@ public int Rebuild(bool fullBuild)
18971902

18981903
var nodeIndex = _root;
18991904
ref var baseRef = ref _nodes[0];
1900-
var node = baseRef;
1905+
ref var node = ref Unsafe.Add(ref baseRef, nodeIndex);
19011906

19021907
// These are the nodes that get sorted to rebuild the tree.
19031908
// I'm using indices because the node pool may grow during the build.
@@ -1942,7 +1947,7 @@ public int Rebuild(bool fullBuild)
19421947
stack.Push(node.Child2);
19431948
}
19441949

1945-
node = Unsafe.Add(ref baseRef, nodeIndex);
1950+
node = ref Unsafe.Add(ref baseRef, nodeIndex);
19461951

19471952
// Remove doomed node
19481953
FreeNode(doomedNodeIndex);
@@ -1956,7 +1961,7 @@ public int Rebuild(bool fullBuild)
19561961
}
19571962

19581963
nodeIndex = stack.Pop();
1959-
node = Unsafe.Add(ref baseRef, nodeIndex);
1964+
node = ref Unsafe.Add(ref baseRef, nodeIndex);
19601965
}
19611966

19621967
#if B2_VALIDATE
@@ -2068,6 +2073,9 @@ internal void RayCastNew(RayCastInput input, long mask, ref WorldRayCastContext
20682073
var p1 = input.Origin;
20692074
var d = input.Translation;
20702075

2076+
if (d.LengthSquared() < float.Epsilon)
2077+
return;
2078+
20712079
var r = d.Normalized();
20722080

20732081
// v is perpendicular to the segment.
@@ -2084,7 +2092,7 @@ internal void RayCastNew(RayCastInput input, long mask, ref WorldRayCastContext
20842092
// Build a bounding box for the segment.
20852093
var segmentAABB = new Box2(Vector2.Min(p1, p2), Vector2.Max(p1, p2));
20862094

2087-
var stack = new GrowableStack<Proxy>(stackalloc Proxy[256]);
2095+
var stack = new GrowableStack<Proxy>(stackalloc Proxy[TreeStackSize]);
20882096
ref var baseRef = ref _nodes[0];
20892097
stack.Push(_root);
20902098

@@ -2141,15 +2149,10 @@ internal void RayCastNew(RayCastInput input, long mask, ref WorldRayCastContext
21412149
}
21422150
else
21432151
{
2144-
var stackCount = stack.GetCount();
2145-
Assert( stackCount < 256 - 1 );
2146-
if (stackCount < 256 - 1 )
2147-
{
2148-
// TODO_ERIN just put one node on the stack, continue on a child node
2149-
// TODO_ERIN test ordering children by nearest to ray origin
2150-
stack.Push(node.Child1);
2151-
stack.Push(node.Child2);
2152-
}
2152+
// TODO_ERIN just put one node on the stack, continue on a child node
2153+
// TODO_ERIN test ordering children by nearest to ray origin
2154+
stack.Push(node.Child1);
2155+
stack.Push(node.Child2);
21532156
}
21542157
}
21552158
}
@@ -2205,7 +2208,7 @@ internal void ShapeCast(ShapeCastInput input, long maskBits, TreeShapeCastCallba
22052208
var subInput = input;
22062209

22072210
ref var baseRef = ref _nodes[0];
2208-
var stack = new GrowableStack<Proxy>(stackalloc Proxy[256]);
2211+
var stack = new GrowableStack<Proxy>(stackalloc Proxy[TreeStackSize]);
22092212
stack.Push(_root);
22102213

22112214
while (stack.GetCount() > 0)
@@ -2258,16 +2261,10 @@ internal void ShapeCast(ShapeCastInput input, long maskBits, TreeShapeCastCallba
22582261
}
22592262
else
22602263
{
2261-
var stackCount = stack.GetCount();
2262-
Assert(stackCount < 256 - 1);
2263-
2264-
if (stackCount < 255)
2265-
{
2266-
// TODO_ERIN just put one node on the stack, continue on a child node
2267-
// TODO_ERIN test ordering children by nearest to ray origin
2268-
stack.Push(node.Child1);
2269-
stack.Push(node.Child2);
2270-
}
2264+
// TODO_ERIN just put one node on the stack, continue on a child node
2265+
// TODO_ERIN test ordering children by nearest to ray origin
2266+
stack.Push(node.Child1);
2267+
stack.Push(node.Child2);
22712268
}
22722269
}
22732270
}

Robust.Shared/Physics/DynamicTree.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,11 @@ public void Clear()
103103
{
104104
foreach (var proxy in _nodeLookup.Values)
105105
{
106-
_b2Tree.DestroyProxy(proxy);
106+
if (proxy != DynamicTree.Proxy.Free)
107+
_b2Tree.DestroyProxy(proxy);
107108
}
109+
110+
_nodeLookup.Clear();
108111
}
109112

110113
public bool Contains(T item)

0 commit comments

Comments
 (0)