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