001 /* @(#)FitsMatrix.java $Revision: 1.9 $ $Date: 2003/04/11 08:41:15 $
002 *
003 * Copyright (C) 2000 European Southern Observatory
004 * License: GNU General Public License version 2 or later
005 */
006 package org.eso.fits;
007
008 import java.lang.*;
009 import java.io.*;
010
011 /** FitsMatrix class represents a FITS data matrix either as a prime
012 * HD unit or as an image extension.
013 *
014 * @version $Revision: 1.9 $ $Date: 2003/04/11 08:41:15 $
015 * @author P.Grosbol, DMD/ESO, <pgrosbol@eso.org>
016 */
017 public class FitsMatrix extends FitsData {
018
019 private int noValues;
020 private int dataFormat = Fits.FLOAT;
021 private int bytesPerData = 4;
022 private boolean scaling = false;
023 private double zero = 0.0;
024 private double scale = 1.0;
025 private FitsWCS wcs;
026
027 /** Constructor for FitsMatrix class given a FITS prime matrix or
028 * an image extension header with associated data unit as a file.
029 *
030 * @param header FitsHeader object with the image header
031 * @param file RandomAccess file positioned at the start of the
032 * associated data unit
033 * @param sflag Flag for storing data matrix internally
034 * @exception FitsException */
035 public FitsMatrix(FitsHeader header, DataInput file, boolean sflag) throws FitsException {
036 super(header, file, sflag);
037
038 if (type != Fits.IMAGE) {
039 throw new FitsException("Wrong header type", FitsException.HEADER);
040 }
041
042 FitsKeyword kw = header.getKeyword("BITPIX");
043 if ((kw == null) || (kw.getType() != FitsKeyword.INTEGER)) {
044 throw new FitsException("Invalid or missing BITPIX", FitsException.HEADER);
045 }
046
047 dataFormat = kw.getInt();
048 bytesPerData = Math.abs(dataFormat)/8;
049 noValues = (int) (size / bytesPerData);
050
051 wcs = new FitsWCS(header);
052
053 kw = header.getKeyword("BSCALE"); // check if scale is given
054 if (kw!=null) {
055 scale = kw.getReal();
056 if (scale != 1.0) {
057 scaling = true;
058 }
059 }
060
061 kw = header.getKeyword("BZERO"); // check if zero point is given
062 if (kw!=null) {
063 zero = kw.getReal();
064 if (zero != 0.0) {
065 scaling = true;
066 }
067 }
068 }
069
070 /** Constructor for FitsMatrix class given definition of the matrix
071 * size and the associated 1D data array.
072 *
073 * @param bitpix value of FITS BITPIX keyword bits/pixel
074 * @param nax Integer array defining the dimensions of the
075 * data matrix or for BINTABLE the heap size
076 * @exception FitsException */
077 public FitsMatrix(int bitpix, int nax[]) throws FitsException {
078 super(bitpix, nax);
079 type = Fits.IMAGE;
080 dataFormat = bitpix;
081 bytesPerData = Math.abs(dataFormat)/8;
082 noValues = (int) (size / bytesPerData);
083 wcs = new FitsWCS(nax.length);
084 }
085
086 /** Create and return a minimum FITS header for data Matrix.
087 */
088 public FitsHeader getHeader() {
089 FitsHeader hdr = super.getHeader();
090
091 hdr.addKeyword(new FitsKeyword("", ""));
092 for (int n=1; n<=naxis.length; n++) {
093 hdr.addKeyword(new FitsKeyword("CRPIX"+n, wcs.crpix[n-1], "Reference pixel"));
094 hdr.addKeyword(new FitsKeyword("CRVAL"+n, wcs.crval[n-1], "Coordinate at reference pixel"));
095 hdr.addKeyword(new FitsKeyword("CDELT"+n, wcs.cdelt[n-1], "Coordinate increament per pixel"));
096 }
097
098 return hdr;
099 }
100
101 /** Gets set of data points from the matrix as a short values.
102 * Only FITS file with BITPIX 8, 16 and 32 are read.
103 *
104 * @param offset pixel offset within hte data matrix
105 * @param size no. of pixel values to be read
106 * @param data array which will hold the return values.
107 * If null an array of size is created.
108 * @return data[] array updated with pixel values
109 * @exception FitsException */
110 public short[] getShortValues(int offset, int size, short data[]) throws FitsException {
111
112 if ((offset<0) || (size<1)) return data;
113 if (noValues < offset+size) size = (int) (noValues - offset);
114 if ((data == null) || (data.length<size)) data = new short[size];
115
116 int n = 0;
117 DataInputStream dis = getInStream(offset, size);
118 try {
119 switch (dataFormat) {
120 case Fits.BYTE:
121 while (n<size) data[n++] = (short) dis.readUnsignedByte();
122 break;
123 case Fits.SHORT:
124 while (n<size) data[n++] = dis.readShort();
125 break;
126 case Fits.INT:
127 while (n<size) data[n++] = (short) dis.readInt();
128 break;
129 case Fits.FLOAT:
130 case Fits.DOUBLE:
131 default: return data;
132 }
133 } catch (IOException e) {
134 throw new FitsException("Cannot convert data", FitsException.DATA);
135 }
136
137 if (scaling) {
138 for (int i=0; i<n; i++) data[i] = (short) (scale*data[i]+zero);
139 }
140
141 return data;
142 }
143
144 /** Gets set of data points from the matrix as a int values.
145 * Only FITS file with BITPIX 8, 16 and 32 are read.
146 *
147 * @param offset pixel offset within hte data matrix
148 * @param size no. of pixel values to be read
149 * @param data array which will hold the return values.
150 * If null an array of size is created.
151 * @return data[] array updated with pixel values
152 * @exception FitsException */
153 public int[] getIntValues(int offset, int size, int data[]) throws FitsException {
154
155 if ((offset<0) || (size<1)) return data;
156 if (noValues < offset+size) size = (int) (noValues - offset);
157 if ((data == null) || (data.length<size)) data = new int[size];
158
159 int n = 0;
160 DataInputStream dis = getInStream(offset, size);
161 try {
162 switch (dataFormat) {
163 case Fits.BYTE:
164 while (n<size) data[n++] = (int) dis.readUnsignedByte();
165 break;
166 case Fits.SHORT:
167 while (n<size) data[n++] = (int) dis.readShort();
168 break;
169 case Fits.INT:
170 while (n<size) data[n++] = dis.readInt();
171 break;
172 case Fits.FLOAT:
173 case Fits.DOUBLE:
174 default: return data;
175 }
176 } catch (IOException e) {
177 throw new FitsException("Cannot read data", FitsException.DATA);
178 }
179
180 if (scaling) {
181 for (int i=0; i<n; i++) data[i] = (int) (scale*data[i]+zero);
182 }
183
184 return data;
185 }
186
187 /** Read set of data values from the matrix as a float array. The
188 * values are returned as a float array.
189 *
190 * @param offset pixel offset within hte data matrix
191 * @param size no. of pixel values to be read
192 * @param data array which will hold the return values.
193 * If null an array of size is created.
194 * @return data[] array updated with pixel values
195 * @exception FitsException */
196 public float[] getFloatValues(int offset, int size, float data[])
197 throws FitsException {
198
199 if ((offset<0) || (size<1)) return data;
200 if (noValues < offset+size) size = (int) (noValues - offset);
201 if ((data == null) || (data.length<size)) data = new float[size];
202
203 int n = 0;
204 DataInputStream dis = getInStream(offset, size);
205 try {
206 switch (dataFormat) {
207 case Fits.BYTE:
208 while (n<size) data[n++] = (float) dis.readUnsignedByte();
209 break;
210 case Fits.SHORT:
211 while (n<size) data[n++] = (float) dis.readShort();
212 break;
213 case Fits.INT:
214 while (n<size) data[n++] = (float) dis.readInt();
215 break;
216 case Fits.FLOAT:
217 while (n<size) data[n++] = dis.readFloat();
218 break;
219 case Fits.DOUBLE:
220 while (n<size) data[n++] = (float) dis.readDouble();
221 break;
222 default: return data;
223 }
224 } catch (IOException e) {
225 throw new FitsException("Cannot read data", FitsException.DATA);
226 }
227
228 if (scaling) {
229 for (int i=0; i<n; i++) data[i] = (float) (scale*data[i]+zero);
230 }
231
232 return data;
233 }
234
235 private DataInputStream getInStream(int offset, int size)
236 throws FitsException {
237 DataInputStream dis;
238 try {
239 dataFile.seek(dataOffset+offset*bytesPerData);
240 if (noValues < offset + size) {
241 size = (int) (noValues - offset);
242 }
243 byte[] dbuf = new byte[size*bytesPerData];
244 dataFile.read(dbuf);
245 dis = new DataInputStream(new ByteArrayInputStream(dbuf));
246 } catch (IOException e) {
247 throw new FitsException("Cannot read InStream data",
248 FitsException.DATA);
249 }
250 return dis;
251 }
252
253 /** Store set of data values from a short array into the data matrix.
254 *
255 * @param offset pixel offset within the data matrix
256 * @param sdata array with values.
257 * @exception FitsException */
258 public void setShortValues(int offset, short sdata[])
259 throws FitsException {
260
261 if ((offset<0) || (noValues<=offset))
262 throw new FitsException("Invalid pixel offset",
263 FitsException.DATA);
264 if (sdata == null) throw new FitsException("Invalid data array",
265 FitsException.DATA);
266
267 ByteArrayOutputStream baos = new ByteArrayOutputStream(sdata.length *
268 bytesPerData);
269 DataOutputStream dos = new DataOutputStream(baos);
270
271 if (scaling) {
272 throw new FitsException("Scaling of short not supported",
273 FitsException.DATA);
274 }
275
276 int n = 0;
277 try {
278 switch (dataFormat) {
279 case Fits.BYTE:
280 throw new FitsException("Cannot convert data to BYTE",
281 FitsException.DATA);
282 case Fits.SHORT:
283 while (n<sdata.length) dos.writeShort((short) sdata[n++]);
284 break;
285 case Fits.INT:
286 while (n<sdata.length) dos.writeInt((int) sdata[n++]);
287 break;
288 case Fits.FLOAT:
289 while (n<sdata.length) dos.writeFloat((float) sdata[n++]);
290 break;
291 case Fits.DOUBLE:
292 while (n<sdata.length) dos.writeDouble((double) sdata[n++]);
293 break;
294 default: throw new FitsException("Invalid data format",
295 FitsException.DATA);
296 }
297
298 if (isRAFile) {
299 dataFile.seek(dataOffset+offset*bytesPerData);
300 dataFile.write(baos.toByteArray());
301 } else {
302 byte[] vals = baos.toByteArray();
303 n = (int) (dataOffset * bytesPerData);
304 for (int i=0; i<vals.length; i++) {
305 dataArray[n++] = vals[i];
306 }
307 }
308 } catch (IOException e) {
309 throw new FitsException("Cannot convert data", FitsException.DATA);
310 }
311 }
312
313 /** Store set of data values from an int array into the data matrix.
314 *
315 * @param offset pixel offset within the data matrix
316 * @param idata array with data values.
317 * @exception FitsException */
318 public void setIntValues(int offset, int idata[])
319 throws FitsException {
320 if ((offset<0) || (noValues<=offset))
321 throw new FitsException("Invalid pixel offset",
322 FitsException.DATA);
323 if (idata == null) throw new FitsException("Invalid data array",
324 FitsException.DATA);
325
326 ByteArrayOutputStream baos = new ByteArrayOutputStream(idata.length *
327 bytesPerData);
328 DataOutputStream dos = new DataOutputStream(baos);
329
330 if (scaling) {
331 throw new FitsException("Scaling of int not supported",
332 FitsException.DATA);
333 }
334
335 int n = 0;
336 try {
337 switch (dataFormat) {
338 case Fits.BYTE:
339 throw new FitsException("Cannot convert data",
340 FitsException.DATA);
341 case Fits.SHORT:
342 while (n<idata.length) dos.writeShort((short) idata[n++]);
343 break;
344 case Fits.INT:
345 while (n<idata.length) dos.writeInt((int) idata[n++]);
346 break;
347 case Fits.FLOAT:
348 while (n<idata.length) dos.writeFloat((float) idata[n++]);
349 break;
350 case Fits.DOUBLE:
351 while (n<idata.length) dos.writeDouble((double) idata[n++]);
352 break;
353 default: throw new FitsException("Invalid data format",
354 FitsException.DATA);
355 }
356
357 if (isRAFile) {
358 dataFile.seek(dataOffset+offset*bytesPerData);
359 dataFile.write(baos.toByteArray());
360 } else {
361 byte[] vals = baos.toByteArray();
362 n = (int) (dataOffset * bytesPerData);
363 for (int i=0; i<vals.length; i++) {
364 dataArray[n++] = vals[i];
365 }
366 }
367 } catch (IOException e) {
368 throw new FitsException("Cannot write data", FitsException.DATA);
369 }
370 }
371
372 /** Store set of data values from a float array into the data matrix.
373 *
374 * @param offset pixel offset within the data matrix
375 * @param data array with data values.
376 * @exception FitsException */
377 public void setFloatValues(int offset, float data[])
378 throws FitsException {
379
380 if ((offset<0) || (noValues<=offset))
381 throw new FitsException("Invalid pixel offset",
382 FitsException.DATA);
383 if (data == null) throw new FitsException("Invalid data array",
384 FitsException.DATA);
385
386 ByteArrayOutputStream baos = new ByteArrayOutputStream(data.length *
387 bytesPerData);
388 DataOutputStream dos = new DataOutputStream(baos);
389
390 if (scaling) {
391 for (int i=0; i<data.length; i++)
392 data[i] = (float) ((data[i]-zero)/scale);
393 }
394
395 int n = 0;
396 try {
397 switch (dataFormat) {
398 case Fits.BYTE:
399 throw new FitsException("Cannot convert data",
400 FitsException.DATA);
401 case Fits.SHORT:
402 while (n<data.length) dos.writeShort((short) data[n++]);
403 break;
404 case Fits.INT:
405 while (n<data.length) dos.writeInt((int) data[n++]);
406 break;
407 case Fits.FLOAT:
408 while (n<data.length) dos.writeFloat((float) data[n++]);
409 break;
410 case Fits.DOUBLE:
411 while (n<data.length) dos.writeDouble((double) data[n++]);
412 break;
413 default: throw new FitsException("Invalid data format",
414 FitsException.DATA);
415 }
416
417 if (isRAFile) {
418 dataFile.seek(dataOffset+offset*bytesPerData);
419 dataFile.write(baos.toByteArray());
420 } else {
421 byte[] vals = baos.toByteArray();
422 n = (int) (dataOffset * bytesPerData);
423 for (int i=0; i<vals.length; i++) {
424 dataArray[n++] = vals[i];
425 }
426 }
427 } catch (IOException e) {
428 throw new FitsException("Cannot write data", FitsException.DATA);
429 }
430 }
431
432 /** Gets the total number of data values in the data matrix. */
433 public int getNoValues(){
434 return noValues;
435 }
436
437 /** Sets reference pixel for the axes (see CRPIXn). */
438 public void setCrpix(double crp[]){
439 wcs.crpix = new double[naxis.length];
440 for (int n=0; n<naxis.length; n++) {
441 wcs.crpix[n] = ((crp!=null) && (n<crp.length)) ? crp[n] : 1.0;
442 }
443 }
444 /** Gets reference pixel for the axes (see CRPIXn). */
445 public double[] getCrpix(){
446 return wcs.crpix;
447 }
448
449 /** Sets coordinate value for the reference pixel of the axes
450 * (see CRVALn). */
451 public void setCrval(double crv[]){
452 wcs.crval = new double[naxis.length];
453 for (int n=0; n<naxis.length; n++) {
454 wcs.crval[n] = ((crv!=null) && (n<crv.length)) ? crv[n] : 1.0;
455 }
456 }
457
458 /** Gets coordinate value for the reference pixel of the axes
459 * (see CRVALn). */
460 public double[] getCrval(){
461 return wcs.crval;
462 }
463
464 /** Sets step size for the axes (see CDELTn). */
465 public void setCdelt(double cd[]){
466 wcs.cdelt = new double[naxis.length];
467 for (int n=0; n<naxis.length; n++) {
468 wcs.cdelt[n] = ((cd!=null) && (n<cd.length)) ? cd[n] : 1.0;
469 }
470 }
471
472 /** Gets step size for the axes (see CDELTn). */
473 public double[] getCdelt(){
474 return wcs.cdelt;
475 }
476
477 /** Gets the WCS object for the image. */
478 public FitsWCS getWCS(){
479 return wcs;
480 }
481
482 /** Compute World Coordinates from pixel coordinates.
483 *
484 * @param pix Array with pixel coordinates
485 */
486 public double[] toWCS(double[] pix) {
487 return wcs.toWCS(pix);
488 }
489
490 /** Compute pixel coordinates from a set of World Coordinates.
491 *
492 * @param wc Array with World Coordinates
493 */
494 public double[] toPixel(double[] wc) {
495 return wcs.toPixel(wc);
496 }
497 }
498
499