24 #include "IsisDebug.h"
34 #include <QListIterator>
35 #include <QMapIterator>
79 CubeIoHandler::CubeIoHandler(QFile * dataFile,
80 const QList<int> *virtualBandList,
const Pvl &label,
bool alreadyOnDisk) {
82 m_cachingAlgorithms = NULL;
83 m_dataIsOnDiskMap = NULL;
85 m_virtualBands = NULL;
86 m_nullChunkData = NULL;
87 m_lastProcessByLineChunks = NULL;
89 m_ioThreadPool = NULL;
90 m_writeThreadMutex = NULL;
94 IString msg =
"Cannot create a CubeIoHandler with a NULL data file";
101 Preference::Preferences().findGroup(
"Performance");
102 IString cubeWritePerfOpt = performancePrefs[
"CubeWriteThread"][0];
103 m_useOptimizedCubeWrite = (cubeWritePerfOpt.
DownCase() ==
"optimized");
104 if ((m_useOptimizedCubeWrite && !alreadyOnDisk) ||
105 cubeWritePerfOpt.
DownCase() ==
"always") {
106 m_ioThreadPool =
new QThreadPool;
107 m_ioThreadPool->setMaxThreadCount(1);
110 m_consecutiveOverflowCount = 0;
111 m_lastOperationWasWrite =
false;
114 m_writeCache->first =
new QMutex;
115 m_writeThreadMutex =
new QMutex;
117 m_idealFlushSize = 32;
121 m_dataFile = dataFile;
126 QString byteOrderStr = pixelGroup.
findKeyword(
"ByteOrder")[0];
128 byteOrderStr.toUpper());
130 m_multiplier = pixelGroup.
findKeyword(
"Multiplier");
136 if(!m_byteSwapper->willSwap()) {
137 delete m_byteSwapper;
138 m_byteSwapper = NULL;
146 m_startByte = (int)core.
findKeyword(
"StartByte") - 1;
148 m_samplesInChunk = -1;
156 setVirtualBands(virtualBandList);
159 IString msg =
"Constructing CubeIoHandler failed";
163 IString msg =
"Constructing CubeIoHandler failed";
173 CubeIoHandler::~CubeIoHandler() {
174 ASSERT( m_rawData ? m_rawData->size() == 0 : 1 );
177 m_ioThreadPool->waitForDone();
179 delete m_ioThreadPool;
180 m_ioThreadPool = NULL;
182 delete m_dataIsOnDiskMap;
183 m_dataIsOnDiskMap = NULL;
185 if (m_cachingAlgorithms) {
186 QListIterator<CubeCachingAlgorithm *> it(*m_cachingAlgorithms);
187 while (it.hasNext()) {
190 delete m_cachingAlgorithms;
191 m_cachingAlgorithms = NULL;
195 QMapIterator<int, RawCubeChunk *> it(*m_rawData);
196 while (it.hasNext()) {
209 delete m_writeCache->first;
210 m_writeCache->first = NULL;
212 for (
int i = 0; i < m_writeCache->second.size(); i++) {
213 delete m_writeCache->second[i];
215 m_writeCache->second.clear();
221 delete m_byteSwapper;
222 m_byteSwapper = NULL;
224 delete m_virtualBands;
225 m_virtualBands = NULL;
227 delete m_nullChunkData;
228 m_nullChunkData = NULL;
230 delete m_lastProcessByLineChunks;
231 m_lastProcessByLineChunks = NULL;
233 delete m_writeThreadMutex;
234 m_writeThreadMutex = NULL;
246 void CubeIoHandler::read(
Buffer &bufferToFill)
const {
249 int lastChunkCount = m_rawData->size();
251 if (m_lastOperationWasWrite) {
253 flushWriteCache(
true);
255 m_lastOperationWasWrite =
false;
259 if (m_useOptimizedCubeWrite) {
260 delete m_ioThreadPool;
261 m_ioThreadPool = NULL;
265 QMutexLocker lock(m_writeThreadMutex);
276 if (bufferSampleCount == m_samplesInChunk &&
277 bufferLineCount == m_linesInChunk &&
278 bufferBandCount == m_bandsInChunk) {
279 int bufferStartSample = bufferToFill.
Sample();
280 int bufferStartLine = bufferToFill.
Line();
281 int bufferStartBand = bufferToFill.
Band();
283 int bufferEndSample = bufferStartSample + bufferSampleCount - 1;
284 int bufferEndLine = bufferStartLine + bufferLineCount - 1;
285 int bufferEndBand = bufferStartBand + bufferBandCount - 1;
288 int startBand = bufferStartBand - 1;
290 startBand = m_virtualBands->at(bufferStartBand - 1);
292 int expectedChunkIndex =
293 ((bufferStartSample - 1) / getSampleCountInChunk()) +
294 ((bufferStartLine - 1) / getLineCountInChunk()) *
295 getChunkCountInSampleDimension() +
296 ((startBand - 1) / getBandCountInChunk()) *
297 getChunkCountInSampleDimension() *
298 getChunkCountInLineDimension();
300 int chunkStartSample, chunkStartLine, chunkStartBand,
301 chunkEndSample, chunkEndLine, chunkEndBand;
303 getChunkPlacement(expectedChunkIndex,
304 chunkStartSample, chunkStartLine, chunkStartBand,
305 chunkEndSample, chunkEndLine, chunkEndBand);
307 if (chunkStartSample == bufferStartSample &&
308 chunkStartLine == bufferStartLine &&
309 chunkStartBand == bufferStartBand &&
310 chunkEndSample == bufferEndSample &&
311 chunkEndLine == bufferEndLine &&
312 chunkEndBand == bufferEndBand) {
313 cubeChunks.append(getChunk(expectedChunkIndex,
true));
314 chunkBands.append(cubeChunks.last()->getStartBand());
318 if (cubeChunks.empty()) {
321 for(
int i = 0; i < bufferToFill.
size(); i++) {
322 bufferToFill[i] =
Null;
326 chunkInfo = findCubeChunks(
330 cubeChunks = chunkInfo.first;
331 chunkBands = chunkInfo.second;
334 for (
int i = 0; i < cubeChunks.size(); i++) {
335 writeIntoDouble(*cubeChunks[i], bufferToFill, chunkBands[i]);
339 if (lastChunkCount != m_rawData->size()) {
340 minimizeCache(cubeChunks, bufferToFill);
354 void CubeIoHandler::write(
const Buffer &bufferToWrite) {
355 m_lastOperationWasWrite =
true;
357 if (m_ioThreadPool) {
361 QMutexLocker locker(m_writeCache->first);
362 m_writeCache->second.append(copy);
368 QMutexLocker lock(m_writeThreadMutex);
370 synchronousWrite(bufferToWrite);
385 m_cachingAlgorithms->prepend(algorithm);
399 void CubeIoHandler::clearCache(
bool blockForWriteCache)
const {
400 if (blockForWriteCache) {
402 flushWriteCache(
true);
407 if(m_dataIsOnDiskMap) {
408 writeNullDataToDisk();
414 QMapIterator<int, RawCubeChunk *> it(*m_rawData);
415 while (it.hasNext()) {
419 if(it.value()->isDirty()) {
430 if(m_lastProcessByLineChunks) {
431 delete m_lastProcessByLineChunks;
432 m_lastProcessByLineChunks = NULL;
441 BigInt CubeIoHandler::getDataSize()
const {
442 return (BigInt)getChunkCountInSampleDimension() *
443 (BigInt)getChunkCountInLineDimension() *
444 (BigInt)getChunkCountInBandDimension() *
445 (BigInt)getBytesPerChunk();
458 void CubeIoHandler::setVirtualBands(
const QList<int> *virtualBandList) {
460 delete m_virtualBands;
461 m_virtualBands = NULL;
464 if(virtualBandList && !virtualBandList->empty())
465 m_virtualBands =
new QList<int>(*virtualBandList);
475 QMutex *CubeIoHandler::dataFileMutex() {
476 return m_writeThreadMutex;
482 int CubeIoHandler::bandCount()
const {
490 int CubeIoHandler::getBandCountInChunk()
const {
491 return m_bandsInChunk;
502 BigInt CubeIoHandler::getBytesPerChunk()
const {
503 return m_samplesInChunk * m_linesInChunk * m_bandsInChunk *
512 int CubeIoHandler::getChunkCountInBandDimension()
const {
513 return (
int)ceil((
double)m_numBands / (
double)m_bandsInChunk);
521 int CubeIoHandler::getChunkCountInLineDimension()
const {
522 return (
int)ceil((
double)m_numLines / (
double)m_linesInChunk);
530 int CubeIoHandler::getChunkCountInSampleDimension()
const {
531 return (
int)ceil((
double)m_numSamples / (
double)m_samplesInChunk);
551 int sampleIndex = (chunk.
getStartSample() - 1) / getSampleCountInChunk();
552 int lineIndex = (chunk.
getStartLine() - 1) / getLineCountInChunk();
553 int bandIndex = (chunk.
getStartBand() - 1) / getBandCountInChunk();
556 sampleIndex + lineIndex * getChunkCountInSampleDimension();
557 int indexOffsetToBand = bandIndex * getChunkCountInSampleDimension() *
558 getChunkCountInLineDimension();
560 return indexOffsetToBand + indexInBand;
567 BigInt CubeIoHandler::getDataStartByte()
const {
578 QFile * CubeIoHandler::getDataFile() {
587 int CubeIoHandler::lineCount()
const {
595 int CubeIoHandler::getLineCountInChunk()
const {
596 return m_linesInChunk;
612 int CubeIoHandler::sampleCount()
const {
620 int CubeIoHandler::getSampleCountInChunk()
const {
621 return m_samplesInChunk;
637 void CubeIoHandler::setChunkSizes(
638 int numSamples,
int numLines,
int numBands) {
639 bool success =
false;
642 if(m_samplesInChunk != -1 || m_linesInChunk != -1 || m_bandsInChunk != -1) {
643 IString msg =
"You cannot change the chunk sizes once set";
645 else if(numSamples < 1) {
646 msg =
"Negative and zero chunk sizes are not supported, samples per chunk"
647 " cannot be [" +
IString(numSamples) +
"]";
649 else if(numLines < 1) {
650 msg =
"Negative and zero chunk sizes are not supported, lines per chunk "
651 "cannot be [" +
IString(numLines) +
"]";
653 else if(numBands < 1) {
654 msg =
"Negative and zero chunk sizes are not supported, lines per chunk "
655 "cannot be [" +
IString(numBands) +
"]";
662 m_samplesInChunk = numSamples;
663 m_linesInChunk = numLines;
664 m_bandsInChunk = numBands;
666 if(m_dataIsOnDiskMap) {
667 m_dataFile->resize(getDataStartByte() + getDataSize());
669 else if(m_dataFile->size() < getDataStartByte() + getDataSize()) {
671 msg =
"File size [" +
IString((BigInt)m_dataFile->size()) +
672 " bytes] not big enough to hold data [" +
673 IString(getDataStartByte() + getDataSize()) +
" bytes] where the "
674 "offset to the cube data is [" +
IString(getDataStartByte()) +
690 void CubeIoHandler::blockUntilThreadPoolEmpty()
const {
691 if (m_ioThreadPool) {
692 QMutexLocker lock(m_writeThreadMutex);
704 bool CubeIoHandler::bufferLessThan(
Buffer *
const &lhs,
Buffer *
const &rhs) {
705 bool lessThan =
false;
726 lessThan = lhs->
Band() < rhs->
Band();
728 else if (lhs->
Line() != rhs->
Line()) {
729 lessThan = lhs->
Line() < rhs->
Line();
754 int numSamples,
int startLine,
int numLines,
int startBand,
755 int numBands)
const {
759 int lastBand = startBand + numBands - 1;
765 QPoint(max(startSample, 1),
767 QPoint(min(startSample + numSamples - 1,
769 min(startLine + numLines - 1,
775 for(
int band = startBand; band <= lastBand; band ++) {
777 QRect areaLeftInBand(areaInBand);
779 int actualBand = band;
782 if (band < 1 || band > m_virtualBands->size())
785 actualBand = (m_virtualBands->at(band - 1) - 1) / m_bandsInChunk + 1;
789 while(!areaLeftInBand.isEmpty()) {
837 int areaStartLine = areaLeftInBand.top();
838 int areaStartSample = areaLeftInBand.left();
840 int initialChunkXPos = (areaStartSample - 1) / m_samplesInChunk;
841 int initialChunkYPos = (areaStartLine - 1) / m_linesInChunk;
842 int initialChunkZPos = (actualBand - 1) / m_bandsInChunk;
843 int initialChunkBand = initialChunkZPos * m_bandsInChunk + 1;
846 QRect chunkRect(initialChunkXPos * m_samplesInChunk + 1,
847 initialChunkYPos * m_linesInChunk + 1,
848 m_samplesInChunk, m_linesInChunk);
853 while(chunkRect.intersects(areaLeftInBand) &&
854 (initialChunkBand >= 1 && initialChunkBand <= bandCount())) {
855 int chunkXPos = (chunkRect.left() - 1) / m_samplesInChunk;
856 int chunkYPos = (chunkRect.top() - 1) / m_linesInChunk;
857 int chunkZPos = initialChunkZPos;
860 int chunkIndex = chunkXPos +
861 (chunkYPos * getChunkCountInSampleDimension()) +
862 (chunkZPos * getChunkCountInSampleDimension() *
863 getChunkCountInLineDimension());
867 results.append(newChunk);
868 resultBands.append(band);
870 chunkRect.moveLeft(chunkRect.right() + 1);
873 areaLeftInBand.setTop(chunkRect.bottom() + 1);
898 void CubeIoHandler::findIntersection(
900 int &startX,
int &startY,
int &startZ,
901 int &endX,
int &endY,
int &endZ)
const {
908 int startVBand = cube2.
Band();
911 int startPhysicalBand = 0;
912 int endPhysicalBand = 0;
914 bool startVBandFound =
false;
915 for(
int virtualBand = startVBand; virtualBand <= endVBand; virtualBand ++) {
916 int physicalBand = virtualBand;
918 bool bandExists =
true;
920 if (virtualBand < 1 || virtualBand > m_virtualBands->size())
923 physicalBand = m_virtualBands->at(virtualBand - 1);
928 if(!startVBandFound) {
929 startPhysicalBand = physicalBand;
930 endPhysicalBand = physicalBand;
931 startVBandFound =
true;
934 if(physicalBand < startPhysicalBand)
935 startPhysicalBand = physicalBand;
937 if(physicalBand > endPhysicalBand)
938 endPhysicalBand = physicalBand;
965 void CubeIoHandler::flushWriteCache(
bool force)
const {
966 if (m_ioThreadPool) {
967 bool shouldFlush = m_writeCache->second.size() >= m_idealFlushSize ||
969 bool cacheOverflowing =
970 (m_writeCache->second.size() > m_idealFlushSize * 10);
971 bool shouldAndCanFlush =
false;
972 bool forceStart = force;
975 shouldAndCanFlush = m_writeThreadMutex->tryLock();
976 if (shouldAndCanFlush) {
977 m_writeThreadMutex->unlock();
981 if (cacheOverflowing && !shouldAndCanFlush) {
983 m_consecutiveOverflowCount++;
987 blockUntilThreadPoolEmpty();
989 if (m_writeCache->second.size() != 0) {
990 m_idealFlushSize = m_writeCache->second.size();
992 shouldAndCanFlush =
true;
995 else if (!cacheOverflowing && shouldAndCanFlush) {
996 m_consecutiveOverflowCount = 0;
999 if (cacheOverflowing && m_useOptimizedCubeWrite) {
1000 blockUntilThreadPoolEmpty();
1004 if (m_consecutiveOverflowCount > 10) {
1005 delete m_ioThreadPool;
1006 m_ioThreadPool = NULL;
1010 foreach (
Buffer *bufferToWrite, m_writeCache->second) {
1011 const_cast<CubeIoHandler *
>(
this)->synchronousWrite(*bufferToWrite);
1012 delete bufferToWrite;
1015 m_writeCache->second.clear();
1018 if (shouldAndCanFlush && m_ioThreadPool) {
1019 QMutexLocker locker(m_writeCache->first);
1021 const_cast<CubeIoHandler *>(
this), m_writeCache->second);
1023 m_ioThreadPool->start(writer);
1025 m_writeCache->second.clear();
1026 m_lastOperationWasWrite =
true;
1030 blockUntilThreadPoolEmpty();
1043 if(chunkToFree && m_rawData) {
1044 int chunkIndex = getChunkIndex(*chunkToFree);
1046 m_rawData->erase(m_rawData->find(chunkIndex));
1049 (const_cast<CubeIoHandler *>(
this))->writeRaw(*chunkToFree);
1053 if(m_lastProcessByLineChunks) {
1054 delete m_lastProcessByLineChunks;
1055 m_lastProcessByLineChunks = NULL;
1071 bool allocateIfNecessary)
const {
1075 chunk = m_rawData->value(chunkIndex);
1078 if(allocateIfNecessary && !chunk) {
1079 if(m_dataIsOnDiskMap && !(*m_dataIsOnDiskMap)[chunkIndex]) {
1080 chunk = getNullChunk(chunkIndex);
1081 (*m_dataIsOnDiskMap)[chunkIndex] =
true;
1090 getChunkPlacement(chunkIndex, startSample, startLine, startBand,
1091 endSample, endLine, endBand);
1092 chunk =
new RawCubeChunk(startSample, startLine, startBand,
1093 endSample, endLine, endBand,
1094 getBytesPerChunk());
1100 (*m_rawData)[chunkIndex] = chunk;
1111 int CubeIoHandler::getChunkCount()
const {
1112 return getChunkCountInSampleDimension() *
1113 getChunkCountInLineDimension() *
1114 getChunkCountInBandDimension();
1129 void CubeIoHandler::getChunkPlacement(
int chunkIndex,
1130 int &startSample,
int &startLine,
int &startBand,
1131 int &endSample,
int &endLine,
int &endBand)
const {
1132 int chunkSampleIndex = chunkIndex % getChunkCountInSampleDimension();
1135 (chunkIndex - chunkSampleIndex) / getChunkCountInSampleDimension();
1137 int chunkLineIndex = chunkIndex % getChunkCountInLineDimension();
1138 chunkIndex = (chunkIndex - chunkLineIndex) / getChunkCountInLineDimension();
1140 int chunkBandIndex = chunkIndex;
1142 startSample = chunkSampleIndex * getSampleCountInChunk() + 1;
1143 endSample = startSample + getSampleCountInChunk() - 1;
1144 startLine = chunkLineIndex * getLineCountInChunk() + 1;
1145 endLine = startLine + getLineCountInChunk() - 1;
1146 startBand = chunkBandIndex * getBandCountInChunk() + 1;
1147 endBand = startBand + getBandCountInChunk() - 1;
1165 int startSample = 0;
1173 getChunkPlacement(chunkIndex, startSample, startLine, startBand,
1174 endSample, endLine, endBand);
1177 endSample, endLine, endBand, getBytesPerChunk());
1179 if(!m_nullChunkData) {
1189 for(
int i = 0; i < nullBuffer.size(); i++) {
1190 nullBuffer[i] =
Null;
1193 writeIntoRaw(nullBuffer, *result, result->
getStartBand());
1194 m_nullChunkData =
new QByteArray(result->
getRawData());
1215 const Buffer &justRequested)
const {
1218 if (m_rawData->size() * getBytesPerChunk() > 1 * 1024 * 1024 ||
1219 m_cachingAlgorithms->size() > 1) {
1220 bool algorithmAccepted =
false;
1222 int algorithmIndex = 0;
1223 while(!algorithmAccepted &&
1224 algorithmIndex < m_cachingAlgorithms->size()) {
1233 if(algorithmAccepted) {
1237 foreach(chunkToFree, chunksToFree) {
1238 freeChunk(chunkToFree);
1246 if(!algorithmAccepted && m_rawData->size() > 100) {
1263 void CubeIoHandler::synchronousWrite(
const Buffer &bufferToWrite) {
1272 if(m_lastProcessByLineChunks &&
1273 m_lastProcessByLineChunks->size()) {
1275 if(bufferToWrite.
Sample() == 1 &&
1276 bufferSampleCount == sampleCount() &&
1277 bufferLineCount == 1 &&
1278 bufferBandCount == 1) {
1281 int bufferLine = bufferToWrite.
Line();
1282 int chunkStartLine =
1283 (*m_lastProcessByLineChunks)[0]->getStartLine();
1285 (*m_lastProcessByLineChunks)[0]->lineCount();
1286 int bufferBand = bufferToWrite.
Band();
1287 int chunkStartBand =
1288 (*m_lastProcessByLineChunks)[0]->getStartBand();
1290 (*m_lastProcessByLineChunks)[0]->bandCount();
1292 if(bufferLine >= chunkStartLine &&
1293 bufferLine <= chunkStartLine + chunkLines - 1 &&
1294 bufferBand >= chunkStartBand &&
1295 bufferBand <= chunkStartBand + chunkBands - 1) {
1296 cubeChunks = *m_lastProcessByLineChunks;
1297 for (
int i = 0; i < cubeChunks.size(); i++) {
1298 cubeChunkBands.append( cubeChunks[i]->getStartBand() );
1304 else if (bufferSampleCount == m_samplesInChunk &&
1305 bufferLineCount == m_linesInChunk &&
1306 bufferBandCount == m_bandsInChunk) {
1307 int bufferStartSample = bufferToWrite.
Sample();
1308 int bufferStartLine = bufferToWrite.
Line();
1309 int bufferStartBand = bufferToWrite.
Band();
1311 int bufferEndSample = bufferStartSample + bufferSampleCount - 1;
1312 int bufferEndLine = bufferStartLine + bufferLineCount - 1;
1313 int bufferEndBand = bufferStartBand + bufferBandCount - 1;
1315 int expectedChunkIndex =
1316 ((bufferStartSample - 1) / getSampleCountInChunk()) +
1317 ((bufferStartLine - 1) / getLineCountInChunk()) *
1318 getChunkCountInSampleDimension() +
1319 ((bufferStartBand - 1) / getBandCountInChunk()) *
1320 getChunkCountInSampleDimension() *
1321 getChunkCountInLineDimension();
1323 int chunkStartSample, chunkStartLine, chunkStartBand,
1324 chunkEndSample, chunkEndLine, chunkEndBand;
1326 getChunkPlacement(expectedChunkIndex,
1327 chunkStartSample, chunkStartLine, chunkStartBand,
1328 chunkEndSample, chunkEndLine, chunkEndBand);
1330 if (chunkStartSample == bufferStartSample &&
1331 chunkStartLine == bufferStartLine &&
1332 chunkStartBand == bufferStartBand &&
1333 chunkEndSample == bufferEndSample &&
1334 chunkEndLine == bufferEndLine &&
1335 chunkEndBand == bufferEndBand) {
1336 cubeChunks.append(getChunk(expectedChunkIndex,
true));
1337 cubeChunkBands.append(cubeChunks.last()->getStartBand());
1342 if(cubeChunks.empty()) {
1343 chunkInfo = findCubeChunks(
1344 bufferToWrite.
Sample(), bufferSampleCount,
1345 bufferToWrite.
Line(), bufferLineCount,
1346 bufferToWrite.
Band(), bufferBandCount);
1347 cubeChunks = chunkInfo.first;
1348 cubeChunkBands = chunkInfo.second;
1352 if(bufferToWrite.
Sample() == 1 &&
1353 bufferSampleCount == sampleCount() &&
1354 bufferLineCount == 1 &&
1355 bufferBandCount == 1) {
1356 if(!m_lastProcessByLineChunks)
1357 m_lastProcessByLineChunks =
1360 *m_lastProcessByLineChunks = cubeChunks;
1363 for(
int i = 0; i < cubeChunks.size(); i++) {
1364 writeIntoRaw(bufferToWrite, *cubeChunks[i], cubeChunkBands[i]);
1367 minimizeCache(cubeChunks, bufferToWrite);
1378 Buffer &output,
int index)
const {
1393 findIntersection(chunk, output, startX, startY, startZ, endX, endY, endZ);
1395 int bufferBand = output.
Band();
1401 int chunkBandSize = chunkLineSize * chunk.
lineCount();
1404 const char *chunkBuf = chunk.
getRawData().data();
1405 char *buffersRawBuf = (
char *)output.
RawBuffer();
1407 for(
int z = startZ; z <= endZ; z++) {
1408 const int &bandIntoChunk = z - chunkStartBand;
1409 int virtualBand = z;
1411 virtualBand = index;
1413 if(virtualBand != 0 && virtualBand >= bufferBand &&
1414 virtualBand <= bufferBand + bufferBands - 1) {
1416 for(
int y = startY; y <= endY; y++) {
1417 const int &lineIntoChunk = y - chunkStartLine;
1418 int bufferIndex = output.
Index(startX, y, virtualBand);
1420 for(
int x = startX; x <= endX; x++) {
1421 const int &sampleIntoChunk = x - chunkStartSample;
1423 const int &chunkIndex = sampleIntoChunk +
1424 (chunkLineSize * lineIntoChunk) +
1425 (chunkBandSize * bandIntoChunk);
1427 double &bufferVal = buffersDoubleBuf[bufferIndex];
1429 if(m_pixelType == Real) {
1430 float raw = ((
float *)chunkBuf)[chunkIndex];
1432 raw = m_byteSwapper->Float(&raw);
1434 if(raw >= VALID_MIN4) {
1435 bufferVal = (double) raw;
1440 else if(raw == LOW_INSTR_SAT4)
1441 bufferVal = LOW_INSTR_SAT8;
1442 else if(raw == LOW_REPR_SAT4)
1443 bufferVal = LOW_REPR_SAT8;
1444 else if(raw == HIGH_INSTR_SAT4)
1445 bufferVal = HIGH_INSTR_SAT8;
1446 else if(raw == HIGH_REPR_SAT4)
1447 bufferVal = HIGH_REPR_SAT8;
1449 bufferVal = LOW_REPR_SAT8;
1452 ((
float *)buffersRawBuf)[bufferIndex] = raw;
1455 else if(m_pixelType == SignedWord) {
1456 short raw = ((
short *)chunkBuf)[chunkIndex];
1458 raw = m_byteSwapper->ShortInt(&raw);
1460 if(raw >= VALID_MIN2) {
1461 bufferVal = (double) raw * m_multiplier + m_base;
1466 else if(raw == LOW_INSTR_SAT2)
1467 bufferVal = LOW_INSTR_SAT8;
1468 else if(raw == LOW_REPR_SAT2)
1469 bufferVal = LOW_REPR_SAT8;
1470 else if(raw == HIGH_INSTR_SAT2)
1471 bufferVal = HIGH_INSTR_SAT8;
1472 else if(raw == HIGH_REPR_SAT2)
1473 bufferVal = HIGH_REPR_SAT8;
1475 bufferVal = LOW_REPR_SAT8;
1478 ((
short *)buffersRawBuf)[bufferIndex] = raw;
1482 else if(m_pixelType == UnsignedWord) {
1483 unsigned short raw = ((
unsigned short *)chunkBuf)[chunkIndex];
1485 raw = m_byteSwapper->UnsignedShortInt(&raw);
1487 if(raw >= VALID_MINU2) {
1488 bufferVal = (double) raw * m_multiplier + m_base;
1490 else if (raw > VALID_MAXU2) {
1491 if(raw == HIGH_INSTR_SATU2)
1492 bufferVal = HIGH_INSTR_SAT8;
1493 else if(raw == HIGH_REPR_SATU2)
1494 bufferVal = HIGH_REPR_SAT8;
1496 bufferVal = LOW_REPR_SAT8;
1501 else if(raw == LOW_INSTR_SATU2)
1502 bufferVal = LOW_INSTR_SAT8;
1503 else if(raw == LOW_REPR_SATU2)
1504 bufferVal = LOW_REPR_SAT8;
1506 bufferVal = LOW_REPR_SAT8;
1509 ((
unsigned short *)buffersRawBuf)[bufferIndex] = raw;
1512 else if(m_pixelType == UnsignedByte) {
1513 unsigned char raw = ((
unsigned char *)chunkBuf)[chunkIndex];
1518 else if(raw == HIGH_REPR_SAT1) {
1519 bufferVal = HIGH_REPR_SAT8;
1522 bufferVal = (double) raw * m_multiplier + m_base;
1525 ((
unsigned char *)buffersRawBuf)[bufferIndex] = raw;
1559 findIntersection(output, buffer, startX, startY, startZ, endX, endY, endZ);
1561 int bufferBand = buffer.
Band();
1567 int bandSize = lineSize * output.
lineCount();
1571 for(
int z = startZ; z <= endZ; z++) {
1572 const int &bandIntoChunk = z - outputStartBand;
1573 int virtualBand = index;
1576 if(m_virtualBands) {
1577 virtualBand = m_virtualBands->indexOf(virtualBand) + 1;
1580 if(virtualBand != 0 && virtualBand >= bufferBand &&
1581 virtualBand <= bufferBand + bufferBands - 1) {
1583 for(
int y = startY; y <= endY; y++) {
1584 const int &lineIntoChunk = y - outputStartLine;
1585 int bufferIndex = buffer.
Index(startX, y, virtualBand);
1587 for(
int x = startX; x <= endX; x++) {
1588 const int &sampleIntoChunk = x - outputStartSample;
1590 const int &chunkIndex = sampleIntoChunk +
1591 (lineSize * lineIntoChunk) + (bandSize * bandIntoChunk);
1593 double bufferVal = buffersDoubleBuf[bufferIndex];
1595 if(m_pixelType == Real) {
1598 if(bufferVal >= VALID_MIN8) {
1599 double filePixelValueDbl = (bufferVal - m_base) /
1602 if(filePixelValueDbl < (
double) VALID_MIN4) {
1603 raw = LOW_REPR_SAT4;
1605 else if(filePixelValueDbl > (
double) VALID_MAX4) {
1606 raw = HIGH_REPR_SAT4;
1609 raw = (float) filePixelValueDbl;
1613 if(bufferVal == NULL8)
1615 else if(bufferVal == LOW_INSTR_SAT8)
1616 raw = LOW_INSTR_SAT4;
1617 else if(bufferVal == LOW_REPR_SAT8)
1618 raw = LOW_REPR_SAT4;
1619 else if(bufferVal == HIGH_INSTR_SAT8)
1620 raw = HIGH_INSTR_SAT4;
1621 else if(bufferVal == HIGH_REPR_SAT8)
1622 raw = HIGH_REPR_SAT4;
1624 raw = LOW_REPR_SAT4;
1626 ((
float *)chunkBuf)[chunkIndex] =
1627 m_byteSwapper ? m_byteSwapper->Float(&raw) : raw;
1629 else if(m_pixelType == SignedWord) {
1632 if(bufferVal >= VALID_MIN8) {
1633 double filePixelValueDbl = (bufferVal - m_base) /
1635 if(filePixelValueDbl < VALID_MIN2 - 0.5) {
1636 raw = LOW_REPR_SAT2;
1638 if(filePixelValueDbl > VALID_MAX2 + 0.5) {
1639 raw = HIGH_REPR_SAT2;
1642 int filePixelValue = (int)round(filePixelValueDbl);
1644 if(filePixelValue < VALID_MIN2) {
1645 raw = LOW_REPR_SAT2;
1647 else if(filePixelValue > VALID_MAX2) {
1648 raw = HIGH_REPR_SAT2;
1651 raw = filePixelValue;
1656 if(bufferVal == NULL8)
1658 else if(bufferVal == LOW_INSTR_SAT8)
1659 raw = LOW_INSTR_SAT2;
1660 else if(bufferVal == LOW_REPR_SAT8)
1661 raw = LOW_REPR_SAT2;
1662 else if(bufferVal == HIGH_INSTR_SAT8)
1663 raw = HIGH_INSTR_SAT2;
1664 else if(bufferVal == HIGH_REPR_SAT8)
1665 raw = HIGH_REPR_SAT2;
1667 raw = LOW_REPR_SAT2;
1670 ((
short *)chunkBuf)[chunkIndex] =
1671 m_byteSwapper ? m_byteSwapper->ShortInt(&raw) : raw;
1673 else if(m_pixelType == UnsignedWord) {
1676 if(bufferVal >= VALID_MIN8) {
1677 double filePixelValueDbl = (bufferVal - m_base) /
1679 if(filePixelValueDbl < VALID_MINU2 - 0.5) {
1680 raw = LOW_REPR_SATU2;
1682 if(filePixelValueDbl > VALID_MAXU2 + 0.5) {
1683 raw = HIGH_REPR_SATU2;
1686 int filePixelValue = (int)round(filePixelValueDbl);
1688 if(filePixelValue < VALID_MINU2) {
1689 raw = LOW_REPR_SATU2;
1691 else if(filePixelValue > VALID_MAXU2) {
1692 raw = HIGH_REPR_SATU2;
1695 raw = filePixelValue;
1700 if(bufferVal == NULL8)
1702 else if(bufferVal == LOW_INSTR_SAT8)
1703 raw = LOW_INSTR_SATU2;
1704 else if(bufferVal == LOW_REPR_SAT8)
1705 raw = LOW_REPR_SATU2;
1706 else if(bufferVal == HIGH_INSTR_SAT8)
1707 raw = HIGH_INSTR_SATU2;
1708 else if(bufferVal == HIGH_REPR_SAT8)
1709 raw = HIGH_REPR_SATU2;
1711 raw = LOW_REPR_SATU2;
1714 ((
unsigned short *)chunkBuf)[chunkIndex] =
1715 m_byteSwapper ? m_byteSwapper->UnsignedShortInt(&raw) : raw;
1717 else if(m_pixelType == UnsignedByte) {
1720 if(bufferVal >= VALID_MIN8) {
1721 double filePixelValueDbl = (bufferVal - m_base) /
1723 if(filePixelValueDbl < VALID_MIN1 - 0.5) {
1724 raw = LOW_REPR_SAT1;
1726 else if(filePixelValueDbl > VALID_MAX1 + 0.5) {
1727 raw = HIGH_REPR_SAT1;
1730 int filePixelValue = (int)(filePixelValueDbl + 0.5);
1731 if(filePixelValue < VALID_MIN1) {
1732 raw = LOW_REPR_SAT1;
1734 else if(filePixelValue > VALID_MAX1) {
1735 raw = HIGH_REPR_SAT1;
1738 raw = (
unsigned char)(filePixelValue);
1743 if(bufferVal == NULL8)
1745 else if(bufferVal == LOW_INSTR_SAT8)
1746 raw = LOW_INSTR_SAT1;
1747 else if(bufferVal == LOW_REPR_SAT8)
1748 raw = LOW_REPR_SAT1;
1749 else if(bufferVal == HIGH_INSTR_SAT8)
1750 raw = HIGH_INSTR_SAT1;
1751 else if(bufferVal == HIGH_REPR_SAT8)
1752 raw = HIGH_REPR_SAT1;
1754 raw = LOW_REPR_SAT1;
1757 ((
unsigned char *)chunkBuf)[chunkIndex] = raw;
1771 void CubeIoHandler::writeNullDataToDisk()
const {
1772 if(!m_dataIsOnDiskMap) {
1773 IString msg =
"Cannot call CubeIoHandler::writeNullDataToDisk unless "
1774 "data is not already on disk (Cube::Create was called)";
1778 int numChunks = getChunkCount();
1779 for(
int i = 0; i < numChunks; i++) {
1780 if(!(*m_dataIsOnDiskMap)[i]) {
1783 (*m_dataIsOnDiskMap)[i] =
true;
1805 CubeIoHandler::BufferToChunkWriter::BufferToChunkWriter(
1807 m_ioHandler = ioHandler;
1809 m_timer =
new QTime;
1812 m_ioHandler->m_writeThreadMutex->lock();
1826 CubeIoHandler::BufferToChunkWriter::~BufferToChunkWriter() {
1827 int elapsedMs = m_timer->elapsed();
1828 int idealFlushElapsedTime = 100;
1834 int msOffIdeal = elapsedMs - idealFlushElapsedTime;
1835 double percentOffIdeal = msOffIdeal / (double)idealFlushElapsedTime;
1838 int currentCacheSize = m_ioHandler->m_idealFlushSize;
1839 int desiredAdjustment = -1 * currentCacheSize * percentOffIdeal;
1840 int desiredCacheSize = (int)(currentCacheSize + desiredAdjustment);
1841 m_ioHandler->m_idealFlushSize = (int)(qMin(5000,
1842 qMax(32, desiredCacheSize)));
1847 m_ioHandler->m_writeThreadMutex->unlock();
1850 ASSERT(m_buffersToWrite->isEmpty());
1851 delete m_buffersToWrite;
1852 m_buffersToWrite = NULL;
1861 void CubeIoHandler::BufferToChunkWriter::run() {
1881 foreach (
Buffer * bufferToWrite, *m_buffersToWrite) {
1882 m_ioHandler->synchronousWrite(*bufferToWrite);
1883 delete bufferToWrite;
1886 m_buffersToWrite->clear();
1887 m_ioHandler->m_dataFile->flush();
Buffer for reading and writing cube data.
int Line(const int index=0) const
Returns the line position associated with a shape buffer index.
void setRawData(QByteArray rawData)
Sets the chunk's raw data.
const double Null
Value for an Isis Null pixel.
int LineDimension() const
Returns the number of lines in the shape buffer.
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
Represents a 3D area (a 3D "cube")
int BandDimension() const
Returns the number of bands in the shape buffer.
QList< RawCubeChunk * > getChunksToFree() const
PvlObjectIterator findObject(const QString &name, PvlObjectIterator beg, PvlObjectIterator end)
Find the index of object with a specified name, between two indexes.
int SizeOf(Isis::PixelType pixelType)
Returns the number of bytes of the specified PixelType.
Buffer for containing a three dimensional section of an image.
void SetBasePosition(const int start_sample, const int start_line, const int start_band)
This method is used to set the base position of the shape buffer.
double * DoubleBuffer() const
Returns the value of the shape buffer.
int Sample(const int index=0) const
Returns the sample position associated with a shape buffer index.
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
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...
Distance measurement, usually in meters.
PixelType
Enumerations for Isis Pixel Types.
Handles converting buffers to and from disk.
void * RawBuffer() const
Returns a void pointer to the raw buffer.
virtual CacheResult recommendChunksToFree(QList< RawCubeChunk * > allocated, QList< RawCubeChunk * > justUsed, const Buffer &justRequested)=0
Call this to determine which chunks should be freed from memory.
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
Isis::PixelType PixelTypeEnumeration(const QString &type)
Returns PixelType enumeration given a string.
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
This algorithm recommends chunks to be freed that are not within the last IO.
bool algorithmUnderstoodData() const
If this is true, then the results (be them empty or not) should be considered valid.
int Band(const int index=0) const
Returns the band position associated with a shape buffer index.
Area3D intersect(const Area3D &otherArea) const
Returns the intersection of this 3D area with another 3D area.
QByteArray & getRawData() const
PvlKeyword & findKeyword(const QString &kname, FindOptions opts)
Finds a keyword in the current PvlObject, or deeper inside other PvlObjects and Pvlgroups within this...
Contains multiple PvlContainers.
#define _FILEINFO_
Macro for the filename and line number.
A section of raw data on the disk.
bool isValid() const
Returns true if all of the positions of the 3D area are valid (i.e.
Container for cube-like labels.
PvlKeyword & findKeyword(const QString &name)
Find a keyword with a specified name.
IString DownCase()
Converts all upper case letters in the object IString into lower case characters. ...
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...
int size() const
Returns the total number of pixels in the shape buffer.
Displacement is a signed length, usually in meters.
Adds specific functionality to C++ strings.
This stores the results of the caching algorithm.
This class is designed to handle write() asynchronously.
int getStartSample() const
Contains Pvl Groups and Pvl Objects.
This is the parent of the caching algorithms.
int SampleDimension() const
Returns the number of samples in the shape buffer.