Newer
Older
package azgracompress.io.loader;
public abstract class BasicLoader {
protected final V3i dims;
private DataWrappingStrategy wrappingStrategy = DataWrappingStrategy.MirroredRepeat;
protected BasicLoader(final V3i datasetDims) {
this.dims = datasetDims;
}
public V3i getImageDimensions() {
return dims;
}
public DataWrappingStrategy getWrappingStrategy() {
return wrappingStrategy;
}
public void setWrappingStrategy(DataWrappingStrategy strategy) {
wrappingStrategy = strategy;
}
/**
* 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 {
final int rowVectorCount = (int) Math.ceil((double) dims.getX() / (double) vectorSize);
final int planeCount = planeRange.getTo() - planeRange.getFrom();
final int vectorCount = planeCount * dims.getY() * rowVectorCount;
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())
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;
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// Row overflow
if (srcY >= dims.getY()) {
if (wrappingStrategy == DataWrappingStrategy.LeaveBlank)
break;
if (wrappingStrategy == DataWrappingStrategy.ClampToEdge) {
final int srcRow = dims.getY() - 1;
final int dstOffset = y * blockDim.getX();
for (int x = 0; x < blockDim.getX(); x++) {
srcX = (blockXOffset + x);
if (srcX >= dims.getX())
srcX = dims.getX() - 1;
block[dstOffset + x] = valueAt(planeIndex, Block.index(srcX, srcRow, dims.getX()));
}
continue;
} else if (wrappingStrategy == DataWrappingStrategy.MirroredRepeat) {
final int srcRow = dims.getY() - ((srcY - dims.getY()) + 1);
final int dstOffset = y * blockDim.getX();
for (int x = 0; x < blockDim.getX(); x++) {
srcX = (blockXOffset + x);
if (srcX >= dims.getX())
srcX = dims.getX() - 1;
block[dstOffset + x] = valueAt(planeIndex, Block.index(srcX, srcRow, dims.getX()));
}
continue;
}
}
for (int x = 0; x < blockDim.getX(); x++) {
srcX = blockXOffset + x;
// Column overflow.
if (srcX >= dims.getX()) {
if (wrappingStrategy == DataWrappingStrategy.LeaveBlank)
break;
if (wrappingStrategy == DataWrappingStrategy.ClampToEdge) {
block[Block.index(x, y, blockDim.getX())] = valueAt(planeIndex, Block.index(dims.getX() - 1, srcY, dims.getX()));
continue;
} else if (wrappingStrategy == DataWrappingStrategy.MirroredRepeat) {
block[Block.index(x, y, blockDim.getX())] =
valueAt(planeIndex, Block.index(dims.getX() - ((srcX - dims.getX()) + 1), srcY, dims.getX()));
continue;
}
}
block[Block.index(x, y, blockDim.getX())] = valueAt(planeIndex, Block.index(srcX, srcY, dims.getX()));
}
}
}
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 (wrappingStrategy == DataWrappingStrategy.LeaveBlank)
break;
if (wrappingStrategy == DataWrappingStrategy.ClampToEdge) {
final int srcRow = dims.getY() - 1;
final int dstOffset = y * blockDim.getX();
for (int x = 0; x < blockDim.getX(); x++) {
srcX = (blockXOffset + x);
if (srcX >= dims.getX())
srcX = dims.getX() - 1;
block[dstOffset + x] = planeData[Block.index(srcX, srcRow, dims.getX())];
}
continue;
} else if (wrappingStrategy == DataWrappingStrategy.MirroredRepeat) {
final int srcRow = dims.getY() - ((srcY - dims.getY()) + 1);
final int dstOffset = y * blockDim.getX();
for (int x = 0; x < blockDim.getX(); x++) {
srcX = (blockXOffset + x);
if (srcX >= dims.getX())
srcX = dims.getX() - 1;
block[dstOffset + x] = planeData[Block.index(srcX, srcRow, dims.getX())];
}
continue;
}
for (int x = 0; x < blockDim.getX(); x++) {
srcX = blockXOffset + x;
// Column overflow.
if (srcX >= dims.getX()) {
if (wrappingStrategy == DataWrappingStrategy.LeaveBlank)
break;
if (wrappingStrategy == DataWrappingStrategy.ClampToEdge) {
block[Block.index(x, y, blockDim.getX())] = planeData[Block.index(dims.getX() - 1, srcY, dims.getX())];
continue;
} else if (wrappingStrategy == DataWrappingStrategy.MirroredRepeat) {
block[Block.index(x, y, blockDim.getX())] =
planeData[Block.index(dims.getX() - ((srcX - dims.getX()) + 1), srcY, dims.getX())];
continue;
}
}
block[Block.index(x, y, blockDim.getX())] = planeData[Block.index(srcX, srcY, dims.getX())];
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
private void loadVoxel(final int[] voxel,
final int voxelXOffset,
final int voxelYOffset,
final int voxelZOffset,
final V3i voxelDim) {
int srcX, srcY, srcZ;
for (int z = 0; z < voxelDim.getZ(); z++) {
srcZ = voxelZOffset + z;
if (srcZ >= dims.getZ()) {
// Handle plane overflow.
break;
}
for (int y = 0; y < voxelDim.getY(); y++) {
srcY = voxelYOffset + y;
if (srcY >= dims.getY()) {
// Handle row overflow.
break;
}
for (int x = 0; x < voxelDim.getX(); x++) {
srcX = voxelXOffset + x;
if (srcX >= dims.getX()) {
// Handle column overflow
break;
}
voxel[Voxel.dataIndex(x, y, z, voxelDim)] = valueAt(srcZ, Block.index(x, y, dims.getX()));
}
}
}
}
protected int[][] experimentalLoadVoxelsImplByValueAt(final V3i voxelDim, final Range<Integer> planeRange) {
System.out.println("experimentalLoadVoxelsImplByValueAt");
final int voxelCount = Voxel.calculateRequiredVoxelCount(dims, voxelDim);
final int voxelElementCount = (int) voxelDim.multiplyTogether();
int[][] voxels = new int[voxelCount][voxelElementCount];
int voxelIndex = 0;
for (int voxelZOffset = planeRange.getFrom(); voxelZOffset < planeRange.getTo(); voxelZOffset += voxelDim.getZ()) {
for (int voxelYOffset = 0; voxelYOffset < dims.getY(); voxelYOffset += voxelDim.getY()) {
for (int voxelXOffset = 0; voxelXOffset < dims.getX(); voxelXOffset += voxelDim.getX()) {
loadVoxel(voxels[voxelIndex++], voxelXOffset, voxelYOffset, voxelZOffset, voxelDim);
}
}
}
return voxels;
}
* 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++) {
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];
* 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 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);
for (int wId = 0; wId < threadCount; wId++) {
threads[wId].join();
throw new IOException("threads[wId].join() failed.", e);
public void setWorkerCount(final int threadCount) {
this.threadCount = threadCount;
}