Skip to content

Commit

Permalink
Unifying the signature of non-alloc query methods in BoundsOctree and…
Browse files Browse the repository at this point in the history
… PointOctree.
  • Loading branch information
mcserep committed Aug 19, 2022
1 parent 545b893 commit b9ba8eb
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 53 deletions.
45 changes: 15 additions & 30 deletions Octree.Tests/BoundOctreeTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public void AddTest()
}

/// <summary>
/// Tests the <see cref="BoundsOctree{T}.IsColliding" /> method.
/// Tests the <see cref="BoundsOctree{T}.IsColliding(Octree.BoundingBox)" /> method.
/// </summary>
[Fact]
public void CollisionTest()
Expand Down Expand Up @@ -84,7 +84,7 @@ public void CollisionTest()
}

/// <summary>
/// Tests the <see cref="BoundsOctree{T}.GetColliding(List{T},Octree.BoundingBox)" /> method.
/// Tests the <see cref="BoundsOctree{T}.GetColliding(Octree.BoundingBox)" /> method.
/// </summary>
[Fact]
public void SearchByPositionTest()
Expand All @@ -94,26 +94,19 @@ public void SearchByPositionTest()
_octree.Add(i, new BoundingBox(new Vector3(i), Vector3.Zero));

// Should be empty for bounding boxes that do not contain any of the geometries
List<int> result = new List<int>();
_octree.GetColliding(result, new BoundingBox(new Vector3(0.5f), new Vector3(0.2f)));
result.ShouldBeEmpty();
_octree.GetColliding(result, new BoundingBox(new Vector3(100), Vector3.One));
result.ShouldBeEmpty();
_octree.GetColliding(result, new BoundingBox(new Vector3(200), new Vector3(20)));
result.ShouldBeEmpty();
_octree.GetColliding(new BoundingBox(new Vector3(0.5f), new Vector3(0.2f))).ShouldBeEmpty();
_octree.GetColliding(new BoundingBox(new Vector3(100), Vector3.One)).ShouldBeEmpty();
_octree.GetColliding(new BoundingBox(new Vector3(200), new Vector3(20))).ShouldBeEmpty();

// Should find all geometries
_octree.GetColliding(result, new BoundingBox(new Vector3(50), new Vector3(100)));
result.Count.ShouldBe(_octree.Count);
result.Clear();
_octree.GetColliding(new BoundingBox(new Vector3(50), new Vector3(100))).Length.ShouldBe(_octree.Count);

// Should find some geometries
_octree.GetColliding(result, new BoundingBox(new Vector3(50), new Vector3(50)));
result.Count.ShouldBe(51);
_octree.GetColliding(new BoundingBox(new Vector3(50), new Vector3(50))).Length.ShouldBe(51);
}

/// <summary>
/// Tests the <see cref="BoundsOctree{T}.GetColliding(List{T},Octree.Ray,float)" /> method.
/// Tests the <see cref="BoundsOctree{T}.GetColliding(Octree.Ray,float)" /> method.
/// </summary>
[Fact]
public void SearchByRayTest()
Expand All @@ -123,26 +116,18 @@ public void SearchByRayTest()
_octree.Add(i, new BoundingBox(new Vector3(i), Vector3.Zero));

// Should find some geometries (distance measured from origin of ray)
List<int> result = new List<int>();
_octree.GetColliding(result, new Ray(Vector3.Zero, Vector3.One), 2);
result.Count.ShouldBe(1);
result.Clear();
_octree.GetColliding(result, new Ray(Vector3.Zero, Vector3.One), 5);
result.Count.ShouldBe(2);
result.Clear();
_octree.GetColliding(result, new Ray(new Vector3(50), Vector3.One), 5);
result.Count.ShouldBe(3);
result.Clear();
_octree.GetColliding(new Ray(Vector3.Zero, Vector3.One), 2).Length.ShouldBe(1);
_octree.GetColliding(new Ray(Vector3.Zero, Vector3.One), 5).Length.ShouldBe(2);
_octree.GetColliding(new Ray(new Vector3(50), Vector3.One), 5).Length.ShouldBe(3);

// Should find no geometries
_octree.GetColliding(result, new Ray(new Vector3(50), Vector3.UnitX), 2);
_octree.GetColliding(result, new Ray(new Vector3(50), Vector3.UnitY), 2);
_octree.GetColliding(result, new Ray(new Vector3(50), Vector3.UnitZ), 2);
result.ShouldBeEmpty();
_octree.GetColliding(new Ray(new Vector3(50), Vector3.UnitX), 2).ShouldBeEmpty();
_octree.GetColliding(new Ray(new Vector3(50), Vector3.UnitY), 2).ShouldBeEmpty();
_octree.GetColliding(new Ray(new Vector3(50), Vector3.UnitZ), 2).ShouldBeEmpty();
}

/// <summary>
/// Tests the <see cref="BoundsOctree{T}.Remove" /> method.
/// Tests the <see cref="BoundsOctree{T}.Remove(T)" /> method.
/// </summary>
[Fact]
public void RemoveTest()
Expand Down
2 changes: 2 additions & 0 deletions Octree.Tests/Octree.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<Authors>Máté Cserép</Authors>
<Copyright>Copyright © Máté Cserép 2022</Copyright>

<IsPackable>false</IsPackable>
</PropertyGroup>
Expand Down
49 changes: 43 additions & 6 deletions Octree/BoundsOctree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,26 +188,63 @@ public bool IsColliding(Ray checkRay, float maxDistance)
}

/// <summary>
/// Returns an array of objects that intersect with the specified bounds, if any. Otherwise returns an empty array. See also: IsColliding.
/// Returns an array of objects that intersect with the specified bounds, if any.
/// Otherwise returns an empty array.
/// </summary>
/// <param name="collidingWith">list to store intersections.</param>
/// <seealso cref="IsColliding(Octree.BoundingBox)"/>
/// <param name="checkBounds">bounds to check.</param>
/// <returns>Objects that intersect with the specified bounds.</returns>
public void GetColliding(List<T> collidingWith, BoundingBox checkBounds)
public T[] GetColliding(BoundingBox checkBounds)
{
List<T> collidingWith = new List<T>();
_rootNode.GetColliding(ref checkBounds, collidingWith);
return collidingWith.ToArray();
}

/// <summary>
/// Returns an array of objects that intersect with the specified ray, if any. Otherwise returns an empty array. See also: IsColliding.
/// Returns an array of objects that intersect with the specified ray, if any.
/// Otherwise returns an empty array.
/// </summary>
/// <param name="collidingWith">list to store intersections.</param>
/// <seealso cref="IsColliding(Octree.BoundingBox)"/>
/// <param name="checkRay">ray to check.</param>
/// <param name="maxDistance">distance to check.</param>
/// <returns>Objects that intersect with the specified ray.</returns>
public void GetColliding(List<T> collidingWith, Ray checkRay, float maxDistance = float.PositiveInfinity)
public T[] GetColliding(Ray checkRay, float maxDistance = float.PositiveInfinity)
{
List<T> collidingWith = new List<T>();
_rootNode.GetColliding(ref checkRay, collidingWith, maxDistance);
return collidingWith.ToArray();
}

/// <summary>
/// Returns an array of objects that intersect with the specified bounds, if any.
/// Otherwise returns an empty array.
/// </summary>
/// <seealso cref="IsColliding(Octree.BoundingBox)"/>
/// <param name="collidingWith">list to store intersections.</param>
/// <param name="checkBounds">bounds to check.</param>
/// <returns><c>true</c> if items are found, <c>false</c> otherwise.</returns>
public bool GetCollidingNonAlloc(List<T> collidingWith, BoundingBox checkBounds)
{
collidingWith.Clear();
_rootNode.GetColliding(ref checkBounds, collidingWith);
return collidingWith.Count > 0;
}

/// <summary>
/// Returns an array of objects that intersect with the specified ray, if any.
/// Otherwise returns an empty array.
/// </summary>
/// <seealso cref="IsColliding(Octree.BoundingBox)"/>
/// <param name="collidingWith">list to store intersections.</param>
/// <param name="checkRay">ray to check.</param>
/// <param name="maxDistance">distance to check.</param>
/// <returns><c>true</c> if items are found, <c>false</c> otherwise.</returns>
public bool GetCollidingNonAlloc(List<T> collidingWith, Ray checkRay, float maxDistance = float.PositiveInfinity)
{
collidingWith.Clear();
_rootNode.GetColliding(ref checkRay, collidingWith, maxDistance);
return collidingWith.Count > 0;
}

// #### PRIVATE METHODS ####
Expand Down
28 changes: 20 additions & 8 deletions Octree/NuGetReadme.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ This seems to be the standard way that loose octrees are done. I did an experime
Example Usage
-----------

**Create An Octree**
**Create an Octree**

```C#
// Initial size (metres), initial centre position, minimum node size (metres), looseness
Expand All @@ -50,7 +50,7 @@ PointOctree<DataType> pointTree = new PointOctree<DataType>(15, position, 1);
- The minimum node size is effectively a depth limit; it limits how many times the tree can divide. If all your objects are e.g. 1m+ wide, you wouldn't want to set it smaller than 1m.
- The best way to choose a looseness value is to try different values (between 1 and maybe 1.5) and check the performance with your particular data. Generally around 1.2 is good.

**Add And Remove**
**Add and Remove**

```C#
boundsTree.Add(myObject, myBounds);
Expand All @@ -62,25 +62,37 @@ boundsTree.Remove(myObject);
- The object's type depends on the tree's type.
- The bounds or point determine where it's inserted.

**Built-in Functions**
**Search in the Octree**

```C#
bool isColliding = boundsTree.IsColliding(bounds);
```

```C#
List<DataType> collidingWith = new List<DataType>();
boundsTree.GetColliding(collidingWith, bounds);
DataType[] collidingWith = boundsTree.GetColliding(bounds);
```
- Where `DataType` is the type of the octree

```C#
pointTree.GetNearby(myRay, 4);
DataType[] nearby = pointTree.GetNearby(myRay, 4);
```
- Where `myRay` is a `Ray`
- In this case we're looking for any point within 4m of the closest point on the ray

```C#
pointTree.GetNearby(myPos, 4);
DataType[] nearby = pointTree.GetNearby(myPos, 4);
```
- Where `myPos` is a `Vector3` from `System.Numerics`

**Non-Alloc query functions**

A pre-initialized list can be used to store the results, which can be useful when executing a large number of queries with potentially large result sets.

```C#
List<DataType> collidingWith = new List<DataType>();
boundsTree.GetColliding(collidingWith, bounds);
```

```C#
pointTree.GetNearby(myRay, 4, collidingWith);
```
- Where `myPos` is a `Vector3`
2 changes: 1 addition & 1 deletion Octree/Octree.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<PackageReadmeFile>NuGetReadme.md</PackageReadmeFile>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>1.1.0</Version>
<Version>2.0.0</Version>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)'=='Release'">
Expand Down
30 changes: 30 additions & 0 deletions Octree/PointOctree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,36 @@ public T[] GetNearby(Vector3 position, float maxDistance)
return collidingWith.ToArray();
}

/// <summary>
/// Returns objects that are within <paramref name="maxDistance"/> of the specified ray.
/// If none, returns false. Uses supplied list for results.
/// </summary>
/// <param name="ray">The ray. Passing as ref to improve performance since it won't have to be copied.</param>
/// <param name="maxDistance">Maximum distance from the ray to consider.</param>
/// <param name="nearby">Pre-initialized list to populate.</param>
/// <returns><c>true</c> if items are found, <c>false</c> otherwise.</returns>
public bool GetNearbyNonAlloc(Ray ray, float maxDistance, List<T> nearby)
{
nearby.Clear();
_rootNode.GetNearby(ref ray, maxDistance, nearby);
return nearby.Count > 0;
}

/// <summary>
/// Returns objects that are within <paramref name="maxDistance"/> of the specified position.
/// If none, returns false. Uses supplied list for results.
/// </summary>
/// <param name="position">The position. Passing as ref to improve performance since it won't have to be copied.</param>
/// <param name="maxDistance">Maximum distance from the position to consider.</param>
/// <param name="nearby">Pre-initialized list to populate.</param>
/// <returns><c>true</c> if items are found, <c>false</c> otherwise.</returns>
public bool GetNearbyNonAlloc(Vector3 position, float maxDistance, List<T> nearby)
{
nearby.Clear();
_rootNode.GetNearby(ref position, maxDistance, nearby);
return nearby.Count > 0;
}

/// <summary>
/// Returns all objects in the tree.
/// If none, returns an empty array (not null).
Expand Down
27 changes: 19 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ This seems to be the standard way that loose octrees are done. I did an experime
Example Usage
-----------

**Create An Octree**
**Create an Octree**

```C#
// Initial size (metres), initial centre position, minimum node size (metres), looseness
Expand All @@ -70,7 +70,7 @@ PointOctree<DataType> pointTree = new PointOctree<DataType>(15, position, 1);
- The minimum node size is effectively a depth limit; it limits how many times the tree can divide. If all your objects are e.g. 1m+ wide, you wouldn't want to set it smaller than 1m.
- The best way to choose a looseness value is to try different values (between 1 and maybe 1.5) and check the performance with your particular data. Generally around 1.2 is good.

**Add And Remove**
**Add and Remove**

```C#
boundsTree.Add(myObject, myBounds);
Expand All @@ -82,29 +82,40 @@ boundsTree.Remove(myObject);
- The object's type depends on the tree's type.
- The bounds or point determine where it's inserted.

**Built-in Functions**
**Search in the Octree**

```C#
bool isColliding = boundsTree.IsColliding(bounds);
```

```C#
List<DataType> collidingWith = new List<DataType>();
boundsTree.GetColliding(collidingWith, bounds);
DataType[] collidingWith = boundsTree.GetColliding(bounds);
```
- Where `DataType` is the type of the octree

```C#
pointTree.GetNearby(myRay, 4);
DataType[] nearby = pointTree.GetNearby(myRay, 4);
```
- Where `myRay` is a `Ray`
- In this case we're looking for any point within 4m of the closest point on the ray

```C#
pointTree.GetNearby(myPos, 4);
DataType[] nearby = pointTree.GetNearby(myPos, 4);
```
- Where `myPos` is a `Vector3`
- Where `myPos` is a `Vector3` from `System.Numerics`

**Non-Alloc query functions**

A pre-initialized list can be used to store the results, which can be useful when executing a large number of queries with potentially large result sets.

```C#
List<DataType> collidingWith = new List<DataType>();
boundsTree.GetColliding(collidingWith, bounds);
```

```C#
pointTree.GetNearby(myRay, 4, collidingWith);
```

**Potential Improvements**

Expand Down

0 comments on commit b9ba8eb

Please sign in to comment.