added methods for expanding trees to include points outside current bounds
This commit is contained in:
parent
ba8a2eee0a
commit
5ece1f35eb
3 changed files with 802 additions and 93 deletions
|
@ -4,6 +4,9 @@ import java.io.DataInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.util.BitSet;
|
||||||
|
|
||||||
|
import regions.Tree.Node;
|
||||||
|
|
||||||
public class Octree extends Tree
|
public class Octree extends Tree
|
||||||
{
|
{
|
||||||
|
@ -25,7 +28,7 @@ public class Octree extends Tree
|
||||||
return a == -1 || b == -1 ?
|
return a == -1 || b == -1 ?
|
||||||
|
|
||||||
new Node( false ) :
|
new Node( false ) :
|
||||||
new Node( new Node[] { parseBytes(input, (a >>> 6 & 3)),
|
new Node( parseBytes(input, (a >>> 6 & 3)),
|
||||||
parseBytes(input, (a >>> 4 & 3)),
|
parseBytes(input, (a >>> 4 & 3)),
|
||||||
parseBytes(input, (a >>> 2 & 3)),
|
parseBytes(input, (a >>> 2 & 3)),
|
||||||
parseBytes(input, (a & 3)),
|
parseBytes(input, (a & 3)),
|
||||||
|
@ -34,7 +37,7 @@ public class Octree extends Tree
|
||||||
parseBytes(input, (b >>> 4 & 3)),
|
parseBytes(input, (b >>> 4 & 3)),
|
||||||
parseBytes(input, (b >>> 2 & 3)),
|
parseBytes(input, (b >>> 2 & 3)),
|
||||||
parseBytes(input, (b & 3))
|
parseBytes(input, (b & 3))
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------
|
||||||
|
@ -75,27 +78,336 @@ public class Octree extends Tree
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------
|
/*
|
||||||
Methods used by constructors.
|
╔══════════════════════════════════════════════════════════════════════════════════════════════╗
|
||||||
-------------------------------------*/
|
║ ╔══════════════════════════════════════════════════════════════════════════════════════════╗ ║
|
||||||
|
║ ║ ║ ║
|
||||||
|
║ ║ EVALUATE ║ ║
|
||||||
|
║ ║ ║ ║
|
||||||
|
║ ╚══════════════════════════════════════════════════════════════════════════════════════════╝ ║
|
||||||
|
╚══════════════════════════════════════════════════════════════════════════════════════════════╝ */
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final TreeEditor<Octree> newEditor()
|
public boolean contains(int... coords)
|
||||||
{
|
{
|
||||||
return new TreeEditor<Octree>(this, min[0], min[1], min[2]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
╔══════════════════════════════════════════════════════════════════════════════════════════════╗
|
||||||
|
║ ╔══════════════════════════════════════════════════════════════════════════════════════════╗ ║
|
||||||
|
║ ║ ║ ║
|
||||||
|
║ ║ ADD VOLUME ║ ║
|
||||||
|
║ ║ ║ ║
|
||||||
|
║ ╚══════════════════════════════════════════════════════════════════════════════════════════╝ ║
|
||||||
|
╚══════════════════════════════════════════════════════════════════════════════════════════════╝ */
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
expand()
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
----------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param xMinExpansion
|
||||||
|
* @param zMinExpansion
|
||||||
|
* @param yMinExpansion
|
||||||
|
* @param xMaxExpansion
|
||||||
|
* @param zMaxExpansion
|
||||||
|
* @param yMaxExpansion
|
||||||
|
*/
|
||||||
|
protected void expand(double xMinExpansion, double zMinExpansion, double yMinExpansion,
|
||||||
|
double xMaxExpansion, double zMaxExpansion, double yMaxExpansion
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int xMinRounded = (int) Math.ceil(xMinExpansion),
|
||||||
|
zMinRounded = (int) Math.ceil(zMinExpansion),
|
||||||
|
yMinRounded = (int) Math.ceil(yMinExpansion),
|
||||||
|
xMaxRounded = (int) Math.ceil(xMaxExpansion),
|
||||||
|
zMaxRounded = (int) Math.ceil(zMaxExpansion),
|
||||||
|
yMaxRounded = (int) Math.ceil(yMaxExpansion),
|
||||||
|
|
||||||
|
size = nextPowerOfTwo( xMinRounded + xMaxRounded + 1,
|
||||||
|
zMinRounded + zMaxRounded + 1,
|
||||||
|
yMinRounded + yMaxRounded + 1
|
||||||
|
),
|
||||||
|
|
||||||
|
xMargin = size - (xMinRounded + xMaxRounded + 1),
|
||||||
|
zMargin = size - (zMinRounded + zMaxRounded + 1),
|
||||||
|
yMargin = size - (yMinRounded + yMaxRounded + 1),
|
||||||
|
|
||||||
|
xMarginHalf = xMargin / 2,
|
||||||
|
zMarginHalf = zMargin / 2,
|
||||||
|
yMarginHalf = yMargin / 2;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
xMinRounded += xMarginHalf;
|
||||||
|
zMinRounded += zMarginHalf;
|
||||||
|
yMinRounded += yMarginHalf;
|
||||||
|
xMaxRounded += xMarginHalf;
|
||||||
|
zMaxRounded += zMarginHalf;
|
||||||
|
yMaxRounded += yMarginHalf;
|
||||||
|
|
||||||
|
/* if margin is odd, add 1
|
||||||
|
* to the more close-fitting side
|
||||||
|
*/
|
||||||
|
if (xMargin % 2 == 1)
|
||||||
|
if (xMinRounded - xMinExpansion > xMaxRounded - xMaxExpansion) xMinRounded++; else xMaxRounded++;
|
||||||
|
|
||||||
|
if (zMargin % 2 == 1)
|
||||||
|
if (zMinRounded - zMinExpansion > zMaxRounded - zMaxExpansion) zMinRounded++; else zMaxRounded++;
|
||||||
|
|
||||||
|
if (yMargin % 2 == 1)
|
||||||
|
if (yMinRounded - yMinExpansion > yMaxRounded - yMaxExpansion) yMinRounded++; else yMaxRounded++;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int index;
|
||||||
|
Node[] children;
|
||||||
|
Node[] newRootChildren = children = Node.emptyNodeArray(8);
|
||||||
|
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
size >>>= 1;
|
||||||
|
index = 0;
|
||||||
|
|
||||||
|
if (xMinRounded >= size)
|
||||||
|
xMinRounded -= size;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xMaxRounded -= size;
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
if (zMinRounded >= size)
|
||||||
|
zMinRounded -= size;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
zMaxRounded -= size;
|
||||||
|
index += 2;
|
||||||
|
}
|
||||||
|
if (yMinRounded >= size)
|
||||||
|
yMinRounded -= size;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
yMaxRounded -= size;
|
||||||
|
index += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size > 1)
|
||||||
|
children[index].children = children = Node.emptyNodeArray(8);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
children[index].children = root.children;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
root.children = newRootChildren;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
CALCULATIONS
|
expandAsNeeded()
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
----------------------------------------------------------------------------*/
|
----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Node[] getNodes(Node parentNode, int[][] regionBounds)
|
protected void expandAsNeeded(int... coords)
|
||||||
|
{
|
||||||
|
int sideLength = max[0] - min[0] + 1;
|
||||||
|
|
||||||
|
double xMinExpansion = 0,
|
||||||
|
zMinExpansion = 0,
|
||||||
|
yMinExpansion = 0,
|
||||||
|
xMaxExpansion = 0,
|
||||||
|
zMaxExpansion = 0,
|
||||||
|
yMaxExpansion = 0;
|
||||||
|
|
||||||
|
if (coords[0] < min[0]) xMinExpansion = (min[0] - coords[0]) / sideLength;
|
||||||
|
else if (coords[0] > max[0]) xMaxExpansion = (coords[0] - max[0]) / sideLength;
|
||||||
|
|
||||||
|
if (coords[1] < min[1]) xMinExpansion = (min[1] - coords[1]) / sideLength;
|
||||||
|
else if (coords[1] > max[1]) xMaxExpansion = (coords[1] - max[1]) / sideLength;
|
||||||
|
|
||||||
|
if (coords[2] < min[2]) xMinExpansion = (min[2] - coords[2]) / sideLength;
|
||||||
|
else if (coords[2] > max[2]) xMaxExpansion = (coords[2] - max[2]) / sideLength;
|
||||||
|
|
||||||
|
if (xMinExpansion != 0 ||
|
||||||
|
zMinExpansion != 0 ||
|
||||||
|
yMinExpansion != 0 ||
|
||||||
|
xMaxExpansion != 0 ||
|
||||||
|
zMaxExpansion != 0 ||
|
||||||
|
yMaxExpansion != 0
|
||||||
|
)
|
||||||
|
expand(xMinExpansion,
|
||||||
|
zMinExpansion,
|
||||||
|
yMinExpansion,
|
||||||
|
xMaxExpansion,
|
||||||
|
zMaxExpansion,
|
||||||
|
yMaxExpansion);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void expandAsNeeded(int[]... bounds)
|
||||||
|
{
|
||||||
|
int sideLength = max[0] - min[0] + 1;
|
||||||
|
|
||||||
|
double xMinExpansion = 0,
|
||||||
|
zMinExpansion = 0,
|
||||||
|
yMinExpansion = 0,
|
||||||
|
xMaxExpansion = 0,
|
||||||
|
zMaxExpansion = 0,
|
||||||
|
yMaxExpansion = 0;
|
||||||
|
|
||||||
|
if (bounds[0][0] < min[0]) xMinExpansion = (min[0] - bounds[0][0]) / sideLength;
|
||||||
|
if (bounds[0][1] > max[0]) xMaxExpansion = (bounds[0][1] - max[0]) / sideLength;
|
||||||
|
|
||||||
|
if (bounds[1][0] < min[1]) xMinExpansion = (min[1] - bounds[1][0]) / sideLength;
|
||||||
|
if (bounds[1][1] > max[1]) xMaxExpansion = (bounds[1][1] - max[1]) / sideLength;
|
||||||
|
|
||||||
|
if (bounds[2][0] < min[2]) xMinExpansion = (min[2] - bounds[2][0]) / sideLength;
|
||||||
|
if (bounds[2][1] > max[2]) xMaxExpansion = (bounds[2][1] - max[2]) / sideLength;
|
||||||
|
|
||||||
|
if (xMinExpansion != 0 ||
|
||||||
|
zMinExpansion != 0 ||
|
||||||
|
yMinExpansion != 0 ||
|
||||||
|
xMaxExpansion != 0 ||
|
||||||
|
zMaxExpansion != 0 ||
|
||||||
|
yMaxExpansion != 0
|
||||||
|
)
|
||||||
|
expand(xMinExpansion,
|
||||||
|
zMinExpansion,
|
||||||
|
yMinExpansion,
|
||||||
|
xMaxExpansion,
|
||||||
|
zMaxExpansion,
|
||||||
|
yMaxExpansion);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
add()
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(int... coords)
|
||||||
|
{
|
||||||
|
expandAsNeeded(coords);
|
||||||
|
|
||||||
|
Node node = root;
|
||||||
|
|
||||||
|
int[] min = this.min;
|
||||||
|
int[] max = this.max;
|
||||||
|
|
||||||
|
int size = max[0] - min[0] + 1;
|
||||||
|
int half = size / 2;
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
outerloop:
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (node.full) return;
|
||||||
|
if (node.children.length == 0) node.children = Node.emptyNodeArray(8);
|
||||||
|
|
||||||
|
if ((min[0] + half) > coords[0])
|
||||||
|
max[0] -= half;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
min[0] += half;
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
if ((min[1] + half) > coords[1])
|
||||||
|
max[1] -= half;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
min[1] += half;
|
||||||
|
index += 2;
|
||||||
|
}
|
||||||
|
if ((min[2] + half) > coords[2])
|
||||||
|
max[2] -= half;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
min[2] += half;
|
||||||
|
index += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((size >>>= 1) > 1)
|
||||||
|
{
|
||||||
|
node = node.children[index];
|
||||||
|
half = size / 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node.children[index].full = true;
|
||||||
|
|
||||||
|
for (Node child : node.children)
|
||||||
|
{
|
||||||
|
if (!child.full)
|
||||||
|
{
|
||||||
|
break outerloop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node.full = true;
|
||||||
|
node.children = new Node[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(int[]... bounds)
|
||||||
|
{
|
||||||
|
expandAsNeeded(bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(BitSet blocks, int[]... bounds)
|
||||||
|
{
|
||||||
|
expandAsNeeded(bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
╔══════════════════════════════════════════════════════════════════════════════════════════════╗
|
||||||
|
║ ╔══════════════════════════════════════════════════════════════════════════════════════════╗ ║
|
||||||
|
║ ║ ║ ║
|
||||||
|
║ ║ REMOVE VOLUME ║ ║
|
||||||
|
║ ║ ║ ║
|
||||||
|
║ ╚══════════════════════════════════════════════════════════════════════════════════════════╝ ║
|
||||||
|
╚══════════════════════════════════════════════════════════════════════════════════════════════╝ */
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trimAsNeeded()
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(int... coords)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(int[]... bounds)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(BitSet blocks, int[]... bounds)
|
||||||
{
|
{
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import java.io.DataInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.util.BitSet;
|
||||||
|
|
||||||
public class Quadtree extends Tree
|
public class Quadtree extends Tree
|
||||||
{
|
{
|
||||||
|
@ -24,11 +25,11 @@ public class Quadtree extends Tree
|
||||||
return a == -1 ?
|
return a == -1 ?
|
||||||
|
|
||||||
new Node( false ) :
|
new Node( false ) :
|
||||||
new Node( new Node[] { parseBytes(input, (a >>> 6 & 3)),
|
new Node( parseBytes(input, (a >>> 6 & 3)),
|
||||||
parseBytes(input, (a >>> 4 & 3)),
|
parseBytes(input, (a >>> 4 & 3)),
|
||||||
parseBytes(input, (a >>> 2 & 3)),
|
parseBytes(input, (a >>> 2 & 3)),
|
||||||
parseBytes(input, (a & 3))
|
parseBytes(input, (a & 3))
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------
|
||||||
|
@ -64,27 +65,287 @@ public class Quadtree extends Tree
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------
|
/*
|
||||||
Methods used by constructors.
|
╔══════════════════════════════════════════════════════════════════════════════════════════════╗
|
||||||
-------------------------------------*/
|
║ ╔══════════════════════════════════════════════════════════════════════════════════════════╗ ║
|
||||||
|
║ ║ ║ ║
|
||||||
|
║ ║ EVALUATE ║ ║
|
||||||
|
║ ║ ║ ║
|
||||||
|
║ ╚══════════════════════════════════════════════════════════════════════════════════════════╝ ║
|
||||||
|
╚══════════════════════════════════════════════════════════════════════════════════════════════╝ */
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final TreeEditor<Quadtree> newEditor()
|
public boolean contains(int... coords)
|
||||||
{
|
{
|
||||||
return new TreeEditor<Quadtree>(this, min[0], min[1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
╔══════════════════════════════════════════════════════════════════════════════════════════════╗
|
||||||
|
║ ╔══════════════════════════════════════════════════════════════════════════════════════════╗ ║
|
||||||
|
║ ║ ║ ║
|
||||||
|
║ ║ ADD VOLUME ║ ║
|
||||||
|
║ ║ ║ ║
|
||||||
|
║ ╚══════════════════════════════════════════════════════════════════════════════════════════╝ ║
|
||||||
|
╚══════════════════════════════════════════════════════════════════════════════════════════════╝ */
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
expand()
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param xMinExpansion
|
||||||
|
* @param zMinExpansion
|
||||||
|
* @param xMaxExpansion
|
||||||
|
* @param zMaxExpansion
|
||||||
|
*/
|
||||||
|
protected void expand(double xMinExpansion, double zMinExpansion, double xMaxExpansion, double zMaxExpansion)
|
||||||
|
{
|
||||||
|
int xMinRounded = (int) Math.ceil(xMinExpansion),
|
||||||
|
zMinRounded = (int) Math.ceil(zMinExpansion),
|
||||||
|
xMaxRounded = (int) Math.ceil(xMaxExpansion),
|
||||||
|
zMaxRounded = (int) Math.ceil(zMaxExpansion),
|
||||||
|
|
||||||
|
size = nextPowerOfTwo( xMinRounded + xMaxRounded + 1,
|
||||||
|
zMinRounded + zMaxRounded + 1
|
||||||
|
),
|
||||||
|
|
||||||
|
xMargin = size - (xMinRounded + xMaxRounded + 1),
|
||||||
|
zMargin = size - (zMinRounded + zMaxRounded + 1),
|
||||||
|
|
||||||
|
xMarginHalf = xMargin / 2,
|
||||||
|
zMarginHalf = zMargin / 2;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
xMinRounded += xMarginHalf;
|
||||||
|
zMinRounded += zMarginHalf;
|
||||||
|
xMaxRounded += xMarginHalf;
|
||||||
|
zMaxRounded += zMarginHalf;
|
||||||
|
|
||||||
|
/* if margin is odd, add 1
|
||||||
|
* to the more close-fitting side
|
||||||
|
*/
|
||||||
|
if (xMargin % 2 == 1)
|
||||||
|
if (xMinRounded - xMinExpansion > xMaxRounded - xMaxExpansion) xMinRounded++; else xMaxRounded++;
|
||||||
|
|
||||||
|
if (zMargin % 2 == 1)
|
||||||
|
if (zMinRounded - zMinExpansion > zMaxRounded - zMaxExpansion) zMinRounded++; else zMaxRounded++;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int index;
|
||||||
|
Node[] children;
|
||||||
|
Node[] newRootChildren = children = Node.emptyNodeArray(4);
|
||||||
|
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
size >>>= 1;
|
||||||
|
index = 0;
|
||||||
|
|
||||||
|
if (xMinRounded >= size)
|
||||||
|
xMinRounded -= size;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xMaxRounded -= size;
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
if (zMinRounded >= size)
|
||||||
|
zMinRounded -= size;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
zMaxRounded -= size;
|
||||||
|
index += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size > 1)
|
||||||
|
children[index].children = children = Node.emptyNodeArray(4);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
children[index].children = root.children;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
root.children = newRootChildren;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
CALCULATIONS
|
expandAsNeeded()
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
----------------------------------------------------------------------------*/
|
----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Node[] getNodes(Node parentNode, int[][] regionBounds)
|
protected void expandAsNeeded(int... coords)
|
||||||
|
{
|
||||||
|
int sideLength = max[0] - min[0] + 1;
|
||||||
|
|
||||||
|
double xMinExpansion = 0,
|
||||||
|
zMinExpansion = 0,
|
||||||
|
xMaxExpansion = 0,
|
||||||
|
zMaxExpansion = 0;
|
||||||
|
|
||||||
|
if (coords[0] < min[0]) xMinExpansion = (min[0] - coords[0]) / sideLength;
|
||||||
|
else if (coords[0] > max[0]) xMaxExpansion = (coords[0] - max[0]) / sideLength;
|
||||||
|
|
||||||
|
if (coords[1] < min[1]) xMinExpansion = (min[1] - coords[1]) / sideLength;
|
||||||
|
else if (coords[1] > max[1]) xMaxExpansion = (coords[1] - max[1]) / sideLength;
|
||||||
|
|
||||||
|
if (xMinExpansion != 0 ||
|
||||||
|
zMinExpansion != 0 ||
|
||||||
|
xMaxExpansion != 0 ||
|
||||||
|
zMaxExpansion != 0
|
||||||
|
)
|
||||||
|
expand(xMinExpansion,
|
||||||
|
zMinExpansion,
|
||||||
|
xMaxExpansion,
|
||||||
|
zMaxExpansion);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void expandAsNeeded(int[]... bounds)
|
||||||
|
{
|
||||||
|
int sideLength = max[0] - min[0] + 1;
|
||||||
|
|
||||||
|
double xMinExpansion = 0,
|
||||||
|
zMinExpansion = 0,
|
||||||
|
xMaxExpansion = 0,
|
||||||
|
zMaxExpansion = 0;
|
||||||
|
|
||||||
|
if (bounds[0][0] < min[0]) xMinExpansion = (min[0] - bounds[0][0]) / sideLength;
|
||||||
|
if (bounds[0][1] > max[0]) xMaxExpansion = (bounds[0][1] - max[0]) / sideLength;
|
||||||
|
|
||||||
|
if (bounds[1][0] < min[1]) xMinExpansion = (min[1] - bounds[1][0]) / sideLength;
|
||||||
|
if (bounds[1][1] > max[1]) xMaxExpansion = (bounds[1][1] - max[1]) / sideLength;
|
||||||
|
|
||||||
|
if (xMinExpansion != 0 ||
|
||||||
|
zMinExpansion != 0 ||
|
||||||
|
xMaxExpansion != 0 ||
|
||||||
|
zMaxExpansion != 0
|
||||||
|
)
|
||||||
|
expand(xMinExpansion,
|
||||||
|
zMinExpansion,
|
||||||
|
xMaxExpansion,
|
||||||
|
zMaxExpansion);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
add()
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(int... coords)
|
||||||
|
{
|
||||||
|
expandAsNeeded(coords);
|
||||||
|
|
||||||
|
Node node = root;
|
||||||
|
|
||||||
|
int[] min = this.min;
|
||||||
|
int[] max = this.max;
|
||||||
|
|
||||||
|
int size = max[0] - min[0] + 1;
|
||||||
|
int half = size / 2;
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
outerloop:
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (node.full) return;
|
||||||
|
if (node.children.length == 0) node.children = Node.emptyNodeArray(4);
|
||||||
|
|
||||||
|
if ((min[0] + half) > coords[0])
|
||||||
|
max[0] -= half;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
min[0] += half;
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
if ((min[1] + half) > coords[1])
|
||||||
|
max[1] -= half;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
min[1] += half;
|
||||||
|
index += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((size >>>= 1) > 1)
|
||||||
|
{
|
||||||
|
node = node.children[index];
|
||||||
|
half = size / 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node.children[index].full = true;
|
||||||
|
|
||||||
|
for (Node child : node.children)
|
||||||
|
{
|
||||||
|
if (!child.full)
|
||||||
|
{
|
||||||
|
break outerloop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node.full = true;
|
||||||
|
node.children = new Node[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(int[]... bounds)
|
||||||
|
{
|
||||||
|
expandAsNeeded(bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(BitSet blocks, int[]... bounds)
|
||||||
|
{
|
||||||
|
expandAsNeeded(bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------
|
||||||
|
REMOVE VOLUME
|
||||||
|
-------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trimAsNeeded()
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(int... coords)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(int[]... bounds)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(BitSet blocks, int[]... bounds)
|
||||||
{
|
{
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,27 +7,23 @@ import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.util.BitSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a superclass for octrees, quadtrees, and any other spatial trees.<p>
|
* A superclass for octrees and quadtrees. Concept credit to Don Meagher, who first named and
|
||||||
|
* described Octrees in his 1980 paper, "Octree Encoding: A New Technique for the Representation,
|
||||||
|
* Manipulation and Display of Arbitrary 3-D Objects by Computer."<p>
|
||||||
*
|
*
|
||||||
* concept credit to Don Meagher, who first named and described Octrees in his 1980 paper,
|
* Octree application can be visualized like this:<p>
|
||||||
* "Octree Encoding: A New Technique for the Representation, Manipulation and Display of
|
|
||||||
* Arbitrary 3-D Objects by Computer."<p>
|
|
||||||
*
|
*
|
||||||
* The idea works like this:<p>
|
* For any arbitrary 3-D object, find the bounding cube of the shape (or the smallest cube it will
|
||||||
|
* fit inside of). Divide this bounding cube into 8 sub-cubes, or octants.<p>
|
||||||
*
|
*
|
||||||
* For some arbitrary shape, you first define the bounding box of the shape (or the
|
* With the space thus divided, evaluate which octants the object fills, which it avoids, and which
|
||||||
* smallest box your shape will fit inside of). This box outlines the minimum and maximum
|
* it intersects. Divide intersected octants again. Continue dividing until no partial octants remain,
|
||||||
* x, y, and z dimensions of the shape.<p>
|
* or until the desired resolution is reached.<p>
|
||||||
*
|
*
|
||||||
* Next, you divide this cube evenly into 8 more cubes, determining which of these cubes
|
* Useful for testing whether an arbitrary 3-D object contains any given point.
|
||||||
* your shape fills, which it leaves empty, and which it intersects. Intersected cubes are
|
|
||||||
* divided again into 8 more cubes, and the process repeats until only completely full
|
|
||||||
* (<tt>true</tt>) and completely empty (<tt>false</tt>) cubes remain.<p>
|
|
||||||
*
|
|
||||||
* With this tree, you can quickly determine whether any arbitrary point is inside or outside
|
|
||||||
* your shape by navigating the tree to reach the smallest cube containing your point.
|
|
||||||
*
|
*
|
||||||
* @author Kevin Mathewson
|
* @author Kevin Mathewson
|
||||||
*
|
*
|
||||||
|
@ -47,11 +43,28 @@ public abstract class Tree
|
||||||
this.full = full;
|
this.full = full;
|
||||||
this.children = new Node[0];
|
this.children = new Node[0];
|
||||||
}
|
}
|
||||||
public Node(Node[] nodes)
|
public Node(Node... nodes)
|
||||||
{
|
{
|
||||||
this.full = false;
|
this.full = false;
|
||||||
this.children = nodes;
|
this.children = nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array containing the given number of empty, childless nodes
|
||||||
|
*
|
||||||
|
* @param length desired size of array
|
||||||
|
*/
|
||||||
|
public static Node[] emptyNodeArray(int length)
|
||||||
|
{
|
||||||
|
Node[] array = new Node[length];
|
||||||
|
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
array[i] = new Node(false);
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -170,14 +183,12 @@ public abstract class Tree
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the tree below this node, appending in depth-first order the result of invoking
|
* Appends to the OutputStream the result of invoking <tt>{@link #getByte(Node, Node, Node, Node)
|
||||||
* <tt>{@link #getByte(Node, Node, Node, Node) getByte(children)}</tt> for each encountered
|
* getByte(children)}</tt> for each node, skipping childless nodes. Assumes an OutputStream that
|
||||||
* node in the tree, skipping childless nodes.<p>
|
* appends with each write. Traverses depth-first.
|
||||||
*
|
|
||||||
* Assumes an OutputStream that appends with each write.
|
|
||||||
*
|
*
|
||||||
* @param node the node to be parsed
|
* @param node the node to be parsed
|
||||||
* @return a byte array representing the node and all its child nodes
|
* @param output the OutputStream to write to
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public abstract void writeBytes(Node node, OutputStream output) throws IOException;
|
public abstract void writeBytes(Node node, OutputStream output) throws IOException;
|
||||||
|
@ -266,7 +277,6 @@ public abstract class Tree
|
||||||
|
|
||||||
public final File file;
|
public final File file;
|
||||||
public final Node root;
|
public final Node root;
|
||||||
public final TreeEditor<? extends Tree> editor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a Tree from the given binary file. Invokes {@link #parseBytes(File)}
|
* Create a Tree from the given binary file. Invokes {@link #parseBytes(File)}
|
||||||
|
@ -280,7 +290,19 @@ public abstract class Tree
|
||||||
|
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.root = parseBytes(file);
|
this.root = parseBytes(file);
|
||||||
this.editor = newEditor();
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param file The source file, and save destination, for this Tree
|
||||||
|
* @param blocks BitSet representing all <tt>true</tt> points in the given volume
|
||||||
|
* @param bounds Min and max coordinates of the bounding box
|
||||||
|
*/
|
||||||
|
public Tree(File file, BitSet blocks, int[][] bounds)
|
||||||
|
{
|
||||||
|
this.file = file;
|
||||||
|
this.root = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -298,21 +320,12 @@ public abstract class Tree
|
||||||
*
|
*
|
||||||
* @param file the source file to examine
|
* @param file the source file to examine
|
||||||
*/
|
*/
|
||||||
private static void setBoundsFromFilename(File file)
|
private void setBoundsFromFilename(File file)
|
||||||
{
|
{
|
||||||
//TODO finish setBoundsFromFilename() method
|
//TODO finish setBoundsFromFilename() method
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract method, returns a new object
|
|
||||||
* extending the abstract class TreeEditor
|
|
||||||
*
|
|
||||||
* @return a new TreeEditor
|
|
||||||
*/
|
|
||||||
abstract TreeEditor<? extends Tree> newEditor();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
╔══════════════════════════════════════════════════════════════════════════════════════════════╗
|
╔══════════════════════════════════════════════════════════════════════════════════════════════╗
|
||||||
|
@ -323,23 +336,146 @@ public abstract class Tree
|
||||||
║ ╚══════════════════════════════════════════════════════════════════════════════════════════╝ ║
|
║ ╚══════════════════════════════════════════════════════════════════════════════════════════╝ ║
|
||||||
╚══════════════════════════════════════════════════════════════════════════════════════════════╝ */
|
╚══════════════════════════════════════════════════════════════════════════════════════════════╝ */
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
STATIC CALCULATIONS
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*-------------------------------------
|
||||||
|
OVERLOADS : nextPowerOfTwo()
|
||||||
|
-------------------------------------*/
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param parentNode
|
* @param a
|
||||||
* @param regionBounds
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public abstract Node[] getNodes(Node parentNode, int[][] regionBounds);
|
public static int nextPowerOfTwo(int a)
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param regionBounds
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Node[] getNodes(int[][] regionBounds)
|
|
||||||
{
|
{
|
||||||
return getNodes(root, regionBounds);
|
return java.lang.Integer.highestOneBit(a) << 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param a
|
||||||
|
* @param b
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static int nextPowerOfTwo(int a, int b)
|
||||||
|
{
|
||||||
|
return java.lang.Integer.highestOneBit(Math.max(a, b)) << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param a
|
||||||
|
* @param b
|
||||||
|
* @param c
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static int nextPowerOfTwo(int a, int b, int c)
|
||||||
|
{
|
||||||
|
return java.lang.Integer.highestOneBit(Math.max(Math.max(a, b), c)) << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
EVALUATE
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param coords
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public abstract boolean contains(int... coords);
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
ADD VOLUME
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param coordinates
|
||||||
|
*/
|
||||||
|
protected abstract void expandAsNeeded(int...coords);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param bounds
|
||||||
|
*/
|
||||||
|
protected abstract void expandAsNeeded(int[]...bounds);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param coordinates
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public abstract void add(int...coords);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param bounds
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public abstract void add(int[]...bounds);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param blocks
|
||||||
|
* @param bounds
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public abstract void add(BitSet blocks, int[]...bounds);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
REMOVE VOLUME
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract void trimAsNeeded();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param coordinates
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public abstract void remove(int...coords);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param bounds
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public abstract void remove(int[]...bounds);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param blocks
|
||||||
|
* @param bounds
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public abstract void remove(BitSet blocks, int[]...bounds);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue