/*
* Copyright (C) 2014 Shiyang Hu
* CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
*/
package edu.stanford.rsl.conrad.data.numeric;
import java.util.ArrayList;
import edu.stanford.rsl.conrad.utils.ImageUtil;
/**
* The four-dimensional version of a Grid.
*
* Adopted from Grid3D
*
* @author Shiyang Hu
*/
public class Grid4D extends NumericGrid {
/**
* The actual data buffer. This is supposed to be initialized outside of and
* before it is wrapped by Grid1D.
*/
protected ArrayList<Grid3D> buffer = null;
/**
* Constructor that directly allocates the Memory
* @param width
* @param height
* @param depth
* @param dimension
*/
public Grid4D(int width, int height, int depth, int dimension){
this(width, height, depth, dimension, true);
}
/**
* Constructor does not allocate the Memory but saves the size
* @param width
* @param height
* @param depth
* @param allocateImmediately Boolean flag for memory allocation
*/
public Grid4D(int width, int height, int depth, int dimension, boolean allocateImmediately)
{
buffer = new ArrayList<Grid3D>(dimension);
this.size = new int[] { width, height, depth, dimension};
this.spacing = new double[4];
this.origin = new double[4];
for (int i = 0; i < 4; ++i) {
assert this.size[4] > 0 : "Size values have to be greater than zero!";
}
if (allocateImmediately) {
allocate();
} else {
for (int i=0; i < size[3]; ++i) {
buffer.add(null);
}
}
}
/**
* Allocate the memory for all slices
*/
public void allocate ()
{
for (int i=0; i < size[3]; ++i) {
buffer.add(new Grid3D(size[0],size[1],size[2]));
}
}
public ArrayList<Grid3D> getBuffer() {
notifyBeforeRead();
return this.buffer;
}
public Grid4D(Grid4D input){
this.size = input.size;
this.spacing = input.spacing;
this.origin = input.origin;
this.buffer = new ArrayList<Grid3D>(size[3]);
for (int i=0; i < size[3]; ++i) {
buffer.add(new Grid3D(input.getSubGrid(i)));
}
}
public Grid3D getSubGrid(int i) {
notifyBeforeRead();
return this.buffer.get(i);
}
public void setSubGrid(int i, Grid3D grid) {
this.buffer.set(i, grid);
notifyAfterWrite();
}
public double[] indexToPhysical(double i, double j, double k, double l) {
return new double[] { i * this.spacing[0] + this.origin[0],
j * this.spacing[1] + this.origin[1],
k * this.spacing[2] + this.origin[2],
l * this.spacing[3] + this.origin[3],
};
}
public double[] physicalToIndex(double x, double y, double z, double w) {
return new double[] { (x - this.origin[0]) / this.spacing[0],
(y - this.origin[1]) / this.spacing[1],
(z - this.origin[2]) / this.spacing[2],
(w - this.origin[3]) / this.spacing[3]};
}
public float getAtIndex(int i, int j, int k, int m) {
notifyBeforeRead();
return this.buffer.get(m).getAtIndex(i, j, k);
}
public void setAtIndex(int i, int j, int k, int m, float val) {
this.buffer.get(m).setAtIndex(i, j,k, val);
notifyAfterWrite();
}
public void addAtIndex(int i, int j, int k, int m, float val) {
notifyBeforeRead();
setAtIndex(i, j, k,m, getAtIndex(i, j, k, m) + val);
notifyAfterWrite();
}
public void multiplyAtIndex(int i, int j, int k, int m, float val) {
notifyBeforeRead();
setAtIndex(i, j, k,m, getAtIndex(i, j, k, m) + val);
notifyAfterWrite();
}
@Override
public String toString() {
String result = new String();
result += "[";
for (int i = 0; i < this.buffer.size(); ++i) {
if (i != 0)
result += ", ";
result += this.getSubGrid(i).toString();
}
result += "]";
return result;
}
public void show(String title){
ImageUtil.wrapGrid4D(this, title).show();
}
public void show(){
show("Grid3D");
}
@Override
public float getValue(int[] idx) {
notifyBeforeRead();
return this.getAtIndex(idx[0], idx[1], idx[2], idx[3]);
}
@Override
public NumericGrid clone() {
notifyBeforeRead();
return (new Grid4D(this));
}
@Override
public void setSpacing(double... spacing){
super.setSpacing(spacing);
for (Grid3D slice : buffer){
if (slice != null)
slice.setSpacing(spacing[0],spacing[1]);
}
}
@Override
public void setOrigin(double... origin){
super.setOrigin(origin);
for (Grid3D slice : buffer){
if (slice != null)
slice.setOrigin(origin[0],origin[1]);
}
}
@Override
public void setValue(float val, int[] idx) {
setAtIndex(idx[0], idx[1], idx[2], idx[3], val);
}
}