001 /*
002 * $Id: FlatFileReader.java,v 1.10 2012/02/19 17:35:44 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2012
007 * Space Science and Engineering Center (SSEC)
008 * University of Wisconsin - Madison
009 * 1225 W. Dayton Street, Madison, WI 53706, USA
010 * https://www.ssec.wisc.edu/mcidas
011 *
012 * All Rights Reserved
013 *
014 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
015 * some McIDAS-V source code is based on IDV and VisAD source code.
016 *
017 * McIDAS-V is free software; you can redistribute it and/or modify
018 * it under the terms of the GNU Lesser Public License as published by
019 * the Free Software Foundation; either version 3 of the License, or
020 * (at your option) any later version.
021 *
022 * McIDAS-V is distributed in the hope that it will be useful,
023 * but WITHOUT ANY WARRANTY; without even the implied warranty of
024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
025 * GNU Lesser Public License for more details.
026 *
027 * You should have received a copy of the GNU Lesser Public License
028 * along with this program. If not, see http://www.gnu.org/licenses.
029 */
030 package edu.wisc.ssec.mcidasv.data;
031
032 import java.awt.Image;
033 import java.awt.Toolkit;
034 import java.io.*;
035 import java.rmi.RemoteException;
036
037 import ucar.unidata.data.BadDataException;
038 import ucar.unidata.data.grid.GridUtil;
039 import ucar.unidata.util.IOUtil;
040 import visad.CoordinateSystem;
041 import visad.Data;
042 import visad.FlatField;
043 import visad.FunctionType;
044 import visad.Gridded2DSet;
045 import visad.Linear2DSet;
046 import visad.RealTupleType;
047 import visad.RealType;
048 import visad.VisADException;
049 import visad.util.ImageHelper;
050
051 import edu.wisc.ssec.mcidasv.data.HeaderInfo;
052 import edu.wisc.ssec.mcidasv.data.hydra.LongitudeLatitudeCoordinateSystem;
053 import edu.wisc.ssec.mcidasv.data.hydra.SwathNavigation;
054
055 public class FlatFileReader {
056
057 /** The url */
058 private String url = null;
059
060 /** The dimensions */
061 private int lines = 0;
062 private int elements = 0;
063 private int strideLines = 0;
064 private int strideElements = 0;
065 private int band = 1;
066 private int bandCount = 1;
067 private String unit = "";
068 private int stride = 1;
069
070 /** The nav dimensions */
071 private int navLines = 0;
072 private int navElements = 0;
073
074 /** The data parameters */
075 private String interleave = HeaderInfo.kInterleaveSequential;
076 private boolean bigEndian = false;
077 private int offset = 0;
078 private String delimiter = "\\s+";
079 private int dataScale = 1;
080
081 /** The nav parameters */
082 private double ulLat = Double.NaN;
083 private double ulLon = Double.NaN;
084 private double lrLat = Double.NaN;
085 private double lrLon = Double.NaN;
086 private String latFile = null;
087 private String lonFile = null;
088 private int latlonScale = 1;
089 private boolean eastPositive = false;
090
091 /** which format this object is representing */
092 private int myFormat = HeaderInfo.kFormatUnknown;
093 private int myNavigation = HeaderInfo.kNavigationUnknown;
094
095 /** the actual floats read from the file */
096 float[] floatData = null;
097
098 /** cache the nav info when possible */
099 Gridded2DSet navigationSet = null;
100 CoordinateSystem navigationCoords = null;
101
102 /**
103 * Ctor for xml encoding
104 */
105 public FlatFileReader() {}
106
107 /**
108 * CTOR
109 *
110 * @param filename The filename
111 */
112 public FlatFileReader(String filename) {
113 this.url = filename;
114 }
115
116 /**
117 * CTOR
118 *
119 * @param filename The filename
120 * @param lines The number of lines
121 * @param elements The number of elements
122 * @param band The band
123 */
124 public FlatFileReader(String filename, int lines, int elements) {
125 this.url = filename;
126 this.lines = lines;
127 this.elements = elements;
128 setStride(1);
129 }
130
131 /**
132 * @param delimiter The data value delimiter
133 * @param dataScale The data scale factor
134 */
135 public void setBinaryInfo(int format, String interleave, boolean bigEndian, int offset, int band, int bandCount) {
136 this.myFormat = format;
137 this.interleave = interleave;
138 this.bigEndian = bigEndian;
139 this.offset = offset;
140 this.band = band;
141 this.bandCount = bandCount;
142 }
143
144 /**
145 * @param delimiter The data value delimiter
146 * @param dataScale The data scale factor
147 */
148 public void setAsciiInfo(String delimiter, int dataScale) {
149 this.myFormat = HeaderInfo.kFormatASCII;
150 if (delimiter == null || delimiter.trim().length() == 0) delimiter="\\s+";
151 this.delimiter = delimiter;
152 this.dataScale = dataScale;
153 }
154
155 /**
156 * @param delimiter The data value delimiter
157 * @param dataScale The data scale factor
158 */
159 public void setImageInfo() {
160 this.myFormat = HeaderInfo.kFormatImage;
161 }
162
163 /**
164 * @param ulLat The upper left latitude
165 * @param ulLon The upper left longitude
166 * @param lrLat The lower right latitude
167 * @param lrLon The lower right longitude
168 */
169 public void setNavBounds(double ulLat, double ulLon, double lrLat, double lrLon) {
170 this.myNavigation = HeaderInfo.kNavigationBounds;
171 this.ulLat = ulLat;
172 this.ulLon = ulLon;
173 this.lrLat = lrLat;
174 this.lrLon = lrLon;
175 this.latlonScale = 1;
176 }
177
178 /**
179 * @param ulLat The latitude file
180 * @param ulLon The longitude file
181 * @param latlonScale The navigation value scaling
182 */
183 public void setNavFiles(String latFile, String lonFile, int latlonScale) {
184 this.myNavigation = HeaderInfo.kNavigationFiles;
185 this.latFile = latFile;
186 this.lonFile = lonFile;
187 this.latlonScale = latlonScale;
188 }
189
190 /**
191 * @param eastPositive
192 */
193 public void setEastPositive(boolean eastPositive) {
194 this.eastPositive = eastPositive;
195 }
196
197 /**
198 * @param stride
199 */
200 public void setStride(int stride) {
201 if (stride < 1) stride=1;
202 this.stride = stride;
203 this.strideElements = (int)Math.ceil((float)this.elements/(float)stride);
204 this.strideLines = (int)Math.ceil((float)this.lines/(float)stride);
205 }
206
207 /**
208 * @param unit
209 */
210 public void setUnit(String unit) {
211 if (unit.trim().equals("")) unit="";
212 this.unit = unit;
213 }
214
215 /**
216 * Read floats from a binary file
217 */
218 private void readFloatsFromBinary() {
219 System.out.println("FlatFileInfo.readFloatsFromBinary()");
220
221 int bytesEach = 1;
222 switch (this.myFormat) {
223 case HeaderInfo.kFormat1ByteUInt:
224 bytesEach = 1;
225 break;
226 case HeaderInfo.kFormat2ByteUInt:
227 bytesEach = 2;
228 break;
229 case HeaderInfo.kFormat2ByteSInt:
230 bytesEach = 2;
231 break;
232 case HeaderInfo.kFormat4ByteSInt:
233 bytesEach = 4;
234 break;
235 case HeaderInfo.kFormat4ByteFloat:
236 bytesEach = 4;
237 break;
238 default:
239 System.err.println("FlatFileReader: Unrecognized binary format: " + this.myFormat);
240 return;
241 }
242
243 int curPixel = 0;
244 int curElement = 0;
245 int curLine = 0;
246 int lastRead = 0;
247 int readEach = 8192;
248 int startPointer = 0;
249 int endPointer = -1;
250 int pixelPointer = 0;
251
252 int readPixels = this.strideElements * this.strideLines;
253 floatData = new float[readPixels];
254 byte[] readBytes = new byte[readEach];
255
256 try {
257 FileInputStream fis = new FileInputStream(url);
258
259 // byte boundaries
260 assert(readEach % 64 == 0);
261
262 // assure we read the first time
263 assert(endPointer < 0);
264
265 while ((curPixel < readPixels && curLine < lines && lastRead > 0) || curPixel == 0) {
266
267 pixelPointer = this.offset;
268 if (this.interleave.equals(HeaderInfo.kInterleaveSequential)) {
269 // Skip to the right band
270 pixelPointer += (this.band - 1) * (this.lines * this.elements * bytesEach);
271 // Skip into the band
272 pixelPointer += (curLine * this.elements * bytesEach) + (curElement * bytesEach);
273 }
274 else if (this.interleave.equals(HeaderInfo.kInterleaveByLine)) {
275 // Skip to the right line
276 pixelPointer += curLine * (this.bandCount * this.elements * bytesEach);
277 // Skip into the line
278 pixelPointer += ((this.band - 1) * this.elements * bytesEach) + (curElement * bytesEach);
279 }
280 else if (this.interleave.equals(HeaderInfo.kInterleaveByPixel)) {
281 // Skip to the right line
282 pixelPointer += curLine * (this.bandCount * this.elements * bytesEach);
283 // Skip into the line
284 pixelPointer += (curElement * bandCount * bytesEach) + ((this.band - 1) * bytesEach);
285 }
286 else {
287 System.err.println("FlatFileReader: Unrecognized interleave type: " + this.interleave);
288 }
289
290 // We need data outside of our buffer
291 if (pixelPointer > endPointer) {
292
293 // Skip ahead to useful data
294 int skipBytes = pixelPointer - endPointer - 1;
295 if (skipBytes > 0) {
296 // System.out.println(" Skipping " + skipBytes + " bytes");
297 startPointer += lastRead + fis.skip(skipBytes);
298 endPointer = startPointer;
299 }
300
301 // Read more bytes
302 lastRead = fis.read(readBytes);
303 if (startPointer != endPointer)
304 startPointer = endPointer + 1;
305 endPointer = startPointer + lastRead - 1;
306 // System.out.println(" Read " + lastRead + " bytes, from " + startPointer);
307
308 }
309
310 int readOffset = pixelPointer - startPointer;
311 switch (this.myFormat) {
312 case HeaderInfo.kFormat1ByteUInt:
313 floatData[curPixel++] = (float)bytesTo1ByteUInt(readBytes, readOffset);
314 break;
315 case HeaderInfo.kFormat2ByteUInt:
316 floatData[curPixel++] = (float)bytesTo2ByteUInt(readBytes, readOffset);
317 break;
318 case HeaderInfo.kFormat2ByteSInt:
319 floatData[curPixel++] = (float)bytesTo2ByteSInt(readBytes, readOffset);
320 break;
321 case HeaderInfo.kFormat4ByteSInt:
322 floatData[curPixel++] = (float)bytesTo4ByteSInt(readBytes, readOffset);
323 break;
324 case HeaderInfo.kFormat4ByteFloat:
325 floatData[curPixel++] = (float)bytesTo4ByteFloat(readBytes, readOffset);
326 break;
327 }
328
329 curElement+=stride;
330 if (curElement >= elements) {
331 curElement = 0;
332 curLine+=stride;
333 }
334 }
335
336 fis.close();
337
338 System.out.println(" read " + curPixel + " floats (expected " + readPixels + ")");
339
340 } catch (NumberFormatException exc) {
341 throw new BadDataException("Error parsing binary file");
342 } catch (Exception e) {
343 throw new BadDataException("Error reading binary file: " + url + "\n" + e);
344 }
345 }
346
347 /**
348 * Read floats from an ASCII file
349 */
350 private void readFloatsFromAscii() {
351 System.out.println("FlatFileInfo.readFloatsFromAscii()");
352
353 int curPixel = 0;
354 int curElement = 0;
355 int curLine = 0;
356
357 int readPixels = this.strideElements * this.strideLines;
358 floatData = new float[readPixels];
359
360 try {
361 InputStream is = IOUtil.getInputStream(url, getClass());
362 BufferedReader in = new BufferedReader(new InputStreamReader(is));
363 String aLine;
364
365 while ((aLine = in.readLine()) != null) {
366 aLine = aLine.trim();
367 String[] words = aLine.split(delimiter);
368 for (int i=0; i<words.length; i++) {
369
370 if (curLine % stride == 0 && curElement % stride == 0) {
371 floatData[curPixel++] = Float.parseFloat(words[i]);
372 }
373
374 // Keep track of what element/line we are reading so we can stride appropriately
375 curElement++;
376 if (curElement >= elements) {
377 curElement = 0;
378 curLine++;
379 }
380 if (curLine > lines || curPixel > readPixels) {
381 throw new BadDataException("Error parsing ASCII file: Bad dimensions");
382 }
383
384 }
385 }
386 in.close();
387
388 System.out.println(" read " + curPixel + " floats (expected " + readPixels + ")");
389
390 } catch (NumberFormatException exc) {
391 throw new BadDataException("Error parsing ASCII file");
392 } catch (Exception e) {
393 throw new BadDataException("Error reading ASCII file: " + url + "\n" + e);
394 }
395 }
396
397 /**
398 * Make a FlatField from an Image
399 */
400 private Data getDataFromImage() {
401 System.out.println("FlatFileInfo.getDataFromImage()");
402 try {
403 floatData = new float[0];
404 InputStream is = IOUtil.getInputStream(url, getClass());
405 byte[] imageContent = IOUtil.readBytes(is);
406 Image image = Toolkit.getDefaultToolkit().createImage(imageContent);
407 ImageHelper ih = new ImageHelper();
408 image.getWidth(ih);
409 if (ih.badImage) {
410 throw new IllegalStateException("Bad image: " + url);
411 }
412
413 makeCoordinateSystem();
414
415 FlatField field = (FlatField) ucar.visad.Util.makeField(image,true);
416 return GridUtil.setSpatialDomain(field, navigationSet);
417
418 } catch (Exception e) {
419 throw new BadDataException("Error reading image file: " + url + "\n" + e);
420 }
421 }
422
423 /**
424 * Make a Gridded2DSet from bounds
425 */
426 private Gridded2DSet getNavigationSetFromBounds() {
427 System.out.println("FlatFileInfo.getNavigationSetFromBounds()");
428 try {
429 this.navElements = this.strideElements;
430 this.navLines = this.strideLines;
431 int lonScale = this.latlonScale;
432 int latScale = this.latlonScale;
433 if (eastPositive) lonScale *= -1;
434 return new Linear2DSet(RealTupleType.SpatialEarth2DTuple,
435 ulLon / lonScale, lrLon / lonScale, navElements,
436 ulLat / latScale, lrLat / latScale, navLines);
437 } catch (Exception e) {
438 throw new BadDataException("Error setting navigation bounds:\n" + e);
439 }
440 }
441
442 /**
443 * Make a Gridded2DSet from files
444 */
445 private Gridded2DSet getNavigationSetFromFiles() {
446 System.out.println("FlatFileInfo.getNavigationSetFromFiles()");
447 try {
448 float[][] lalo = new float[0][0];
449
450 FlatFileReader lonData, latData;
451
452 // ASCII nav files
453 if (this.myFormat == HeaderInfo.kFormatASCII) {
454 System.out.println(" ASCII nav file");
455
456 this.navElements = this.elements;
457 this.navLines = this.lines;
458 lalo = new float[2][navElements * navLines];
459
460 // Longitude band
461 lonData = new FlatFileReader(lonFile, navLines, navElements);
462 lonData.setAsciiInfo(delimiter, 1);
463
464 // Latitude band
465 latData = new FlatFileReader(latFile, navLines, navElements);
466 latData.setAsciiInfo(delimiter, 1);
467
468 }
469
470 // Binary nav files
471 else {
472
473 System.out.println(" Binary nav file");
474
475 // ENVI header for nav
476 EnviInfo enviLat = new EnviInfo(latFile);
477 EnviInfo enviLon = new EnviInfo(lonFile);
478 if (enviLat.isNavHeader() && enviLon.isNavHeader()) {
479 System.out.println(" ENVI nav file");
480
481 this.navElements = enviLat.getParameter(HeaderInfo.ELEMENTS, 0);
482 this.navLines = enviLat.getParameter(HeaderInfo.LINES, 0);
483 lalo = new float[2][navElements * navLines];
484
485 // Longitude band
486 lonData = new FlatFileReader(enviLon.getLonBandFile(),
487 enviLon.getParameter(HeaderInfo.LINES, 0),
488 enviLon.getParameter(HeaderInfo.ELEMENTS, 0));
489 lonData.setBinaryInfo(
490 enviLon.getParameter(HeaderInfo.DATATYPE, HeaderInfo.kFormatUnknown),
491 enviLon.getParameter(HeaderInfo.INTERLEAVE, HeaderInfo.kInterleaveSequential),
492 enviLon.getParameter(HeaderInfo.BIGENDIAN, false),
493 enviLon.getParameter(HeaderInfo.OFFSET, 0),
494 enviLon.getLonBandNum(),
495 enviLon.getBandCount());
496
497 // Latitude band
498 latData = new FlatFileReader(enviLat.getLatBandFile(),
499 enviLat.getParameter(HeaderInfo.LINES, 0),
500 enviLat.getParameter(HeaderInfo.ELEMENTS, 0));
501 latData.setBinaryInfo(
502 enviLat.getParameter(HeaderInfo.DATATYPE, HeaderInfo.kFormatUnknown),
503 enviLat.getParameter(HeaderInfo.INTERLEAVE, HeaderInfo.kInterleaveSequential),
504 enviLat.getParameter(HeaderInfo.BIGENDIAN, false),
505 enviLat.getParameter(HeaderInfo.OFFSET, 0),
506 enviLat.getLatBandNum(),
507 enviLat.getBandCount());
508
509 }
510
511 else {
512 System.out.println(" AXFORM nav file");
513
514 this.navElements = this.elements;
515 this.navLines = this.lines;
516 lalo = new float[2][navElements * navLines];
517
518 // Longitude band
519 lonData = new FlatFileReader(lonFile, navLines, navElements);
520 lonData.setBinaryInfo(HeaderInfo.kFormat2ByteUInt, HeaderInfo.kInterleaveSequential, bigEndian, offset, 1, 1);
521
522 // Latitude band
523 latData = new FlatFileReader(latFile, navLines, navElements);
524 latData.setBinaryInfo(HeaderInfo.kFormat2ByteUInt, HeaderInfo.kInterleaveSequential, bigEndian, offset, 1, 1);
525
526 }
527
528 }
529
530 // Set the stride if the dimensions are the same and read the floats
531 if (this.lines == this.navLines && this.elements == this.navElements && stride != 1) {
532 System.out.println("Setting stride for nav files: " + stride);
533 lonData.setStride(this.stride);
534 latData.setStride(this.stride);
535 this.navElements = this.strideElements;
536 this.navLines = this.strideLines;
537 lalo = new float[2][this.navElements * this.navLines];
538 }
539 lalo[0] = lonData.getFloats();
540 lalo[1] = latData.getFloats();
541
542 // Take into account scaling and east positive
543 int latScale = this.latlonScale;
544 int lonScale = this.latlonScale;
545 if (eastPositive) lonScale = -1 * lonScale;
546 for (int i=0; i<lalo[0].length; i++) {
547 lalo[0][i] = lalo[0][i] / (float)lonScale;
548 }
549 for (int i=0; i<lalo[1].length; i++) {
550 lalo[1][i] = lalo[1][i] / (float)latScale;
551 }
552
553 return new Gridded2DSet(RealTupleType.SpatialEarth2DTuple,
554 lalo, navElements, navLines,
555 null, null, null,
556 false, false);
557
558 } catch (NumberFormatException exc) {
559 throw new BadDataException("Error parsing ASCII navigation file");
560 } catch (Exception e) {
561 throw new BadDataException("Error setting navigation from file: " + url + "\n" + e);
562 }
563 }
564
565 /**
566 * Create navigation info if it hasn't been built
567 */
568 private void makeCoordinateSystem() {
569 System.out.println("FlatFileInfo.makeCoordinateSystem()");
570
571 if (navigationSet != null && navigationCoords != null) return;
572
573 switch (this.myNavigation) {
574 case HeaderInfo.kNavigationBounds:
575 navigationSet = getNavigationSetFromBounds();
576 break;
577 case HeaderInfo.kNavigationFiles:
578 navigationSet = getNavigationSetFromFiles();
579 break;
580 default:
581 System.err.println("Unknown navigation format");
582 }
583
584 // myElements, myLines: Nav dimensions
585 // this.elements, this.lines: Data dimensions
586 float ratioElements = (float)this.strideElements / (float)this.navElements;
587 float ratioLines = (float)this.strideLines / (float)this.navLines;
588 int[] geo_start = new int[2];
589 int[] geo_count = new int[2];
590 int[] geo_stride = new int[2];
591 try {
592 Linear2DSet domainSet = SwathNavigation.getNavigationDomain(
593 0, strideElements-1, 1,
594 0, strideLines-1, 1,
595 ratioElements, ratioLines, 0, 0,
596 geo_start, geo_count, geo_stride);
597
598 // System.out.println("makeCoordinateSystem stats for " + url + ":");
599 // System.out.println(" Elements: " + strideElements + ", Lines: " + strideLines);
600 // System.out.println(" navElements: " + navElements + ", navLines: " + navLines);
601 // System.out.println(" ratioElements: " + ratioElements + ", ratioLines: " + ratioLines);
602 // System.out.println(" navigationSet: " + navigationSet.getLength(0) + " x " + navigationSet.getLength(1));
603 // System.out.println(" geo_start: " + geo_start[0] + ", " + geo_start[1]);
604 // System.out.println(" geo_count: " + geo_count[0] + ", " + geo_count[1]);
605 // System.out.println(" geo_stride: " + geo_stride[0] + ", " + geo_stride[1]);
606 // System.out.println(" domainSet: " + domainSet.getLength(0) + " x " + domainSet.getLength(1));
607 // System.out.println(" domainSet.toString(): " + domainSet.toString());
608
609 navigationCoords = new LongitudeLatitudeCoordinateSystem(domainSet, navigationSet);
610 } catch (Exception e) {
611 // TODO Auto-generated catch block
612 e.printStackTrace();
613 }
614 }
615
616 /**
617 * Return a valid data object for a DataSource
618 */
619 public Data getData() {
620 System.out.println("FlatFileInfo.getData()");
621
622 Data d = null;
623 FlatField field;
624
625 try {
626
627 switch (this.myFormat) {
628 case HeaderInfo.kFormatImage:
629 d = getDataFromImage();
630 break;
631 default:
632 floatData = getFloats();
633 field = getFlatField();
634 // d = GridUtil.setSpatialDomain(field, navigationSet);
635 d = field;
636 break;
637 }
638
639 } catch (IOException e) {
640 // TODO Auto-generated catch block
641 e.printStackTrace();
642 } catch (VisADException e) {
643 // TODO Auto-generated catch block
644 e.printStackTrace();
645 }
646
647 return d;
648 }
649
650 /**
651 * Return the array of floats making up the data
652 */
653 public float[] getFloats() {
654 System.out.println("FlatFileInfo.getFloats()");
655
656 if (floatData != null) return floatData;
657
658 switch (this.myFormat) {
659 case HeaderInfo.kFormatImage:
660 break;
661 case HeaderInfo.kFormatASCII:
662 readFloatsFromAscii();
663 break;
664 default:
665 readFloatsFromBinary();
666 break;
667 }
668
669
670
671 // DEBUG!
672 // File justName = new File(url);
673 // try {
674 // BufferedWriter out = new BufferedWriter(new FileWriter("/tmp/mcv/" + justName.getName()));
675 // for (int i=0; i<floatData.length; i++) {
676 // if (i%strideElements==0) out.write("New line " + (i/strideElements) + " at element " + i + "\n");
677 // out.write(floatData[i] + "\n");
678 // }
679 // out.close();
680 // }
681 // catch (IOException e) {
682 // System.out.println("Exception ");
683 // }
684
685
686
687 return floatData;
688 }
689
690 /**
691 * float array -> flatfield
692 */
693 private FlatField getFlatField()
694 throws IOException, VisADException {
695
696 makeCoordinateSystem();
697
698 // RealType[] unit = new RealType[] { RealType.Generic };
699 // RealTupleType unitType = new RealTupleType(unit);
700
701 RealType unitType = RealType.getRealType(unit);
702
703 RealType line = RealType.getRealType("ImageLine");
704 RealType element = RealType.getRealType("ImageElement");
705 RealType[] domain_components = { element, line };
706 RealTupleType image_domain = new RealTupleType(domain_components, navigationCoords, null);
707 FunctionType image_type = new FunctionType(image_domain, unitType);
708 Linear2DSet domain_set = new Linear2DSet(image_domain,
709 0.0, (float) (strideElements - 1.0), strideElements,
710 0.0, (float) (strideLines - 1.0), strideLines);
711
712 FlatField field = new FlatField(image_type, domain_set);
713
714 float[][] samples = new float[][] { floatData };
715 try {
716 field.setSamples(samples, false);
717 } catch (RemoteException e) {
718 throw new VisADException("Couldn't finish FlatField initialization");
719 }
720
721 return field;
722 }
723
724 /**
725 * toString
726 *
727 * @return toString
728 */
729 public String toString() {
730 return "url: " + url + ", lines: " + lines + ", elements: " + elements;
731 }
732
733 // byte[] conversion functions
734 // TODO: are these replicated elsewhere in McV?
735
736 private static int bytesTo1ByteUInt (byte[] bytes, int offset) {
737 return (int) ( bytes[offset] & 0xff );
738 }
739
740 private static int bytesTo2ByteUInt (byte[] bytes, int offset) {
741 int accum = 0;
742 for ( int shiftBy = 0; shiftBy < 16; shiftBy += 8 ) {
743 accum |= ( (long)( bytes[offset] & 0xff ) ) << shiftBy;
744 offset++;
745 }
746 return (int)( accum );
747 }
748
749 private static int bytesTo2ByteSInt (byte[] bytes, int offset) {
750 return (bytesTo2ByteUInt(bytes, offset)) - 32768;
751 }
752
753 private static int bytesTo4ByteSInt (byte[] bytes, int offset) {
754 int accum = 0;
755 for ( int shiftBy = 0; shiftBy < 32; shiftBy += 8 ) {
756 accum |= ( (long)( bytes[offset] & 0xff ) ) << shiftBy;
757 offset++;
758 }
759 return (int)( accum );
760 }
761
762 private static float bytesTo4ByteFloat (byte[] bytes, int offset) {
763 int accum = 0;
764 for ( int shiftBy = 0; shiftBy < 32; shiftBy += 8 ) {
765 accum |= ( (long)( bytes[offset] & 0xff ) ) << shiftBy;
766 offset++;
767 }
768 return Float.intBitsToFloat(accum);
769 }
770
771 private static long bytesToLong (byte[] bytes) {
772 if (bytes.length != 4) return 0;
773 long accum = 0;
774 int i = 0;
775 for ( int shiftBy = 0; shiftBy < 32; shiftBy += 8 ) {
776 accum |= ( (long)( bytes[i] & 0xff ) ) << shiftBy;
777 i++;
778 }
779 return accum;
780 }
781
782 private static double bytesToDouble (byte[] bytes) {
783 if (bytes.length != 8) return 0;
784 long accum = 0;
785 int i = 0;
786 for ( int shiftBy = 0; shiftBy < 64; shiftBy += 8 ) {
787 accum |= ( (long)( bytes[i] & 0xff ) ) << shiftBy;
788 i++;
789 }
790 return Double.longBitsToDouble(accum);
791 }
792
793 }