-
Vojtech Moravec authoredVojtech Moravec authored
BasicLoader.java 12.36 KiB
package azgracompress.io.loader;
import azgracompress.data.*;
import java.io.IOException;
public abstract class BasicLoader {
protected final V3i dims;
protected int threadCount = 1;
protected BasicLoader(final V3i datasetDims) {
this.dims = datasetDims;
}
public V3i getImageDimensions() {
return dims;
}
/**
* Abstract method to load specified plane data.
*
* @param plane Zero based plane index.
* @return Plane data.
* @throws IOException when fails to load plane data for some reason.
*/
public abstract int[] loadPlaneData(final int plane) throws IOException;
protected int valueAt(final int plane, final int offset) {
new Exception().printStackTrace(System.err);
assert (false) : "Unimplemented overload of BasicLoader::valueAt()";
return Integer.MIN_VALUE;
}
protected int[][] loadRowVectorsImplByLoadPlaneData(final int vectorSize, final Range<Integer> planeRange) throws IOException {
System.out.println("we are here and maybe it is wrong.");
final int rowVectorCount = (int) Math.ceil((double) dims.getX() / (double) vectorSize);
final int planeCount = planeRange.getTo() - planeRange.getFrom();
System.out.println("vectorSize="+vectorSize);
System.out.println("planeCount="+planeCount);
final int vectorCount = planeCount * dims.getY() * rowVectorCount;
System.out.println("vectorCount="+vectorCount);
int[][] rowVectors = new int[vectorCount][vectorSize];
int vectorIndex = 0;
int baseX;
for (int plane = planeRange.getFrom(); plane < planeRange.getTo(); plane++) {
final int[] planeData = loadPlaneData(plane);
for (int row = 0; row < dims.getY(); row++) {
for (int rowVectorIndex = 0; rowVectorIndex < rowVectorCount; rowVectorIndex++) {
// Copy single vector.
baseX = rowVectorIndex * vectorSize;
for (int vectorX = 0; vectorX < vectorSize; vectorX++) {
if ((baseX + vectorX) >= dims.getY())
break;
rowVectors[vectorIndex][vectorX] = planeData[Block.index((baseX + vectorX), row, dims.getX())];
}
++vectorIndex;
}
}
}
return rowVectors;
}
protected int[][] loadRowVectorsImplByValueAt(final int vectorSize, final Range<Integer> planeRange) {
final int rowVectorCount = (int) Math.ceil((double) dims.getX() / (double) vectorSize);
final int vectorCount = dims.getZ() * dims.getY() * rowVectorCount;
int[][] rowVectors = new int[vectorCount][vectorSize];
int vectorIndex = 0;
int baseX;
for (int plane = planeRange.getFrom(); plane < planeRange.getTo(); plane++) {
for (int row = 0; row < dims.getY(); row++) {
for (int rowVectorIndex = 0; rowVectorIndex < rowVectorCount; rowVectorIndex++) {
// Copy single vector.
baseX = rowVectorIndex * vectorSize;
for (int vectorX = 0; vectorX < vectorSize; vectorX++) {
if (baseX + vectorX >= dims.getY())
break;
rowVectors[vectorIndex][vectorX] = valueAt(plane, Block.index((baseX + vectorX), row, dims.getY()));
}
++vectorIndex;
}
}
}
return rowVectors;
}
protected int[][] loadBlocksImplByLoadPlaneData(final V2i blockDim, final Range<Integer> planeRange) throws IOException {
final int blockSize = blockDim.multiplyTogether();
final int planeCount = planeRange.getTo() - planeRange.getFrom();
final int blockCount = planeCount * Block.calculateRequiredChunkCount(dims.toV2i(), blockDim);
int[][] blocks = new int[blockCount][blockSize];
int blockIndex = 0;
for (int plane = planeRange.getFrom(); plane < planeRange.getTo(); plane++) {
final int[] planeData = loadPlaneData(plane);
for (int blockYOffset = 0; blockYOffset < dims.getY(); blockYOffset += blockDim.getY()) {
for (int blockXOffset = 0; blockXOffset < dims.getX(); blockXOffset += blockDim.getX()) {
loadBlock(blocks[blockIndex++], planeData, blockXOffset, blockYOffset, blockDim);
}
}
}
return blocks;
}
protected int[][] loadBlocksImplByValueAt(final V2i blockDim, final Range<Integer> planeRange) {
final int blockSize = blockDim.multiplyTogether();
final int planeCount = planeRange.getTo() - planeRange.getFrom();
final int blockCount = planeCount * Block.calculateRequiredChunkCount(dims.toV2i(), blockDim);
int[][] blocks = new int[blockCount][blockSize];
int blockIndex = 0;
for (int plane = planeRange.getFrom(); plane < planeRange.getTo(); plane++) {
for (int blockYOffset = 0; blockYOffset < dims.getY(); blockYOffset += blockDim.getY()) {
for (int blockXOffset = 0; blockXOffset < dims.getX(); blockXOffset += blockDim.getX()) {
loadBlock(blocks[blockIndex++], plane, blockXOffset, blockYOffset, blockDim);
}
}
}
return blocks;
}
private void loadBlock(final int[] block, final int planeIndex, final int blockXOffset, final int blockYOffset, final V2i blockDim) {
int srcX, srcY;
for (int y = 0; y < blockDim.getY(); y++) {
srcY = blockYOffset + y;
if (srcY >= dims.getY())
break;
for (int x = 0; x < blockDim.getX(); x++) {
srcX = blockXOffset + x;
if (srcX >= dims.getX())
break;
block[Block.index(x, y, blockDim.getY())] = valueAt(planeIndex, Block.index(srcX, srcY, dims.getY()));
}
}
}
private void loadBlock(final int[] block, final int[] planeData, final int blockXOffset, final int blockYOffset, final V2i blockDim) {
int srcX, srcY;
for (int y = 0; y < blockDim.getY(); y++) {
srcY = blockYOffset + y;
if (srcY >= dims.getY())
break;
for (int x = 0; x < blockDim.getX(); x++) {
srcX = blockXOffset + x;
if (srcX >= dims.getX())
break;
block[Block.index(x, y, blockDim.getY())] = planeData[Block.index(srcX, srcY, dims.getY())];
}
}
}
/**
* Load specified planes from dataset to voxel of specified dimensions.
* This overload uses the loadPlaneData function to read src data.
*
* @param voxelDim Single voxel dimensions.
* @param planeRange Range of planes to load voxels from.
* @return Voxel data arranged in arrays.
*/
protected int[][] loadVoxelsImplByLoadPlaneData(final V3i voxelDim, final Range<Integer> planeRange) throws IOException {
final Voxel dstVoxel = new Voxel(voxelDim);
final int rangeSize = planeRange.getTo() - planeRange.getFrom();
final V3i srcVoxel = new V3i(dims.getX(), dims.getY(), rangeSize);
final int xVoxelCount = (int) Math.ceil((double) dims.getX() / (double) voxelDim.getX());
final int yVoxelCount = (int) Math.ceil((double) dims.getY() / (double) voxelDim.getY());
final int voxelIndexOffset = -((planeRange.getFrom() / voxelDim.getZ()) * (xVoxelCount * yVoxelCount));
int[][] voxels = new int[Voxel.calculateRequiredVoxelCount(srcVoxel, voxelDim)][(int) voxelDim.multiplyTogether()];
final int dimX = dims.getX();
final int dimY = dims.getY();
final int dimZ = planeRange.getTo();
final int voxelDimX = voxelDim.getX();
final int voxelDimY = voxelDim.getY();
final int voxelDimZ = voxelDim.getZ();
int dstZ, dstY, dstX, voxelX, voxelY, voxelZ, voxelIndex;
int[] planeData;
for (int srcZ = planeRange.getFrom(); srcZ < dimZ; srcZ++) {
planeData = loadPlaneData(srcZ);
dstZ = srcZ / voxelDimZ;
voxelZ = srcZ - (dstZ * voxelDimZ);
for (int srcY = 0; srcY < dimY; srcY++) {
dstY = srcY / voxelDimY;
voxelY = srcY - (dstY * voxelDimY);
for (int srcX = 0; srcX < dimX; srcX++) {
dstX = srcX / voxelDimX;
voxelX = srcX - (dstX * voxelDimX);
voxelIndex = voxelIndexOffset + ((dstZ * (xVoxelCount * yVoxelCount)) + (dstY * xVoxelCount) + dstX);
voxels[voxelIndex][dstVoxel.dataIndex(voxelX, voxelY, voxelZ, voxelDim)] = planeData[(srcY * dimX) + srcX];
}
}
}
return voxels;
}
/**
* Load specified planes from dataset to voxel of specified dimensions.
* This overload uses the valueAt function to read src data.
*
* @param voxelDim Single voxel dimensions.
* @param planeRange Range of planes to load voxels from.
* @return Voxel data arranged in arrays.
* @throws IOException When fails to load plane data.
*/
protected int[][] loadVoxelsImplByValueAt(final V3i voxelDim,
final Range<Integer> planeRange) throws IOException {
// TODO(Moravec): Improve performance of loading.
final Voxel dstVoxel = new Voxel(voxelDim);
final int rangeSize = planeRange.getTo() - planeRange.getFrom();
final V3i srcVoxel = new V3i(dims.getX(), dims.getY(), rangeSize);
final int xVoxelCount = (int) Math.ceil((double) dims.getX() / (double) voxelDim.getX());
final int yVoxelCount = (int) Math.ceil((double) dims.getY() / (double) voxelDim.getY());
// NOTE(Moravec): We need voxelIndexOffset in case that planeRange is not the whole dataset.
// voxelIndex which is calculated inside the loop doesn't know that we are loading
// only some voxel layer. So we need to set the offset and start filling voxel data from the start.
final int voxelIndexOffset = -((planeRange.getFrom() / voxelDim.getZ()) * (xVoxelCount * yVoxelCount));
int[][] voxels = new int[Voxel.calculateRequiredVoxelCount(srcVoxel, voxelDim)][(int) voxelDim.multiplyTogether()];
final int workSize = rangeSize / threadCount;
final Thread[] threads = new Thread[threadCount];
for (int wId = 0; wId < threadCount; wId++) {
final int fromZ = wId * workSize;
final int toZ = (wId == threadCount - 1) ? rangeSize : (workSize + (wId * workSize));
threads[wId] = new Thread(() -> {
final int dimX = dims.getX();
final int dimY = dims.getY();
final int zBase = planeRange.getFrom();
final int voxelDimX = voxelDim.getX();
final int voxelDimY = voxelDim.getY();
final int voxelDimZ = voxelDim.getZ();
int srcZ, dstZ, dstY, dstX, voxelX, voxelY, voxelZ, voxelIndex;
for (int zOffset = fromZ; zOffset < toZ; zOffset++) {
srcZ = zBase + zOffset;
dstZ = srcZ / voxelDimZ;
voxelZ = srcZ - (dstZ * voxelDimZ);
for (int srcY = 0; srcY < dimY; srcY++) {
dstY = srcY / voxelDimY;
voxelY = srcY - (dstY * voxelDimY);
for (int srcX = 0; srcX < dimX; srcX++) {
dstX = srcX / voxelDimX;
voxelX = srcX - (dstX * voxelDimX);
voxelIndex = voxelIndexOffset + ((dstZ * (xVoxelCount * yVoxelCount)) + (dstY * xVoxelCount) + dstX);
voxels[voxelIndex][dstVoxel.dataIndex(voxelX, voxelY, voxelZ, voxelDim)] = valueAt(srcZ, (srcY * dimX) + srcX);
}
}
}
});
threads[wId].start();
}
try {
for (int wId = 0; wId < threadCount; wId++) {
threads[wId].join();
}
} catch (InterruptedException e) {
throw new IOException("threads[wId].join() failed.", e);
}
return voxels;
}
public void setWorkerCount(final int threadCount) {
this.threadCount = threadCount;
}
}