QTree.MonoGame.Common 1.0.3

dotnet add package QTree.MonoGame.Common --version 1.0.3
                    
NuGet\Install-Package QTree.MonoGame.Common -Version 1.0.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="QTree.MonoGame.Common" Version="1.0.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="QTree.MonoGame.Common" Version="1.0.3" />
                    
Directory.Packages.props
<PackageReference Include="QTree.MonoGame.Common" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add QTree.MonoGame.Common --version 1.0.3
                    
#r "nuget: QTree.MonoGame.Common, 1.0.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#addin nuget:?package=QTree.MonoGame.Common&version=1.0.3
                    
Install as a Cake Addin
#tool nuget:?package=QTree.MonoGame.Common&version=1.0.3
                    
Install as a Cake Tool

QTree

A simple quadtree implementation.

Installation

Raw:
dotnet add package QTree --version 1.0.5
MonoGame .net 8:
dotnet add package QTree.MonoGame.Common --version 1.0.2

Example usage

Quad tree

// create the quadtree:

// this tree is faster but constrained to the initial bounds
var quadTree = new QuadTree<string>(x: 0, y: 0, width: 2000, height: 2000);

// this tree is a bit slower but has no constrictions in space
var dynamicTree = new DynamicQuadTree<string>();

// add some objects to the tree
for(var x = 0; x < 2000; x += 20)
{
    for(var y = 0; y < 2000; y += 20)
    {
        quadTree.Add(x, y, 10, 10, "whatevs");
        dynamicTree.Add(x, y, 10, 10, "whatevs");
    }
}

// find some objects
var objectsInArea = quadTree.FindNode(500, 500, 50, 50);
var otherObjectsInSameArea = dynamicTree.FindNode(500, 500, 50, 50);

// remove an object
quadTree.Remove(objectsInArea.First());
dynamicTree.Remove(objectsInArea.First());

// clear the tree
quadTree.Clear();
dynamicTree.Clear();

Ray casting

MonoGame

Small disclaimer: In the monogame framework there is already a class called Ray which is used with Vector3, and BoundingBox. To avoid collision, the Ray class in this project is called QTreeRay inside the QTree.MonoGame namespace

// create a ray with a start point and direction
var searchStartPosition = new Vector2(100, 100);
var direction = new Vector2(.5f, .5f);
var ray = new QTreeRay(searchStartPosition, direction);

// if you want to use an angle in radians instead you can do
var rayFromRadians = new QTreeRay(searchStartPosition, 3.14f);

// and if you want the angle to be between two positions you can do
var otherPosition = new Vector2(200, 200);
var rayBetweenPositions = QTreeRay.BetweenVectors(searchStartPosition, otherPosition);

// ray cast all in specific range
var distanceResults = qtree.RayCast(ray).Where(result => Vector2.Distance(ray.Start, result.Hit) < YOUR_MAX_DISTANCE);

// get first collision from start point
var firstHit = qtree.RayCast(ray).OrderBy(result => Vector2.Distance(ray.Start, result.Hit)).FirstOrDefault()?.Object;

// get everything in collision with the ray
var all = qtree.RayCast(ray).ToList();
Not monogame
// create a ray with a start point and direction
var searchStartPosition = new Point2D(100, 100);
var direction = new PointF2D(.5f, .5f);
var ray = new Ray(searchStartPostion, direction);

// if you want to use an angle in radians instead you can do
var rayFromRadians = new Ray(searchStartPosition, 3.14f);

// and if you want the angle to be between two positions you can do
var otherPosition = new Point2D(200, 200);
var rayBetweenPositions = Ray.BetweenVectors(searchStartPosition, otherPosition);

// ray cast all in specific range
var distanceResults = qtree.RayCast(ray).Where(result => Vector2.Distance(ray.Start, result.Hit) < YOUR_MAX_DISTANCE);

// get first collision from start point
var firstHit = qtree.RayCast(ray).OrderBy(result => Vector2.Distance(ray.Start, result.Hit)).FirstOrDefault()?.Object;

// get everything in collision with the ray
var all = qtree.RayCast(ray).ToList();

Benchmarks

Adding a point

Benchmark is located here

Method ItemsInTree Depth SplitLimit Mean Error StdDev
AddPoint 10000 5 5 82.64 ns 0.162 ns 0.151 ns
DynamicTreeAddPoint 10000 5 5 82.71 ns 0.380 ns 0.336 ns
AddPoint 10000 5 50 64.58 ns 0.283 ns 0.251 ns
DynamicTreeAddPoint 10000 5 50 81.18 ns 0.381 ns 0.356 ns
AddPoint 10000 5 100 64.62 ns 0.293 ns 0.245 ns
DynamicTreeAddPoint 10000 5 100 81.60 ns 0.529 ns 0.495 ns
AddPoint 10000 10 5 107.77 ns 0.283 ns 0.265 ns
DynamicTreeAddPoint 10000 10 5 135.14 ns 0.324 ns 0.271 ns
AddPoint 10000 10 50 71.14 ns 0.192 ns 0.170 ns
DynamicTreeAddPoint 10000 10 50 127.48 ns 0.234 ns 0.219 ns
AddPoint 10000 10 100 65.68 ns 0.194 ns 0.172 ns
DynamicTreeAddPoint 10000 10 100 99.86 ns 0.289 ns 0.270 ns
AddPoint 10000 100 5 108.04 ns 0.323 ns 0.302 ns
DynamicTreeAddPoint 10000 100 5 848.29 ns 2.068 ns 1.833 ns
AddPoint 10000 100 50 65.59 ns 0.105 ns 0.098 ns
DynamicTreeAddPoint 10000 100 50 127.20 ns 0.303 ns 0.268 ns
AddPoint 10000 100 100 65.92 ns 0.060 ns 0.053 ns
DynamicTreeAddPoint 10000 100 100 97.02 ns 0.180 ns 0.160 ns

Finding a point

Benchmark is located here

Method ItemsInTree Depth SplitLimit Mean Error StdDev
FindPoint 10000 5 5 270.90 ns 5.477 ns 12.137 ns
DynamicTreeFindPoint 10000 5 5 30,223.47 ns 223.111 ns 208.698 ns
FindPoint 10000 5 50 450.84 ns 8.862 ns 11.831 ns
DynamicTreeFindPoint 10000 5 50 5,978.30 ns 35.328 ns 33.046 ns
FindPoint 10000 5 100 670.52 ns 12.310 ns 11.515 ns
DynamicTreeFindPoint 10000 5 100 38.20 ns 0.815 ns 1.088 ns
FindPoint 10000 10 5 305.56 ns 6.058 ns 9.953 ns
DynamicTreeFindPoint 10000 10 5 34,925.07 ns 70.888 ns 66.309 ns
FindPoint 10000 10 50 451.99 ns 8.863 ns 10.885 ns
DynamicTreeFindPoint 10000 10 50 5,921.33 ns 12.147 ns 10.143 ns
FindPoint 10000 10 100 660.98 ns 12.755 ns 14.689 ns
DynamicTreeFindPoint 10000 10 100 37.82 ns 0.814 ns 1.030 ns
FindPoint 10000 100 5 297.16 ns 5.962 ns 9.796 ns
DynamicTreeFindPoint 10000 100 5 43,150.67 ns 145.498 ns 136.099 ns
FindPoint 10000 100 50 436.63 ns 8.777 ns 8.620 ns
DynamicTreeFindPoint 10000 100 50 5,922.11 ns 21.402 ns 20.020 ns
FindPoint 10000 100 100 676.08 ns 13.486 ns 14.430 ns
DynamicTreeFindPoint 10000 100 100 38.97 ns 0.833 ns 1.054 ns

Ray cast

Benchmark is located here

Method ItemsInTree Depth SplitLimit Mean Error StdDev
RayCastPoint 10000 5 5 35,265.8 ns 683.35 ns 1,022.81 ns
DynamicTreeRayCastPoint 10000 5 5 172,338.9 ns 3,366.68 ns 4,134.58 ns
RayCastPoint 10000 5 50 40,555.5 ns 807.47 ns 1,021.19 ns
DynamicTreeRayCastPoint 10000 5 50 161,928.0 ns 3,150.83 ns 3,502.13 ns
RayCastPoint 10000 5 100 41,600.2 ns 786.92 ns 874.66 ns
DynamicTreeRayCastPoint 10000 5 100 237.9 ns 4.81 ns 6.90 ns
RayCastPoint 10000 10 5 36,947.5 ns 719.90 ns 1,009.20 ns
DynamicTreeRayCastPoint 10000 10 5 209,144.6 ns 4,026.88 ns 4,475.86 ns
RayCastPoint 10000 10 50 40,364.2 ns 802.20 ns 1,014.53 ns
DynamicTreeRayCastPoint 10000 10 50 157,122.2 ns 3,139.09 ns 3,855.08 ns
RayCastPoint 10000 10 100 41,275.1 ns 821.07 ns 1,008.34 ns
DynamicTreeRayCastPoint 10000 10 100 239.5 ns 4.67 ns 6.69 ns
RayCastPoint 10000 100 5 91,642.0 ns 1,781.23 ns 2,926.61 ns
DynamicTreeRayCastPoint 10000 100 5 206,320.2 ns 652.77 ns 578.66 ns
RayCastPoint 10000 100 50 39,155.4 ns 225.38 ns 210.82 ns
DynamicTreeRayCastPoint 10000 100 50 151,230.9 ns 949.32 ns 792.73 ns
RayCastPoint 10000 100 100 41,906.1 ns 831.93 ns 1,110.61 ns
DynamicTreeRayCastPoint 10000 100 100 242.2 ns 4.91 ns 7.65 ns

Difference from previous version

Add point
Find point
Ray cast

Find point speed has gone down significantly from the previous version. Add point seems to be a bit faster, and ray cast has gotten slower. Not sure why that is since it is so dependent on the find function.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.3 146 4/6/2025
1.0.2 152 10/12/2024
1.0.1 133 10/12/2024
1.0.0 281 11/17/2022