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);
478 void CubeIoHandler::updateLabels(
Pvl &labels) {
489 QMutex *CubeIoHandler::dataFileMutex() {
490 return m_writeThreadMutex;
496 int CubeIoHandler::bandCount()
const {
504 int CubeIoHandler::getBandCountInChunk()
const {
505 return m_bandsInChunk;
516 BigInt CubeIoHandler::getBytesPerChunk()
const {
517 return m_samplesInChunk * m_linesInChunk * m_bandsInChunk *
526 int CubeIoHandler::getChunkCountInBandDimension()
const {
527 return (
int)ceil((
double)m_numBands / (
double)m_bandsInChunk);
535 int CubeIoHandler::getChunkCountInLineDimension()
const {
536 return (
int)ceil((
double)m_numLines / (
double)m_linesInChunk);
544 int CubeIoHandler::getChunkCountInSampleDimension()
const {
545 return (
int)ceil((
double)m_numSamples / (
double)m_samplesInChunk);
565 int sampleIndex = (chunk.
getStartSample() - 1) / getSampleCountInChunk();
566 int lineIndex = (chunk.
getStartLine() - 1) / getLineCountInChunk();
567 int bandIndex = (chunk.
getStartBand() - 1) / getBandCountInChunk();
570 sampleIndex + lineIndex * getChunkCountInSampleDimension();
571 int indexOffsetToBand = bandIndex * getChunkCountInSampleDimension() *
572 getChunkCountInLineDimension();
574 return indexOffsetToBand + indexInBand;
581 BigInt CubeIoHandler::getDataStartByte()
const {
592 QFile * CubeIoHandler::getDataFile() {
601 int CubeIoHandler::lineCount()
const {
609 int CubeIoHandler::getLineCountInChunk()
const {
610 return m_linesInChunk;
626 int CubeIoHandler::sampleCount()
const {
634 int CubeIoHandler::getSampleCountInChunk()
const {
635 return m_samplesInChunk;
651 void CubeIoHandler::setChunkSizes(
652 int numSamples,
int numLines,
int numBands) {
653 bool success =
false;
656 if(m_samplesInChunk != -1 || m_linesInChunk != -1 || m_bandsInChunk != -1) {
657 IString msg =
"You cannot change the chunk sizes once set";
659 else if(numSamples < 1) {
660 msg =
"Negative and zero chunk sizes are not supported, samples per chunk"
661 " cannot be [" +
IString(numSamples) +
"]";
663 else if(numLines < 1) {
664 msg =
"Negative and zero chunk sizes are not supported, lines per chunk "
665 "cannot be [" +
IString(numLines) +
"]";
667 else if(numBands < 1) {
668 msg =
"Negative and zero chunk sizes are not supported, lines per chunk "
669 "cannot be [" +
IString(numBands) +
"]";
676 m_samplesInChunk = numSamples;
677 m_linesInChunk = numLines;
678 m_bandsInChunk = numBands;
680 if(m_dataIsOnDiskMap) {
681 m_dataFile->resize(getDataStartByte() + getDataSize());
683 else if(m_dataFile->size() < getDataStartByte() + getDataSize()) {
685 msg =
"File size [" +
IString((BigInt)m_dataFile->size()) +
686 " bytes] not big enough to hold data [" +
687 IString(getDataStartByte() + getDataSize()) +
" bytes] where the "
688 "offset to the cube data is [" +
IString(getDataStartByte()) +
704 void CubeIoHandler::blockUntilThreadPoolEmpty()
const {
705 if (m_ioThreadPool) {
706 QMutexLocker lock(m_writeThreadMutex);
718 bool CubeIoHandler::bufferLessThan(
Buffer *
const &lhs,
Buffer *
const &rhs) {
719 bool lessThan =
false;
740 lessThan = lhs->
Band() < rhs->
Band();
742 else if (lhs->
Line() != rhs->
Line()) {
743 lessThan = lhs->
Line() < rhs->
Line();
768 int numSamples,
int startLine,
int numLines,
int startBand,
769 int numBands)
const {
773 int lastBand = startBand + numBands - 1;
779 QPoint(max(startSample, 1),
781 QPoint(min(startSample + numSamples - 1,
783 min(startLine + numLines - 1,
789 for(
int band = startBand; band <= lastBand; band ++) {
791 QRect areaLeftInBand(areaInBand);
793 int actualBand = band;
796 if (band < 1 || band > m_virtualBands->size())
799 actualBand = (m_virtualBands->at(band - 1) - 1) / m_bandsInChunk + 1;
803 while(!areaLeftInBand.isEmpty()) {
851 int areaStartLine = areaLeftInBand.top();
852 int areaStartSample = areaLeftInBand.left();
854 int initialChunkXPos = (areaStartSample - 1) / m_samplesInChunk;
855 int initialChunkYPos = (areaStartLine - 1) / m_linesInChunk;
856 int initialChunkZPos = (actualBand - 1) / m_bandsInChunk;
857 int initialChunkBand = initialChunkZPos * m_bandsInChunk + 1;
860 QRect chunkRect(initialChunkXPos * m_samplesInChunk + 1,
861 initialChunkYPos * m_linesInChunk + 1,
862 m_samplesInChunk, m_linesInChunk);
867 while(chunkRect.intersects(areaLeftInBand) &&
868 (initialChunkBand >= 1 && initialChunkBand <= bandCount())) {
869 int chunkXPos = (chunkRect.left() - 1) / m_samplesInChunk;
870 int chunkYPos = (chunkRect.top() - 1) / m_linesInChunk;
871 int chunkZPos = initialChunkZPos;
874 int chunkIndex = chunkXPos +
875 (chunkYPos * getChunkCountInSampleDimension()) +
876 (chunkZPos * getChunkCountInSampleDimension() *
877 getChunkCountInLineDimension());
881 results.append(newChunk);
882 resultBands.append(band);
884 chunkRect.moveLeft(chunkRect.right() + 1);
887 areaLeftInBand.setTop(chunkRect.bottom() + 1);
912 void CubeIoHandler::findIntersection(
914 int &startX,
int &startY,
int &startZ,
915 int &endX,
int &endY,
int &endZ)
const {
922 int startVBand = cube2.
Band();
925 int startPhysicalBand = 0;
926 int endPhysicalBand = 0;
928 bool startVBandFound =
false;
929 for(
int virtualBand = startVBand; virtualBand <= endVBand; virtualBand ++) {
930 int physicalBand = virtualBand;
932 bool bandExists =
true;
934 if (virtualBand < 1 || virtualBand > m_virtualBands->size())
937 physicalBand = m_virtualBands->at(virtualBand - 1);
942 if(!startVBandFound) {
943 startPhysicalBand = physicalBand;
944 endPhysicalBand = physicalBand;
945 startVBandFound =
true;
948 if(physicalBand < startPhysicalBand)
949 startPhysicalBand = physicalBand;
951 if(physicalBand > endPhysicalBand)
952 endPhysicalBand = physicalBand;
979 void CubeIoHandler::flushWriteCache(
bool force)
const {
980 if (m_ioThreadPool) {
981 bool shouldFlush = m_writeCache->second.size() >= m_idealFlushSize ||
983 bool cacheOverflowing =
984 (m_writeCache->second.size() > m_idealFlushSize * 10);
985 bool shouldAndCanFlush =
false;
986 bool forceStart = force;
989 shouldAndCanFlush = m_writeThreadMutex->tryLock();
990 if (shouldAndCanFlush) {
991 m_writeThreadMutex->unlock();
995 if (cacheOverflowing && !shouldAndCanFlush) {
997 m_consecutiveOverflowCount++;
1001 blockUntilThreadPoolEmpty();
1003 if (m_writeCache->second.size() != 0) {
1004 m_idealFlushSize = m_writeCache->second.size();
1006 shouldAndCanFlush =
true;
1009 else if (!cacheOverflowing && shouldAndCanFlush) {
1010 m_consecutiveOverflowCount = 0;
1013 if (cacheOverflowing && m_useOptimizedCubeWrite) {
1014 blockUntilThreadPoolEmpty();
1018 if (m_consecutiveOverflowCount > 10) {
1019 delete m_ioThreadPool;
1020 m_ioThreadPool = NULL;
1024 foreach (
Buffer *bufferToWrite, m_writeCache->second) {
1025 const_cast<CubeIoHandler *
>(
this)->synchronousWrite(*bufferToWrite);
1026 delete bufferToWrite;
1029 m_writeCache->second.clear();
1032 if (shouldAndCanFlush && m_ioThreadPool) {
1033 QMutexLocker locker(m_writeCache->first);
1035 const_cast<CubeIoHandler *>(
this), m_writeCache->second);
1037 m_ioThreadPool->start(writer);
1039 m_writeCache->second.clear();
1040 m_lastOperationWasWrite =
true;
1044 blockUntilThreadPoolEmpty();
1057 if(chunkToFree && m_rawData) {
1058 int chunkIndex = getChunkIndex(*chunkToFree);
1060 m_rawData->erase(m_rawData->find(chunkIndex));
1063 (const_cast<CubeIoHandler *>(
this))->writeRaw(*chunkToFree);
1067 if(m_lastProcessByLineChunks) {
1068 delete m_lastProcessByLineChunks;
1069 m_lastProcessByLineChunks = NULL;
1085 bool allocateIfNecessary)
const {
1089 chunk = m_rawData->value(chunkIndex);
1092 if(allocateIfNecessary && !chunk) {
1093 if(m_dataIsOnDiskMap && !(*m_dataIsOnDiskMap)[chunkIndex]) {
1094 chunk = getNullChunk(chunkIndex);
1095 (*m_dataIsOnDiskMap)[chunkIndex] =
true;
1104 getChunkPlacement(chunkIndex, startSample, startLine, startBand,
1105 endSample, endLine, endBand);
1106 chunk =
new RawCubeChunk(startSample, startLine, startBand,
1107 endSample, endLine, endBand,
1108 getBytesPerChunk());
1114 (*m_rawData)[chunkIndex] = chunk;
1125 int CubeIoHandler::getChunkCount()
const {
1126 return getChunkCountInSampleDimension() *
1127 getChunkCountInLineDimension() *
1128 getChunkCountInBandDimension();
1143 void CubeIoHandler::getChunkPlacement(
int chunkIndex,
1144 int &startSample,
int &startLine,
int &startBand,
1145 int &endSample,
int &endLine,
int &endBand)
const {
1146 int chunkSampleIndex = chunkIndex % getChunkCountInSampleDimension();
1149 (chunkIndex - chunkSampleIndex) / getChunkCountInSampleDimension();
1151 int chunkLineIndex = chunkIndex % getChunkCountInLineDimension();
1152 chunkIndex = (chunkIndex - chunkLineIndex) / getChunkCountInLineDimension();
1154 int chunkBandIndex = chunkIndex;
1156 startSample = chunkSampleIndex * getSampleCountInChunk() + 1;
1157 endSample = startSample + getSampleCountInChunk() - 1;
1158 startLine = chunkLineIndex * getLineCountInChunk() + 1;
1159 endLine = startLine + getLineCountInChunk() - 1;
1160 startBand = chunkBandIndex * getBandCountInChunk() + 1;
1161 endBand = startBand + getBandCountInChunk() - 1;
1179 int startSample = 0;
1187 getChunkPlacement(chunkIndex, startSample, startLine, startBand,
1188 endSample, endLine, endBand);
1191 endSample, endLine, endBand, getBytesPerChunk());
1193 if(!m_nullChunkData) {
1203 for(
int i = 0; i < nullBuffer.size(); i++) {
1204 nullBuffer[i] =
Null;
1207 writeIntoRaw(nullBuffer, *result, result->
getStartBand());
1208 m_nullChunkData =
new QByteArray(result->
getRawData());
1229 const Buffer &justRequested)
const {
1232 if (m_rawData->size() * getBytesPerChunk() > 1 * 1024 * 1024 ||
1233 m_cachingAlgorithms->size() > 1) {
1234 bool algorithmAccepted =
false;
1236 int algorithmIndex = 0;
1237 while(!algorithmAccepted &&
1238 algorithmIndex < m_cachingAlgorithms->size()) {
1247 if(algorithmAccepted) {
1251 foreach(chunkToFree, chunksToFree) {
1252 freeChunk(chunkToFree);
1260 if(!algorithmAccepted && m_rawData->size() > 100) {
1277 void CubeIoHandler::synchronousWrite(
const Buffer &bufferToWrite) {
1286 if(m_lastProcessByLineChunks &&
1287 m_lastProcessByLineChunks->size()) {
1289 if(bufferToWrite.
Sample() == 1 &&
1290 bufferSampleCount == sampleCount() &&
1291 bufferLineCount == 1 &&
1292 bufferBandCount == 1) {
1295 int bufferLine = bufferToWrite.
Line();
1296 int chunkStartLine =
1297 (*m_lastProcessByLineChunks)[0]->getStartLine();
1299 (*m_lastProcessByLineChunks)[0]->lineCount();
1300 int bufferBand = bufferToWrite.
Band();
1301 int chunkStartBand =
1302 (*m_lastProcessByLineChunks)[0]->getStartBand();
1304 (*m_lastProcessByLineChunks)[0]->bandCount();
1306 if(bufferLine >= chunkStartLine &&
1307 bufferLine <= chunkStartLine + chunkLines - 1 &&
1308 bufferBand >= chunkStartBand &&
1309 bufferBand <= chunkStartBand + chunkBands - 1) {
1310 cubeChunks = *m_lastProcessByLineChunks;
1311 for (
int i = 0; i < cubeChunks.size(); i++) {
1312 cubeChunkBands.append( cubeChunks[i]->getStartBand() );
1318 else if (bufferSampleCount == m_samplesInChunk &&
1319 bufferLineCount == m_linesInChunk &&
1320 bufferBandCount == m_bandsInChunk) {
1321 int bufferStartSample = bufferToWrite.
Sample();
1322 int bufferStartLine = bufferToWrite.
Line();
1323 int bufferStartBand = bufferToWrite.
Band();
1325 int bufferEndSample = bufferStartSample + bufferSampleCount - 1;
1326 int bufferEndLine = bufferStartLine + bufferLineCount - 1;
1327 int bufferEndBand = bufferStartBand + bufferBandCount - 1;
1329 int expectedChunkIndex =
1330 ((bufferStartSample - 1) / getSampleCountInChunk()) +
1331 ((bufferStartLine - 1) / getLineCountInChunk()) *
1332 getChunkCountInSampleDimension() +
1333 ((bufferStartBand - 1) / getBandCountInChunk()) *
1334 getChunkCountInSampleDimension() *
1335 getChunkCountInLineDimension();
1337 int chunkStartSample, chunkStartLine, chunkStartBand,
1338 chunkEndSample, chunkEndLine, chunkEndBand;
1340 getChunkPlacement(expectedChunkIndex,
1341 chunkStartSample, chunkStartLine, chunkStartBand,
1342 chunkEndSample, chunkEndLine, chunkEndBand);
1344 if (chunkStartSample == bufferStartSample &&
1345 chunkStartLine == bufferStartLine &&
1346 chunkStartBand == bufferStartBand &&
1347 chunkEndSample == bufferEndSample &&
1348 chunkEndLine == bufferEndLine &&
1349 chunkEndBand == bufferEndBand) {
1350 cubeChunks.append(getChunk(expectedChunkIndex,
true));
1351 cubeChunkBands.append(cubeChunks.last()->getStartBand());
1356 if(cubeChunks.empty()) {
1357 chunkInfo = findCubeChunks(
1358 bufferToWrite.
Sample(), bufferSampleCount,
1359 bufferToWrite.
Line(), bufferLineCount,
1360 bufferToWrite.
Band(), bufferBandCount);
1361 cubeChunks = chunkInfo.first;
1362 cubeChunkBands = chunkInfo.second;
1366 if(bufferToWrite.
Sample() == 1 &&
1367 bufferSampleCount == sampleCount() &&
1368 bufferLineCount == 1 &&
1369 bufferBandCount == 1) {
1370 if(!m_lastProcessByLineChunks)
1371 m_lastProcessByLineChunks =
1374 *m_lastProcessByLineChunks = cubeChunks;
1377 for(
int i = 0; i < cubeChunks.size(); i++) {
1378 writeIntoRaw(bufferToWrite, *cubeChunks[i], cubeChunkBands[i]);
1381 minimizeCache(cubeChunks, bufferToWrite);
1392 Buffer &output,
int index)
const {
1407 findIntersection(chunk, output, startX, startY, startZ, endX, endY, endZ);
1409 int bufferBand = output.
Band();
1415 int chunkBandSize = chunkLineSize * chunk.
lineCount();
1418 const char *chunkBuf = chunk.
getRawData().data();
1419 char *buffersRawBuf = (
char *)output.
RawBuffer();
1421 for(
int z = startZ; z <= endZ; z++) {
1422 const int &bandIntoChunk = z - chunkStartBand;
1423 int virtualBand = z;
1425 virtualBand = index;
1427 if(virtualBand != 0 && virtualBand >= bufferBand &&
1428 virtualBand <= bufferBand + bufferBands - 1) {
1430 for(
int y = startY; y <= endY; y++) {
1431 const int &lineIntoChunk = y - chunkStartLine;
1432 int bufferIndex = output.
Index(startX, y, virtualBand);
1434 for(
int x = startX; x <= endX; x++) {
1435 const int &sampleIntoChunk = x - chunkStartSample;
1437 const int &chunkIndex = sampleIntoChunk +
1438 (chunkLineSize * lineIntoChunk) +
1439 (chunkBandSize * bandIntoChunk);
1441 double &bufferVal = buffersDoubleBuf[bufferIndex];
1443 if(m_pixelType == Real) {
1444 float raw = ((
float *)chunkBuf)[chunkIndex];
1446 raw = m_byteSwapper->Float(&raw);
1448 if(raw >= VALID_MIN4) {
1449 bufferVal = (double) raw;
1454 else if(raw == LOW_INSTR_SAT4)
1455 bufferVal = LOW_INSTR_SAT8;
1456 else if(raw == LOW_REPR_SAT4)
1457 bufferVal = LOW_REPR_SAT8;
1458 else if(raw == HIGH_INSTR_SAT4)
1459 bufferVal = HIGH_INSTR_SAT8;
1460 else if(raw == HIGH_REPR_SAT4)
1461 bufferVal = HIGH_REPR_SAT8;
1463 bufferVal = LOW_REPR_SAT8;
1466 ((
float *)buffersRawBuf)[bufferIndex] = raw;
1468 else if(m_pixelType == SignedWord) {
1469 short raw = ((
short *)chunkBuf)[chunkIndex];
1471 raw = m_byteSwapper->ShortInt(&raw);
1473 if(raw >= VALID_MIN2) {
1474 bufferVal = (double) raw * m_multiplier + m_base;
1479 else if(raw == LOW_INSTR_SAT2)
1480 bufferVal = LOW_INSTR_SAT8;
1481 else if(raw == LOW_REPR_SAT2)
1482 bufferVal = LOW_REPR_SAT8;
1483 else if(raw == HIGH_INSTR_SAT2)
1484 bufferVal = HIGH_INSTR_SAT8;
1485 else if(raw == HIGH_REPR_SAT2)
1486 bufferVal = HIGH_REPR_SAT8;
1488 bufferVal = LOW_REPR_SAT8;
1491 ((
short *)buffersRawBuf)[bufferIndex] = raw;
1493 else if(m_pixelType == UnsignedByte) {
1494 unsigned char raw = ((
unsigned char *)chunkBuf)[chunkIndex];
1499 else if(raw == HIGH_REPR_SAT1) {
1500 bufferVal = HIGH_REPR_SAT8;
1503 bufferVal = (double) raw * m_multiplier + m_base;
1506 ((
unsigned char *)buffersRawBuf)[bufferIndex] = raw;
1540 findIntersection(output, buffer, startX, startY, startZ, endX, endY, endZ);
1542 int bufferBand = buffer.
Band();
1548 int bandSize = lineSize * output.
lineCount();
1552 for(
int z = startZ; z <= endZ; z++) {
1553 const int &bandIntoChunk = z - outputStartBand;
1554 int virtualBand = index;
1557 if(m_virtualBands) {
1558 virtualBand = m_virtualBands->indexOf(virtualBand) + 1;
1561 if(virtualBand != 0 && virtualBand >= bufferBand &&
1562 virtualBand <= bufferBand + bufferBands - 1) {
1564 for(
int y = startY; y <= endY; y++) {
1565 const int &lineIntoChunk = y - outputStartLine;
1566 int bufferIndex = buffer.
Index(startX, y, virtualBand);
1568 for(
int x = startX; x <= endX; x++) {
1569 const int &sampleIntoChunk = x - outputStartSample;
1571 const int &chunkIndex = sampleIntoChunk +
1572 (lineSize * lineIntoChunk) + (bandSize * bandIntoChunk);
1574 double bufferVal = buffersDoubleBuf[bufferIndex];
1576 if(m_pixelType == Real) {
1579 if(bufferVal >= VALID_MIN8) {
1580 double filePixelValueDbl = (bufferVal - m_base) /
1583 if(filePixelValueDbl < (
double) VALID_MIN4) {
1584 raw = LOW_REPR_SAT4;
1586 else if(filePixelValueDbl > (
double) VALID_MAX4) {
1587 raw = HIGH_REPR_SAT4;
1590 raw = (float) filePixelValueDbl;
1594 if(bufferVal == NULL8)
1596 else if(bufferVal == LOW_INSTR_SAT8)
1597 raw = LOW_INSTR_SAT4;
1598 else if(bufferVal == LOW_REPR_SAT8)
1599 raw = LOW_REPR_SAT4;
1600 else if(bufferVal == HIGH_INSTR_SAT8)
1601 raw = HIGH_INSTR_SAT4;
1602 else if(bufferVal == HIGH_REPR_SAT8)
1603 raw = HIGH_REPR_SAT4;
1605 raw = LOW_REPR_SAT4;
1607 ((
float *)chunkBuf)[chunkIndex] =
1608 m_byteSwapper ? m_byteSwapper->Float(&raw) : raw;
1610 else if(m_pixelType == SignedWord) {
1613 if(bufferVal >= VALID_MIN8) {
1614 double filePixelValueDbl = (bufferVal - m_base) /
1616 if(filePixelValueDbl < VALID_MIN2 - 0.5) {
1617 raw = LOW_REPR_SAT2;
1619 if(filePixelValueDbl > VALID_MAX2 + 0.5) {
1620 raw = HIGH_REPR_SAT2;
1623 int filePixelValue = (int)round(filePixelValueDbl);
1625 if(filePixelValue < VALID_MIN2) {
1626 raw = LOW_REPR_SAT2;
1628 else if(filePixelValue > VALID_MAX2) {
1629 raw = HIGH_REPR_SAT2;
1632 raw = filePixelValue;
1637 if(bufferVal == NULL8)
1639 else if(bufferVal == LOW_INSTR_SAT8)
1640 raw = LOW_INSTR_SAT2;
1641 else if(bufferVal == LOW_REPR_SAT8)
1642 raw = LOW_REPR_SAT2;
1643 else if(bufferVal == HIGH_INSTR_SAT8)
1644 raw = HIGH_INSTR_SAT2;
1645 else if(bufferVal == HIGH_REPR_SAT8)
1646 raw = HIGH_REPR_SAT2;
1648 raw = LOW_REPR_SAT2;
1651 ((
short *)chunkBuf)[chunkIndex] =
1652 m_byteSwapper ? m_byteSwapper->ShortInt(&raw) : raw;
1654 else if(m_pixelType == UnsignedByte) {
1657 if(bufferVal >= VALID_MIN8) {
1658 double filePixelValueDbl = (bufferVal - m_base) /
1660 if(filePixelValueDbl < VALID_MIN1 - 0.5) {
1661 raw = LOW_REPR_SAT1;
1663 else if(filePixelValueDbl > VALID_MAX1 + 0.5) {
1664 raw = HIGH_REPR_SAT1;
1667 int filePixelValue = (int)(filePixelValueDbl + 0.5);
1668 if(filePixelValue < VALID_MIN1) {
1669 raw = LOW_REPR_SAT1;
1671 else if(filePixelValue > VALID_MAX1) {
1672 raw = HIGH_REPR_SAT1;
1675 raw = (
unsigned char)(filePixelValue);
1680 if(bufferVal == NULL8)
1682 else if(bufferVal == LOW_INSTR_SAT8)
1683 raw = LOW_INSTR_SAT1;
1684 else if(bufferVal == LOW_REPR_SAT8)
1685 raw = LOW_REPR_SAT1;
1686 else if(bufferVal == HIGH_INSTR_SAT8)
1687 raw = HIGH_INSTR_SAT1;
1688 else if(bufferVal == HIGH_REPR_SAT8)
1689 raw = HIGH_REPR_SAT1;
1691 raw = LOW_REPR_SAT1;
1694 ((
unsigned char *)chunkBuf)[chunkIndex] = raw;
1708 void CubeIoHandler::writeNullDataToDisk()
const {
1709 if(!m_dataIsOnDiskMap) {
1710 IString msg =
"Cannot call CubeIoHandler::writeNullDataToDisk unless "
1711 "data is not already on disk (Cube::Create was called)";
1715 int numChunks = getChunkCount();
1716 for(
int i = 0; i < numChunks; i++) {
1717 if(!(*m_dataIsOnDiskMap)[i]) {
1720 (*m_dataIsOnDiskMap)[i] =
true;
1742 CubeIoHandler::BufferToChunkWriter::BufferToChunkWriter(
1744 m_ioHandler = ioHandler;
1746 m_timer =
new QTime;
1749 m_ioHandler->m_writeThreadMutex->lock();
1763 CubeIoHandler::BufferToChunkWriter::~BufferToChunkWriter() {
1764 int elapsedMs = m_timer->elapsed();
1765 int idealFlushElapsedTime = 100;
1771 int msOffIdeal = elapsedMs - idealFlushElapsedTime;
1772 double percentOffIdeal = msOffIdeal / (double)idealFlushElapsedTime;
1775 int currentCacheSize = m_ioHandler->m_idealFlushSize;
1776 int desiredAdjustment = -1 * currentCacheSize * percentOffIdeal;
1777 int desiredCacheSize = (int)(currentCacheSize + desiredAdjustment);
1778 m_ioHandler->m_idealFlushSize = (int)(qMin(5000,
1779 qMax(32, desiredCacheSize)));
1784 m_ioHandler->m_writeThreadMutex->unlock();
1787 ASSERT(m_buffersToWrite->isEmpty());
1788 delete m_buffersToWrite;
1789 m_buffersToWrite = NULL;
1798 void CubeIoHandler::BufferToChunkWriter::run() {
1818 foreach (
Buffer * bufferToWrite, *m_buffersToWrite) {
1819 m_ioHandler->synchronousWrite(*bufferToWrite);
1820 delete bufferToWrite;
1823 m_buffersToWrite->clear();
1824 m_ioHandler->m_dataFile->flush();