/*
* omeis.providers.re.data.Plane2D
*
* Copyright 2006 University of Dundee. All rights reserved.
* Use is subject to license terms supplied in LICENSE.txt
*/
package omeis.providers.re.data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ome.util.PixelData;
import ome.model.core.Pixels;
import ome.model.enums.PixelsType;
/**
* Allows to extract pixels intensity values from a given plane within a pixels
* set. The plane can be one of the types defined by {@link PlaneDef}
* <i>XY, ZY, XZ</i>. So extracting a pixel value from a sequence of bytes
* given the pixel coordinates within the plane requires to know:
* <ul>
* <li>The offset, in the byte sequence, of the first byte containing the
* value.</li>
* <li>The number of bytes that make up the value.</li>
* <li>How to interpret those bytes in order to convert them into a <code>
* double</code>
* value.</li>
* </ul>
* <p>
* An instance of this class is created with a byte array that contains the
* plane. This array contains just the plane data in the case of an <i>XY</i>
* plane, but the whole stack in which that plane belongs in the case of an
* <i>ZY</i> or <i>XZ</i> plane. For this reason we have three concrete sub-
* classes (one per plane type) that know how to calculate the offset.
* </p>
*
* @author Jean-Marie Burel <a
* href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a>
* @author <br>
* Andrea Falconi <a
* href="mailto:a.falconi@dundee.ac.uk"> a.falconi@dundee.ac.uk</a>
* @version 2.2 <small> (<b>Internal version:</b> $Revision$ $Date:
* 2005/06/08 20:15:03 $) </small>
* @since OME2.2
*/
/**
* @author callan
*
*/
public class Plane2D {
/** The logger for this particular class */
private static Logger log = LoggerFactory.getLogger(Plane2D.class);
/** Contains the plane data. */
private PixelData data;
/** The type of plane. */
protected PlaneDef planeDef;
/** How many bytes make up a pixel value. */
protected int bytesPerPixel;
/** Number of pixels along the <i>X</i>-axis. */
protected int sizeX;
/** Number of pixels along the <i>Y</i>-axis. */
protected int sizeY;
/** The sign of the type */
protected boolean signed;
/** The slice we're working with */
protected int slice;
/**
* Constructor that sub-classes must call.
*
* @param pDef
* The type of plane.
* @param pixels
* The pixels set which the Plane2D references.
* @param data
* The raw pixels.
*/
public Plane2D(PlaneDef pDef, Pixels pixels, PixelData data) {
this.planeDef = pDef;
RegionDef region = pDef.getRegion();
if (region != null) {
sizeX = region.getWidth();
sizeY = region.getHeight();
} else {
sizeX = pixels.getSizeX();
sizeY = pixels.getSizeY();
}
int stride = pDef.getStride();
if (stride < 0) stride = 0;
stride++;
sizeX = sizeX/stride;
sizeY = sizeY/stride;
this.data = data;
// Grab the pixel type from the pixels set
PixelsType type = pixels.getPixelsType();
this.bytesPerPixel = PlaneFactory.bytesPerPixel(type);
//this.javaType = PlaneFactory.javaType(type);
this.signed = PlaneFactory.isTypeSigned(type);
this.slice = pDef.getSlice();
log.debug("Created Plane2D with dimensions " + sizeX + "x" + sizeY + "x"
+ bytesPerPixel);
}
/**
* Returns the pixel intensity value of the pixel at <code>(x1, x2)</code>.
* The coordinates are relative to the <i>XY</i>, <i>ZY</i> or <i>XZ</i>
* reference frame, depending on the plane type. (So <code>x1</code> is
* <code>x</code> and <code>x2</code> is <code>y</code> if the plane
* type is <i>XY</i>, etc.)
*
* @param x1
* The first coordinate.
* @param x2
* The second coordinate.
* @return The intensity value.
*/
public double getPixelValue(int x1, int x2) {
switch (slice)
{
case PlaneDef.XY:
return data.getPixelValueDirect(
bytesPerPixel * (sizeX * x2 + x1));
case PlaneDef.XZ:
return data.getPixelValueDirect(
bytesPerPixel
* (x2 * sizeX * sizeY + sizeX * planeDef.getY() + x1));
case PlaneDef.ZY:
return data.getPixelValueDirect(
bytesPerPixel
* (x1 * sizeX * sizeY + sizeX * x2 + planeDef.getX()));
default:
throw new RuntimeException("Unknown PlaneDef slice: " + slice);
}
}
/**
* Returns the pixel intensity value of the pixel at a given offset within
* the backing buffer. This method takes into account bytes per pixel. So
* the number of offsets is equal to the buffer size /
* <code>bytesPerPixel</code>.
*
* @param offset The relative offset (taking into account the number of
* bytes per pixel) within the backing buffer.
* @return The intensity value.
*/
public double getPixelValue(int offset)
{
return data.getPixelValue(offset);
}
/**
* Returns <code>true</code> if the plane is an <code>XY-plane</code>,
* <code>false</code> otherwise.
*
* @return See above.
*/
public boolean isXYPlanar()
{
return (slice == PlaneDef.XY);
}
/**
* Returns the pixel data that is used to back this Plane.
*
* @return See above.
*/
public PixelData getData()
{
return data;
}
}