001 /* @(#)FitsColumn.java $Revision: 1.5 $ $Date: 2003/04/11 08:41:15 $ 002 * 003 * Copyright (C) 1999 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 import java.util.*; 011 012 /** FitsColumn class represents a FITS table column in either ASCII or 013 * BINARY table format. Note: only binary data formats A,L,I,J,E,D 014 * are fully supported. 015 * 016 * @version $Revision: 1.5 $ $Date: 2003/04/11 08:41:15 $ 017 * @author P.Grosbol, DMD/ESO, <pgrosbol@eso.org> 018 */ 019 public class FitsColumn { 020 021 private String stringNull = null; 022 private long intNull; 023 private boolean intNullDefined = false; 024 private int repeat = 1; 025 private char dataType = '\0'; 026 private long columnOffset = 0; 027 private int recordSize = 0; 028 private FitsTform format; 029 private int bytesPerData = 0; 030 private long noRows = 0; 031 private boolean binColumn = true; 032 private String display; 033 private String label; 034 private String unit; 035 private double zero; 036 private double scale; 037 private boolean scaling = false; 038 039 private RandomAccessFile dataFile = null; 040 private long dataOffset = 0; 041 private boolean isRAFile = true; 042 private byte[] dataArray = null; 043 044 /** Constructor for FitsColumn class from a file 045 * 046 * @param type storage type of column i.e. Fits.ATABLE or 047 * Fits.BTABLE, by default Fits.BTABLE is assumed 048 * @param tform storage format of data in column 049 * @param label name of column 050 * @param rows no. of rows in the column 051 * @exception FitsException 052 */ 053 public FitsColumn(int type, String tform, String label, int rows) 054 throws FitsException { 055 056 this.format = new FitsTform(tform); 057 this.dataType = format.getDataType(); 058 this.repeat = format.getRepeat(); 059 this.bytesPerData = format.getWidth(); 060 this.label = label; 061 this.noRows = rows; 062 this.binColumn = (type == Fits.BTABLE); 063 } 064 065 /** Sets data matrix with the table data as a RandomAcessFile. 066 * 067 * @param file associated RandomAccessFile with FITS data 068 * @param dataOffset byte offset of the table data unit in the FITS file 069 * @param position relative byte start position of of column data 070 * within record (first byte is 0) 071 * @param recordSize byte size of table record 072 */ 073 public void setData(RandomAccessFile file, long dataOffset, 074 int position, int recordSize) { 075 dataFile = file; 076 this.dataOffset = dataOffset; 077 isRAFile = true; 078 this.columnOffset = position; 079 this.recordSize = recordSize; 080 } 081 082 /** Sets data matrix with the table data as a byte array 083 * 084 * @param array byte array with table data matrix 085 * @param position relative byte start position of of column data 086 * within record (first byte is 0) 087 * @param recordSize byte size of table record 088 */ 089 public void setData(byte[] array, int position, int recordSize) { 090 dataArray = array; 091 isRAFile = false; 092 this.columnOffset = position; 093 this.recordSize = recordSize; 094 } 095 096 /** Read single column element as integer value. An ndefined 097 * value is returned as Integer.MIN_VALUE. The following column 098 * types are supported i.e. binary I/J formats. For array type 099 * elements only the first element is read. Note: ASCII table 100 * columns are read with free format and does not conform to the 101 * FITS standard in the current implementation. 102 * 103 * @param row no. of element in column (starting with 0) 104 */ 105 public int getInt(int row) { 106 int value = Integer.MIN_VALUE; 107 byte[] dbuf = getBytes(row); 108 109 try { 110 if (binColumn) { 111 DataInputStream di = 112 new DataInputStream(new ByteArrayInputStream(dbuf)); 113 switch (dataType) { 114 case 'I' : 115 value = (int) di.readShort(); 116 break; 117 case 'J' : 118 value = di.readInt(); 119 break; 120 } 121 if (intNullDefined && value==intNull) { 122 value = Integer.MIN_VALUE; 123 } else if (scaling) { 124 value = (int) (zero + scale*value); 125 } 126 } else { 127 String str = new String(dbuf); 128 if (stringNull == null || !str.startsWith(stringNull)) { 129 value = (Integer.valueOf(str)).intValue(); 130 if (scaling) { 131 value = (int) (zero + scale*value); 132 } 133 } 134 } 135 } catch (Exception e) { 136 } 137 138 return value; 139 } 140 141 /** Read single column element as integer array. Undefined values 142 * are returned as Integer.MIN_VALUE. The following column types 143 * are supported i.e. binary I/J formats. Note: ASCII table 144 * columns are read with free format and does not conform to the 145 * FITS standard in the current implementation. 146 * 147 * @param row no. of element in column (starting with 0) 148 */ 149 public int[] getInts(int row) { 150 int[] arr = new int[repeat]; 151 byte[] dbuf = getBytes(row); 152 153 try { 154 if (binColumn) { 155 DataInputStream di = 156 new DataInputStream(new ByteArrayInputStream(dbuf)); 157 int value; 158 for (int n=0; n<repeat; n++) { 159 value = Integer.MIN_VALUE; 160 switch (dataType) { 161 case 'I' : 162 value = (int) di.readShort(); 163 break; 164 case 'J' : 165 value = di.readInt(); 166 break; 167 } 168 if (intNullDefined && value==intNull) { 169 value = Integer.MIN_VALUE; 170 } else if (scaling) { 171 value = (int) (zero + scale*value); 172 } 173 arr[n] = value; 174 } 175 } else { 176 String str = new String(dbuf); 177 arr[0] = Integer.MIN_VALUE; 178 if (stringNull == null || !str.startsWith(stringNull)) { 179 arr[0] = (Integer.valueOf(str)).intValue(); 180 if (scaling) { 181 arr[0] = (int) (zero + scale*arr[0]); 182 } 183 } 184 } 185 } catch (Exception e) { 186 } 187 188 return arr; 189 } 190 191 /** Read single column element as double value. An undefined 192 * value is returned as Double.NaN. The following column types 193 * are supported i.e. binary I/J/E/D formats. For array type 194 * elements only the first element is read. Note: ASCII table 195 * columns are read with free format and does not conform to the 196 * FITS standard in the current implementation. 197 * 198 * @param row no. of element in column (starting with 0) 199 */ 200 public double getReal(int row) { 201 double value = Double.NaN; 202 byte[] dbuf = getBytes(row); 203 204 try { 205 if (binColumn) { 206 DataInputStream di = 207 new DataInputStream(new ByteArrayInputStream(dbuf)); 208 switch (dataType) { 209 case 'I' : 210 value = (double) di.readShort(); 211 break; 212 case 'J' : 213 value = (double) di.readInt(); 214 break; 215 case 'E' : 216 value = (double) di.readFloat(); 217 break; 218 case 'D' : 219 value = di.readDouble(); 220 break; 221 } 222 if (scaling) { 223 value = zero + scale*value; 224 } 225 } 226 else { 227 String str = new String(dbuf); 228 if ((stringNull == null) || !str.startsWith(stringNull)) { 229 value = (Double.valueOf(str)).doubleValue(); 230 if (scaling) { 231 value = zero + scale*value; 232 } 233 } 234 } 235 } catch (Exception e) { 236 } 237 238 return value; 239 } 240 241 /** Read single column element as double array. Undefined value 242 * are returned as Double.NaN. The following column types are 243 * supported: binary I/J/E/D formats. Note: ASCII table columns 244 * are read with free format and does not conform to the FITS 245 * standard in the current implementation. 246 * 247 * @param row no. of element in column (starting with 0) 248 */ 249 public double[] getReals(int row) { 250 double[] arr = new double[repeat]; 251 byte[] dbuf = getBytes(row); 252 253 try { 254 if (binColumn) { 255 DataInputStream di = 256 new DataInputStream(new ByteArrayInputStream(dbuf)); 257 for (int n=0; n<repeat; n++) { 258 switch (dataType) { 259 case 'I' : 260 arr[n] = (double) di.readShort(); 261 break; 262 case 'J' : 263 arr[n] = (double) di.readInt(); 264 break; 265 case 'E' : 266 arr[n] = (double) di.readFloat(); 267 break; 268 case 'D' : 269 arr[n] = di.readDouble(); 270 break; 271 } 272 if (scaling) { 273 arr[n] = zero + scale*arr[n]; 274 } 275 } 276 } else { 277 double value = Double.NaN; 278 String str = new String(dbuf); 279 if ((stringNull == null) || !str.startsWith(stringNull)) { 280 arr[0] = (Double.valueOf(str)).doubleValue(); 281 if (scaling) { 282 arr[0] = zero + scale*arr[0]; 283 } 284 } 285 } 286 } catch (Exception e) { 287 } 288 289 return arr; 290 } 291 292 /** Read single column element as string. An undefined value 293 * is returned as a NULL string. The following column types are 294 * supported: A/L formats. 295 * 296 * @param row number of element in column (starting with 0) 297 */ 298 public String getString(int row) { 299 String str = null; 300 if ((dataType == 'A') || (dataType == 'L')) { 301 byte[] dbuf = getBytes(row); 302 if (dbuf != null) { 303 if ((stringNull == null) || !str.startsWith(stringNull)) { 304 str = new String(dbuf); 305 } 306 } 307 } 308 return str; 309 } 310 311 /** Extract a column element from the 'file' as byte array. 312 * 313 * @param row number of element in column (starting with 0) 314 */ 315 private byte[] getBytes(int row) { 316 if (row<0 || noRows<=row) return null; 317 byte[] dbuf = new byte[getWidth()]; 318 319 if (isRAFile) { 320 try { 321 if (dataFile == null) return null; 322 dataFile.seek(dataOffset + columnOffset + row*recordSize); 323 dataFile.read(dbuf); 324 } catch (IOException e) { 325 return null; 326 } 327 } else { 328 if (dataArray == null) return null; 329 int k = 0; 330 int n = (int) (columnOffset + row*recordSize); 331 int nsize = getWidth(); 332 while (0 < nsize--) dbuf[k++] = dataArray[n++]; 333 } 334 335 return dbuf; 336 } 337 338 /** Define NULL string for ASCII table column. 339 * 340 * @param nullValue string with null value 341 */ 342 public void setNull(String nullValue){ 343 this.stringNull = nullValue; 344 } 345 346 /** Define NULL value for interger format Binary table columns 347 * @param nullValue value of NULL integer */ 348 public void setNull(int nullValue){ 349 this.intNull = nullValue; 350 intNullDefined = true; 351 } 352 353 /** Define dimension of binary table column. Note: This is not 354 * used in the current implementation 355 * 356 * @param dim string with dimension soecification for column 357 */ 358 public void setDim(String dim){ 359 } 360 361 /** Retrieve repeat factor that is number of values per column element */ 362 public int getRepeat() { 363 return this.repeat; 364 } 365 366 /** Get the data type character for column as given in the TFORM 367 * FITS keyword. */ 368 public char getDataType() { 369 return this.dataType; 370 } 371 372 /** Calculate the number of bytes associated to a column entry. */ 373 protected int getWidth() { 374 return repeat*bytesPerData; 375 } 376 377 /** Retrieve the display format for the column (ref. TDISP keyword). */ 378 public String getDisplay(){ 379 return display; 380 } 381 382 /** Set the display format of the column. 383 * 384 * @param display string with the display format for the column */ 385 public void setDisplay(String display){ 386 this.display = display; 387 } 388 389 /** Retrieve unit string for the column. */ 390 public String getUnit(){ 391 return unit; 392 } 393 394 /** Set unit string for column. 395 * 396 * @param unit string with the unit of the column */ 397 public void setUnit(String unit){ 398 this.unit = unit; 399 } 400 401 /** Retrieve column label. */ 402 public String getLabel(){ 403 return label; 404 } 405 406 /** Set label of the column. 407 * 408 * @param label string with the column label */ 409 public void setLabel(String label){ 410 this.label = label; 411 } 412 413 /** Get scaling zero point for table column. */ 414 public double getZero(){ 415 return zero; 416 } 417 418 /** Define scaling zero point for table column. 419 * 420 * @param zero scaling zero point applied on raw data values */ 421 public void setZero(double zero){ 422 this.zero = zero; 423 this.scaling = true; 424 } 425 426 /** Get scaling factor for table column. */ 427 public double getScale(){ 428 return scale; 429 } 430 431 /** Define scaling factor for table column. 432 * 433 * @param scale scaling factor applied on raw data values */ 434 public void setScale(double scale){ 435 this.scale = scale; 436 this.scaling = true; 437 } 438 }