/* * Copyright (C) 2010-2014 - Andreas Keil * 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 three-dimensional version of a Grid. * * @see Grid * * @author Andreas Keil */ public class Grid3D extends NumericGrid { /** * The actual data buffer. This is supposed to be initialized outside of and * before it is wrapped by Grid1D. */ protected ArrayList<Grid2D> buffer = null; /** * Constructor that directly allocates the Memory * @param width * @param height * @param depth */ public Grid3D(int width, int height, int depth){ this(width, height, depth, 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 Grid3D(int width, int height, int depth, boolean allocateImmediately){ buffer = new ArrayList<Grid2D>(depth); this.size = new int[] { width, height, depth}; this.spacing = new double[3]; this.origin = new double[3]; for (int i = 0; i < 3; ++i) { assert this.size[i] > 0 : "Size values have to be greater than zero!"; } if (allocateImmediately) { allocate(); } else { for (int i=0; i < size[2]; ++i) { buffer.add(null); } } } /** * Allocate the memory for all slices */ public void allocate () { for (int i=0; i < size[2]; ++i) { buffer.add(new Grid2D(size[0],size[1])); // Each subgrid has to inherit spacing and origin of parent grid buffer.get(i).setSpacing(this.getSpacing()[0],this.getSpacing()[1]); buffer.get(i).setOrigin( this.getOrigin()[0], this.getOrigin()[1]); } } // TODO Does this need to copy data or simply safe the reference?? // Removed because never used and won't work when using OpenCLGrid3D // public void addSlice(Grid2D slice) // { // buffer.add(slice); // size[2]=buffer.size(); // notifyAfterWrite(); // } // // public void removeSlice(int idx){ // assert(idx >= 0 && idx < buffer.size()); // buffer.remove(idx); // size[2]=buffer.size(); // notifyAfterWrite(); // } /* public Grid3D(float[][][] buffer, int[] boundarySize) { assert boundarySize.length == 3 : "A boundarySize dimension of " + boundarySize.length + " does not match this Grid's dimension!"; this.buffer = buffer; this.size = new int[] { buffer.length - boundarySize[0] * 2, buffer[0].length - boundarySize[1] * 2, buffer[0][0].length - boundarySize[2] * 2 }; this.spacing = new double[3]; this.origin = new double[3]; for (int i = 0; i < 3; ++i) { assert this.size[i] > 0 : "Size values have to be greater than zero!"; } this.subGrids = new Grid2D[this.buffer.length]; for (int i = 0; i < this.buffer.length; ++i) this.subGrids[i] = new Grid2D(this.buffer[i]); } */ public ArrayList<Grid2D> getBuffer() { notifyBeforeRead(); return this.buffer; } public Grid3D(Grid3D input){ this.size = input.size; this.spacing = input.spacing; this.origin = input.origin; this.buffer = new ArrayList<Grid2D>(size[2]); for (int i=0; i < size[2]; ++i) { buffer.add(new Grid2D(input.getSubGrid(i))); } } public Grid3D(Grid3D input, boolean ensureValidValues){ this(input); if(ensureValidValues) getGridOperator().fillInvalidValues(this); } public Grid2D getSubGrid(int i) { notifyBeforeRead(); if (i >= buffer.size()) return null; if (i < 0) return null; return this.buffer.get(i); } /* * Be careful when using this method. If the grid is larger than the old grid the size will be * overwritten and the origin etc may change! */ public void setSubGrid(int i, Grid2D grid) { if(grid.getWidth() != size[0] || grid.getHeight() != size[1]) { size[0] = grid.getWidth(); size[1] = grid.getHeight(); System.out.println("Warning. Changing grid size! Be careful while setting the 2D subgrid!"); } this.buffer.set(i, grid); notifyAfterWrite(); } public double[] indexToPhysical(double i, double j, double k) { return new double[] { i * this.spacing[0] + this.origin[0], j * this.spacing[1] + this.origin[1], k * this.spacing[2] + this.origin[2] }; } public double[] physicalToIndex(double x, double y, double z) { return new double[] { (x - this.origin[0]) / this.spacing[0], (y - this.origin[1]) / this.spacing[1], (z - this.origin[2]) / this.spacing[2] }; } public float getAtIndex(int i, int j, int k) { notifyBeforeRead(); return this.buffer.get(k).getPixelValue(i, j); } public void setAtIndex(int i, int j, int k, float val) { this.buffer.get(k).putPixelValue(i, j,val); notifyAfterWrite(); } public void addAtIndex(int i, int j, int k, float val) { notifyBeforeRead(); float gridVal = getAtIndex(i, j, k); // TODO test for debug setAtIndex(i, j, k, gridVal + val); notifyAfterWrite(); } public void multiplyAtIndex(int i, int j, int k, float val) { notifyBeforeRead(); setAtIndex(i, j, k, getAtIndex(i, j, k) * val); notifyAfterWrite(); } @Override public String toString() { this.notifyBeforeRead(); String result = new String(); result += "["; for (int i = 0; i < this.buffer.size(); ++i) { if (i != 0) result += ", "; result += this.getSubGrid(i).toString(); } result += "]"; if(debug){ float min = this.getGridOperator().min(this); float max = this.getGridOperator().max(this); result += " " + min + ":" + max; } return result; } public void show(String title){ ImageUtil.wrapGrid3D(this, title).show(); } public void show(){ show("Grid3D"); } @Override public float getValue(int[] idx) { notifyBeforeRead(); return this.getAtIndex(idx[0], idx[1], idx[2]); } @Override public NumericGrid clone() { notifyBeforeRead(); return (new Grid3D(this)); } @Override public void setSpacing(double... spacing){ super.setSpacing(spacing); for (Grid2D slice : buffer){ if (slice != null) slice.setSpacing(spacing[0],spacing[1]); } } @Override public void setOrigin(double... origin){ super.setOrigin(origin); for (Grid2D 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], val); notifyAfterWrite(); } }