static TestCollidable[] GetRandomLeaves(int leafCount, BoundingBox bounds, Vector3 minimumSize, Vector3 maximumSize, float sizePower, VelocityDescription velocityDescription) { var leaves = new TestCollidable[leafCount]; Random random = new Random(5); var range = bounds.Max - bounds.Min; var sizeRange = maximumSize - minimumSize; for (int i = 0; i < leafCount; ++i) { leaves[i] = new TestCollidable(); leaves[i].HalfSize = 0.5f * (minimumSize + new Vector3((float)Math.Pow(random.NextDouble(), sizePower), (float)Math.Pow(random.NextDouble(), sizePower), (float)Math.Pow(random.NextDouble(), sizePower)) * sizeRange); leaves[i].Position = bounds.Min + new Vector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()) * range; } for (int i = 0; i < leaves.Length * velocityDescription.PortionOfMovingLeaves; ++i) { var speed = (float)(velocityDescription.MinVelocity + (velocityDescription.MaxVelocity - velocityDescription.MinVelocity) * Math.Pow(random.NextDouble(), velocityDescription.VelocityDistributionPower)); var direction = new Vector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()) * 2 - Vector3.One; var lengthSquared = direction.LengthSquared(); if (lengthSquared < 1e-9f) { direction = new Vector3(0, 1, 0); } else { direction /= (float)Math.Sqrt(lengthSquared); } leaves[i].Velocity = speed * direction; } return(leaves); }
static TestCollidable[] GetRandomLeaves(int leafCount, BoundingBox bounds, Vector3 minimumSize, Vector3 maximumSize, float sizePower, VelocityDescription velocityDescription) { var leaves = new TestCollidable[leafCount]; Random random = new Random(5); var range = bounds.Max - bounds.Min; var sizeRange = maximumSize - minimumSize; for (int i = 0; i < leafCount; ++i) { leaves[i] = new TestCollidable(); leaves[i].HalfSize = 0.5f * (minimumSize + new Vector3((float)Math.Pow(random.NextDouble(), sizePower), (float)Math.Pow(random.NextDouble(), sizePower), (float)Math.Pow(random.NextDouble(), sizePower)) * sizeRange); leaves[i].Position = bounds.Min + new Vector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()) * range; } for (int i = 0; i < leaves.Length * velocityDescription.PortionOfMovingLeaves; ++i) { var speed = (float)(velocityDescription.MinVelocity + (velocityDescription.MaxVelocity - velocityDescription.MinVelocity) * Math.Pow(random.NextDouble(), velocityDescription.VelocityDistributionPower)); var direction = new Vector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()) * 2 - Vector3.One; var lengthSquared = direction.LengthSquared(); if (lengthSquared < 1e-9f) { direction = new Vector3(0, 1, 0); } else { direction /= (float)Math.Sqrt(lengthSquared); } leaves[i].Velocity = speed * direction; } return leaves; }
static TestCollidable[] GetLeaves(int width, int height, int length, float size, float gap) { var leaves = new TestCollidable[width * height * length]; var offset = size + gap; for (int i = 0; i < width; ++i) { for (int j = 0; j < height; ++j) { for (int k = 0; k < length; ++k) { var collidable = new TestCollidable(); collidable.HalfSize = new Vector3(size * 0.5f); collidable.Position = collidable.HalfSize + new Vector3(i * offset, j * offset, k * offset); leaves[height * length * i + length * j + k] = collidable; } } } return(leaves); }
static TestCollidable[] GetLeaves(int width, int height, int length, float size, float gap) { var leaves = new TestCollidable[width * height * length]; var offset = size + gap; for (int i = 0; i < width; ++i) { for (int j = 0; j < height; ++j) { for (int k = 0; k < length; ++k) { var collidable = new TestCollidable(); collidable.HalfSize = new Vector3(size * 0.5f); collidable.Position = collidable.HalfSize + new Vector3(i * offset, j * offset, k * offset); leaves[height * length * i + length * j + k] = collidable; } } } return leaves; }
public static void TestBaseline(TestCollidable[] leaves, BoundingBox[] queries, int queryCount, int selfTestCount, int refitCount) { { var warmLeaves = GetLeaves(10, 10, 10, 10, 10); BaselineTree tree = new BaselineTree(); //for (int i = 0; i < leaves.Length; ++i) //{ // tree.Insert(warmLeaves[i]); //} //tree.BuildMedianSplit(warmLeaves); tree.BuildVolumeHeuristic(warmLeaves); Console.WriteLine($"Baseline Cachewarm Build: {tree.LeafCount}"); tree.RefitLeaves(); tree.Refit(); var list = new QuickList<int>(new BufferPool<int>()); BoundingBox aabb = new BoundingBox { Min = new Vector3(0, 0, 0), Max = new Vector3(1, 1, 1) }; tree.QueryRecursive(ref aabb, ref list); list.Dispose(); var overlaps = new QuickList<Overlap<TestCollidable>>(new BufferPool<Overlap<TestCollidable>>()); tree.GetSelfOverlaps(ref overlaps); Console.WriteLine($"Cachewarm overlaps: {overlaps.Count}"); overlaps = new QuickList<Overlap<TestCollidable>>(new BufferPool<Overlap<TestCollidable>>()); tree.GetSelfOverlapsViaQueries(ref overlaps); Console.WriteLine($"Cachewarm overlaps: {overlaps.Count}"); tree.Dispose(); } { Console.WriteLine($"Baseline arity: {BaselineTree.ChildrenCapacity}"); BaselineTree tree = new BaselineTree(leaves.Length, 32); var startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; //for (int i = 0; i < leaves.Length; ++i) //{ // tree.Insert(leaves[(int)((982451653L * i) % leaves.Length)]); // //tree.InsertGlobal(leaves[(int)((982451653L * i) % leaves.Length)]); // //tree.Insert(leaves[i]); // //tree.InsertGlobal(leaves[i]); //} //tree.BuildMedianSplit(leaves); tree.BuildVolumeHeuristic(leaves); var endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"Baseline Build Time: {endTime - startTime}, depth: {tree.MaximumDepth}"); Console.WriteLine($"Cost heuristic: {tree.MeasureCostHeuristic()}"); tree.Validate(); //var leafCount = tree.LeafCount; //for (int i = 0; i < leafCount; ++i) //{ // tree.RemoveAt(0); // tree.Validate(); //} int nodeCount, childCount; tree.MeasureNodeOccupancy(out nodeCount, out childCount); Console.WriteLine($"Baseline Occupancy: {childCount / (double)nodeCount}"); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < refitCount; ++i) { //tree.RefitLeaves(); tree.Refit(); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"Baseline Refit Time: {endTime - startTime}"); var list = new QuickList<int>(new BufferPool<int>()); var queryMask = queries.Length - 1; startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < queryCount; ++i) { list.Count = 0; //tree.Query(ref queries[i & queryMask], ref list); tree.QueryRecursive(ref queries[i & queryMask], ref list); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"Baseline Query Time: {endTime - startTime}, overlaps: {list.Count}"); Array.Clear(list.Elements, 0, list.Elements.Length); list.Dispose(); var overlaps = new QuickList<Overlap<TestCollidable>>(new BufferPool<Overlap<TestCollidable>>()); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < selfTestCount; ++i) { overlaps.Count = 0; tree.GetSelfOverlaps(ref overlaps); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"Baseline SelfTree Time: {endTime - startTime}, overlaps: {overlaps.Count}"); overlaps = new QuickList<Overlap<TestCollidable>>(new BufferPool<Overlap<TestCollidable>>()); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < selfTestCount; ++i) { overlaps.Count = 0; tree.GetSelfOverlapsViaQueries(ref overlaps); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"Baseline SelfQuery Time: {endTime - startTime}, overlaps: {overlaps.Count}"); tree.Dispose(); } }
public static unsafe TestResults TestSingleArray(TestCollidable[] leaves, BoundingBox[] queries, BoundingBox positionBounds, int queryCount, int selfTestCount, int refitCount, int frameCount, float dt, ParallelLooper looper) { { var warmLeaves = GetLeaves(10, 10, 10, 10, 10); Tree tree = new Tree(); //for (int i = 0; i < leaves.Length; ++i) //{ // BoundingBox box; // leaves[i].GetBoundingBox(out box); // //tree.Insert(i, ref box); // tree.AddGlobal(i, ref box); //} int[] leafIds = new int[warmLeaves.Length]; BoundingBox[] leafBounds = new BoundingBox[warmLeaves.Length]; for (int i = 0; i < warmLeaves.Length; ++i) { leafIds[i] = i; warmLeaves[i].GetBoundingBox(out leafBounds[i]); } //tree.BuildMedianSplit(leafIds, leafBounds); //tree.BuildVolumeHeuristic(leafIds, leafBounds); tree.SweepBuild(leafIds, leafBounds); Console.WriteLine($"SingleArray Cachewarm Build: {tree.LeafCount}"); tree.Refit(); //tree.BottomUpAgglomerativeRefine(); //tree.TopDownAgglomerativeRefine(); //tree.BottomUpSweepRefine(); //tree.TopDownSweepRefine(); tree.RefitAndRefine(0); var context = new Tree.RefitAndRefineMultithreadedContext(tree); tree.RefitAndRefine(0, looper, context); var selfTestContext = new Tree.SelfTestMultithreadedContext(looper.ThreadCount, BufferPools<Overlap>.Locking); tree.GetSelfOverlaps(looper, selfTestContext); var list = new QuickList<int>(new BufferPool<int>()); BoundingBox aabb = new BoundingBox { Min = new Vector3(0, 0, 0), Max = new Vector3(1, 1, 1) }; tree.QueryRecursive(ref aabb, ref list); list.Dispose(); var overlaps = new QuickList<Overlap>(new BufferPool<Overlap>()); tree.GetSelfOverlaps(ref overlaps); overlaps = new QuickList<Overlap>(new BufferPool<Overlap>()); tree.GetSelfOverlapsArityDedicated(ref overlaps); tree.IncrementalCacheOptimize(0); overlaps = new QuickList<Overlap>(new BufferPool<Overlap>()); tree.GetSelfOverlapsViaQueries(ref overlaps); Console.WriteLine($"Cachewarm overlaps: {overlaps.Count}"); tree.Dispose(); } { Console.WriteLine($"SingleArray arity: {Tree.ChildrenCapacity}"); Tree tree = new Tree(Math.Max(1, leaves.Length)); var startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < leaves.Length; ++i) { var leafIndex = (int)((982451653L * i) % leaves.Length); BoundingBox box; leaves[leafIndex].GetBoundingBox(out box); tree.Add(leafIndex, ref box); //tree.AddGlobal(leafIndex, ref box); } //int[] leafIds = new int[leaves.Length]; //BoundingBox[] leafBounds = new BoundingBox[leaves.Length]; //for (int i = 0; i < leaves.Length; ++i) //{ // leafIds[i] = i; // leaves[i].GetBoundingBox(out leafBounds[i]); //} ////tree.BuildMedianSplit(leafIds, leafBounds); ////tree.BuildVolumeHeuristic(leafIds, leafBounds); //tree.SweepBuild(leafIds, leafBounds); var endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"SingleArray Build Time: {endTime - startTime}, depth: {tree.ComputeMaximumDepth()}"); int nodeCount, childCount; tree.MeasureNodeOccupancy(out nodeCount, out childCount); Console.WriteLine($"SingleArray Occupancy: {childCount / (double)nodeCount}"); Console.WriteLine($"Cost metric: {tree.MeasureCostMetric()}"); Console.WriteLine($"Cache Quality: {tree.MeasureCacheQuality()}"); tree.Validate(); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < refitCount; ++i) { //for (int i = 0; i < tree.LeafCount; ++i) //{ // BoundingBox box; // leaves[tree.Leaves[i].Id].GetBoundingBox(out box); // tree.UpdateLeafBoundingBox(i, ref box); //} tree.Refit(); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"SingleArray Refit Time1: {endTime - startTime}"); var overlaps = new QuickList<Overlap>(new BufferPool<Overlap>()); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < selfTestCount; ++i) { overlaps.Count = 0; tree.GetSelfOverlaps(ref overlaps); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"SingleArray SelfTree Time1: {endTime - startTime}, overlaps: {overlaps.Count}"); int[] buffer; MemoryRegion region; BinnedResources resources; const int maximumSubtrees = 262144; var spareNodes = new QuickList<int>(new BufferPool<int>(), 8); var subtreeReferences = new QuickList<int>(BufferPools<int>.Thread, BufferPool<int>.GetPoolIndex(maximumSubtrees)); var treeletInternalNodes = new QuickList<int>(BufferPools<int>.Thread, BufferPool<int>.GetPoolIndex(maximumSubtrees)); Tree.CreateBinnedResources(BufferPools<int>.Thread, maximumSubtrees, out buffer, out region, out resources); bool nodesInvalidated; overlaps = new QuickList<Overlap>(new BufferPool<Overlap>()); var refineContext = new Tree.RefitAndRefineMultithreadedContext(tree); var selfTestContext = new Tree.SelfTestMultithreadedContext(looper.ThreadCount, BufferPools<Overlap>.Locking); var visitedNodes = new QuickSet<int>(BufferPools<int>.Thread, BufferPools<int>.Thread); //**************** Dynamic Testing Random random = new Random(5); TestResults results = new TestResults("New", frameCount); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int t = 0; t < frameCount; ++t) { //Update the positions of objects. for (int i = 0; i < tree.LeafCount; ++i) { var leafId = tree.Leaves[i].Id; var leaf = leaves[leafId]; //Bounce off the walls. if (leaf.Position.X < positionBounds.Min.X && leaf.Velocity.X < 0) leaf.Velocity.X = -leaf.Velocity.X; if (leaf.Position.Y < positionBounds.Min.Y && leaf.Velocity.Y < 0) leaf.Velocity.Y = -leaf.Velocity.Y; if (leaf.Position.Z < positionBounds.Min.Z && leaf.Velocity.Z < 0) leaf.Velocity.Z = -leaf.Velocity.Z; if (leaf.Position.X > positionBounds.Max.X && leaf.Velocity.X > 0) leaf.Velocity.X = -leaf.Velocity.X; if (leaf.Position.Y > positionBounds.Max.Y && leaf.Velocity.Y > 0) leaf.Velocity.Y = -leaf.Velocity.Y; if (leaf.Position.Z > positionBounds.Max.Z && leaf.Velocity.Z > 0) leaf.Velocity.Z = -leaf.Velocity.Z; leaf.Position += leaf.Velocity * dt; BoundingBox boundingBox; leaf.GetBoundingBox(out boundingBox); tree.SetLeafBoundingBox(i, ref boundingBox); } var refineStartTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; int refinementCount; if(looper.ThreadCount > 1) refinementCount = tree.RefitAndRefine(t, looper, refineContext); else refinementCount = tree.RefitAndRefine(t); var refineEndTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; int overlapsCount; if (looper.ThreadCount > 1) { tree.GetSelfOverlaps(looper, selfTestContext); overlapsCount = 0; for (int i = 0; i < selfTestContext.WorkerOverlaps.Length; ++i) { overlapsCount += selfTestContext.WorkerOverlaps[i].Count; } } else { overlaps.Count = 0; tree.GetSelfOverlapsArityDedicated(ref overlaps); overlapsCount = overlaps.Count; } var testEndTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; results.Refine[t] = 1000 * (refineEndTime - refineStartTime); results.SelfTest[t] = 1000 * (testEndTime - refineEndTime); results.Total[t] = 1000 * (testEndTime - refineStartTime); results.OverlapCounts[t] = overlapsCount; results.TreeCosts[t] = tree.MeasureCostMetric(); if (t % 16 == 0) { Console.WriteLine($"_________________{t}_________________"); Console.WriteLine($"Refinement count: {refinementCount}"); Console.WriteLine($"Refine time: {results.Refine[t]}"); Console.WriteLine($"Test time: {results.SelfTest[t]}"); Console.WriteLine($"TIME: {results.Total[t]}"); Console.WriteLine($"Cost metric: {results.TreeCosts[t]}"); Console.WriteLine($"Overlaps: {results.OverlapCounts[t]}"); Console.WriteLine($"Cache Quality: {tree.MeasureCacheQuality()}"); GC.Collect(); } tree.Validate(); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; tree.Validate(); Console.WriteLine($"SingleArray Cache Quality: {tree.MeasureCacheQuality()}"); Console.WriteLine($"Cost metric: {tree.MeasureCostMetric()}"); region.Dispose(); tree.RemoveUnusedInternalNodes(ref spareNodes); BufferPools<int>.Thread.GiveBack(buffer); //******************** tree.MeasureNodeOccupancy(out nodeCount, out childCount); Console.WriteLine($"SingleArray Occupancy: {childCount / (double)nodeCount}"); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < refitCount; ++i) { //for (int i = 0; i < tree.LeafCount; ++i) //{ // BoundingBox box; // leaves[tree.Leaves[i].Id].GetBoundingBox(out box); // tree.UpdateLeafBoundingBox(i, ref box); //} tree.Refit(); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"SingleArray Refit Time2: {endTime - startTime}"); var list = new QuickList<int>(new BufferPool<int>()); var queryMask = queries.Length - 1; startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < queryCount; ++i) { list.Count = 0; //tree.Query2(ref queries[i & queryMask], ref list); tree.QueryRecursive(ref queries[i & queryMask], ref list); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"SingleArray Query Time: {endTime - startTime}, overlaps: {list.Count}"); Array.Clear(list.Elements, 0, list.Elements.Length); list.Dispose(); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < selfTestCount; ++i) { overlaps.Count = 0; tree.GetSelfOverlaps(ref overlaps); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"SingleArray SelfTree Time: {endTime - startTime}, overlaps: {overlaps.Count}"); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < selfTestCount; ++i) { overlaps.Count = 0; tree.GetSelfOverlapsArityDedicated(ref overlaps); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"SingleArray Arity-Dedicated SelfTree Time: {endTime - startTime}, overlaps: {overlaps.Count}"); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < selfTestCount; ++i) { overlaps.Count = 0; tree.GetSelfOverlapsViaQueries(ref overlaps); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"SingleArray SelfQuery Time: {endTime - startTime}, overlaps: {overlaps.Count}"); tree.Dispose(); return results; } }
public static void TestVectorized(TestCollidable[] leaves, BoundingBox[] queries, int queryCount, int selfTestCount, int refitCount) { { var warmLeaves = GetLeaves(8, 8, 8, 10, 10); Tree<TestCollidable> tree = new Tree<TestCollidable>(); for (int i = 0; i < warmLeaves.Length; ++i) { tree.Insert(warmLeaves[i]); } Console.WriteLine($"Cachewarm Build: {tree.LeafCount}"); tree.RefitLeaves(); var list = new QuickList<int>(new BufferPool<int>()); BoundingBox aabb = new BoundingBox { Min = new Vector3(0, 0, 0), Max = new Vector3(1, 1, 1) }; tree.Query(ref aabb, ref list); list.Dispose(); var overlaps = new QuickList<Overlap>(new BufferPool<Overlap>()); tree.GetSelfOverlaps(ref overlaps); Console.WriteLine($"Warm overlaps: {overlaps.Count}"); overlaps = new QuickList<Overlap>(new BufferPool<Overlap>()); tree.GetSelfOverlapsViaQueries(ref overlaps); Console.WriteLine($"Warm overlaps: {overlaps.Count}"); overlaps = new QuickList<Overlap>(new BufferPool<Overlap>()); tree.GetSelfOverlapsViaStreamingQueries(ref overlaps); Console.WriteLine($"Warm overlaps: {overlaps.Count}"); } { Tree<TestCollidable> tree = new Tree<TestCollidable>(leaves.Length, 32); var startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < leaves.Length; ++i) { tree.Insert(leaves[(int)((982451653L * i) % leaves.Length)]); //tree.Insert(leaves[i]); } var endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"Build Time: {endTime - startTime}, depth: {tree.MaximumDepth}"); int nodeCount, childCount; tree.MeasureNodeOccupancy(out nodeCount, out childCount); Console.WriteLine($"Occupancy: {childCount / (double)nodeCount}"); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < refitCount; ++i) { //tree.RefitLeaves(); tree.Refit(); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"Refit Time: {endTime - startTime}"); var list = new QuickList<int>(new BufferPool<int>()); var queryMask = queries.Length - 1; startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < queryCount; ++i) { list.Count = 0; //tree.Query(ref queries[i & queryMask], ref list); tree.QueryRecursive(ref queries[i & queryMask], ref list); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"Query Time: {endTime - startTime}, overlaps: {list.Count}"); list.Dispose(); var overlaps = new QuickList<Overlap>(new BufferPool<Overlap>()); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < selfTestCount; ++i) { overlaps.Count = 0; tree.GetSelfOverlaps(ref overlaps); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"SelfTree Time: {endTime - startTime}, overlaps: {overlaps.Count}"); overlaps = new QuickList<Overlap>(new BufferPool<Overlap>()); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < selfTestCount; ++i) { overlaps.Count = 0; tree.GetSelfOverlapsViaQueries(ref overlaps); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"SelfQuery Time: {endTime - startTime}, overlaps: {overlaps.Count}"); overlaps = new QuickList<Overlap>(new BufferPool<Overlap>()); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < selfTestCount; ++i) { overlaps.Count = 0; tree.GetSelfOverlapsViaStreamingQueries(ref overlaps); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"StreamingSelfQuery Time: {endTime - startTime}, overlaps: {overlaps.Count}"); } }