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 }