Skip to content

Commit 001ff40

Browse files
committed
Merge branch 'master' of https://github.com/Nition/UnityOctree
2 parents 70314c4 + 347ccdb commit 001ff40

File tree

5 files changed

+252
-19
lines changed

5 files changed

+252
-19
lines changed

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ There are two octree implementations here:
1717
**A few functions are implemented:**
1818

1919
With BoundsOctree, you can pass in bounds and get a true/false answer for if it's colliding with anything (IsColliding), or get a list of everything it's collising with (GetColliding).
20-
With PointOctree, you can cast a ray and get a list of objects that are within x distance of that ray (GetNearby).
20+
With PointOctree, you can cast a ray and get a list of objects that are within x distance of that ray (GetNearby). You may also get a list of objects that are within x distance from a specified origin point.
2121

2222
It shouldn't be too hard to implement additional functions if needed. For instance, PointOctree could check for points that fall inside a given bounds.
2323

@@ -79,6 +79,11 @@ pointTree.GetNearby(myRay, 4);
7979
- Where myRay is a [Ray](http://docs.unity3d.com/Documentation/ScriptReference/Ray.html)
8080
- In this case we're looking for any point within 4m of the closest point on the ray
8181

82+
```C#
83+
pointTree.GetNearby(myPos, 4);
84+
```
85+
- Where myPos is a [Vector3](http://docs.unity3d.com/Documentation/ScriptReference/Vector3.html)
86+
8287
**Debugging Visuals**
8388

8489
![Visualisation example.](https://raw.github.com/nition/UnityOctree/master/octree-visualisation.jpg)

Scripts/BoundsOctree.cs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,17 @@
2424
public class BoundsOctree<T> {
2525
// The total amount of objects currently in the tree
2626
public int Count { get; private set; }
27-
27+
2828
// Root node of the octree
2929
BoundsOctreeNode<T> rootNode;
30+
3031
// Should be a value between 1 and 2. A multiplier for the base size of a node.
3132
// 1.0 is a "normal" octree, while values > 1 have overlap
3233
readonly float looseness;
34+
3335
// Size that the octree was on creation
3436
readonly float initialSize;
37+
3538
// Minimum side length that a node can be - essentially an alternative to having a max depth
3639
readonly float minSize;
3740
// For collision visualisation. Automatically removed in builds.
@@ -97,6 +100,24 @@ public bool Remove(T obj) {
97100
return removed;
98101
}
99102

103+
/// <summary>
104+
/// Removes the specified object at the given position. Makes the assumption that the object only exists once in the tree.
105+
/// </summary>
106+
/// <param name="obj">Object to remove.</param>
107+
/// <param name="objBounds">3D bounding box around the object.</param>
108+
/// <returns>True if the object was removed successfully.</returns>
109+
public bool Remove(T obj, Bounds objBounds) {
110+
bool removed = rootNode.Remove(obj, objBounds);
111+
112+
// See if we can shrink the octree down now that we've removed the item
113+
if (removed) {
114+
Count--;
115+
Shrink();
116+
}
117+
118+
return removed;
119+
}
120+
100121
/// <summary>
101122
/// Check if the specified bounds intersect with anything in the tree. See also: GetColliding.
102123
/// </summary>
@@ -153,8 +174,7 @@ public void GetColliding(List<T> collidingWith, Ray checkRay, float maxDistance
153174
rootNode.GetColliding(ref checkRay, collidingWith, maxDistance);
154175
}
155176

156-
public Bounds GetMaxBounds()
157-
{
177+
public Bounds GetMaxBounds() {
158178
return rootNode.GetBounds();
159179
}
160180

@@ -244,19 +264,15 @@ void Grow(Vector3 direction) {
244264
// Create a new, bigger octree root node
245265
rootNode = new BoundsOctreeNode<T>(newLength, minSize, looseness, newCenter);
246266

247-
if (oldRoot.HasAnyObjects())
248-
{
267+
if (oldRoot.HasAnyObjects()) {
249268
// Create 7 new octree children to go with the old root as children of the new root
250269
int rootPos = GetRootPosIndex(xDirection, yDirection, zDirection);
251270
BoundsOctreeNode<T>[] children = new BoundsOctreeNode<T>[8];
252-
for (int i = 0; i < 8; i++)
253-
{
254-
if (i == rootPos)
255-
{
271+
for (int i = 0; i < 8; i++) {
272+
if (i == rootPos) {
256273
children[i] = oldRoot;
257274
}
258-
else
259-
{
275+
else {
260276
xDirection = i % 2 == 0 ? -1 : 1;
261277
yDirection = i > 3 ? -1 : 1;
262278
zDirection = (i < 2 || (i > 3 && i < 6)) ? -1 : 1;

Scripts/BoundsOctreeNode.cs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,31 @@
66
public class BoundsOctreeNode<T> {
77
// Centre of this node
88
public Vector3 Center { get; private set; }
9+
910
// Length of this node if it has a looseness of 1.0
1011
public float BaseLength { get; private set; }
1112

1213
// Looseness value for this node
1314
float looseness;
15+
1416
// Minimum size for a node in this octree
1517
float minSize;
18+
1619
// Actual length of sides, taking the looseness value into account
1720
float adjLength;
21+
1822
// Bounding box that represents this node
1923
Bounds bounds = default(Bounds);
24+
2025
// Objects in this node
2126
readonly List<OctreeObject> objects = new List<OctreeObject>();
27+
2228
// Child nodes, if any
2329
BoundsOctreeNode<T>[] children = null;
30+
2431
// Bounds of potential children to this node. These are actual size (with looseness taken into account), not base size
2532
Bounds[] childBounds;
33+
2634
// If there are already numObjectsAllowed in a node, we split it into children
2735
// A generally good number seems to be something around 8-15
2836
const int numObjectsAllowed = 8;
@@ -92,6 +100,19 @@ public bool Remove(T obj) {
92100
return removed;
93101
}
94102

103+
/// <summary>
104+
/// Removes the specified object at the given position. Makes the assumption that the object only exists once in the tree.
105+
/// </summary>
106+
/// <param name="obj">Object to remove.</param>
107+
/// <param name="objBounds">3D bounding box around the object.</param>
108+
/// <returns>True if the object was removed successfully.</returns>
109+
public bool Remove(T obj, Bounds objBounds) {
110+
if (!Encapsulates(bounds, objBounds)) {
111+
return false;
112+
}
113+
return SubRemove(obj, objBounds);
114+
}
115+
95116
/// <summary>
96117
/// Check if the specified bounds intersect with anything in the tree. See also: GetColliding.
97118
/// </summary>
@@ -223,8 +244,7 @@ public void SetChildren(BoundsOctreeNode<T>[] childOctrees) {
223244
children = childOctrees;
224245
}
225246

226-
public Bounds GetBounds()
227-
{
247+
public Bounds GetBounds() {
228248
return bounds;
229249
}
230250

@@ -446,6 +466,37 @@ void SubAdd(T obj, Bounds objBounds) {
446466
}
447467
}
448468

469+
/// <summary>
470+
/// Private counterpart to the public <see cref="Remove(T, Bounds)"/> method.
471+
/// </summary>
472+
/// <param name="obj">Object to remove.</param>
473+
/// <param name="objBounds">3D bounding box around the object.</param>
474+
/// <returns>True if the object was removed successfully.</returns>
475+
bool SubRemove(T obj, Bounds objBounds) {
476+
bool removed = false;
477+
478+
for (int i = 0; i < objects.Count; i++) {
479+
if (objects[i].Obj.Equals(obj)) {
480+
removed = objects.Remove(objects[i]);
481+
break;
482+
}
483+
}
484+
485+
if (!removed && children != null) {
486+
int bestFitChild = BestFitChild(objBounds);
487+
removed = children[bestFitChild].SubRemove(obj, objBounds);
488+
}
489+
490+
if (removed && children != null) {
491+
// Check if we should merge nodes now that we've removed an item
492+
if (ShouldMerge()) {
493+
Merge();
494+
}
495+
}
496+
497+
return removed;
498+
}
499+
449500
/// <summary>
450501
/// Splits the octree into eight children.
451502
/// </summary>

Scripts/PointOctree.cs

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717
public class PointOctree<T> where T : class {
1818
// The total amount of objects currently in the tree
1919
public int Count { get; private set; }
20-
20+
2121
// Root node of the octree
2222
PointOctreeNode<T> rootNode;
23+
2324
// Size that the octree was on creation
2425
readonly float initialSize;
26+
2527
// Minimum side length that a node can be - essentially an alternative to having a max depth
2628
readonly float minSize;
2729

@@ -79,6 +81,40 @@ public bool Remove(T obj) {
7981
return removed;
8082
}
8183

84+
/// <summary>
85+
/// Removes the specified object at the given position. Makes the assumption that the object only exists once in the tree.
86+
/// </summary>
87+
/// <param name="obj">Object to remove.</param>
88+
/// <param name="objPos">Position of the object.</param>
89+
/// <returns>True if the object was removed successfully.</returns>
90+
public bool Remove(T obj, Vector3 objPos) {
91+
bool removed = rootNode.Remove(obj, objPos);
92+
93+
// See if we can shrink the octree down now that we've removed the item
94+
if (removed) {
95+
Count--;
96+
Shrink();
97+
}
98+
99+
return removed;
100+
}
101+
102+
/// <summary>
103+
/// Returns objects that are within maxDistance of the specified ray.
104+
/// If none returns false. Uses supplied list for results.
105+
/// </summary>
106+
/// <param name="ray">The ray. Passing as ref to improve performance since it won't have to be copied.</param>
107+
/// <param name="maxDistance">Maximum distance from the ray to consider</param>
108+
/// <param name="nearBy">Pre-initialized list to populate</param>
109+
/// <returns>True if items are found, false if not</returns>
110+
public bool GetNearbyNonAlloc(Ray ray, float maxDistance, List<T> nearBy) {
111+
nearBy.Clear();
112+
rootNode.GetNearby(ref ray, ref maxDistance, nearBy);
113+
if (nearBy.Count > 0)
114+
return true;
115+
return false;
116+
}
117+
82118
/// <summary>
83119
/// Return objects that are within maxDistance of the specified ray.
84120
/// If none, returns an empty array (not null).
@@ -92,6 +128,30 @@ public T[] GetNearby(Ray ray, float maxDistance) {
92128
return collidingWith.ToArray();
93129
}
94130

131+
/// <summary>
132+
/// Return objects that are within <paramref name="maxDistance"/> of the specified position.
133+
/// If none, returns an empty array (not null).
134+
/// </summary>
135+
/// <param name="position">The position. Passing as ref to improve performance since it won't have to be copied.</param>
136+
/// <param name="maxDistance">Maximum distance from the ray to consider.</param>
137+
/// <returns>Objects within range.</returns>
138+
public T[] GetNearby(Vector3 position, float maxDistance) {
139+
List<T> collidingWith = new List<T>();
140+
rootNode.GetNearby(ref position, ref maxDistance, collidingWith);
141+
return collidingWith.ToArray();
142+
}
143+
144+
/// <summary>
145+
/// Return all objects in the tree.
146+
/// If none, returns an empty array (not null).
147+
/// </summary>
148+
/// <returns>All objects.</returns>
149+
public ICollection<T> GetAll() {
150+
List<T> objects = new List<T>(Count);
151+
rootNode.GetAll(objects);
152+
return objects;
153+
}
154+
95155
/// <summary>
96156
/// Draws node boundaries visually for debugging.
97157
/// Must be called from OnDrawGizmos externally. See also: DrawAllObjects.

0 commit comments

Comments
 (0)