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.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.BitSet;
|
||||
|
||||
import regions.Tree.Node;
|
||||
|
||||
public class Octree extends Tree
|
||||
{
|
||||
|
@ -25,16 +28,16 @@ public class Octree extends Tree
|
|||
return a == -1 || b == -1 ?
|
||||
|
||||
new Node( false ) :
|
||||
new Node( new Node[] { parseBytes(input, (a >>> 6 & 3)),
|
||||
parseBytes(input, (a >>> 4 & 3)),
|
||||
parseBytes(input, (a >>> 2 & 3)),
|
||||
parseBytes(input, (a & 3)),
|
||||
new Node( parseBytes(input, (a >>> 6 & 3)),
|
||||
parseBytes(input, (a >>> 4 & 3)),
|
||||
parseBytes(input, (a >>> 2 & 3)),
|
||||
parseBytes(input, (a & 3)),
|
||||
|
||||
parseBytes(input, (b >>> 6 & 3)),
|
||||
parseBytes(input, (b >>> 4 & 3)),
|
||||
parseBytes(input, (b >>> 2 & 3)),
|
||||
parseBytes(input, (b & 3))
|
||||
});
|
||||
parseBytes(input, (b >>> 6 & 3)),
|
||||
parseBytes(input, (b >>> 4 & 3)),
|
||||
parseBytes(input, (b >>> 2 & 3)),
|
||||
parseBytes(input, (b & 3))
|
||||
);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
|
@ -46,17 +49,17 @@ public class Octree extends Tree
|
|||
@Override
|
||||
public void writeBytes(Node node, OutputStream output) throws IOException
|
||||
{
|
||||
output.write( getByte( node.children[0],
|
||||
node.children[1],
|
||||
node.children[2],
|
||||
node.children[3]
|
||||
));
|
||||
output.write( getByte( node.children[0],
|
||||
node.children[1],
|
||||
node.children[2],
|
||||
node.children[3]
|
||||
));
|
||||
|
||||
output.write( getByte( node.children[4],
|
||||
node.children[5],
|
||||
node.children[6],
|
||||
node.children[7]
|
||||
));
|
||||
output.write( getByte( node.children[4],
|
||||
node.children[5],
|
||||
node.children[6],
|
||||
node.children[7]
|
||||
));
|
||||
|
||||
for (Node child : node.children)
|
||||
if (child.children.length > 0)
|
||||
|
@ -75,27 +78,336 @@ public class Octree extends Tree
|
|||
}
|
||||
|
||||
|
||||
/*-------------------------------------
|
||||
Methods used by constructors.
|
||||
-------------------------------------*/
|
||||
/*
|
||||
╔══════════════════════════════════════════════════════════════════════════════════════════════╗
|
||||
║ ╔══════════════════════════════════════════════════════════════════════════════════════════╗ ║
|
||||
║ ║ ║ ║
|
||||
║ ║ EVALUATE ║ ║
|
||||
║ ║ ║ ║
|
||||
║ ╚══════════════════════════════════════════════════════════════════════════════════════════╝ ║
|
||||
╚══════════════════════════════════════════════════════════════════════════════════════════════╝ */
|
||||
|
||||
|
||||
@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
|
||||
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
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.io.DataInputStream;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.BitSet;
|
||||
|
||||
public class Quadtree extends Tree
|
||||
{
|
||||
|
@ -24,11 +25,11 @@ public class Quadtree extends Tree
|
|||
return a == -1 ?
|
||||
|
||||
new Node( false ) :
|
||||
new Node( new Node[] { parseBytes(input, (a >>> 6 & 3)),
|
||||
parseBytes(input, (a >>> 4 & 3)),
|
||||
parseBytes(input, (a >>> 2 & 3)),
|
||||
parseBytes(input, (a & 3))
|
||||
});
|
||||
new Node( parseBytes(input, (a >>> 6 & 3)),
|
||||
parseBytes(input, (a >>> 4 & 3)),
|
||||
parseBytes(input, (a >>> 2 & 3)),
|
||||
parseBytes(input, (a & 3))
|
||||
);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
|
@ -40,11 +41,11 @@ public class Quadtree extends Tree
|
|||
@Override
|
||||
public void writeBytes(Node node, OutputStream output) throws IOException
|
||||
{
|
||||
output.write( getByte( node.children[0],
|
||||
node.children[1],
|
||||
node.children[2],
|
||||
node.children[3]
|
||||
));
|
||||
output.write( getByte( node.children[0],
|
||||
node.children[1],
|
||||
node.children[2],
|
||||
node.children[3]
|
||||
));
|
||||
|
||||
for (Node child : node.children)
|
||||
if (child.children.length > 0)
|
||||
|
@ -64,27 +65,287 @@ public class Quadtree extends Tree
|
|||
}
|
||||
|
||||
|
||||
/*-------------------------------------
|
||||
Methods used by constructors.
|
||||
-------------------------------------*/
|
||||
/*
|
||||
╔══════════════════════════════════════════════════════════════════════════════════════════════╗
|
||||
║ ╔══════════════════════════════════════════════════════════════════════════════════════════╗ ║
|
||||
║ ║ ║ ║
|
||||
║ ║ EVALUATE ║ ║
|
||||
║ ║ ║ ║
|
||||
║ ╚══════════════════════════════════════════════════════════════════════════════════════════╝ ║
|
||||
╚══════════════════════════════════════════════════════════════════════════════════════════════╝ */
|
||||
|
||||
|
||||
@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
|
||||
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
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,27 +7,23 @@ import java.io.FileInputStream;
|
|||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
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 Encoding: A New Technique for the Representation, Manipulation and Display of
|
||||
* Arbitrary 3-D Objects by Computer."<p>
|
||||
* Octree application can be visualized like this:<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
|
||||
* smallest box your shape will fit inside of). This box outlines the minimum and maximum
|
||||
* x, y, and z dimensions of the shape.<p>
|
||||
* With the space thus divided, evaluate which octants the object fills, which it avoids, and which
|
||||
* it intersects. Divide intersected octants again. Continue dividing until no partial octants remain,
|
||||
* or until the desired resolution is reached.<p>
|
||||
*
|
||||
* Next, you divide this cube evenly into 8 more cubes, determining which of these cubes
|
||||
* 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.
|
||||
* Useful for testing whether an arbitrary 3-D object contains any given point.
|
||||
*
|
||||
* @author Kevin Mathewson
|
||||
*
|
||||
|
@ -47,11 +43,28 @@ public abstract class Tree
|
|||
this.full = full;
|
||||
this.children = new Node[0];
|
||||
}
|
||||
public Node(Node[] nodes)
|
||||
public Node(Node... nodes)
|
||||
{
|
||||
this.full = false;
|
||||
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
|
||||
* <tt>{@link #getByte(Node, Node, Node, Node) getByte(children)}</tt> for each encountered
|
||||
* node in the tree, skipping childless nodes.<p>
|
||||
*
|
||||
* Assumes an OutputStream that appends with each write.
|
||||
* Appends to the OutputStream the result of invoking <tt>{@link #getByte(Node, Node, Node, Node)
|
||||
* getByte(children)}</tt> for each node, skipping childless nodes. Assumes an OutputStream that
|
||||
* appends with each write. Traverses depth-first.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
public abstract void writeBytes(Node node, OutputStream output) throws IOException;
|
||||
|
@ -266,7 +277,6 @@ public abstract class Tree
|
|||
|
||||
public final File file;
|
||||
public final Node root;
|
||||
public final TreeEditor<? extends Tree> editor;
|
||||
|
||||
/**
|
||||
* Create a Tree from the given binary file. Invokes {@link #parseBytes(File)}
|
||||
|
@ -280,7 +290,19 @@ public abstract class Tree
|
|||
|
||||
this.file = 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
|
||||
*/
|
||||
private static void setBoundsFromFilename(File file)
|
||||
private void setBoundsFromFilename(File file)
|
||||
{
|
||||
//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 regionBounds
|
||||
* @param a
|
||||
* @return
|
||||
*/
|
||||
public abstract Node[] getNodes(Node parentNode, int[][] regionBounds);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param regionBounds
|
||||
* @return
|
||||
*/
|
||||
public Node[] getNodes(int[][] regionBounds)
|
||||
public static int nextPowerOfTwo(int a)
|
||||
{
|
||||
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