package speedytools.common.selections;
/**
* User: The Grey Ghost
* Date: 23/09/2014
* Used to iterate through a Voxel region in a chunkwise fashion:
* Iterates through the chunks as
* cz=0: cx=0, cx=1, cx=2 etc then cz=1: cx=0, cx=1, cx=2 etc
* Within each chunk: y fastest, z next, x slowest eg
* [0,0,0] [0,1,0] .. [0,15,0]
* [0,0,1] [0,1,1] .. [0,15,1]
* to
* [0,0,15] .. [0,15,15]
* then
* [1,0,0] [1,1,0] .. [1,15,0]
* etc
*/
public class VoxelChunkwiseIterator implements IVoxelIterator
{
public VoxelChunkwiseIterator(int i_wxOrigin, int i_wyOrigin, int i_wzOrigin, int i_xSize, int i_ySize, int i_zSize)
{
if (i_xSize < 0) throw new IllegalArgumentException("xSize < 0: " + i_xSize);
if (i_ySize < 0) throw new IllegalArgumentException("ySize < 0: " + i_ySize);
if (i_zSize < 0) throw new IllegalArgumentException("zSize < 0: " + i_zSize);
wxOrigin = i_wxOrigin;
wyOrigin = i_wyOrigin;
wzOrigin = i_wzOrigin;
xSize = i_xSize;
ySize = i_ySize;
zSize = i_zSize;
reset();
}
/**
* resets the iterator to start at the beginning
*/
public void reset()
{
atEnd = false;
cxMin = wxOrigin >> 4;
cxMax = (wxOrigin + xSize - 1) >> 4;
czMin = wzOrigin >> 4;
czMax = (wzOrigin + zSize - 1) >> 4;
enteredNewChunk = true;
cx = cxMin;
cz = czMin;
setIterationLimits(cx, cz);
wxLSB = wxLSBmin;
wy = wyMin;
wzLSB = wzLSBmin;
blockCount = 0;
}
/**
* advances to the next voxel coordinate
* @return true if the coordinate position is valid, false otherwise
*/
public boolean next(boolean ignored)
{
if (atEnd) return false;
++blockCount;
if (wy < wyMax) {
++wy;
} else {
wy = wyMin;
if (wzLSB < wzLSBmax) {
++wzLSB;
} else {
wzLSB = wzLSBmin;
if (wxLSB < wxLSBmax) {
++wxLSB;
} else {
wxLSB = wxLSBmin;
enteredNewChunk = true;
if (cz < czMax) {
++cz;
} else {
cz = czMin;
if (cx < cxMax) {
++cx;
} else {
atEnd = true;
}
}
if (!atEnd) {
setIterationLimits(cx, cz);
wxLSB = wxLSBmin;
wzLSB = wzLSBmin;
}
}
}
}
return !atEnd;
}
/** returns true on the first call after the iterator has moved into a new chunk
* @return
*/
public boolean hasEnteredNewChunk() {
boolean retval = enteredNewChunk;
enteredNewChunk = false;
return retval;
}
/** has the iterator reached the end of the region?
* @return
*/
public boolean isAtEnd() {return atEnd;}
/**
* return the chunk x, z coordinate the iterator is currently in
* @return
*/
public int getChunkX() {return cx;}
public int getChunkZ() {return cz;}
/** return the world x, y, z of the current iterator position
* @return
*/
public int getWX() {return (cx << 4) + wxLSB;}
public int getWY() {return wy;}
public int getWZ() {return (cz << 4) + wzLSB;}
/** get the [x,y,z] index of the current iterator position, i.e. relative to the origin
* @return
*/
public int getXpos() {return getWX() - wxOrigin;}
public int getYpos() {return getWY() - wyOrigin;}
public int getZpos() {return getWZ() - wzOrigin;}
/** estimate the fraction of the range that has been iterated through
* @return [0 .. 1]
*/
public float estimatedFractionComplete()
{
return blockCount / (xSize * (float)ySize * zSize);
}
/**
* for a given chunk coordinates, set the LSB iteration limits within that chunk
* eg if cx = 1 and wxOrigin = 21 ( = 16 * cx + 5), then the LSBmin is set to 5.
* @param cx
* @param cz
*/
private void setIterationLimits(int cx, int cz)
{
int wxChunk = cx << 4;
int wxChunkPlus15 = wxChunk + 15;
int wxMin = Math.max(wxOrigin, wxChunk);
int wxMax = Math.min(wxOrigin + xSize - 1, wxChunkPlus15);
assert (wxMin <= wxMax);
wxLSBmin = wxMin & 0x0f;
wxLSBmax = (wxMax & 0x0f);
int wzChunk = cz << 4;
int wzChunkPlus15 = wzChunk + 15;
int wzMin = Math.max(wzOrigin, wzChunk);
int wzMax = Math.min(wzOrigin + zSize - 1, wzChunkPlus15);
assert (wzMin <= wzMax);
wzLSBmin = wzMin & 0x0f;
wzLSBmax = (wzMax & 0x0f);
final int MINIMUM_Y_COORDINATE = 0;
final int MAXIMUM_Y_COORDINATE = 255;
wyMin = Math.max(MINIMUM_Y_COORDINATE, wyOrigin);
wyMax = Math.min(MAXIMUM_Y_COORDINATE, wyOrigin + ySize - 1);
}
private int cxMin;
private int cxMax;
private int czMin;
private int czMax;
private int wxLSBmin;
private int wxLSBmax;
private int wzLSBmin;
private int wzLSBmax;
private int wyMin;
private int wyMax;
private int wxLSB;
private int wzLSB;
private int wy;
private int cx;
private int cz;
private boolean atEnd;
private boolean enteredNewChunk;
private int wxOrigin;
private int wyOrigin;
private int wzOrigin;
private int xSize;
private int ySize;
private int zSize;
private int blockCount;
}