classpublicPriority 3
OctTree
com.hypixel.hytale.builtin.portals.utils.spatial.OctTree
6
Methods
6
Public Methods
2
Fields
3
Constructors
Constants
intDEFAULT_NODE_CAPACITY= 4
intSIZE= 8
Constructors
public
OctTree(double inradius)public
OctTree(Box boundary)public
OctTree(Box boundary, int nodeCapacity)Methods
Public Methods (6)
public
void add(Vector3d pos, T value)public
void addPoint(Vector3d pos, T value)public
Map<T, Vector3d> getAllPoints()public
Map<T, Vector3d> queryRange(Vector3d position, double inradius)public
Map<T, Vector3d> queryRange(Box range)public
int size()Fields
Private/Package Fields (2)
private
int nodeCapacityprivate
OctTree<T>.Node rootRelated Classes
Source Code
package com.hypixel.hytale.builtin.portals.utils.spatial;
import com.hypixel.hytale.math.shape.Box;
import com.hypixel.hytale.math.vector.Vector3d;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.List;
import java.util.Map;
public class OctTree<T> {
private static final int SIZE = 8;
private static final int DEFAULT_NODE_CAPACITY = 4;
private final OctTree<T>.Node root;
private final int nodeCapacity;
public OctTree(double inradius) {
this(new Box(-inradius, -inradius, -inradius, inradius, inradius, inradius), 4);
}
public OctTree(Box boundary) {
this(boundary, 4);
}
public OctTree(Box boundary, int nodeCapacity) {
this.root = new OctTree.Node(boundary);
this.nodeCapacity = nodeCapacity;
}
public void add(Vector3d pos, T value) {
this.add(this.root, pos, value);
}
private boolean add(OctTree<T>.Node node, Vector3d pos, T value) {
if (node != null && node.boundary.containsPosition(pos)) {
if (node.size() < this.nodeCapacity) {
node.addPoint(pos, value);
return true;
} else {
if (node.dirs.isEmpty()) {
this.subdivide(node);
}
for (int i = 0; i < 8; i++) {
if (this.add(node.dirs.get(i), pos, value)) {
return true;
}
}
return false;
}
} else {
return false;
}
}
private void subdivide(OctTree<T>.Node node) {
Vector3d min = node.boundary.min;
double side = node.boundary.width() / 2.0;
for (int i = 0; i < 8; i++) {
Vector3d subMin = new Vector3d(min.x + ((i & 1) > 0 ? side : 0.0), min.y + ((i & 2) > 0 ? side : 0.0), min.z + ((i & 4) > 0 ? side : 0.0));
Box sub = Box.cube(subMin, side);
node.dirs.add(new OctTree.Node(sub));
}
}
public Map<T, Vector3d> getAllPoints() {
return this.queryRange(this.root.boundary);
}
public Map<T, Vector3d> queryRange(Vector3d position, double inradius) {
Box range = Box.centeredCube(position, inradius);
return this.queryRange(range);
}
public Map<T, Vector3d> queryRange(Box range) {
Map<T, Vector3d> out = new Object2ObjectOpenHashMap();
this.queryRange(this.root, range, out);
return out;
}
private void queryRange(OctTree<T>.Node node, Box range, Map<T, Vector3d> out) {
if (node != null && node.boundary.isIntersecting(range)) {
for (int i = 0; i < node.size(); i++) {
Vector3d point = node.points[i];
if (range.containsPosition(point)) {
T value = node.values.get(i);
out.put(value, point);
}
}
for (OctTree<T>.Node dir : node.dirs) {
this.queryRange(dir, range, out);
}
}
}
private class Node {
private final Box boundary;
private final List<OctTree<T>.Node> dirs = new ObjectArrayList(8);
private final Vector3d[] points = new Vector3d[OctTree.this.nodeCapacity];
private final List<T> values = new ObjectArrayList(OctTree.this.nodeCapacity);
private int count;
public Node(Box boundary) {
this.boundary = boundary;
}
public int size() {
return this.count;
}
public void addPoint(Vector3d pos, T value) {
this.points[this.count++] = pos;
this.values.add(value);
}
}
}