package org.jwildfire.create.tina.variation;
import java.util.ArrayList;
import java.util.List;
public class OctreeNode {
private final double xmin, xmax, xcentre;
private final double ymin, ymax, ycentre;
private final double zmin, zmax, zcentre;
private final double minsize;
private OctreeNode childs[];
private final List<OctreeValue> values = new ArrayList<>();
public OctreeNode(double pSize) {
this(-pSize / 2.0, pSize / 2.0, -pSize / 2.0, pSize / 2.0, -pSize / 2.0, pSize / 2.0);
}
public OctreeNode(double xmin, double xmax, double ymin, double ymax, double zmin, double zmax) {
this.xmin = xmin;
this.xmax = xmax;
double dx = (xmax - xmin);
this.xcentre = xmin + dx / 2.0;
this.ymin = ymin;
this.ymax = ymax;
double dy = (ymax - ymin);
this.ycentre = ymin + dy / 2.0;
this.zmin = zmin;
this.zmax = zmax;
double dz = (zmax - zmin);
this.zcentre = zmin + dz / 2.0;
minsize = Math.min(Math.min(dx, dy), dz);
}
//
//+Y +Z
//| /
//| /
//| /
//| o---------------o---------------o
//| / / /|
//| / 5 / 6 / |
//| / / / |
//| o---------------o---------------o |
//| / / /| |
//| / 4 / 7 / | 6 |
//|/ / / | o
//o---------------o---------------o | /|
//| | | | / |
//| | | 7 |/ |
//| | | o |
//| 4 | 6 | /| |
//| | | / | 2 |
//| | |/ | o
//o---------------o---------------o | /
//| | | | /
//| | | 3 |/
//| | | o
//| 0 | 3 | /
//| | | /
//| | |/
//o---------------o---------------o -----------------+X
//
public void subdivide() {
double dxh = (xmax - xmin) / 2.0;
double dyh = (ymax - ymin) / 2.0;
double dzh = (zmax - zmin) / 2.0;
childs = new OctreeNode[8];
childs[0] = new OctreeNode(xmin, xmin + dxh, ymin, ymin + dyh, zmin, zmin + dzh);
childs[1] = new OctreeNode(xmin, xmin + dxh, ymin, ymin + dyh, zmax - dzh, zmax);
childs[2] = new OctreeNode(xmax - dxh, xmax, ymin, ymin + dyh, zmax - dzh, zmax);
childs[3] = new OctreeNode(xmax - dxh, xmax, ymin, ymin + dyh, zmin, zmin + dzh);
childs[4] = new OctreeNode(xmin, xmin + dxh, ymax - dyh, ymax, zmin, zmin + dzh);
childs[5] = new OctreeNode(xmin, xmin + dxh, ymax - dyh, ymax, zmax - dzh, zmax);
childs[6] = new OctreeNode(xmax - dxh, xmax, ymax - dyh, ymax, zmax - dzh, zmax);
childs[7] = new OctreeNode(xmax - dxh, xmax, ymax - dyh, ymax, zmin, zmin + dzh);
}
public OctreeNode addValue(double x, double y, double z, Object value, double maxcellsize) {
if (x < xmin || x > xmax || y < ymin || y > ymax || z < zmin || z > zmax) {
return null;
}
OctreeNode node = this;
while (node.minsize > maxcellsize) {
if (node.childs == null) {
node.subdivide();
}
node = node.getEnclosingNode(x, y, z);
if (node == null) {
throw new RuntimeException("Error adding object: (x=" + x + ", y=" + y + ", z=" + z + "), range: (x=" + xmin + " ... " + xmax + ") (y=" + ymin + " ... " + ymax + ") (z=" + zmin + " ... " + zmax + ")");
}
}
System.out.println("Added: (x=" + x + ", y=" + y + ", z=" + z + "), range: (x=" + node.xmin + " ... " + node.xmax + ") (y=" + node.ymin + " ... " + node.ymax + ") (z=" + node.zmin + " ... " + node.zmax + ")");
node.values.add(new OctreeValue(x, y, z, value));
return node;
}
public List<OctreeNode> getEnclosedNodes(double centreX, double centreY, double centreZ, double cellsize, int maxCount) {
double c2 = cellsize / 2.0;
double cellXMin = centreX - c2;
double cellXMax = centreX + c2;
double cellYMin = centreY - c2;
double cellYMax = centreY + c2;
double cellZMin = centreZ - c2;
double cellZMax = centreZ + c2;
List<OctreeNode> res = new ArrayList<>();
addEnclosedNodesToList(this, res, cellXMin, cellXMax, cellYMin, cellYMax, cellZMin, cellZMax, maxCount);
return res;
}
private void addEnclosedNodesToList(OctreeNode node, List<OctreeNode> list, double cellXMin, double cellXMax, double cellYMin, double cellYMax, double cellZMin, double cellZMax, int maxCount) {
if (node.childs != null) {
for (OctreeNode child : node.childs) {
if (maxCount > 0 && list.size() >= maxCount) {
break;
}
if (child.xmin >= cellXMin && child.xmax <= cellXMax && child.ymin >= cellYMin && child.ymax <= cellYMax && child.zmin >= cellZMin && child.zmax <= cellZMax) {
list.add(child);
}
addEnclosedNodesToList(child, list, cellXMin, cellXMax, cellYMin, cellYMax, cellZMin, cellZMax, maxCount);
}
}
}
private OctreeNode getEnclosingNode(double x, double y, double z) {
int startIdx, endIdx;
if (y > ycentre) {
startIdx = 4;
endIdx = 7;
}
else {
startIdx = 0;
endIdx = 3;
}
for (int i = startIdx; i <= endIdx; i++) {
if (x >= childs[i].xmin && x <= childs[i].xmax && y >= childs[i].ymin && y <= childs[i].ymax && z >= childs[i].zmin && z <= childs[i].zmax) {
return childs[i];
}
}
return null;
}
public List<OctreeValue> getValues() {
return values;
}
}