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