/* @(#)FitsMatrix.java $Revision: 1.10 $ $Date: 2004/01/12 13:13:23 $
*
* Copyright (C) 2000 European Southern Observatory
* License: GNU General Public License version 2 or later
*/
package fr.unistra.pelican.util.jFits;
import java.io.*;
/** FitsMatrix class represents a FITS data matrix either as a prime
* HD unit or as an image extension.
*
* @version $Revision: 1.10 $ $Date: 2004/01/12 13:13:23 $
* @author P.Grosbol, ESO, <pgrosbol@eso.org>
*/
public class FitsMatrix extends FitsData {
private int noValues;
private int dataFormat = Fits.FLOAT;
private int bytesPerData = 4;
private boolean scaling = false;
private double zero = 0.0;
private double scale = 1.0;
private FitsWCS wcs;
/** Constructor for FitsMatrix class given a FITS prime matrix or
* an image extension header with associated data unit as a file.
*
* @param header FitsHeader object with the image header
* @param file RandomAccess file positioned at the start of the
* associated data unit
* @param sflag Flag for storing data matrix internally
* @exception FitsException */
public FitsMatrix(FitsHeader header, DataInput file, boolean sflag)
throws FitsException {
super(header, file, sflag);
if (type != Fits.IMAGE) {
throw new FitsException("Wrong header type",
FitsException.HEADER);
}
FitsKeyword kw = header.getKeyword("BITPIX");
if ((kw == null) || (kw.getType() != FitsKeyword.INTEGER)) {
throw new FitsException("Invalid or missing BITPIX",
FitsException.HEADER);
}
dataFormat = kw.getInt();
bytesPerData = Math.abs(dataFormat)/8;
noValues = (int) (size / bytesPerData);
wcs = new FitsWCS(header);
kw = header.getKeyword("BSCALE"); // check if scale is given
if (kw!=null) {
scale = kw.getReal();
if (scale != 1.0) {
scaling = true;
}
}
kw = header.getKeyword("BZERO"); // check if zero point is given
if (kw!=null) {
zero = kw.getReal();
if (zero != 0.0) {
scaling = true;
}
}
}
/** Constructor for FitsMatrix class given definition of the matrix
* size and dimensions.
*
* @param bitpix Bits per pixel for data values in matrix
* @param nax Array with dimensions of data matrix
* @exception FitsException */
public FitsMatrix(int bitpix, int nax[]) throws FitsException {
super(bitpix, nax);
type = Fits.IMAGE;
dataFormat = bitpix;
bytesPerData = Math.abs(dataFormat)/8;
noValues = (int) (size / bytesPerData);
wcs = new FitsWCS(nax.length);
}
/** Create and return a minimum FITS header for data Matrix.
*/
public FitsHeader getHeader() {
FitsHeader hdr = super.getHeader();
// hdr.addKeyword(new FitsKeyword("", ""));
// for (int n=1; n<=naxis.length; n++) {
// hdr.addKeyword(new FitsKeyword("CRPIX"+n, wcs.crpix[n-1],
// "Reference pixel"));
// hdr.addKeyword(new FitsKeyword("CRVAL"+n, wcs.crval[n-1],
// "Coordinate at reference pixel"));
// hdr.addKeyword(new FitsKeyword("CDELT"+n, wcs.cdelt[n-1],
// "Coordinate increament per pixel"));
// }
return hdr;
}
/** Gets set of data points from the matrix as a short values.
* Only FITS file with BITPIX 8, 16 and 32 are read.
*
* @param offset pixel offset within hte data matrix
* @param size no. of pixel values to be read
* @param data array which will hold the return values.
* If null an array of size is created.
* @return data[] array updated with pixel values
* @exception FitsException */
public short[] getShortValues(int offset, int size, short data[])
throws FitsException {
if ((offset<0) || (size<1)) return data;
if (noValues < offset+size) size = (int) (noValues - offset);
if ((data == null) || (data.length<size)) data = new short[size];
int n = 0;
DataInputStream dis = getInStream(offset, size);
try {
switch (dataFormat) {
case Fits.BYTE:
while (n<size) data[n++] = (short) dis.readUnsignedByte();
break;
case Fits.SHORT:
while (n<size) data[n++] = dis.readShort();
break;
case Fits.INT:
while (n<size) data[n++] = (short) dis.readInt();
break;
case Fits.FLOAT:
case Fits.DOUBLE:
default: return data;
}
} catch (IOException e) {
throw new FitsException("Cannot convert data", FitsException.DATA);
}
if (scaling) {
for (int i=0; i<n; i++) data[i] = (short) (scale*data[i]+zero);
}
return data;
}
/** Gets set of data points from the matrix as a int values.
* Only FITS file with BITPIX 8, 16 and 32 are read.
*
* @param offset pixel offset within hte data matrix
* @param size no. of pixel values to be read
* @param data array which will hold the return values.
* If null an array of size is created.
* @return data[] array updated with pixel values
* @exception FitsException */
public int[] getIntValues(int offset, int size, int data[])
throws FitsException {
if ((offset<0) || (size<1)) return data;
if (noValues < offset+size) size = (int) (noValues - offset);
if ((data == null) || (data.length<size)) data = new int[size];
int n = 0;
DataInputStream dis = getInStream(offset, size);
try {
switch (dataFormat) {
case Fits.BYTE:
while (n<size) data[n++] = (int) dis.readUnsignedByte();
break;
case Fits.SHORT:
while (n<size) data[n++] = (int) dis.readShort();
break;
case Fits.INT:
while (n<size) data[n++] = dis.readInt();
break;
case Fits.FLOAT:
case Fits.DOUBLE:
default: return data;
}
} catch (IOException e) {
throw new FitsException("Cannot read data", FitsException.DATA);
}
if (scaling) {
for (int i=0; i<n; i++) data[i] = (int) (scale*data[i]+zero);
}
return data;
}
/** Read set of data values from the matrix as a float array. The
* values are returned as a float array.
*
* @param offset pixel offset within the data matrix
* @param size no. of pixel values to be read
* @param data array which will hold the return values.
* If null an array of size is created.
* @return data[] array updated with pixel values
* @exception FitsException */
public float[] getFloatValues(int offset, int size, float data[])
throws FitsException {
if ((offset<0) || (size<1)) return data;
if (noValues < offset+size) size = (int) (noValues - offset);
if ((data == null) || (data.length<size)) data = new float[size];
int n = 0;
DataInputStream dis = getInStream(offset, size);
try {
switch (dataFormat) {
case Fits.BYTE:
while (n<size) data[n++] = (float) dis.readUnsignedByte();
break;
case Fits.SHORT:
while (n<size) data[n++] = (float) dis.readShort();
break;
case Fits.INT:
while (n<size) data[n++] = (float) dis.readInt();
break;
case Fits.FLOAT:
while (n<size) data[n++] = dis.readFloat();
break;
case Fits.DOUBLE:
while (n<size) data[n++] = (float) dis.readDouble();
break;
default: return data;
}
} catch (IOException e) {
throw new FitsException("Cannot read data", FitsException.DATA);
}
if (scaling) {
for (int i=0; i<n; i++) data[i] = (float) (scale*data[i]+zero);
}
return data;
}
/** Read set of data values from the matrix as a double array. The
* values are returned as a double array.
*
* @param offset pixel offset within the data matrix
* @param size no. of pixel values to be read
* @param data array which will hold the return values.
* If null an array of size is created.
* @return data[] array updated with pixel values
* @exception FitsException */
public double[] getDoubleValues(int offset, int size, double data[])
throws FitsException {
if ((offset<0) || (size<1)) return data;
if (noValues < offset+size) size = (int) (noValues - offset);
if ((data == null) || (data.length<size)) data = new double[size];
int n = 0;
DataInputStream dis = getInStream(offset, size);
try {
switch (dataFormat) {
case Fits.BYTE:
while (n<size) data[n++] = (double) dis.readUnsignedByte();
break;
case Fits.SHORT:
while (n<size) data[n++] = (double) dis.readShort();
break;
case Fits.INT:
while (n<size) data[n++] = (double) dis.readInt();
break;
case Fits.FLOAT:
while (n<size) data[n++] = (double)dis.readFloat();
break;
case Fits.DOUBLE:
while (n<size) data[n++] = dis.readDouble();
break;
default: return data;
}
} catch (IOException e) {
throw new FitsException("Cannot read data", FitsException.DATA);
}
if (scaling) {
for (int i=0; i<n; i++) data[i] = (float) (scale*data[i]+zero);
}
return data;
}
private DataInputStream getInStream(int offset, int size)
throws FitsException {
DataInputStream dis;
try {
dataFile.seek(dataOffset+offset*bytesPerData);
if (noValues < offset + size) {
size = (int) (noValues - offset);
}
byte[] dbuf = new byte[size*bytesPerData];
dataFile.read(dbuf);
dis = new DataInputStream(new ByteArrayInputStream(dbuf));
} catch (IOException e) {
throw new FitsException("Cannot read InStream data",
FitsException.DATA);
}
return dis;
}
/** Store set of data values from a short array into the data matrix.
*
* @param offset pixel offset within the data matrix
* @param data array with values.
* @exception FitsException */
public void setShortValues(int offset, short sdata[])
throws FitsException {
if ((offset<0) || (noValues<=offset))
throw new FitsException("Invalid pixel offset",
FitsException.DATA);
if (sdata == null) throw new FitsException("Invalid data array",
FitsException.DATA);
ByteArrayOutputStream baos = new ByteArrayOutputStream(sdata.length *
bytesPerData);
DataOutputStream dos = new DataOutputStream(baos);
if (scaling) {
throw new FitsException("Scaling of short not supported",
FitsException.DATA);
}
int n = 0;
try {
switch (dataFormat) {
case Fits.BYTE:
throw new FitsException("Cannot convert data to BYTE",
FitsException.DATA);
case Fits.SHORT:
while (n<sdata.length) dos.writeShort((short) sdata[n++]);
break;
case Fits.INT:
while (n<sdata.length) dos.writeInt((int) sdata[n++]);
break;
case Fits.FLOAT:
while (n<sdata.length) dos.writeFloat((float) sdata[n++]);
break;
case Fits.DOUBLE:
while (n<sdata.length) dos.writeDouble((double) sdata[n++]);
break;
default: throw new FitsException("Invalid data format",
FitsException.DATA);
}
if (isRAFile) {
dataFile.seek(dataOffset+offset*bytesPerData);
dataFile.write(baos.toByteArray());
} else {
byte[] vals = baos.toByteArray();
n = (int) (dataOffset * bytesPerData);
for (int i=0; i<vals.length; i++) {
dataArray[n++] = vals[i];
}
}
} catch (IOException e) {
throw new FitsException("Cannot convert data", FitsException.DATA);
}
}
/** Store set of data values from an int array into the data matrix.
*
* @param offset pixel offset within the data matrix
* @param data array with data values.
* @exception FitsException */
public void setIntValues(int offset, int idata[])
throws FitsException {
if ((offset<0) || (noValues<=offset))
throw new FitsException("Invalid pixel offset",
FitsException.DATA);
if (idata == null) throw new FitsException("Invalid data array",
FitsException.DATA);
ByteArrayOutputStream baos = new ByteArrayOutputStream(idata.length *
bytesPerData);
DataOutputStream dos = new DataOutputStream(baos);
if (scaling) {
throw new FitsException("Scaling of int not supported",
FitsException.DATA);
}
int n = 0;
try {
switch (dataFormat) {
case Fits.BYTE:
throw new FitsException("Cannot convert data",
FitsException.DATA);
case Fits.SHORT:
while (n<idata.length) dos.writeShort((short) idata[n++]);
break;
case Fits.INT:
while (n<idata.length) dos.writeInt((int) idata[n++]);
break;
case Fits.FLOAT:
while (n<idata.length) dos.writeFloat((float) idata[n++]);
break;
case Fits.DOUBLE:
while (n<idata.length) dos.writeDouble((double) idata[n++]);
break;
default: throw new FitsException("Invalid data format",
FitsException.DATA);
}
if (isRAFile) {
dataFile.seek(dataOffset+offset*bytesPerData);
dataFile.write(baos.toByteArray());
} else {
byte[] vals = baos.toByteArray();
n = (int) (dataOffset * bytesPerData);
for (int i=0; i<vals.length; i++) {
dataArray[n++] = vals[i];
}
}
} catch (IOException e) {
throw new FitsException("Cannot write data", FitsException.DATA);
}
}
/** Store set of data values from a float array into the data matrix.
*
* @param offset pixel offset within the data matrix
* @param data array with data values.
* @exception FitsException */
public void setFloatValues(int offset, float data[])
throws FitsException {
if ((offset<0) || (noValues<=offset))
throw new FitsException("Invalid pixel offset",
FitsException.DATA);
if (data == null) throw new FitsException("Invalid data array",
FitsException.DATA);
ByteArrayOutputStream baos = new ByteArrayOutputStream(data.length *
bytesPerData);
DataOutputStream dos = new DataOutputStream(baos);
if (scaling) {
for (int i=0; i<data.length; i++)
data[i] = (float) ((data[i]-zero)/scale);
}
int n = 0;
try {
switch (dataFormat) {
case Fits.BYTE:
throw new FitsException("Cannot convert data",
FitsException.DATA);
case Fits.SHORT:
while (n<data.length) dos.writeShort((short) data[n++]);
break;
case Fits.INT:
while (n<data.length) dos.writeInt((int) data[n++]);
break;
case Fits.FLOAT:
while (n<data.length) dos.writeFloat((float) data[n++]);
break;
case Fits.DOUBLE:
while (n<data.length) dos.writeDouble((double) data[n++]);
break;
default: throw new FitsException("Invalid data format",
FitsException.DATA);
}
if (isRAFile) {
dataFile.seek(dataOffset+offset*bytesPerData);
dataFile.write(baos.toByteArray());
} else {
byte[] vals = baos.toByteArray();
n = (int) (dataOffset * bytesPerData);
for (int i=0; i<vals.length; i++) {
dataArray[n++] = vals[i];
}
}
} catch (IOException e) {
throw new FitsException("Cannot write data", FitsException.DATA);
}
}
/** Store set of data values from a double array into the data matrix.
*
* @param offset pixel offset within the data matrix
* @param data array with data values.
* @exception FitsException */
public void setDoubleValues(int offset, double data[])
throws FitsException {
if ((offset<0) || (noValues<=offset))
throw new FitsException("Invalid pixel offset",
FitsException.DATA);
if (data == null) throw new FitsException("Invalid data array",
FitsException.DATA);
ByteArrayOutputStream baos = new ByteArrayOutputStream(data.length *
bytesPerData);
DataOutputStream dos = new DataOutputStream(baos);
if (scaling) {
for (int i=0; i<data.length; i++)
data[i] = (double) ((data[i]-zero)/scale);
}
int n = 0;
try {
switch (dataFormat) {
case Fits.BYTE:
throw new FitsException("Cannot convert data",
FitsException.DATA);
case Fits.SHORT:
while (n<data.length) dos.writeShort((short) data[n++]);
break;
case Fits.INT:
while (n<data.length) dos.writeInt((int) data[n++]);
break;
case Fits.FLOAT:
while (n<data.length) dos.writeFloat((float) data[n++]);
break;
case Fits.DOUBLE:
while (n<data.length) dos.writeDouble((double) data[n++]);
break;
default: throw new FitsException("Invalid data format",
FitsException.DATA);
}
if (isRAFile) {
dataFile.seek(dataOffset+offset*bytesPerData);
dataFile.write(baos.toByteArray());
} else {
byte[] vals = baos.toByteArray();
n = (int) (dataOffset * bytesPerData);
for (int i=0; i<vals.length; i++) {
dataArray[n++] = vals[i];
}
}
} catch (IOException e) {
throw new FitsException("Cannot write data", FitsException.DATA);
}
}
/** Gets the total number of data values in the data matrix. */
public int getNoValues(){
return noValues;
}
/** Sets reference pixel for the axes (see CRPIXn). */
public void setCrpix(double crp[]){
wcs.crpix = new double[naxis.length];
for (int n=0; n<naxis.length; n++) {
wcs.crpix[n] = ((crp!=null) && (n<crp.length)) ? crp[n] : 1.0;
}
}
/** Gets reference pixel for the axes (see CRPIXn). */
public double[] getCrpix(){
return wcs.crpix;
}
/** Sets coordinate value for the reference pixel of the axes
* (see CRVALn). */
public void setCrval(double crv[]){
wcs.crval = new double[naxis.length];
for (int n=0; n<naxis.length; n++) {
wcs.crval[n] = ((crv!=null) && (n<crv.length)) ? crv[n] : 1.0;
}
}
/** Gets coordinate value for the reference pixel of the axes
* (see CRVALn). */
public double[] getCrval(){
return wcs.crval;
}
/** Sets step size for the axes (see CDELTn). */
public void setCdelt(double cd[]){
wcs.cdelt = new double[naxis.length];
for (int n=0; n<naxis.length; n++) {
wcs.cdelt[n] = ((cd!=null) && (n<cd.length)) ? cd[n] : 1.0;
}
}
/** Gets step size for the axes (see CDELTn). */
public double[] getCdelt(){
return wcs.cdelt;
}
/** Gets the WCS object for the image. */
public FitsWCS getWCS(){
return wcs;
}
/** Compute World Coordinates from pixel coordinates.
*
* @param pix Array with pixel coordinates
*/
public double[] toWCS(double[] pix) {
return wcs.toWCS(pix);
}
/** Compute pixel coordinates from a set of World Coordinates.
*
* @param wc Array with World Coordinates
*/
public double[] toPixel(double[] wc) {
return wcs.toPixel(wc);
}
}