9 #include "CubeIoHandler.h"
18 #include <QListIterator>
19 #include <QMapIterator>
27 #include "CubeCachingAlgorithm.h"
28 #include "Displacement.h"
31 #include "EndianSwapper.h"
32 #include "IException.h"
34 #include "PixelType.h"
35 #include "Preference.h"
38 #include "PvlObject.h"
39 #include "RawCubeChunk.h"
40 #include "RegionalCachingAlgorithm.h"
41 #include "SpecialPixel.h"
42 #include "Statistics.h"
63 CubeIoHandler::CubeIoHandler(QFile * dataFile,
64 const QList<int> *virtualBandList,
const Pvl &label,
bool alreadyOnDisk) {
66 m_cachingAlgorithms = NULL;
67 m_dataIsOnDiskMap = NULL;
69 m_virtualBands = NULL;
70 m_nullChunkData = NULL;
71 m_lastProcessByLineChunks = NULL;
73 m_ioThreadPool = NULL;
74 m_writeThreadMutex = NULL;
78 IString msg =
"Cannot create a CubeIoHandler with a NULL data file";
79 throw IException(IException::Programmer, msg, _FILEINFO_);
85 Preference::Preferences().findGroup(
"Performance");
86 IString cubeWritePerfOpt = performancePrefs[
"CubeWriteThread"][0];
87 m_useOptimizedCubeWrite = (cubeWritePerfOpt.
DownCase() ==
"optimized");
88 if ((m_useOptimizedCubeWrite && !alreadyOnDisk) ||
89 cubeWritePerfOpt.
DownCase() ==
"always") {
90 m_ioThreadPool =
new QThreadPool;
91 m_ioThreadPool->setMaxThreadCount(1);
94 m_consecutiveOverflowCount = 0;
95 m_lastOperationWasWrite =
false;
98 m_writeCache->first =
new QMutex;
99 m_writeThreadMutex =
new QMutex;
101 m_idealFlushSize = 32;
105 m_dataFile = dataFile;
110 QString byteOrderStr = pixelGroup.
findKeyword(
"ByteOrder")[0];
112 byteOrderStr.toUpper());
114 m_multiplier = pixelGroup.
findKeyword(
"Multiplier");
120 if(!m_byteSwapper->willSwap()) {
121 delete m_byteSwapper;
122 m_byteSwapper = NULL;
130 m_startByte = (int)core.
findKeyword(
"StartByte") - 1;
132 m_samplesInChunk = -1;
140 setVirtualBands(virtualBandList);
143 IString msg =
"Constructing CubeIoHandler failed";
144 throw IException(e, IException::Programmer, msg, _FILEINFO_);
147 IString msg =
"Constructing CubeIoHandler failed";
148 throw IException(IException::Programmer, msg, _FILEINFO_);
157 CubeIoHandler::~CubeIoHandler() {
158 ASSERT( m_rawData ? m_rawData->size() == 0 : 1 );
161 m_ioThreadPool->waitForDone();
163 delete m_ioThreadPool;
164 m_ioThreadPool = NULL;
166 delete m_dataIsOnDiskMap;
167 m_dataIsOnDiskMap = NULL;
169 if (m_cachingAlgorithms) {
170 QListIterator<CubeCachingAlgorithm *> it(*m_cachingAlgorithms);
171 while (it.hasNext()) {
174 delete m_cachingAlgorithms;
175 m_cachingAlgorithms = NULL;
179 QMapIterator<int, RawCubeChunk *> it(*m_rawData);
180 while (it.hasNext()) {
193 delete m_writeCache->first;
194 m_writeCache->first = NULL;
196 for (
int i = 0; i < m_writeCache->second.size(); i++) {
197 delete m_writeCache->second[i];
199 m_writeCache->second.clear();
205 delete m_byteSwapper;
206 m_byteSwapper = NULL;
208 delete m_virtualBands;
209 m_virtualBands = NULL;
211 delete m_nullChunkData;
212 m_nullChunkData = NULL;
214 delete m_lastProcessByLineChunks;
215 m_lastProcessByLineChunks = NULL;
217 delete m_writeThreadMutex;
218 m_writeThreadMutex = NULL;
230 void CubeIoHandler::read(
Buffer &bufferToFill)
const {
233 int lastChunkCount = m_rawData->size();
235 if (m_lastOperationWasWrite) {
237 flushWriteCache(
true);
239 m_lastOperationWasWrite =
false;
243 if (m_useOptimizedCubeWrite) {
244 delete m_ioThreadPool;
245 m_ioThreadPool = NULL;
249 QMutexLocker lock(m_writeThreadMutex);
260 if (bufferSampleCount == m_samplesInChunk &&
261 bufferLineCount == m_linesInChunk &&
262 bufferBandCount == m_bandsInChunk) {
263 int bufferStartSample = bufferToFill.
Sample();
264 int bufferStartLine = bufferToFill.
Line();
265 int bufferStartBand = bufferToFill.
Band();
267 int bufferEndSample = bufferStartSample + bufferSampleCount - 1;
268 int bufferEndLine = bufferStartLine + bufferLineCount - 1;
269 int bufferEndBand = bufferStartBand + bufferBandCount - 1;
272 int startBand = bufferStartBand - 1;
274 startBand = m_virtualBands->at(bufferStartBand - 1);
276 int expectedChunkIndex =
277 ((bufferStartSample - 1) / getSampleCountInChunk()) +
278 ((bufferStartLine - 1) / getLineCountInChunk()) *
279 getChunkCountInSampleDimension() +
280 ((startBand - 1) / getBandCountInChunk()) *
281 getChunkCountInSampleDimension() *
282 getChunkCountInLineDimension();
284 int chunkStartSample, chunkStartLine, chunkStartBand,
285 chunkEndSample, chunkEndLine, chunkEndBand;
287 getChunkPlacement(expectedChunkIndex,
288 chunkStartSample, chunkStartLine, chunkStartBand,
289 chunkEndSample, chunkEndLine, chunkEndBand);
291 if (chunkStartSample == bufferStartSample &&
292 chunkStartLine == bufferStartLine &&
293 chunkStartBand == bufferStartBand &&
294 chunkEndSample == bufferEndSample &&
295 chunkEndLine == bufferEndLine &&
296 chunkEndBand == bufferEndBand) {
297 cubeChunks.append(getChunk(expectedChunkIndex,
true));
298 chunkBands.append(cubeChunks.last()->getStartBand());
302 if (cubeChunks.empty()) {
305 for(
int i = 0; i < bufferToFill.
size(); i++) {
306 bufferToFill[i] =
Null;
310 chunkInfo = findCubeChunks(
314 cubeChunks = chunkInfo.first;
315 chunkBands = chunkInfo.second;
318 for (
int i = 0; i < cubeChunks.size(); i++) {
319 writeIntoDouble(*cubeChunks[i], bufferToFill, chunkBands[i]);
323 if (lastChunkCount != m_rawData->size()) {
324 minimizeCache(cubeChunks, bufferToFill);
338 void CubeIoHandler::write(
const Buffer &bufferToWrite) {
339 m_lastOperationWasWrite =
true;
341 if (m_ioThreadPool) {
345 QMutexLocker locker(m_writeCache->first);
346 m_writeCache->second.append(copy);
352 QMutexLocker lock(m_writeThreadMutex);
354 synchronousWrite(bufferToWrite);
369 m_cachingAlgorithms->prepend(algorithm);
383 void CubeIoHandler::clearCache(
bool blockForWriteCache)
const {
384 if (blockForWriteCache) {
386 flushWriteCache(
true);
391 if(m_dataIsOnDiskMap) {
392 writeNullDataToDisk();
398 QMapIterator<int, RawCubeChunk *> it(*m_rawData);
399 while (it.hasNext()) {
403 if(it.value()->isDirty()) {
414 if(m_lastProcessByLineChunks) {
415 delete m_lastProcessByLineChunks;
416 m_lastProcessByLineChunks = NULL;
425 BigInt CubeIoHandler::getDataSize()
const {
426 return (
BigInt)getChunkCountInSampleDimension() *
427 (
BigInt)getChunkCountInLineDimension() *
428 (
BigInt)getChunkCountInBandDimension() *
429 (
BigInt)getBytesPerChunk();
442 void CubeIoHandler::setVirtualBands(
const QList<int> *virtualBandList) {
444 delete m_virtualBands;
445 m_virtualBands = NULL;
448 if(virtualBandList && !virtualBandList->empty())
449 m_virtualBands =
new QList<int>(*virtualBandList);
459 QMutex *CubeIoHandler::dataFileMutex() {
460 return m_writeThreadMutex;
466 int CubeIoHandler::bandCount()
const {
474 int CubeIoHandler::getBandCountInChunk()
const {
475 return m_bandsInChunk;
486 BigInt CubeIoHandler::getBytesPerChunk()
const {
487 return m_samplesInChunk * m_linesInChunk * m_bandsInChunk *
496 int CubeIoHandler::getChunkCountInBandDimension()
const {
497 return (
int)ceil((
double)m_numBands / (
double)m_bandsInChunk);
505 int CubeIoHandler::getChunkCountInLineDimension()
const {
506 return (
int)ceil((
double)m_numLines / (
double)m_linesInChunk);
514 int CubeIoHandler::getChunkCountInSampleDimension()
const {
515 return (
int)ceil((
double)m_numSamples / (
double)m_samplesInChunk);
535 int sampleIndex = (chunk.
getStartSample() - 1) / getSampleCountInChunk();
536 int lineIndex = (chunk.
getStartLine() - 1) / getLineCountInChunk();
537 int bandIndex = (chunk.
getStartBand() - 1) / getBandCountInChunk();
540 sampleIndex + lineIndex * getChunkCountInSampleDimension();
541 int indexOffsetToBand = bandIndex * getChunkCountInSampleDimension() *
542 getChunkCountInLineDimension();
544 return indexOffsetToBand + indexInBand;
551 BigInt CubeIoHandler::getDataStartByte()
const {
562 QFile * CubeIoHandler::getDataFile() {
571 int CubeIoHandler::lineCount()
const {
579 int CubeIoHandler::getLineCountInChunk()
const {
580 return m_linesInChunk;
596 int CubeIoHandler::sampleCount()
const {
604 int CubeIoHandler::getSampleCountInChunk()
const {
605 return m_samplesInChunk;
621 void CubeIoHandler::setChunkSizes(
622 int numSamples,
int numLines,
int numBands) {
623 bool success =
false;
626 if(m_samplesInChunk != -1 || m_linesInChunk != -1 || m_bandsInChunk != -1) {
627 IString msg =
"You cannot change the chunk sizes once set";
629 else if(numSamples < 1) {
630 msg =
"Negative and zero chunk sizes are not supported, samples per chunk"
631 " cannot be [" +
IString(numSamples) +
"]";
633 else if(numLines < 1) {
634 msg =
"Negative and zero chunk sizes are not supported, lines per chunk "
635 "cannot be [" +
IString(numLines) +
"]";
637 else if(numBands < 1) {
638 msg =
"Negative and zero chunk sizes are not supported, lines per chunk "
639 "cannot be [" +
IString(numBands) +
"]";
646 m_samplesInChunk = numSamples;
647 m_linesInChunk = numLines;
648 m_bandsInChunk = numBands;
650 if(m_dataIsOnDiskMap) {
651 m_dataFile->resize(getDataStartByte() + getDataSize());
653 else if(m_dataFile->size() < getDataStartByte() + getDataSize()) {
656 " bytes] not big enough to hold data [" +
657 IString(getDataStartByte() + getDataSize()) +
" bytes] where the "
658 "offset to the cube data is [" +
IString(getDataStartByte()) +
663 throw IException(IException::Programmer, msg, _FILEINFO_);
674 void CubeIoHandler::blockUntilThreadPoolEmpty()
const {
675 if (m_ioThreadPool) {
676 QMutexLocker lock(m_writeThreadMutex);
688 bool CubeIoHandler::bufferLessThan(
Buffer *
const &lhs,
Buffer *
const &rhs) {
689 bool lessThan =
false;
710 lessThan = lhs->
Band() < rhs->
Band();
712 else if (lhs->
Line() != rhs->
Line()) {
713 lessThan = lhs->
Line() < rhs->
Line();
738 int numSamples,
int startLine,
int numLines,
int startBand,
739 int numBands)
const {
743 int lastBand = startBand + numBands - 1;
749 QPoint(max(startSample, 1),
751 QPoint(min(startSample + numSamples - 1,
753 min(startLine + numLines - 1,
759 for(
int band = startBand; band <= lastBand; band ++) {
761 QRect areaLeftInBand(areaInBand);
763 int actualBand = band;
766 if (band < 1 || band > m_virtualBands->size())
769 actualBand = (m_virtualBands->at(band - 1) - 1) / m_bandsInChunk + 1;
773 while(!areaLeftInBand.isEmpty()) {
821 int areaStartLine = areaLeftInBand.top();
822 int areaStartSample = areaLeftInBand.left();
824 int initialChunkXPos = (areaStartSample - 1) / m_samplesInChunk;
825 int initialChunkYPos = (areaStartLine - 1) / m_linesInChunk;
826 int initialChunkZPos = (actualBand - 1) / m_bandsInChunk;
827 int initialChunkBand = initialChunkZPos * m_bandsInChunk + 1;
830 QRect chunkRect(initialChunkXPos * m_samplesInChunk + 1,
831 initialChunkYPos * m_linesInChunk + 1,
832 m_samplesInChunk, m_linesInChunk);
837 while(chunkRect.intersects(areaLeftInBand) &&
838 (initialChunkBand >= 1 && initialChunkBand <= bandCount())) {
839 int chunkXPos = (chunkRect.left() - 1) / m_samplesInChunk;
840 int chunkYPos = (chunkRect.top() - 1) / m_linesInChunk;
841 int chunkZPos = initialChunkZPos;
844 int chunkIndex = chunkXPos +
845 (chunkYPos * getChunkCountInSampleDimension()) +
846 (chunkZPos * getChunkCountInSampleDimension() *
847 getChunkCountInLineDimension());
851 results.append(newChunk);
852 resultBands.append(band);
854 chunkRect.moveLeft(chunkRect.right() + 1);
857 areaLeftInBand.setTop(chunkRect.bottom() + 1);
882 void CubeIoHandler::findIntersection(
884 int &startX,
int &startY,
int &startZ,
885 int &endX,
int &endY,
int &endZ)
const {
892 int startVBand = cube2.
Band();
895 int startPhysicalBand = 0;
896 int endPhysicalBand = 0;
898 bool startVBandFound =
false;
899 for(
int virtualBand = startVBand; virtualBand <= endVBand; virtualBand ++) {
900 int physicalBand = virtualBand;
902 bool bandExists =
true;
904 if (virtualBand < 1 || virtualBand > m_virtualBands->size())
907 physicalBand = m_virtualBands->at(virtualBand - 1);
912 if(!startVBandFound) {
913 startPhysicalBand = physicalBand;
914 endPhysicalBand = physicalBand;
915 startVBandFound =
true;
918 if(physicalBand < startPhysicalBand)
919 startPhysicalBand = physicalBand;
921 if(physicalBand > endPhysicalBand)
922 endPhysicalBand = physicalBand;
947 void CubeIoHandler::flushWriteCache(
bool force)
const {
948 if (m_ioThreadPool) {
949 bool shouldFlush = m_writeCache->second.size() >= m_idealFlushSize ||
951 bool cacheOverflowing =
952 (m_writeCache->second.size() > m_idealFlushSize * 10);
953 bool shouldAndCanFlush =
false;
954 bool forceStart = force;
957 shouldAndCanFlush = m_writeThreadMutex->tryLock();
958 if (shouldAndCanFlush) {
959 m_writeThreadMutex->unlock();
963 if (cacheOverflowing && !shouldAndCanFlush) {
965 m_consecutiveOverflowCount++;
969 blockUntilThreadPoolEmpty();
971 if (m_writeCache->second.size() != 0) {
972 m_idealFlushSize = m_writeCache->second.size();
974 shouldAndCanFlush =
true;
977 else if (!cacheOverflowing && shouldAndCanFlush) {
978 m_consecutiveOverflowCount = 0;
981 if (cacheOverflowing && m_useOptimizedCubeWrite) {
982 blockUntilThreadPoolEmpty();
986 if (m_consecutiveOverflowCount > 10) {
987 delete m_ioThreadPool;
988 m_ioThreadPool = NULL;
992 foreach (
Buffer *bufferToWrite, m_writeCache->second) {
993 const_cast<CubeIoHandler *
>(
this)->synchronousWrite(*bufferToWrite);
994 delete bufferToWrite;
997 m_writeCache->second.clear();
1000 if (shouldAndCanFlush && m_ioThreadPool) {
1001 QMutexLocker locker(m_writeCache->first);
1005 m_ioThreadPool->start(writer);
1007 m_writeCache->second.clear();
1008 m_lastOperationWasWrite =
true;
1012 blockUntilThreadPoolEmpty();
1025 if(chunkToFree && m_rawData) {
1026 int chunkIndex = getChunkIndex(*chunkToFree);
1028 m_rawData->erase(m_rawData->find(chunkIndex));
1031 (
const_cast<CubeIoHandler *
>(
this))->writeRaw(*chunkToFree);
1035 if(m_lastProcessByLineChunks) {
1036 delete m_lastProcessByLineChunks;
1037 m_lastProcessByLineChunks = NULL;
1053 bool allocateIfNecessary)
const {
1057 chunk = m_rawData->value(chunkIndex);
1060 if(allocateIfNecessary && !chunk) {
1061 if(m_dataIsOnDiskMap && !(*m_dataIsOnDiskMap)[chunkIndex]) {
1062 chunk = getNullChunk(chunkIndex);
1063 (*m_dataIsOnDiskMap)[chunkIndex] =
true;
1072 getChunkPlacement(chunkIndex, startSample, startLine, startBand,
1073 endSample, endLine, endBand);
1074 chunk =
new RawCubeChunk(startSample, startLine, startBand,
1075 endSample, endLine, endBand,
1076 getBytesPerChunk());
1082 (*m_rawData)[chunkIndex] = chunk;
1093 int CubeIoHandler::getChunkCount()
const {
1094 return getChunkCountInSampleDimension() *
1095 getChunkCountInLineDimension() *
1096 getChunkCountInBandDimension();
1111 void CubeIoHandler::getChunkPlacement(
int chunkIndex,
1112 int &startSample,
int &startLine,
int &startBand,
1113 int &endSample,
int &endLine,
int &endBand)
const {
1114 int chunkSampleIndex = chunkIndex % getChunkCountInSampleDimension();
1117 (chunkIndex - chunkSampleIndex) / getChunkCountInSampleDimension();
1119 int chunkLineIndex = chunkIndex % getChunkCountInLineDimension();
1120 chunkIndex = (chunkIndex - chunkLineIndex) / getChunkCountInLineDimension();
1122 int chunkBandIndex = chunkIndex;
1124 startSample = chunkSampleIndex * getSampleCountInChunk() + 1;
1125 endSample = startSample + getSampleCountInChunk() - 1;
1126 startLine = chunkLineIndex * getLineCountInChunk() + 1;
1127 endLine = startLine + getLineCountInChunk() - 1;
1128 startBand = chunkBandIndex * getBandCountInChunk() + 1;
1129 endBand = startBand + getBandCountInChunk() - 1;
1147 int startSample = 0;
1155 getChunkPlacement(chunkIndex, startSample, startLine, startBand,
1156 endSample, endLine, endBand);
1159 endSample, endLine, endBand, getBytesPerChunk());
1161 if(!m_nullChunkData) {
1171 for(
int i = 0; i < nullBuffer.
size(); i++) {
1172 nullBuffer[i] =
Null;
1175 writeIntoRaw(nullBuffer, *result, result->
getStartBand());
1176 m_nullChunkData =
new QByteArray(result->
getRawData());
1197 const Buffer &justRequested)
const {
1200 if (m_rawData->size() * getBytesPerChunk() > 1 * 1024 * 1024 ||
1201 m_cachingAlgorithms->size() > 1) {
1202 bool algorithmAccepted =
false;
1204 int algorithmIndex = 0;
1205 while(!algorithmAccepted &&
1206 algorithmIndex < m_cachingAlgorithms->size()) {
1215 if(algorithmAccepted) {
1219 foreach(chunkToFree, chunksToFree) {
1220 freeChunk(chunkToFree);
1228 if(!algorithmAccepted && m_rawData->size() > 100) {
1245 void CubeIoHandler::synchronousWrite(
const Buffer &bufferToWrite) {
1254 if(m_lastProcessByLineChunks &&
1255 m_lastProcessByLineChunks->size()) {
1257 if(bufferToWrite.
Sample() == 1 &&
1258 bufferSampleCount == sampleCount() &&
1259 bufferLineCount == 1 &&
1260 bufferBandCount == 1) {
1263 int bufferLine = bufferToWrite.
Line();
1264 int chunkStartLine =
1265 (*m_lastProcessByLineChunks)[0]->getStartLine();
1267 (*m_lastProcessByLineChunks)[0]->lineCount();
1268 int bufferBand = bufferToWrite.
Band();
1269 int chunkStartBand =
1270 (*m_lastProcessByLineChunks)[0]->getStartBand();
1272 (*m_lastProcessByLineChunks)[0]->bandCount();
1274 if(bufferLine >= chunkStartLine &&
1275 bufferLine <= chunkStartLine + chunkLines - 1 &&
1276 bufferBand >= chunkStartBand &&
1277 bufferBand <= chunkStartBand + chunkBands - 1) {
1278 cubeChunks = *m_lastProcessByLineChunks;
1279 for (
int i = 0; i < cubeChunks.size(); i++) {
1280 cubeChunkBands.append( cubeChunks[i]->getStartBand() );
1286 else if (bufferSampleCount == m_samplesInChunk &&
1287 bufferLineCount == m_linesInChunk &&
1288 bufferBandCount == m_bandsInChunk) {
1289 int bufferStartSample = bufferToWrite.
Sample();
1290 int bufferStartLine = bufferToWrite.
Line();
1291 int bufferStartBand = bufferToWrite.
Band();
1293 int bufferEndSample = bufferStartSample + bufferSampleCount - 1;
1294 int bufferEndLine = bufferStartLine + bufferLineCount - 1;
1295 int bufferEndBand = bufferStartBand + bufferBandCount - 1;
1297 int expectedChunkIndex =
1298 ((bufferStartSample - 1) / getSampleCountInChunk()) +
1299 ((bufferStartLine - 1) / getLineCountInChunk()) *
1300 getChunkCountInSampleDimension() +
1301 ((bufferStartBand - 1) / getBandCountInChunk()) *
1302 getChunkCountInSampleDimension() *
1303 getChunkCountInLineDimension();
1305 int chunkStartSample, chunkStartLine, chunkStartBand,
1306 chunkEndSample, chunkEndLine, chunkEndBand;
1308 getChunkPlacement(expectedChunkIndex,
1309 chunkStartSample, chunkStartLine, chunkStartBand,
1310 chunkEndSample, chunkEndLine, chunkEndBand);
1312 if (chunkStartSample == bufferStartSample &&
1313 chunkStartLine == bufferStartLine &&
1314 chunkStartBand == bufferStartBand &&
1315 chunkEndSample == bufferEndSample &&
1316 chunkEndLine == bufferEndLine &&
1317 chunkEndBand == bufferEndBand) {
1318 cubeChunks.append(getChunk(expectedChunkIndex,
true));
1319 cubeChunkBands.append(cubeChunks.last()->getStartBand());
1324 if(cubeChunks.empty()) {
1325 chunkInfo = findCubeChunks(
1326 bufferToWrite.
Sample(), bufferSampleCount,
1327 bufferToWrite.
Line(), bufferLineCount,
1328 bufferToWrite.
Band(), bufferBandCount);
1329 cubeChunks = chunkInfo.first;
1330 cubeChunkBands = chunkInfo.second;
1334 if(bufferToWrite.
Sample() == 1 &&
1335 bufferSampleCount == sampleCount() &&
1336 bufferLineCount == 1 &&
1337 bufferBandCount == 1) {
1338 if(!m_lastProcessByLineChunks)
1339 m_lastProcessByLineChunks =
1342 *m_lastProcessByLineChunks = cubeChunks;
1345 for(
int i = 0; i < cubeChunks.size(); i++) {
1346 writeIntoRaw(bufferToWrite, *cubeChunks[i], cubeChunkBands[i]);
1349 minimizeCache(cubeChunks, bufferToWrite);
1361 Buffer &output,
int index)
const {
1376 findIntersection(chunk, output, startX, startY, startZ, endX, endY, endZ);
1378 int bufferBand = output.
Band();
1384 int chunkBandSize = chunkLineSize * chunk.
lineCount();
1387 const char *chunkBuf = chunk.
getRawData().data();
1388 char *buffersRawBuf = (
char *)output.
RawBuffer();
1390 for(
int z = startZ; z <= endZ; z++) {
1391 const int &bandIntoChunk = z - chunkStartBand;
1392 int virtualBand = z;
1394 virtualBand = index;
1396 if(virtualBand != 0 && virtualBand >= bufferBand &&
1397 virtualBand <= bufferBand + bufferBands - 1) {
1399 for(
int y = startY; y <= endY; y++) {
1400 const int &lineIntoChunk = y - chunkStartLine;
1401 int bufferIndex = output.
Index(startX, y, virtualBand);
1403 for(
int x = startX; x <= endX; x++) {
1404 const int &sampleIntoChunk = x - chunkStartSample;
1406 const int &chunkIndex = sampleIntoChunk +
1407 (chunkLineSize * lineIntoChunk) +
1408 (chunkBandSize * bandIntoChunk);
1410 double &bufferVal = buffersDoubleBuf[bufferIndex];
1412 if(m_pixelType == Real) {
1413 float raw = ((
float *)chunkBuf)[chunkIndex];
1415 raw = m_byteSwapper->Float(&raw);
1417 if(raw >= VALID_MIN4) {
1418 bufferVal = (double) raw;
1423 else if(raw == LOW_INSTR_SAT4)
1424 bufferVal = LOW_INSTR_SAT8;
1425 else if(raw == LOW_REPR_SAT4)
1426 bufferVal = LOW_REPR_SAT8;
1427 else if(raw == HIGH_INSTR_SAT4)
1428 bufferVal = HIGH_INSTR_SAT8;
1429 else if(raw == HIGH_REPR_SAT4)
1430 bufferVal = HIGH_REPR_SAT8;
1432 bufferVal = LOW_REPR_SAT8;
1435 ((
float *)buffersRawBuf)[bufferIndex] = raw;
1438 else if(m_pixelType == SignedWord) {
1439 short raw = ((
short *)chunkBuf)[chunkIndex];
1441 raw = m_byteSwapper->ShortInt(&raw);
1443 if(raw >= VALID_MIN2) {
1444 bufferVal = (double) raw * m_multiplier + m_base;
1449 else if(raw == LOW_INSTR_SAT2)
1450 bufferVal = LOW_INSTR_SAT8;
1451 else if(raw == LOW_REPR_SAT2)
1452 bufferVal = LOW_REPR_SAT8;
1453 else if(raw == HIGH_INSTR_SAT2)
1454 bufferVal = HIGH_INSTR_SAT8;
1455 else if(raw == HIGH_REPR_SAT2)
1456 bufferVal = HIGH_REPR_SAT8;
1458 bufferVal = LOW_REPR_SAT8;
1461 ((
short *)buffersRawBuf)[bufferIndex] = raw;
1465 else if(m_pixelType == UnsignedWord) {
1466 unsigned short raw = ((
unsigned short *)chunkBuf)[chunkIndex];
1468 raw = m_byteSwapper->UnsignedShortInt(&raw);
1470 if(raw >= VALID_MINU2) {
1471 bufferVal = (double) raw * m_multiplier + m_base;
1473 else if (raw > VALID_MAXU2) {
1474 if(raw == HIGH_INSTR_SATU2)
1475 bufferVal = HIGH_INSTR_SAT8;
1476 else if(raw == HIGH_REPR_SATU2)
1477 bufferVal = HIGH_REPR_SAT8;
1479 bufferVal = LOW_REPR_SAT8;
1484 else if(raw == LOW_INSTR_SATU2)
1485 bufferVal = LOW_INSTR_SAT8;
1486 else if(raw == LOW_REPR_SATU2)
1487 bufferVal = LOW_REPR_SAT8;
1489 bufferVal = LOW_REPR_SAT8;
1492 ((
unsigned short *)buffersRawBuf)[bufferIndex] = raw;
1495 else if(m_pixelType == UnsignedInteger) {
1497 unsigned int raw = ((
unsigned int *)chunkBuf)[chunkIndex];
1499 raw = m_byteSwapper->Uint32_t(&raw);
1501 if(raw >= VALID_MINUI4) {
1502 bufferVal = (double) raw * m_multiplier + m_base;
1504 else if (raw > VALID_MAXUI4) {
1505 if(raw == HIGH_INSTR_SATUI4)
1506 bufferVal = HIGH_INSTR_SAT8;
1507 else if(raw == HIGH_REPR_SATUI4)
1508 bufferVal = HIGH_REPR_SAT8;
1510 bufferVal = LOW_REPR_SAT8;
1515 else if(raw == LOW_INSTR_SATUI4)
1516 bufferVal = LOW_INSTR_SAT8;
1517 else if(raw == LOW_REPR_SATUI4)
1518 bufferVal = LOW_REPR_SAT8;
1520 bufferVal = LOW_REPR_SAT8;
1523 ((
unsigned int *)buffersRawBuf)[bufferIndex] = raw;
1529 else if(m_pixelType == UnsignedByte) {
1530 unsigned char raw = ((
unsigned char *)chunkBuf)[chunkIndex];
1535 else if(raw == HIGH_REPR_SAT1) {
1536 bufferVal = HIGH_REPR_SAT8;
1539 bufferVal = (double) raw * m_multiplier + m_base;
1542 ((
unsigned char *)buffersRawBuf)[bufferIndex] = raw;
1577 findIntersection(output, buffer, startX, startY, startZ, endX, endY, endZ);
1579 int bufferBand = buffer.
Band();
1585 int bandSize = lineSize * output.
lineCount();
1589 for(
int z = startZ; z <= endZ; z++) {
1590 const int &bandIntoChunk = z - outputStartBand;
1591 int virtualBand = index;
1594 if(m_virtualBands) {
1595 virtualBand = m_virtualBands->indexOf(virtualBand) + 1;
1598 if(virtualBand != 0 && virtualBand >= bufferBand &&
1599 virtualBand <= bufferBand + bufferBands - 1) {
1601 for(
int y = startY; y <= endY; y++) {
1602 const int &lineIntoChunk = y - outputStartLine;
1603 int bufferIndex = buffer.
Index(startX, y, virtualBand);
1605 for(
int x = startX; x <= endX; x++) {
1606 const int &sampleIntoChunk = x - outputStartSample;
1608 const int &chunkIndex = sampleIntoChunk +
1609 (lineSize * lineIntoChunk) + (bandSize * bandIntoChunk);
1611 double bufferVal = buffersDoubleBuf[bufferIndex];
1613 if(m_pixelType == Real) {
1616 if(bufferVal >= VALID_MIN8) {
1617 double filePixelValueDbl = (bufferVal - m_base) /
1620 if(filePixelValueDbl < (
double) VALID_MIN4) {
1621 raw = LOW_REPR_SAT4;
1623 else if(filePixelValueDbl > (
double) VALID_MAX4) {
1624 raw = HIGH_REPR_SAT4;
1627 raw = (float) filePixelValueDbl;
1631 if(bufferVal == NULL8)
1633 else if(bufferVal == LOW_INSTR_SAT8)
1634 raw = LOW_INSTR_SAT4;
1635 else if(bufferVal == LOW_REPR_SAT8)
1636 raw = LOW_REPR_SAT4;
1637 else if(bufferVal == HIGH_INSTR_SAT8)
1638 raw = HIGH_INSTR_SAT4;
1639 else if(bufferVal == HIGH_REPR_SAT8)
1640 raw = HIGH_REPR_SAT4;
1642 raw = LOW_REPR_SAT4;
1644 ((
float *)chunkBuf)[chunkIndex] =
1645 m_byteSwapper ? m_byteSwapper->Float(&raw) : raw;
1648 else if(m_pixelType == SignedWord) {
1651 if(bufferVal >= VALID_MIN8) {
1652 double filePixelValueDbl = (bufferVal - m_base) /
1654 if(filePixelValueDbl < VALID_MIN2 - 0.5) {
1655 raw = LOW_REPR_SAT2;
1657 if(filePixelValueDbl > VALID_MAX2 + 0.5) {
1658 raw = HIGH_REPR_SAT2;
1661 int filePixelValue = (int)round(filePixelValueDbl);
1663 if(filePixelValue < VALID_MIN2) {
1664 raw = LOW_REPR_SAT2;
1666 else if(filePixelValue > VALID_MAX2) {
1667 raw = HIGH_REPR_SAT2;
1670 raw = filePixelValue;
1675 if(bufferVal == NULL8)
1677 else if(bufferVal == LOW_INSTR_SAT8)
1678 raw = LOW_INSTR_SAT2;
1679 else if(bufferVal == LOW_REPR_SAT8)
1680 raw = LOW_REPR_SAT2;
1681 else if(bufferVal == HIGH_INSTR_SAT8)
1682 raw = HIGH_INSTR_SAT2;
1683 else if(bufferVal == HIGH_REPR_SAT8)
1684 raw = HIGH_REPR_SAT2;
1686 raw = LOW_REPR_SAT2;
1689 ((
short *)chunkBuf)[chunkIndex] =
1690 m_byteSwapper ? m_byteSwapper->ShortInt(&raw) : raw;
1693 else if(m_pixelType == UnsignedInteger) {
1697 if(bufferVal >= VALID_MINUI4) {
1698 double filePixelValueDbl = (bufferVal - m_base) /
1700 if(filePixelValueDbl < VALID_MINUI4 - 0.5) {
1701 raw = LOW_REPR_SATUI4;
1703 if(filePixelValueDbl > VALID_MAXUI4) {
1704 raw = HIGH_REPR_SATUI4;
1707 unsigned int filePixelValue = (
unsigned int)round(filePixelValueDbl);
1709 if(filePixelValue < VALID_MINUI4) {
1710 raw = LOW_REPR_SATUI4;
1712 else if(filePixelValue > VALID_MAXUI4) {
1713 raw = HIGH_REPR_SATUI4;
1716 raw = filePixelValue;
1721 if(bufferVal == NULL8)
1723 else if(bufferVal == LOW_INSTR_SAT8)
1724 raw = LOW_INSTR_SATUI4;
1725 else if(bufferVal == LOW_REPR_SAT8)
1726 raw = LOW_REPR_SATUI4;
1727 else if(bufferVal == HIGH_INSTR_SAT8)
1728 raw = HIGH_INSTR_SATUI4;
1729 else if(bufferVal == HIGH_REPR_SAT8)
1730 raw = HIGH_REPR_SATUI4;
1732 raw = LOW_REPR_SATUI4;
1735 ((
unsigned int *)chunkBuf)[chunkIndex] =
1736 m_byteSwapper ? m_byteSwapper->Uint32_t(&raw) : raw;
1741 else if(m_pixelType == UnsignedWord) {
1744 if(bufferVal >= VALID_MIN8) {
1745 double filePixelValueDbl = (bufferVal - m_base) /
1747 if(filePixelValueDbl < VALID_MINU2 - 0.5) {
1748 raw = LOW_REPR_SATU2;
1750 if(filePixelValueDbl > VALID_MAXU2 + 0.5) {
1751 raw = HIGH_REPR_SATU2;
1754 int filePixelValue = (int)round(filePixelValueDbl);
1756 if(filePixelValue < VALID_MINU2) {
1757 raw = LOW_REPR_SATU2;
1759 else if(filePixelValue > VALID_MAXU2) {
1760 raw = HIGH_REPR_SATU2;
1763 raw = filePixelValue;
1768 if(bufferVal == NULL8)
1770 else if(bufferVal == LOW_INSTR_SAT8)
1771 raw = LOW_INSTR_SATU2;
1772 else if(bufferVal == LOW_REPR_SAT8)
1773 raw = LOW_REPR_SATU2;
1774 else if(bufferVal == HIGH_INSTR_SAT8)
1775 raw = HIGH_INSTR_SATU2;
1776 else if(bufferVal == HIGH_REPR_SAT8)
1777 raw = HIGH_REPR_SATU2;
1779 raw = LOW_REPR_SATU2;
1782 ((
unsigned short *)chunkBuf)[chunkIndex] =
1783 m_byteSwapper ? m_byteSwapper->UnsignedShortInt(&raw) : raw;
1785 else if(m_pixelType == UnsignedByte) {
1788 if(bufferVal >= VALID_MIN8) {
1789 double filePixelValueDbl = (bufferVal - m_base) /
1791 if(filePixelValueDbl < VALID_MIN1 - 0.5) {
1792 raw = LOW_REPR_SAT1;
1794 else if(filePixelValueDbl > VALID_MAX1 + 0.5) {
1795 raw = HIGH_REPR_SAT1;
1798 int filePixelValue = (int)(filePixelValueDbl + 0.5);
1799 if(filePixelValue < VALID_MIN1) {
1800 raw = LOW_REPR_SAT1;
1802 else if(filePixelValue > VALID_MAX1) {
1803 raw = HIGH_REPR_SAT1;
1806 raw = (
unsigned char)(filePixelValue);
1811 if(bufferVal == NULL8)
1813 else if(bufferVal == LOW_INSTR_SAT8)
1814 raw = LOW_INSTR_SAT1;
1815 else if(bufferVal == LOW_REPR_SAT8)
1816 raw = LOW_REPR_SAT1;
1817 else if(bufferVal == HIGH_INSTR_SAT8)
1818 raw = HIGH_INSTR_SAT1;
1819 else if(bufferVal == HIGH_REPR_SAT8)
1820 raw = HIGH_REPR_SAT1;
1822 raw = LOW_REPR_SAT1;
1825 ((
unsigned char *)chunkBuf)[chunkIndex] = raw;
1839 void CubeIoHandler::writeNullDataToDisk()
const {
1840 if(!m_dataIsOnDiskMap) {
1841 IString msg =
"Cannot call CubeIoHandler::writeNullDataToDisk unless "
1842 "data is not already on disk (Cube::Create was called)";
1843 throw IException(IException::Programmer, msg, _FILEINFO_);
1846 int numChunks = getChunkCount();
1847 for(
int i = 0; i < numChunks; i++) {
1848 if(!(*m_dataIsOnDiskMap)[i]) {
1851 (*m_dataIsOnDiskMap)[i] =
true;
1873 CubeIoHandler::BufferToChunkWriter::BufferToChunkWriter(
1875 m_ioHandler = ioHandler;
1877 m_timer =
new QTime;
1880 m_ioHandler->m_writeThreadMutex->lock();
1894 CubeIoHandler::BufferToChunkWriter::~BufferToChunkWriter() {
1895 int elapsedMs = m_timer->elapsed();
1896 int idealFlushElapsedTime = 100;
1902 int msOffIdeal = elapsedMs - idealFlushElapsedTime;
1903 double percentOffIdeal = msOffIdeal / (double)idealFlushElapsedTime;
1906 int currentCacheSize = m_ioHandler->m_idealFlushSize;
1907 int desiredAdjustment = -1 * currentCacheSize * percentOffIdeal;
1908 int desiredCacheSize = (int)(currentCacheSize + desiredAdjustment);
1909 m_ioHandler->m_idealFlushSize = (int)(qMin(5000,
1910 qMax(32, desiredCacheSize)));
1915 m_ioHandler->m_writeThreadMutex->unlock();
1918 ASSERT(m_buffersToWrite->isEmpty());
1919 delete m_buffersToWrite;
1920 m_buffersToWrite = NULL;
1929 void CubeIoHandler::BufferToChunkWriter::run() {
1949 foreach (
Buffer * bufferToWrite, *m_buffersToWrite) {
1950 m_ioHandler->synchronousWrite(*bufferToWrite);
1951 delete bufferToWrite;
1954 m_buffersToWrite->clear();
1955 m_ioHandler->m_dataFile->flush();