All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.livae.util.tree.OctreeNode Maven / Gradle / Ivy

package com.livae.util.tree;

import com.livae.util.ResourcesFactory;
import com.livae.util.math.Vector3f;
import com.livae.util.shape.d3.AxisAlignedBoundingCuboid;
import com.livae.util.shape.d3.Frustum;
import com.livae.util.shape.d3.Intersectable;
import com.livae.util.shape.d3.Sphere;

import java.util.ArrayList;
import java.util.List;

public class OctreeNode extends AxisAlignedBoundingCuboid
  implements Sphere {

	public static final int X_BIT = 0x4;

	public static final int Y_BIT = 0x2;

	public static final int Z_BIT = 0x1;

	private OctreeNode[] nodes;

	private List objects;

	private OctreeNode parent;

	private float radius;

	protected OctreeNode() {
		super(0, 0, 0, 0, 0, 0);
		parent = null;
		//noinspection unchecked
		nodes = (OctreeNode[]) (new OctreeNode[8]);
		objects = new ArrayList();
	}

	protected void init(OctreeNode parent, Vector3f min, Vector3f max) {
		this.parent = parent;
		setMinMaxPoint(min, max);
		objects.clear();
		for (int i = 0; i < nodes.length; i++) {
			nodes[i] = null;
		}
		radius = (float) max.distanceEuclidean(min) / 2;
	}

	public List getObjects() {
		return objects;
	}

	public OctreeNode[] getNodes() {
		return nodes;
	}

	public OctreeNode getParent() {
		return parent;
	}

	public void setParent(OctreeNode node) {
		parent = node;
	}

	public float getRadius() {
		return radius;
	}

	public Vector3f getCentre() {
		return getPosition();
	}

	private boolean contains(Vector3f minZone, Vector3f maxZone, Vector3f minPoint,
	                         Vector3f maxPoint) {
		return minPoint.x >= minZone.x && minPoint.y >= minZone.y && minPoint.z >= minZone.z &&
		       maxPoint.x <= maxZone.x && maxPoint.y <= maxZone.y && maxPoint.z <= maxZone.z;
	}

	protected boolean contains(AxisAlignedBoundingCuboid alignedBox) {
		return contains(getMinPoint(), getMaxPoint(), alignedBox.getMinPoint(),
		                alignedBox.getMaxPoint());
	}

	protected OctreeNode add(k element, ResourcesFactory> factory) {
		AxisAlignedBoundingCuboid alignedCuboid = element.getAxisAlignedBoundingCuboid();
		Vector3f alignedMinPoint = alignedCuboid.getMinPoint();
		Vector3f alignedMaxPoint = alignedCuboid.getMaxPoint();
		Vector3f centerPoint = getCentre();
		int minPos = (centerPoint.x < alignedMinPoint.x ? X_BIT : 0) |
		             (centerPoint.y < alignedMinPoint.y ? Y_BIT : 0) |
		             (centerPoint.z < alignedMinPoint.z ? Z_BIT : 0);
		int maxPos = (centerPoint.x < alignedMaxPoint.x ? X_BIT : 0) |
		             (centerPoint.y < alignedMaxPoint.y ? Y_BIT : 0) |
		             (centerPoint.z < alignedMaxPoint.z ? Z_BIT : 0);
		if (minPos == maxPos) {
			// inside a child
			if (nodes[minPos] == null) {
				nodes[minPos] = factory.getResource();
				Vector3f minPoint = getMinPoint();
				Vector3f maxPoint = getMaxPoint();
				Vector3f newMinPoint = new Vector3f((X_BIT & minPos) > 0 ? centerPoint.x
				                                                         : minPoint.x,
				                                    (Y_BIT & minPos) > 0 ? centerPoint.y
				                                                         : minPoint.y,
				                                    (Z_BIT & minPos) > 0 ? centerPoint.z
				                                                         : minPoint.z);
				Vector3f newMaxPoint = new Vector3f((X_BIT & minPos) > 0 ? maxPoint.x
				                                                         : centerPoint.x,
				                                    (Y_BIT & minPos) > 0 ? maxPoint.y
				                                                         : centerPoint.y,
				                                    (Z_BIT & minPos) > 0 ? maxPoint.z
				                                                         : centerPoint.z);
				nodes[minPos].init(this, newMinPoint, newMaxPoint);
			}
			return nodes[minPos].add(element, factory);
		} else {
			// inside this node
			objects.add(element);
			return this;
		}
	}

	protected void deleteNode(OctreeNode node) {
		int index = 0;
		while (nodes[index] != node) {
			index++;
		}
		nodes[index] = null;
	}

	protected boolean hasChildren() {
		int index = 0;
		while (index < nodes.length && nodes[index] == null) {
			index++;
		}
		return index < nodes.length;
	}

	public void frustumCulling(Frustum frustum, List elements) {
		Frustum.CONTAINS contains = frustum.contains((Sphere) this);
		if (contains == Frustum.CONTAINS.INTERSECTION) {
			contains = frustum.contains((AxisAlignedBoundingCuboid) this);
		}
		switch (contains) {
			case INTERSECTION:
				for (k intersectable : objects) {
					switch (frustum.contains(intersectable.getAxisAlignedBoundingCuboid())) {
						case INTERSECTION:
						case INSIDE:
							elements.add(intersectable);
						case OUTSIDE:
					}
				}
				for (OctreeNode node : nodes) {
					if (node != null) {
						node.frustumCulling(frustum, elements);
					}
				}
				break;
			case INSIDE:
				cullingAddRecursive(elements);
				break;
			case OUTSIDE:
				// nothing
		}
	}

	private void cullingAddRecursive(List elements) {
		for (k object : objects) {
			elements.add(object);
		}
		for (OctreeNode node : nodes) {
			if (node != null) {
				node.cullingAddRecursive(elements);
			}
		}
	}

	public String toString() {
		String s = "[" + getMinPoint() + ";" + getMaxPoint() + "]: ";
		for (Intersectable intersectable : objects) {
			s += intersectable + ", ";
		}
		return s;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy