7#include "CubeIoHandler.h" 
   16#include <QListIterator> 
   17#include <QMapIterator> 
   25#include "CubeCachingAlgorithm.h" 
   26#include "Displacement.h" 
   29#include "EndianSwapper.h" 
   30#include "IException.h" 
   33#include "Preference.h" 
   37#include "RawCubeChunk.h" 
   38#include "RegionalCachingAlgorithm.h" 
   39#include "SpecialPixel.h" 
   40#include "Statistics.h" 
   62      const QList<int> *virtualBandList, 
const Pvl &label, 
bool alreadyOnDisk) {
 
   76        IString msg = 
"Cannot create a CubeIoHandler with a NULL data file";
 
   83          Preference::Preferences().findGroup(
"Performance");
 
   84      IString cubeWritePerfOpt = performancePrefs[
"CubeWriteThread"][0];
 
   87           cubeWritePerfOpt.DownCase() == 
"always") {
 
   94      m_rawData = 
new QMap<int, RawCubeChunk *>;
 
  106      const PvlGroup &pixelGroup = core.findGroup(
"Pixels");
 
  108      QString byteOrderStr = pixelGroup.
findKeyword(
"ByteOrder")[0];
 
  110          byteOrderStr.toUpper());
 
  111      m_base = pixelGroup.findKeyword(
"Base");
 
  123      const PvlGroup &dimensions = core.findGroup(
"Dimensions");
 
  128      m_startByte = (int)core.findKeyword(
"StartByte") - 1;
 
  141      IString msg = 
"Constructing CubeIoHandler failed";
 
  145      IString msg = 
"Constructing CubeIoHandler failed";
 
 
  168      while (it.hasNext()) {
 
  176      QMapIterator<int, RawCubeChunk *> it(*
m_rawData);
 
  177      while (it.hasNext()) {
 
 
  248    QList<RawCubeChunk *> cubeChunks;
 
  249    QList<int > chunkBands;
 
  251    int bufferSampleCount = bufferToFill.SampleDimension();
 
  252    int bufferLineCount = bufferToFill.LineDimension();
 
  253    int bufferBandCount = bufferToFill.BandDimension();
 
  259      int bufferStartSample = bufferToFill.Sample();
 
  260      int bufferStartLine = bufferToFill.Line();
 
  261      int bufferStartBand = bufferToFill.Band();
 
  263      int bufferEndSample = bufferStartSample + bufferSampleCount - 1;
 
  264      int bufferEndLine = bufferStartLine + bufferLineCount - 1;
 
  265      int bufferEndBand = bufferStartBand + bufferBandCount - 1;
 
  268      int startBand = bufferStartBand - 1;
 
  272      int expectedChunkIndex =
 
  280      int chunkStartSample, chunkStartLine, chunkStartBand,
 
  281          chunkEndSample, chunkEndLine, chunkEndBand;
 
  284          chunkStartSample, chunkStartLine, chunkStartBand,
 
  285          chunkEndSample, chunkEndLine, chunkEndBand);
 
  287      if (chunkStartSample == bufferStartSample &&
 
  288          chunkStartLine == bufferStartLine &&
 
  289          chunkStartBand == bufferStartBand &&
 
  290          chunkEndSample == bufferEndSample &&
 
  291          chunkEndLine == bufferEndLine &&
 
  292          chunkEndBand == bufferEndBand) {
 
  293        cubeChunks.append(
getChunk(expectedChunkIndex, 
true));
 
  294      chunkBands.append(cubeChunks.last()->getStartBand());
 
  298    if (cubeChunks.empty()) {
 
  301      for(
int i = 0; i < bufferToFill.size(); i++) {
 
  302        bufferToFill[i] = 
Null;
 
  305    QPair< QList<RawCubeChunk *>, QList<int> > chunkInfo;
 
  307          bufferToFill.Sample(), bufferToFill.SampleDimension(),
 
  308          bufferToFill.Line(), bufferToFill.LineDimension(),
 
  309          bufferToFill.Band(), bufferToFill.BandDimension());
 
  310      cubeChunks = chunkInfo.first;
 
  311      chunkBands = chunkInfo.second;
 
  314    for (
int i = 0; i < cubeChunks.size(); i++) {
 
  319    if (lastChunkCount != 
m_rawData->size()) {
 
 
  380    if (blockForWriteCache) {
 
  394      QMapIterator<int, RawCubeChunk *> it(*
m_rawData);
 
  395      while (it.hasNext()) {
 
  399          if(it.value()->isDirty()) {
 
 
  444    if(virtualBandList && !virtualBandList->empty())
 
 
  537    return indexOffsetToBand + indexInBand;
 
 
  615      int numSamples, 
int numLines, 
int numBands) {
 
  616    bool success = 
false;
 
  620      IString msg = 
"You cannot change the chunk sizes once set";
 
  622    else if(numSamples < 1) {
 
  623      msg = 
"Negative and zero chunk sizes are not supported, samples per chunk" 
  624          " cannot be [" + 
IString(numSamples) + 
"]";
 
  626    else if(numLines < 1) {
 
  627      msg = 
"Negative and zero chunk sizes are not supported, lines per chunk " 
  628            "cannot be [" + 
IString(numLines) + 
"]";
 
  630    else if(numBands < 1) {
 
  631      msg = 
"Negative and zero chunk sizes are not supported, lines per chunk " 
  632            "cannot be [" + 
IString(numBands) + 
"]";
 
  649            " bytes] not big enough to hold data [" +
 
 
  682    bool lessThan = 
false;
 
  701    if (!lhsArea.intersect(rhsArea).isValid()) {
 
  702      if (lhs->Band() != rhs->Band()) {
 
  703        lessThan = lhs->Band() < rhs->Band();
 
  705      else if (lhs->Line() != rhs->Line()) {
 
  706        lessThan = lhs->Line() < rhs->Line();
 
  708      else if (lhs->Sample() != rhs->Sample()) {
 
  709        lessThan = lhs->Sample() < rhs->Sample();
 
 
  731      int numSamples, 
int startLine, 
int numLines, 
int startBand,
 
  732      int numBands)
 const {
 
  733    QList<RawCubeChunk *> results;
 
  734    QList<int> resultBands;
 
  736    int lastBand = startBand + numBands - 1;
 
  742        QPoint(max(startSample, 1),
 
  744        QPoint(min(startSample + numSamples - 1,
 
  746                min(startLine + numLines - 1,
 
  752    for(
int band = startBand; band <= lastBand; band ++) {
 
  754      QRect areaLeftInBand(areaInBand);
 
  756      int actualBand = band;
 
  766      while(!areaLeftInBand.isEmpty()) {
 
  814        int areaStartLine = areaLeftInBand.top();
 
  815        int areaStartSample = areaLeftInBand.left();
 
  830        while(chunkRect.intersects(areaLeftInBand) &&
 
  831              (initialChunkBand >= 1 && initialChunkBand <= 
bandCount())) {
 
  834          int chunkZPos = initialChunkZPos;
 
  837          int chunkIndex = chunkXPos +
 
  844          results.append(newChunk);
 
  845          resultBands.append(band);
 
  847          chunkRect.moveLeft(chunkRect.right() + 1);
 
  850        areaLeftInBand.setTop(chunkRect.bottom() + 1);
 
  854    return QPair< QList<RawCubeChunk *>, QList<int> >(results, resultBands);
 
 
  877      int &startX, 
int &startY, 
int &startZ,
 
  878      int &endX, 
int &endY, 
int &endZ)
 const {
 
  885    int startVBand = cube2.Band();
 
  886    int endVBand = startVBand + cube2.BandDimension() - 1;
 
  888    int startPhysicalBand = 0;
 
  889    int endPhysicalBand = 0;
 
  891    bool startVBandFound = 
false;
 
  892    for(
int virtualBand = startVBand; virtualBand <= endVBand; virtualBand ++) {
 
  893      int physicalBand = virtualBand;
 
  895      bool bandExists = 
true;
 
  905        if(!startVBandFound) {
 
  906          startPhysicalBand = physicalBand;
 
  907          endPhysicalBand = physicalBand;
 
  908          startVBandFound = 
true;
 
  911          if(physicalBand < startPhysicalBand)
 
  912            startPhysicalBand = physicalBand;
 
  914          if(physicalBand > endPhysicalBand)
 
  915            endPhysicalBand = physicalBand;
 
  920    startX = max(cube1.getStartSample(), cube2.Sample());
 
  921    startY = max(cube1.getStartLine(), cube2.Line());
 
  922    startZ = max(cube1.getStartBand(), startPhysicalBand);
 
  923    endX = min(cube1.getStartSample() + cube1.sampleCount() - 1,
 
  924               cube2.Sample() + cube2.SampleDimension() - 1);
 
  925    endY = min(cube1.getStartLine() + cube1.lineCount() - 1,
 
  926               cube2.Line() + cube2.LineDimension() - 1);
 
  927    endZ = min(cube1.getStartBand() + cube1.bandCount() - 1,
 
 
  944      bool cacheOverflowing =
 
  946      bool shouldAndCanFlush = 
false;
 
  947      bool forceStart = force;
 
  951        if (shouldAndCanFlush) {
 
  956      if (cacheOverflowing && !shouldAndCanFlush) {
 
  967          shouldAndCanFlush = 
true;
 
  970      else if (!cacheOverflowing && shouldAndCanFlush) {
 
  987          delete bufferToWrite;
 
 
 1023      if(chunkToFree->isDirty())
 
 1024        (
const_cast<CubeIoHandler *
>(
this))->writeRaw(*chunkToFree);
 
 
 1046                                        bool allocateIfNecessary)
 const {
 
 1053    if(allocateIfNecessary && !chunk) {
 
 1056        (*m_dataIsOnDiskMap)[chunkIndex] = 
true;
 
 1066                          endSample, endLine, endBand);
 
 1067        chunk = 
new RawCubeChunk(startSample, startLine, startBand,
 
 1068                                    endSample, endLine, endBand,
 
 1072        chunk->setDirty(
false);
 
 1075      (*m_rawData)[chunkIndex] = chunk;
 
 
 1105      int &startSample, 
int &startLine, 
int &startBand,
 
 1106      int &endSample, 
int &endLine, 
int &endBand)
 const {
 
 1115    int chunkBandIndex = chunkIndex;
 
 
 1139    int startSample = 0;
 
 1148                      endSample, endLine, endBand);
 
 1163      for(
int i = 0; i < nullBuffer.size(); i++) {
 
 1164        nullBuffer[i] = 
Null;
 
 
 1189                                    const Buffer &justRequested)
 const {
 
 1194      bool algorithmAccepted = 
false;
 
 1196      int algorithmIndex = 0;
 
 1197      while(!algorithmAccepted &&
 
 1198            algorithmIndex < m_cachingAlgorithms->size()) {
 
 1207        if(algorithmAccepted) {
 
 1211          foreach(chunkToFree, chunksToFree) {
 
 1220      if(!algorithmAccepted && 
m_rawData->size() > 100) {
 
 
 1238    QList<RawCubeChunk *> cubeChunks;
 
 1239    QList<int> cubeChunkBands;
 
 1241    int bufferSampleCount = bufferToWrite.SampleDimension();
 
 1242    int bufferLineCount = bufferToWrite.LineDimension();
 
 1243    int bufferBandCount = bufferToWrite.BandDimension();
 
 1249      if(bufferToWrite.Sample() == 1 &&
 
 1251         bufferLineCount == 1 &&
 
 1252         bufferBandCount == 1) {
 
 1255        int bufferLine = bufferToWrite.Line();
 
 1256        int chunkStartLine =
 
 1257            (*m_lastProcessByLineChunks)[0]->getStartLine();
 
 1259            (*m_lastProcessByLineChunks)[0]->lineCount();
 
 1260        int bufferBand = bufferToWrite.Band();
 
 1261        int chunkStartBand =
 
 1262            (*m_lastProcessByLineChunks)[0]->getStartBand();
 
 1264            (*m_lastProcessByLineChunks)[0]->bandCount();
 
 1266        if(bufferLine >= chunkStartLine &&
 
 1267           bufferLine <= chunkStartLine + chunkLines - 1 &&
 
 1268           bufferBand >= chunkStartBand &&
 
 1269           bufferBand <= chunkStartBand + chunkBands - 1) {
 
 1271          for (
int i = 0; i < cubeChunks.size(); i++) {
 
 1272            cubeChunkBands.append( cubeChunks[i]->getStartBand() );
 
 1281      int bufferStartSample = bufferToWrite.Sample();
 
 1282      int bufferStartLine = bufferToWrite.Line();
 
 1283      int bufferStartBand = bufferToWrite.Band();
 
 1285      int bufferEndSample = bufferStartSample + bufferSampleCount - 1;
 
 1286      int bufferEndLine = bufferStartLine + bufferLineCount - 1;
 
 1287      int bufferEndBand = bufferStartBand + bufferBandCount - 1;
 
 1289      int expectedChunkIndex =
 
 1297      int chunkStartSample, chunkStartLine, chunkStartBand,
 
 1298          chunkEndSample, chunkEndLine, chunkEndBand;
 
 1301          chunkStartSample, chunkStartLine, chunkStartBand,
 
 1302          chunkEndSample, chunkEndLine, chunkEndBand);
 
 1304      if (chunkStartSample == bufferStartSample &&
 
 1305          chunkStartLine == bufferStartLine &&
 
 1306          chunkStartBand == bufferStartBand &&
 
 1307          chunkEndSample == bufferEndSample &&
 
 1308          chunkEndLine == bufferEndLine &&
 
 1309          chunkEndBand == bufferEndBand) {
 
 1310        cubeChunks.append(
getChunk(expectedChunkIndex, 
true));
 
 1311        cubeChunkBands.append(cubeChunks.last()->getStartBand());
 
 1315    QPair< QList<RawCubeChunk *>, QList<int> > chunkInfo;
 
 1316    if(cubeChunks.empty()) {
 
 1318         bufferToWrite.Sample(), bufferSampleCount,
 
 1319         bufferToWrite.Line(), bufferLineCount,
 
 1320         bufferToWrite.Band(), bufferBandCount);
 
 1321      cubeChunks = chunkInfo.first;
 
 1322      cubeChunkBands = chunkInfo.second;
 
 1326    if(bufferToWrite.Sample() == 1 &&
 
 1328        bufferLineCount == 1 &&
 
 1329        bufferBandCount == 1) {
 
 1332            new QList<RawCubeChunk *>(cubeChunks);
 
 1337    for(
int i = 0; i < cubeChunks.size(); i++) {
 
 1338      writeIntoRaw(bufferToWrite, *cubeChunks[i], cubeChunkBands[i]);
 
 
 1353                                      Buffer &output, 
int index)
 const {
 
 1370    int bufferBand = output.Band();
 
 1371    int bufferBands = output.BandDimension();
 
 1372    int chunkStartSample = chunk.getStartSample();
 
 1373    int chunkStartLine = chunk.getStartLine();
 
 1374    int chunkStartBand = chunk.getStartBand();
 
 1375    int chunkLineSize = chunk.sampleCount();
 
 1376    int chunkBandSize = chunkLineSize * chunk.lineCount();
 
 1378    double *buffersDoubleBuf = output.DoubleBuffer();
 
 1379    const char *chunkBuf = chunk.getRawData().data();
 
 1380    char *buffersRawBuf = (
char *)output.RawBuffer();
 
 1382    for(
int z = startZ; z <= endZ; z++) {
 
 1383      const int &bandIntoChunk = z - chunkStartBand;
 
 1384      int virtualBand = z;
 
 1386      virtualBand = index;
 
 1388      if(virtualBand != 0 && virtualBand >= bufferBand &&
 
 1389         virtualBand <= bufferBand + bufferBands - 1) {
 
 1391        for(
int y = startY; y <= endY; y++) {
 
 1392          const int &lineIntoChunk = y - chunkStartLine;
 
 1393          int bufferIndex = output.Index(startX, y, virtualBand);
 
 1395          for(
int x = startX; x <= endX; x++) {
 
 1396            const int &sampleIntoChunk = x - chunkStartSample;
 
 1398            const int &chunkIndex = sampleIntoChunk +
 
 1399                (chunkLineSize * lineIntoChunk) +
 
 1400                (chunkBandSize * bandIntoChunk);
 
 1402            double &bufferVal = buffersDoubleBuf[bufferIndex];
 
 1405              float raw = ((
float *)chunkBuf)[chunkIndex];
 
 1409              if(raw >= VALID_MIN4) {
 
 1410                bufferVal = (double) raw;
 
 1415                else if(raw == LOW_INSTR_SAT4)
 
 1416                  bufferVal = LOW_INSTR_SAT8;
 
 1417                else if(raw == LOW_REPR_SAT4)
 
 1418                  bufferVal = LOW_REPR_SAT8;
 
 1419                else if(raw == HIGH_INSTR_SAT4)
 
 1420                  bufferVal = HIGH_INSTR_SAT8;
 
 1421                else if(raw == HIGH_REPR_SAT4)
 
 1422                  bufferVal = HIGH_REPR_SAT8;
 
 1424                  bufferVal = LOW_REPR_SAT8;
 
 1427              ((
float *)buffersRawBuf)[bufferIndex] = raw;
 
 1431              short raw = ((
short *)chunkBuf)[chunkIndex];
 
 1435              if(raw >= VALID_MIN2) {
 
 1441                else if(raw == LOW_INSTR_SAT2)
 
 1442                  bufferVal = LOW_INSTR_SAT8;
 
 1443                else if(raw == LOW_REPR_SAT2)
 
 1444                  bufferVal = LOW_REPR_SAT8;
 
 1445                else if(raw == HIGH_INSTR_SAT2)
 
 1446                  bufferVal = HIGH_INSTR_SAT8;
 
 1447                else if(raw == HIGH_REPR_SAT2)
 
 1448                  bufferVal = HIGH_REPR_SAT8;
 
 1450                  bufferVal = LOW_REPR_SAT8;
 
 1453              ((
short *)buffersRawBuf)[bufferIndex] = raw;
 
 1458              unsigned short raw = ((
unsigned short *)chunkBuf)[chunkIndex];
 
 1462              if(raw >= VALID_MINU2) {
 
 1465              else if (raw > VALID_MAXU2) {
 
 1466                if(raw == HIGH_INSTR_SATU2)
 
 1467                  bufferVal = HIGH_INSTR_SAT8;
 
 1468                else if(raw == HIGH_REPR_SATU2)
 
 1469                  bufferVal = HIGH_REPR_SAT8;
 
 1471                  bufferVal = LOW_REPR_SAT8;
 
 1476                else if(raw == LOW_INSTR_SATU2)
 
 1477                  bufferVal = LOW_INSTR_SAT8;
 
 1478                else if(raw == LOW_REPR_SATU2)
 
 1479                  bufferVal = LOW_REPR_SAT8;
 
 1481                  bufferVal = LOW_REPR_SAT8;
 
 1484              ((
unsigned short *)buffersRawBuf)[bufferIndex] = raw;
 
 1489              unsigned int raw = ((
unsigned int *)chunkBuf)[chunkIndex];
 
 1493              if(raw >= VALID_MINUI4) {
 
 1496              else if (raw > VALID_MAXUI4) {
 
 1497                if(raw == HIGH_INSTR_SATUI4)
 
 1498                  bufferVal = HIGH_INSTR_SAT8;
 
 1499                else if(raw == HIGH_REPR_SATUI4)
 
 1500                  bufferVal = HIGH_REPR_SAT8;
 
 1502                  bufferVal = LOW_REPR_SAT8;
 
 1507                else if(raw == LOW_INSTR_SATUI4)
 
 1508                  bufferVal = LOW_INSTR_SAT8;
 
 1509                else if(raw == LOW_REPR_SATUI4)
 
 1510                  bufferVal = LOW_REPR_SAT8;
 
 1512                  bufferVal = LOW_REPR_SAT8;
 
 1515              ((
unsigned int *)buffersRawBuf)[bufferIndex] = raw;
 
 1522              unsigned char raw = ((
unsigned char *)chunkBuf)[chunkIndex];
 
 1527              else if(raw == HIGH_REPR_SAT1) {
 
 1528                bufferVal = HIGH_REPR_SAT8;
 
 1534              ((
unsigned char *)buffersRawBuf)[bufferIndex] = raw;
 
 
 1568    output.setDirty(
true);
 
 1569    findIntersection(output, buffer, startX, startY, startZ, endX, endY, endZ);
 
 1571    int bufferBand = buffer.
Band();
 
 1573    int outputStartSample = output.getStartSample();
 
 1574    int outputStartLine = output.getStartLine();
 
 1575    int outputStartBand = output.getStartBand();
 
 1576    int lineSize = output.sampleCount();
 
 1577    int bandSize = lineSize * output.lineCount();
 
 1579    char *chunkBuf = output.getRawData().data();
 
 1581    for(
int z = startZ; z <= endZ; z++) {
 
 1582      const int &bandIntoChunk = z - outputStartBand;
 
 1583      int virtualBand = index;
 
 1590      if(virtualBand != 0 && virtualBand >= bufferBand &&
 
 1591         virtualBand <= bufferBand + bufferBands - 1) {
 
 1593        for(
int y = startY; y <= endY; y++) {
 
 1594          const int &lineIntoChunk = y - outputStartLine;
 
 1595          int bufferIndex = buffer.
Index(startX, y, virtualBand);
 
 1597          for(
int x = startX; x <= endX; x++) {
 
 1598            const int &sampleIntoChunk = x - outputStartSample;
 
 1600            const int &chunkIndex = sampleIntoChunk +
 
 1601                (lineSize * lineIntoChunk) + (bandSize * bandIntoChunk);
 
 1603            double bufferVal = buffersDoubleBuf[bufferIndex];
 
 1608              if(bufferVal >= VALID_MIN8) {
 
 1609                double filePixelValueDbl = (bufferVal - 
m_base) /
 
 1612                if(filePixelValueDbl < (
double) VALID_MIN4) {
 
 1613                  raw = LOW_REPR_SAT4;
 
 1615                else if(filePixelValueDbl > (
double) VALID_MAX4) {
 
 1616                  raw = HIGH_REPR_SAT4;
 
 1619                  raw = (float) filePixelValueDbl;
 
 1623                if(bufferVal == NULL8)
 
 1625                else if(bufferVal == LOW_INSTR_SAT8)
 
 1626                  raw = LOW_INSTR_SAT4;
 
 1627                else if(bufferVal == LOW_REPR_SAT8)
 
 1628                  raw = LOW_REPR_SAT4;
 
 1629                else if(bufferVal == HIGH_INSTR_SAT8)
 
 1630                  raw = HIGH_INSTR_SAT4;
 
 1631                else if(bufferVal == HIGH_REPR_SAT8)
 
 1632                  raw = HIGH_REPR_SAT4;
 
 1634                  raw = LOW_REPR_SAT4;
 
 1636              ((
float *)chunkBuf)[chunkIndex] =
 
 1643              if(bufferVal >= VALID_MIN8) {
 
 1644                double filePixelValueDbl = (bufferVal - 
m_base) /
 
 1646                if(filePixelValueDbl < VALID_MIN2 - 0.5) {
 
 1647                  raw = LOW_REPR_SAT2;
 
 1649                if(filePixelValueDbl > VALID_MAX2 + 0.5) {
 
 1650                  raw = HIGH_REPR_SAT2;
 
 1653                  int filePixelValue = (int)round(filePixelValueDbl);
 
 1655                  if(filePixelValue < VALID_MIN2) {
 
 1656                    raw = LOW_REPR_SAT2;
 
 1658                  else if(filePixelValue > VALID_MAX2) {
 
 1659                    raw = HIGH_REPR_SAT2;
 
 1662                    raw = filePixelValue;
 
 1667                if(bufferVal == NULL8)
 
 1669                else if(bufferVal == LOW_INSTR_SAT8)
 
 1670                  raw = LOW_INSTR_SAT2;
 
 1671                else if(bufferVal == LOW_REPR_SAT8)
 
 1672                  raw = LOW_REPR_SAT2;
 
 1673                else if(bufferVal == HIGH_INSTR_SAT8)
 
 1674                  raw = HIGH_INSTR_SAT2;
 
 1675                else if(bufferVal == HIGH_REPR_SAT8)
 
 1676                  raw = HIGH_REPR_SAT2;
 
 1678                  raw = LOW_REPR_SAT2;
 
 1681              ((
short *)chunkBuf)[chunkIndex] =
 
 1689              if(bufferVal >= VALID_MINUI4) {
 
 1690                double filePixelValueDbl = (bufferVal - 
m_base) /
 
 1692                if(filePixelValueDbl < VALID_MINUI4 - 0.5) {
 
 1693                  raw = LOW_REPR_SATUI4;
 
 1695                if(filePixelValueDbl > VALID_MAXUI4) {
 
 1696                  raw = HIGH_REPR_SATUI4;
 
 1699                  unsigned int filePixelValue = (
unsigned int)round(filePixelValueDbl);
 
 1701                  if(filePixelValue < VALID_MINUI4) {
 
 1702                    raw = LOW_REPR_SATUI4;
 
 1704                  else if(filePixelValue > VALID_MAXUI4) {
 
 1705                    raw = HIGH_REPR_SATUI4;
 
 1708                    raw = filePixelValue;
 
 1713                if(bufferVal == NULL8)
 
 1715                else if(bufferVal == LOW_INSTR_SAT8)
 
 1716                  raw = LOW_INSTR_SATUI4;
 
 1717                else if(bufferVal == LOW_REPR_SAT8)
 
 1718                  raw = LOW_REPR_SATUI4;
 
 1719                else if(bufferVal == HIGH_INSTR_SAT8)
 
 1720                  raw = HIGH_INSTR_SATUI4;
 
 1721                else if(bufferVal == HIGH_REPR_SAT8)
 
 1722                  raw = HIGH_REPR_SATUI4;
 
 1724                  raw = LOW_REPR_SATUI4;
 
 1727              ((
unsigned int *)chunkBuf)[chunkIndex] =
 
 1736              if(bufferVal >= VALID_MIN8) {
 
 1737                double filePixelValueDbl = (bufferVal - 
m_base) /
 
 1739                if(filePixelValueDbl < VALID_MINU2 - 0.5) {
 
 1740                  raw = LOW_REPR_SATU2;
 
 1742                if(filePixelValueDbl > VALID_MAXU2 + 0.5) {
 
 1743                  raw = HIGH_REPR_SATU2;
 
 1746                  int filePixelValue = (int)round(filePixelValueDbl);
 
 1748                  if(filePixelValue < VALID_MINU2) {
 
 1749                    raw = LOW_REPR_SATU2;
 
 1751                  else if(filePixelValue > VALID_MAXU2) {
 
 1752                    raw = HIGH_REPR_SATU2;
 
 1755                    raw = filePixelValue;
 
 1760                if(bufferVal == NULL8)
 
 1762                else if(bufferVal == LOW_INSTR_SAT8)
 
 1763                  raw = LOW_INSTR_SATU2;
 
 1764                else if(bufferVal == LOW_REPR_SAT8)
 
 1765                  raw = LOW_REPR_SATU2;
 
 1766                else if(bufferVal == HIGH_INSTR_SAT8)
 
 1767                  raw = HIGH_INSTR_SATU2;
 
 1768                else if(bufferVal == HIGH_REPR_SAT8)
 
 1769                  raw = HIGH_REPR_SATU2;
 
 1771                  raw = LOW_REPR_SATU2;
 
 1774              ((
unsigned short *)chunkBuf)[chunkIndex] =
 
 1780              if(bufferVal >= VALID_MIN8) {
 
 1781                double filePixelValueDbl = (bufferVal - 
m_base) /
 
 1783                if(filePixelValueDbl < VALID_MIN1 - 0.5) {
 
 1784                  raw = LOW_REPR_SAT1;
 
 1786                else if(filePixelValueDbl > VALID_MAX1 + 0.5) {
 
 1787                  raw = HIGH_REPR_SAT1;
 
 1790                  int filePixelValue = (int)(filePixelValueDbl + 0.5);
 
 1791                  if(filePixelValue < VALID_MIN1) {
 
 1792                    raw = LOW_REPR_SAT1;
 
 1794                  else if(filePixelValue > VALID_MAX1) {
 
 1795                    raw = HIGH_REPR_SAT1;
 
 1798                    raw = (
unsigned char)(filePixelValue);
 
 1803                if(bufferVal == NULL8)
 
 1805                else if(bufferVal == LOW_INSTR_SAT8)
 
 1806                  raw = LOW_INSTR_SAT1;
 
 1807                else if(bufferVal == LOW_REPR_SAT8)
 
 1808                  raw = LOW_REPR_SAT1;
 
 1809                else if(bufferVal == HIGH_INSTR_SAT8)
 
 1810                  raw = HIGH_INSTR_SAT1;
 
 1811                else if(bufferVal == HIGH_REPR_SAT8)
 
 1812                  raw = HIGH_REPR_SAT1;
 
 1814                  raw = LOW_REPR_SAT1;
 
 1817              ((
unsigned char *)chunkBuf)[chunkIndex] = raw;
 
 
 1833      IString msg = 
"Cannot call CubeIoHandler::writeNullDataToDisk unless " 
 1834          "data is not already on disk (Cube::Create was called)";
 
 1839    for(
int i = 0; i < numChunks; i++) {
 
 1843        (*m_dataIsOnDiskMap)[i] = 
true;
 
 
 1866      CubeIoHandler * ioHandler, QList<Buffer *> buffersToWrite) {
 
 
 1887    int elapsedMs = m_timer->elapsed();
 
 1888    int idealFlushElapsedTime = 100; 
 
 1894    int msOffIdeal = elapsedMs - idealFlushElapsedTime;
 
 1895    double percentOffIdeal = msOffIdeal / (double)idealFlushElapsedTime;
 
 1898    int currentCacheSize = m_ioHandler->m_idealFlushSize;
 
 1899    int desiredAdjustment = -1 * currentCacheSize * percentOffIdeal;
 
 1900    int desiredCacheSize = (int)(currentCacheSize + desiredAdjustment);
 
 1901    m_ioHandler->m_idealFlushSize = (int)(qMin(5000,
 
 1902                                               qMax(32, desiredCacheSize)));
 
 1907    m_ioHandler->m_writeThreadMutex->unlock();
 
 1910    delete m_buffersToWrite;
 
 1911    m_buffersToWrite = NULL;
 
 
 1940    foreach (
Buffer * bufferToWrite, *m_buffersToWrite) {
 
 1941      m_ioHandler->synchronousWrite(*bufferToWrite);
 
 1942      delete bufferToWrite;
 
 1945    m_buffersToWrite->clear();
 
 1946    m_ioHandler->m_dataFile->flush();
 
 
Represents a 3D area (a 3D "cube")
 
Buffer for containing a three dimensional section of an image.
 
Buffer for reading and writing cube data.
 
double * DoubleBuffer() const
Returns the value of the shape buffer.
 
int Band(const int index=0) const
Returns the band position associated with a shape buffer index.
 
int BandDimension() const
Returns the number of bands in the shape buffer.
 
int Index(const int i_samp, const int i_line, const int i_band) const
Given a sample, line, and band position, this returns the appropriate index in the shape buffer.
 
This stores the results of the caching algorithm.
 
QList< RawCubeChunk * > getChunksToFree() const
 
bool algorithmUnderstoodData() const
If this is true, then the results (be them empty or not) should be considered valid.
 
This is the parent of the caching algorithms.
 
virtual CacheResult recommendChunksToFree(QList< RawCubeChunk * > allocated, QList< RawCubeChunk * > justUsed, const Buffer &justRequested)=0
Call this to determine which chunks should be freed from memory.
 
This class is designed to handle write() asynchronously.
 
QTime * m_timer
Used to calculate the lifetime of an instance of this class.
 
BufferToChunkWriter(CubeIoHandler *ioHandler, QList< Buffer * > buffersToWrite)
Create a BufferToChunkWriter which is designed to asynchronously move the given buffers into the cube...
 
~BufferToChunkWriter()
We're done writing our buffers into the cube, clean up.
 
QList< Buffer * > * m_buffersToWrite
The buffers that need pushed into the IO handler; we own these.
 
void run()
This is the asynchronous computation.
 
CubeIoHandler * m_ioHandler
The IO Handler instance to put the buffers into.
 
Handles converting buffers to and from disk.
 
bool m_useOptimizedCubeWrite
This is true if the Isis preference for the cube write thread is optimized.
 
QList< CubeCachingAlgorithm * > * m_cachingAlgorithms
The caching algorithms to use, in order of priority.
 
int m_consecutiveOverflowCount
How many times the write cache has overflown in a row.
 
int m_numBands
The number of physical bands in the cube.
 
int m_bandsInChunk
The number of physical bands in a cube chunk.
 
void clearCache(bool blockForWriteCache=true) const
Free all cube chunks (cached cube data) from memory and write them to disk.
 
int m_samplesInChunk
The number of samples in a cube chunk.
 
QMap< int, bool > * m_dataIsOnDiskMap
The map from chunk index to on-disk status, all true if not allocated.
 
void freeChunk(RawCubeChunk *chunkToFree) const
If the chunk is dirty, then we write it to disk.
 
int m_linesInChunk
The number of lines in a cube chunk.
 
virtual ~CubeIoHandler()
Cleans up all allocated memory.
 
void addCachingAlgorithm(CubeCachingAlgorithm *algorithm)
This will add the given caching algorithm to the list of attempted caching algorithms.
 
int m_numSamples
The number of samples in the cube.
 
QMutex * dataFileMutex()
Get the mutex that this IO handler is using around I/Os on the given data file.
 
void blockUntilThreadPoolEmpty() const
This blocks (doesn't return) until the number of active runnables in the thread pool goes to 0.
 
QPair< QList< RawCubeChunk * >, QList< int > > findCubeChunks(int startSample, int numSamples, int startLine, int numLines, int startBand, int numBands) const
Get the cube chunks that correspond to the given cube area.
 
PixelType pixelType() const
 
void writeNullDataToDisk() const
Write all NULL cube chunks that have not yet been accessed to disk.
 
QMutex * m_writeThreadMutex
This enables us to block while the write thread is working.
 
QList< int > * m_virtualBands
Converts from virtual band to physical band.
 
volatile int m_idealFlushSize
Ideal write cache flush size.
 
int getChunkCountInLineDimension() const
 
QList< RawCubeChunk * > * m_lastProcessByLineChunks
This is an optimization for process by line.
 
bool m_lastOperationWasWrite
If the last operation was a write then we need to flush the cache when reading.
 
void setChunkSizes(int numSamples, int numLines, int numBands)
This should be called once from the child constructor.
 
PixelType m_pixelType
The format of each DN in the cube.
 
QByteArray * m_nullChunkData
A raw cube chunk's data when it was all NULL's. Used for speed.
 
int getLineCountInChunk() const
 
int getChunkCount() const
 
double m_multiplier
The multiplicative factor of the data on disk.
 
int m_numLines
The number of lines in the cube.
 
int getChunkCountInSampleDimension() const
 
void minimizeCache(const QList< RawCubeChunk * > &justUsed, const Buffer &justRequested) const
Apply the caching algorithms and get rid of excess cube data in memory.
 
QFile * m_dataFile
The file containing cube data.
 
int getChunkCountInBandDimension() const
 
QPair< QMutex *, QList< Buffer * > > * m_writeCache
These are the buffers we need to write to raw cube chunks.
 
double m_base
The additive offset of the data on disk.
 
CubeIoHandler(QFile *dataFile, const QList< int > *virtualBandList, const Pvl &label, bool alreadyOnDisk)
Creates a new CubeIoHandler using a RegionalCachingAlgorithm.
 
BigInt getBytesPerChunk() const
 
QMap< int, RawCubeChunk * > * m_rawData
The map from chunk index to chunk for cached data.
 
QThreadPool * m_ioThreadPool
This contains threads for doing cube writes (and later maybe cube reads).
 
BigInt getDataStartByte() const
 
void findIntersection(const RawCubeChunk &cube1, const Buffer &cube2, int &startX, int &startY, int &startZ, int &endX, int &endY, int &endZ) const
Find the intersection between the buffer area and the cube chunk.
 
void flushWriteCache(bool force=false) const
This attempts to write the so-far-unwritten buffers from m_writeCache into the cube's RawCubeChunk ca...
 
void getChunkPlacement(int chunkIndex, int &startSample, int &startLine, int &startBand, int &endSample, int &endLine, int &endBand) const
Get the X/Y/Z (Sample,Line,Band) range of the chunk at the given index.
 
void read(Buffer &bufferToFill) const
Read cube data from disk into the buffer.
 
RawCubeChunk * getNullChunk(int chunkIndex) const
This creates a chunk filled with NULLs whose placement is at chunkIndex's position.
 
void write(const Buffer &bufferToWrite)
Write buffer data into the cube data on disk.
 
BigInt m_startByte
The start byte of the cube data.
 
void setVirtualBands(const QList< int > *virtualBandList)
This changes the virtual band list.
 
RawCubeChunk * getChunk(int chunkIndex, bool allocateIfNecessary) const
Retrieve the cached chunk at the given chunk index, if there is one.
 
static bool bufferLessThan(Buffer *const &lhs, Buffer *const &rhs)
This is used for sorting buffers into the most efficient write order.
 
int getSampleCountInChunk() const
 
BigInt getDataSize() const
 
int getBandCountInChunk() const
 
void writeIntoRaw(const Buffer &buffer, RawCubeChunk &output, int index) const
Write the intersecting area of the buffer into the chunk.
 
void synchronousWrite(const Buffer &bufferToWrite)
This method takes the given buffer and synchronously puts it into the Cube's cache.
 
EndianSwapper * m_byteSwapper
A helper that swaps byte order to and from file order.
 
void writeIntoDouble(const RawCubeChunk &chunk, Buffer &output, int startIndex) const
Write the intersecting area of the chunk into the buffer.
 
int getChunkIndex(const RawCubeChunk &) const
Given a chunk, what's its index in the file.
 
Displacement is a signed length, usually in meters.
 
@ Pixels
The distance is being specified in pixels.
 
Distance measurement, usually in meters.
 
@ Pixels
The distance is being specified in pixels.
 
float Float(void *buf)
Swaps a floating point value.
 
short int ShortInt(void *buf)
Swaps a short integer value.
 
uint32_t Uint32_t(void *buf)
Swaps a 32bit unsigned integer.
 
unsigned short int UnsignedShortInt(void *buf)
Swaps an unsigned short integer value.
 
@ Programmer
This error is for when a programmer made an API call that was illegal.
 
Adds specific functionality to C++ strings.
 
PvlKeyword & findKeyword(const QString &name)
Find a keyword with a specified name.
 
Contains multiple PvlContainers.
 
Container for cube-like labels.
 
Contains Pvl Groups and Pvl Objects.
 
PvlObjectIterator findObject(const QString &name, PvlObjectIterator beg, PvlObjectIterator end)
Find the index of object with a specified name, between two indexes.
 
A section of raw data on the disk.
 
QByteArray & getRawData() const
 
int getStartSample() const
 
void setDirty(bool dirty)
Sets the chunk's dirty flag, indicating whether or not the chunk's data matches the data that is on d...
 
void setRawData(QByteArray rawData)
Sets the chunk's raw data.
 
This algorithm recommends chunks to be freed that are not within the last IO.
 
This is free and unencumbered software released into the public domain.
 
int SizeOf(Isis::PixelType pixelType)
Returns the number of bytes of the specified PixelType.
 
Isis::PixelType PixelTypeEnumeration(const QString &type)
Returns PixelType enumeration given a string.
 
const double Null
Value for an Isis Null pixel.
 
long long int BigInt
Big int.
 
PixelType
Enumerations for Isis Pixel Types.
 
Namespace for the standard library.