001: package it.geosolutions.imageio.plugins.jhdf;
002:
003: import it.geosolutions.imageio.plugins.slices2D.SliceImageReader;
004: import it.geosolutions.imageio.stream.input.FileImageInputStreamExtImpl;
005:
006: import java.awt.Rectangle;
007: import java.awt.image.BandedSampleModel;
008: import java.awt.image.BufferedImage;
009: import java.awt.image.ColorModel;
010: import java.awt.image.DataBuffer;
011: import java.awt.image.DataBufferByte;
012: import java.awt.image.DataBufferDouble;
013: import java.awt.image.DataBufferFloat;
014: import java.awt.image.DataBufferInt;
015: import java.awt.image.DataBufferShort;
016: import java.awt.image.Raster;
017: import java.awt.image.SampleModel;
018: import java.awt.image.WritableRaster;
019: import java.io.File;
020: import java.io.IOException;
021: import java.util.ArrayList;
022: import java.util.Iterator;
023: import java.util.LinkedHashMap;
024: import java.util.List;
025: import java.util.Set;
026:
027: import javax.imageio.ImageReadParam;
028: import javax.imageio.ImageTypeSpecifier;
029: import javax.imageio.spi.ImageReaderSpi;
030:
031: import ncsa.hdf.object.Dataset;
032: import ncsa.hdf.object.Datatype;
033: import ncsa.hdf.object.FileFormat;
034: import ncsa.hdf.object.HObject;
035:
036: public abstract class BaseHDFImageReader extends SliceImageReader {
037:
038: /** A <code>LinkedHashMap</code> having all the <code>Dataset</code>s
039: * contained within the source */
040: protected LinkedHashMap subDatasetsMap;
041:
042: /** A mutex used to synchronize operations */
043: protected final int[] mutex = new int[] { 0 };
044:
045: /**
046: * Returns a subDataset given a subDatasetIndex
047: *
048: * @param subDatasetIndex
049: * The index of the required subDataset
050: * @return the required subDataset
051: */
052: protected Dataset retrieveDataset(int subDatasetIndex) {
053: synchronized (mutex) {
054: Set set = subDatasetsMap.keySet();
055: Iterator it = set.iterator();
056: for (int j = 0; j < subDatasetIndex; j++)
057: it.next();
058: return (Dataset) subDatasetsMap.get((String) it.next());
059: }
060: }
061:
062: private void checkImageIndex(int imageIndex) {
063: //TODO: implements this to handle supported indexes
064: }
065:
066: // TODO: should be moved in the aboveLayer?
067:
068: /**
069: * Class used to store basic source structure properties such as number of
070: * subdatasets and basic properties of each sub dataset, such as, rank,
071: * dimensions size, chunk size.
072: */
073: protected class SourceStructure {
074:
075: /** the number of subdatasets contained within the data source */
076: protected int nSubdatasets;
077:
078: /** a list of {@link SubDatasetInfo} instances */
079: protected ArrayList subDatasetInfo;
080:
081: /**
082: * Redundant field. Allows index management without scanning all
083: * <code>SubDatasetInfo</code>
084: */
085: protected ArrayList subDatasetSizes;
086:
087: /**
088: * A-priori Constructor. Use this form when you know the exact
089: * subdataset number prior to instantiate the
090: * <code>SourceStructure</code>
091: *
092: * @param subdatasetsNum
093: */
094: public SourceStructure(int subdatasetsNum) {
095: nSubdatasets = subdatasetsNum;
096: subDatasetInfo = new ArrayList(subdatasetsNum);
097: // new SubDatasetInfo[subdatasetsNum];
098: subDatasetSizes = new ArrayList(subdatasetsNum);
099: }
100:
101: /**
102: * Constructor which need to be used when you dont know the exact
103: * subdataset number a priori. After all <code>SubDatasetInfo</code>'s
104: * has been added, you need to call the <code>init</code> method.
105: *
106: */
107:
108: public SourceStructure() {
109: nSubdatasets = 0;
110: subDatasetInfo = new ArrayList(10);
111: subDatasetSizes = new ArrayList(10);
112: }
113:
114: public long getSubDatasetSize(int index) {
115: return ((Long) subDatasetSizes.get(index)).longValue();
116: // return subDatasetSize[0];
117: }
118:
119: public void setSubDatasetSize(int index, long size) {
120: subDatasetSizes.add(index, new Long(size));
121: }
122:
123: public int getNSubdatasets() {
124: return nSubdatasets;
125: }
126:
127: public void setNSubdatasets(int subdatasets) {
128: nSubdatasets = subdatasets;
129: }
130:
131: public long[] getSubDatasetSizes() {
132: final Object[] objArray = subDatasetSizes.toArray();
133: final int length = objArray.length;
134: final long[] array = new long[length];
135: for (int i = 0; i < length; i++)
136: array[i] = ((Long) (objArray[i])).longValue();
137: return array;
138: }
139:
140: public void setSubDatasetInfo(int subDatasetIndex,
141: SubDatasetInfo dsInfo) {
142: // subDatasetInfo[j] = dsInfo;
143: subDatasetInfo.add(subDatasetIndex, dsInfo);
144: }
145:
146: public void addSubDatasetProperties(SubDatasetInfo dsInfo,
147: long subDatasetSize) {
148: // subDatasetInfo[j] = dsInfo;
149: subDatasetInfo.add(nSubdatasets, dsInfo);
150: subDatasetSizes.add(nSubdatasets++,
151: new Long(subDatasetSize));
152: }
153:
154: public SubDatasetInfo getSubDatasetInfo(int subDatasetIndex) {
155: if (subDatasetIndex <= nSubdatasets)
156: // return subDatasetInfo[subDatasetIndex];
157: return (SubDatasetInfo) subDatasetInfo
158: .get(subDatasetIndex);
159: else
160: return null;
161: }
162:
163: public void dispose() {
164: nSubdatasets = 0;
165: subDatasetInfo.clear();
166: subDatasetSizes.clear();
167: }
168: }
169:
170: /**
171: *
172: * @param itemName
173: * The name of the product/subDataset to be checked
174: * @return <code>true</code> if the product/subdataset needs to be taken
175: * on account.
176: */
177: protected abstract boolean isAcceptedItem(final String itemName);
178:
179: /**
180: * Additional initialization for a specific HDF "Profile".
181: * Depending on the HDF data producer, the originating file has a proper
182: * data/metadata structure. For this reason, a specific initialization
183: * should be implemented for each different HDF "Profile".
184: * As an instance, the Automated Processing System (APS) produces HDF files
185: * having a structure which differes from the HDF structure of a file
186: * produced by TIROS Operational Vertical Sounder (TOVS).
187: *
188: * @throws Exception
189: */
190: protected abstract void initializeProfile() throws Exception;
191:
192: protected abstract int getBandNumberFromProduct(
193: final String productName);
194:
195: /** The originating FileFormat */
196: protected FileFormat fileFormat = null;
197:
198: protected ImageTypeSpecifier imageType = null;
199:
200: /**
201: * a <code>SourceStructure</code>'s instance needed to get main
202: * SubDatasets info and properties.
203: */
204: protected SourceStructure sourceStructure;
205:
206: /** root of the FileFormat related to the provided input source */
207: protected HObject root;
208:
209: protected BaseHDFImageReader(ImageReaderSpi originatingProvider) {
210: super (originatingProvider);
211: }
212:
213: /**
214: * Returns the width in pixels of the given image within the input source.
215: *
216: * @param imageIndex
217: * the index of the image to be queried.
218: *
219: * @return the width of the image, as an <code>int</code>.
220: */
221: public int getWidth(final int imageIndex) throws IOException {
222: if (!isInitialized)
223: initialize();
224: return sourceStructure.getSubDatasetInfo(
225: retrieveSubDatasetIndex(imageIndex)).getWidth();
226: }
227:
228: /**
229: * Returns the height in pixels of the given image within the input source.
230: *
231: * @param imageIndex
232: * the index of the image to be queried.
233: *
234: * @return the height of the image, as an <code>int</code>.
235: */
236: public int getHeight(final int imageIndex) throws IOException {
237: if (!isInitialized)
238: initialize();
239: return sourceStructure.getSubDatasetInfo(
240: retrieveSubDatasetIndex(imageIndex)).getHeight();
241: }
242:
243: /**
244: * Reads the image indexed by <code>imageIndex</code> and returns it as a
245: * <code>BufferedImage</code>, using a supplied <code>ImageReadParam</code>
246: *
247: * @param imageIndex
248: * the index of the image to be retrieved.
249: * @param param
250: * an <code>ImageReadParam</code> used to control the reading
251: * process, or <code>null</code>.
252: *
253: * @return the desired portion of the image as a <code>BufferedImage</code>.
254: */
255: public BufferedImage read(final int imageIndex, ImageReadParam param)
256: throws IOException {
257:
258: // ////////////////////////////////////////////////////////////////////
259: //
260: // INITIALIZATIONS
261: //
262: // ////////////////////////////////////////////////////////////////////
263:
264: if (!isInitialized)
265: initialize();
266:
267: //Getting indexing information
268: final int[] slice2DindexCoordinates = getSlice2DIndexCoordinates(imageIndex);
269: final int subDatasetIndex = slice2DindexCoordinates[0];
270: final Dataset dataset = retrieveDataset(subDatasetIndex);
271:
272: BufferedImage bimage = null;
273: SubDatasetInfo sdInfo = sourceStructure
274: .getSubDatasetInfo(subDatasetIndex);
275:
276: final int rank = sdInfo.getRank();
277: final int width = sdInfo.getWidth();
278: final int height = sdInfo.getHeight();
279: final Datatype dt = sdInfo.getDatatype();
280:
281: if (param == null)
282: param = getDefaultReadParam();
283:
284: int dstWidth = -1;
285: int dstHeight = -1;
286: int srcRegionWidth = -1;
287: int srcRegionHeight = -1;
288: int srcRegionXOffset = -1;
289: int srcRegionYOffset = -1;
290: int xSubsamplingFactor = -1;
291: int ySubsamplingFactor = -1;
292:
293: // //
294: //
295: // Retrieving Information about Source Region and doing
296: // additional intialization operations.
297: //
298: // //
299: Rectangle srcRegion = param.getSourceRegion();
300: if (srcRegion != null) {
301: srcRegionWidth = (int) srcRegion.getWidth();
302: srcRegionHeight = (int) srcRegion.getHeight();
303: srcRegionXOffset = (int) srcRegion.getX();
304: srcRegionYOffset = (int) srcRegion.getY();
305:
306: // //
307: //
308: // Minimum correction for wrong source regions
309: //
310: // When you do subsampling or source subsetting it might
311: // happen that the given source region in the read param is
312: // uncorrect, which means it can be or a bit larger than the
313: // original file or can begin a bit before original limits.
314: //
315: // We got to be prepared to handle such case in order to avoid
316: // generating ArrayIndexOutOfBoundsException later in the code.
317: //
318: // //
319:
320: if (srcRegionXOffset < 0)
321: srcRegionXOffset = 0;
322: if (srcRegionYOffset < 0)
323: srcRegionYOffset = 0;
324: if ((srcRegionXOffset + srcRegionWidth) > width) {
325: srcRegionWidth = width - srcRegionXOffset;
326: }
327: // initializing destWidth
328: dstWidth = srcRegionWidth;
329:
330: if ((srcRegionYOffset + srcRegionHeight) > height) {
331: srcRegionHeight = height - srcRegionYOffset;
332: }
333: // initializing dstHeight
334: dstHeight = srcRegionHeight;
335:
336: } else {
337: // Source Region not specified.
338: // Assuming Source Region Dimension equal to Source Image
339: // Dimension
340: dstWidth = width;
341: dstHeight = height;
342: srcRegionXOffset = srcRegionYOffset = 0;
343: srcRegionWidth = width;
344: srcRegionHeight = height;
345: }
346:
347: // SubSampling variables initialization
348: xSubsamplingFactor = param.getSourceXSubsampling();
349: ySubsamplingFactor = param.getSourceYSubsampling();
350:
351: // ////
352: //
353: // Updating the destination size in compliance with
354: // the subSampling parameters
355: //
356: // ////
357:
358: dstWidth = ((dstWidth - 1) / xSubsamplingFactor) + 1;
359: dstHeight = ((dstHeight - 1) / ySubsamplingFactor) + 1;
360:
361: // getting dataset properties.
362: dataset.init();
363: final long[] start = dataset.getStartDims();
364: final long[] stride = dataset.getStride();
365: final long[] sizes = dataset.getSelectedDims();
366:
367: // Setting variables needed to execute read operation.
368: start[rank - 2] = srcRegionYOffset;
369: start[rank - 1] = srcRegionXOffset;
370: sizes[rank - 2] = dstHeight;
371: sizes[rank - 1] = dstWidth;
372: stride[rank - 2] = ySubsamplingFactor;
373: stride[rank - 1] = xSubsamplingFactor;
374:
375: if (rank > 2) {
376: // Setting indexes of dimensions > 2.
377: for (int i = 0; i < rank - 2; i++) {
378: // TODO: Need to change indexing logic?
379: start[i] = slice2DindexCoordinates[i + 1];
380: sizes[i] = 1;
381: stride[i] = 1;
382: }
383: }
384:
385: final int nBands = getBandNumberFromProduct(sdInfo.getName());
386:
387: // bands variables
388: final int[] banks = new int[nBands];
389: final int[] offsets = new int[nBands];
390: for (int band = 0; band < nBands; band++) {
391: banks[band] = band;
392: offsets[band] = 0;
393: }
394:
395: // Setting SampleModel and ColorModel
396: final int bufferType = HDFUtilities
397: .getBufferTypeFromDataType(dt);
398: SampleModel sm = new BandedSampleModel(bufferType, dstWidth,
399: dstHeight, dstWidth, banks, offsets);
400: ColorModel cm = retrieveColorModel(sm);
401:
402: // ////////////////////////////////////////////////////////////////////
403: //
404: // DATA READ
405: //
406: // ////////////////////////////////////////////////////////////////////
407:
408: WritableRaster wr = null;
409: final Object data;
410: try {
411: data = dataset.read();
412: final int size = dstWidth * dstHeight;
413: DataBuffer dataBuffer = null;
414:
415: switch (bufferType) {
416: case DataBuffer.TYPE_BYTE:
417: dataBuffer = new DataBufferByte((byte[]) data, size);
418: break;
419: case DataBuffer.TYPE_SHORT:
420: case DataBuffer.TYPE_USHORT:
421: dataBuffer = new DataBufferShort((short[]) data, size);
422: break;
423: case DataBuffer.TYPE_INT:
424: dataBuffer = new DataBufferInt((int[]) data, size);
425: break;
426: case DataBuffer.TYPE_FLOAT:
427: dataBuffer = new DataBufferFloat((float[]) data, size);
428: break;
429: case DataBuffer.TYPE_DOUBLE:
430: dataBuffer = new DataBufferDouble((double[]) data, size);
431: break;
432: }
433:
434: wr = Raster.createWritableRaster(sm, dataBuffer, null);
435: bimage = new BufferedImage(cm, wr, false, null);
436:
437: } catch (Exception e) {
438: RuntimeException rte = new RuntimeException(
439: "Exception occurred while data Reading" + e);
440: rte.initCause(e);
441: throw rte;
442: }
443:
444: return bimage;
445: }
446:
447: public void setInput(Object input, boolean seekForwardOnly,
448: boolean ignoreMetadata) {
449: this .setInput(input);
450: }
451:
452: public void setInput(Object input, boolean seekForwardOnly) {
453: this .setInput(input, seekForwardOnly);
454: }
455:
456: public void setInput(Object input) {
457: // ////////////////////////////////////////////////////////////////////
458: //
459: // Reset the state of this reader
460: //
461: // Prior to set a new input, I need to do a pre-emptive reset in order
462: // to clear any value-object related to the previous input.
463: // ////////////////////////////////////////////////////////////////////
464:
465: //TODO: Add URL & String support.
466: if (originatingFile != null)
467: reset(); //TODO: Need to reset also sourceStructure
468: if (input instanceof File) {
469: originatingFile = (File) input;
470: }
471:
472: if (input instanceof FileImageInputStreamExtImpl) {
473: //retrieving File
474: originatingFile = ((FileImageInputStreamExtImpl) input)
475: .getFile();
476: }
477:
478: try {
479: initialize();
480: } catch (IOException e) {
481: new RuntimeException("Not a Valid Input", e);
482: }
483: }
484:
485: /**
486: * Simple initialization method
487: */
488: protected void initialize() throws IOException {
489: synchronized (mutex) {
490: if (originatingFile == null)
491: throw new IOException(
492: "Unable to Initialize data. Provided Input is not valid");
493: final String fileName = originatingFile.getAbsolutePath();
494: try {
495: fileFormat = FileFormat.getInstance(fileName);
496: fileFormat = fileFormat.open(fileName, FileFormat.READ);
497: root = fileFormat.get("/");
498: if (root != null)
499: initializeProfile();
500:
501: } catch (Exception e) {
502: IOException ioe = new IOException(
503: "Unable to Initialize data. Provided Input is not valid"
504: + e);
505: ioe.initCause(e);
506: throw ioe;
507: }
508: isInitialized = true;
509: }
510: }
511:
512: /**
513: * Returns an <code>Iterator</code> containing possible image
514: * types to which the given image may be decoded, in the form of
515: * <code>ImageTypeSpecifiers</code>s.
516: *
517: * @param imageIndex the index of the image to be
518: * <code>retrieved</code>.
519: *
520: * @return an <code>Iterator</code> containing at least one
521: * <code>ImageTypeSpecifier</code> representing suggested image
522: * types for decoding the current given image.
523: *
524: * @exception IllegalStateException if the input source has not been set.
525: * @exception IndexOutOfBoundsException if the supplied index is
526: * out of bounds.
527: * @exception IOException if an error occurs reading the format
528: * information from the input source.
529: */
530:
531: public Iterator getImageTypes(final int imageIndex)
532: throws IOException {
533: final List l = new java.util.ArrayList(1);
534: if (!isInitialized)
535: initialize();
536:
537: final SubDatasetInfo sdInfo = sourceStructure
538: .getSubDatasetInfo(retrieveSubDatasetIndex(imageIndex));
539:
540: final Datatype dt = sdInfo.getDatatype();
541: final int width = sdInfo.getWidth();
542: final int height = sdInfo.getHeight();
543: final int nBands = getBandNumberFromProduct(sdInfo.getName());
544:
545: // bands variables
546: final int[] banks = new int[nBands];
547: final int[] offsets = new int[nBands];
548: for (int band = 0; band < nBands; band++) {
549: banks[band] = band;
550: offsets[band] = 0;
551: }
552:
553: // Variable used to specify the data type for the storing samples
554: // of the SampleModel
555: final int bufferType = HDFUtilities
556: .getBufferTypeFromDataType(dt);
557: final SampleModel sm = new BandedSampleModel(bufferType, width,
558: height, width, banks, offsets);
559:
560: final ColorModel cm = retrieveColorModel(sm);
561:
562: imageType = new ImageTypeSpecifier(cm, sm);
563: l.add(imageType);
564: return l.iterator();
565: }
566:
567: /**
568: * Returns the height of a tile in the given image.
569: *
570: * @param imageIndex the index of the image to be queried.
571: *
572: * @return the height of a tile.
573: *
574: * @exception IOException if an error occurs during reading.
575: */
576: public int getTileHeight(final int imageIndex) throws IOException {
577: if (!isInitialized)
578: initialize();
579: final SubDatasetInfo sdInfo = sourceStructure
580: .getSubDatasetInfo(retrieveSubDatasetIndex(imageIndex));
581: final long[] chunkSize = sdInfo.getChunkSize();
582:
583: // TODO: Change this behavior
584: if (chunkSize != null) {
585: final int rank = sdInfo.getRank();
586: return (int) chunkSize[rank - 1];
587: } else
588: return Math.min(512, sdInfo.getHeight());
589: }
590:
591: /**
592: * Returns the width of a tile in the given image.
593: *
594: * @param imageIndex the index of the image to be queried.
595: *
596: * @return the width of a tile.
597: *
598: * @exception IOException if an error occurs during reading.
599: */
600: public int getTileWidth(final int imageIndex) throws IOException {
601: if (!isInitialized)
602: initialize();
603: final SubDatasetInfo sdInfo = sourceStructure
604: .getSubDatasetInfo(retrieveSubDatasetIndex(imageIndex));
605: final long[] chunkSize = sdInfo.getChunkSize();
606:
607: // TODO: Change this behavior
608: if (chunkSize != null) {
609: final int rank = sdInfo.getRank();
610: return (int) chunkSize[rank - 2];
611: } else
612: return Math.min(512, sdInfo.getWidth());
613: }
614:
615: public void dispose() {
616: super .dispose();
617: try {
618: fileFormat.close();
619: sourceStructure.dispose();
620: sourceStructure = null;
621: } catch (Exception e) {
622: // TODO Nothing to do.
623: }
624: }
625:
626: public void reset() {
627: super .setInput(null, false, false);
628: root = null;
629: originatingFile = null;
630: }
631:
632: /**
633: * returns a proper subindex needed to access a specific 2D slice of a
634: * specified coverage/subdataset.
635: *
636: * @param imageIndex
637: * the specified coverage/subDataset
638: * @param selectedIndexOfEachDim
639: * the required index of each dimension
640: *
641: * TODO: Should I use a single long[] input parameter containing also the
642: * subdataset index?
643: */
644: public int retrieveSlice2DIndex(int imageIndex,
645: int[] selectedIndexOfEachDim) {
646: int subIndexOffset = 0;
647: final SubDatasetInfo sdInfo = sourceStructure
648: .getSubDatasetInfo(imageIndex);
649: for (int i = 0; i < imageIndex; i++)
650: subIndexOffset += (sourceStructure.getSubDatasetSize(i));
651:
652: if (selectedIndexOfEachDim != null) {
653: // X and Y dims are not taken in account
654: final int selectedDimsLenght = selectedIndexOfEachDim.length;
655: final long[] subDatasetDims = sdInfo.getDims();
656: final int rank = sdInfo.getRank();
657:
658: // supposing specifying all required subDimensions.
659: // as an instance, if rank=5, I need to specify 3 dimensions-index
660: // TODO: maybe I can assume some default behavior.
661: // as an instance, using 0 as dimension-index when not specified.
662: if (selectedDimsLenght != (rank - 2)) {
663: throw new IndexOutOfBoundsException(
664: "The selected dims array can't be"
665: + "greater than the rank of the subDataset");
666: }
667: for (int i = 0; i < selectedDimsLenght; i++) {
668: if (selectedIndexOfEachDim[i] > subDatasetDims[i]) {
669: final StringBuffer sb = new StringBuffer();
670: sb
671: .append(
672: "At least one of the specified indexes is greater than the max allowed index in that dimension\n")
673: .append("dimension=")
674: .append(i)
675: .append(" index=")
676: .append(selectedIndexOfEachDim[i])
677: .append(
678: " while the maximum index available for this dimension is ")
679: .append(subDatasetDims[i]);
680: throw new IndexOutOfBoundsException(sb.toString());
681: }
682: }
683: long displacement = 0;
684: if (rank > 2) {
685: // The least significant dimension is used as offset
686: long finalOffset = selectedIndexOfEachDim[rank - 3];
687: if (rank > 3) {
688: //TODO: review and test this logic with a 4D dataset.
689: final long[] multipliers = new long[rank - 3];
690: for (int i = 0; i < rank - 3; i++)
691: multipliers[i] = subDatasetDims[i + 2];
692: for (int i = 0; i < rank - 3; i++) {
693: int factor = 1;
694: for (int j = 0; j < rank - 3 - i; j++)
695: factor *= multipliers[j];
696: displacement += (factor * selectedIndexOfEachDim[i]);
697: }
698: }
699: displacement += finalOffset;
700: }
701: subIndexOffset += displacement;
702: }
703: return (int) subIndexOffset;
704: }
705:
706: /**
707: * Given a specifiedIndex as an input, returns a <code>long[]</code>
708: * having the subDataset/coverage index at the first position of the array.
709: * Then, the indexes (of the other dimensions) needed to retrieve a proper
710: * 2D Slice.
711: *
712: * As an instance, suppose a HDF source contains a 4D SubDataset with the
713: * form (X,Y,Z,T). if returnedIndex[]={2,3,1}, the required Slice2D is
714: * available at the subDataset with index=2, timeIndex=3, zIndex=1.
715: *
716: * TODO: Now, we are supposing order is 5thDim -> T -> Z -> (X,Y)
717: *
718: */
719: public int[] getSlice2DIndexCoordinates(int requiredSlice2DIndex) {
720: final int nTotalDataset = sourceStructure.getNSubdatasets();
721: final long[] subDatasetSizes = sourceStructure
722: .getSubDatasetSizes();
723: int iSubdataset = 0;
724: for (; iSubdataset < nTotalDataset; iSubdataset++) {
725: int subDatasetSize = (int) subDatasetSizes[iSubdataset];
726: if (requiredSlice2DIndex >= subDatasetSize)
727: requiredSlice2DIndex -= subDatasetSize;
728: else
729: break;
730: }
731:
732: // Getting the SubDatasetInfo related to the specified subDataset.
733: final SubDatasetInfo sdInfo = sourceStructure
734: .getSubDatasetInfo(iSubdataset);
735: final int rank = sdInfo.getRank();
736:
737: // index initialization
738: final int[] slice2DIndexCoordinates = new int[rank - 1];// subDatasetIndex+(rank-2)
739: for (int i = 0; i < rank - 1; i++)
740: slice2DIndexCoordinates[i] = 0;
741: slice2DIndexCoordinates[0] = iSubdataset;
742:
743: if (rank > 2) {
744:
745: if (rank > 3) {
746: // TODO: review and test this logic with a 4D dataset.
747: final long[] subDatasetDims = sdInfo.getDims();
748: final long[] multipliers = new long[rank - 3];
749: for (int i = 0; i < rank - 3; i++)
750: multipliers[i] = subDatasetDims[i];
751:
752: for (int i = 0; i < rank - 3; i++) {
753: int factor = 1;
754: for (int j = 0; j < rank - 3 - i; j++)
755: factor *= multipliers[j];
756: while (requiredSlice2DIndex >= factor) {
757: requiredSlice2DIndex -= factor;
758: slice2DIndexCoordinates[i + 1]++;
759: }
760: }
761: }
762: slice2DIndexCoordinates[rank - 2] = requiredSlice2DIndex;
763: }
764: return slice2DIndexCoordinates;
765: }
766:
767: // /**
768: // * Given a specifiedIndex as an input, returns a <code>long[]</code>
769: // * having the subDataset/coverage index at the first position of the
770: // array.
771: // * Then, the indexes (of the other dimensions) needed to retrieve a proper
772: // * 2D Slice.
773: // *
774: // * As an instance, suppose a HDF source contains a 4D SubDataset with the
775: // * form (X,Y,Z,T). if returnedIndex[]={2,3,1}, the required Slice2D is
776: // * available at the subDataset with index=2, timeIndex=3, zIndex=1.
777: // *
778: // * TODO: Now, we are supposing order is 5thDim -> T -> Z -> (X,Y)
779: // *
780: // */
781: // public int[] getSlice2DIndexCoordinates(int requiredSlice2DIndex) {
782: // final int nTotalDataset = sourceStructure.getNSubdatasets();
783: // final long[] subDatasetSizes = sourceStructure.getSubDatasetSizes();
784: // int iSubdataset = 0;
785: // for (; iSubdataset < nTotalDataset; iSubdataset++) {
786: // int subDatasetSize = (int) subDatasetSizes[iSubdataset];
787: // if (requiredSlice2DIndex >= subDatasetSize)
788: // requiredSlice2DIndex -= subDatasetSize;
789: // else
790: // break;
791: // }
792: //
793: // // Getting the SubDatasetInfo related to the specified subDataset.
794: // final SubDatasetInfo sdInfo = sourceStructure
795: // .getSubDatasetInfo(iSubdataset);
796: // final int rank = sdInfo.getRank();
797: //
798: // // index initialization
799: // final int[] slice2DIndexCoordinates = new int[rank - 1];//
800: // subDatasetIndex+(rank-2)
801: // for (int i = 0; i < rank - 1; i++)
802: // slice2DIndexCoordinates[i] = 0;
803: // slice2DIndexCoordinates[0] = iSubdataset;
804: //
805: // if (rank > 2) {
806: // final long[] subDatasetDims = sdInfo.getDims();
807: // if (rank > 3) {
808: // final long[] multipliers = new long[rank - 3];
809: // for (int i = 0; i < rank - 3; i++)
810: // multipliers[i] = subDatasetDims[i + 2];
811: //
812: // for (int i = 0; i < rank - 3; i++) {
813: // int factor = 1;
814: // for (int j = 0; j < rank - 3 - i; j++)
815: // factor *= multipliers[j];
816: // while (requiredSlice2DIndex >= factor) {
817: // requiredSlice2DIndex -= factor;
818: // slice2DIndexCoordinates[i + 1]++;
819: // }
820: // }
821: // }
822: // slice2DIndexCoordinates[rank - 2] = requiredSlice2DIndex;
823: // }
824: // return slice2DIndexCoordinates;
825: // }
826:
827: /**
828: * Given the index of a 2D image, retrieve the index of the subDataset
829: * containing that image.
830: *
831: * @param imageIndex
832: * the index of a 2D image
833: * @return the index of the subDataset containing that image.
834: */
835: protected int retrieveSubDatasetIndex(int imageIndex) {
836: checkImageIndex(imageIndex);
837: final int nTotalDataset = sourceStructure.getNSubdatasets();
838: final long[] subDatasetSizes = sourceStructure
839: .getSubDatasetSizes();
840: int iSubdataset = 0;
841: for (; iSubdataset < nTotalDataset; iSubdataset++) {
842: int subDatasetSize = (int) subDatasetSizes[iSubdataset];
843: if (imageIndex >= subDatasetSize)
844: imageIndex -= subDatasetSize;
845: else
846: break;
847: }
848: return iSubdataset;
849: }
850: }
|