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