4 #include "ViewportBufferAction.h"
5 #include "ViewportBufferStretch.h"
6 #include "ViewportBufferFill.h"
7 #include "ViewportBufferTransform.h"
9 #include <QApplication>
15 #include "CubeDataThread.h"
21 #define round(x) ((x) > 0.0 ? (x) + 0.5 : (x) - 0.5)
39 p_dataThread = cubeData;
45 p_viewport = viewport;
46 p_bufferInitialized =
false;
49 p_initialStretchDone =
false;
50 p_viewportHeight = p_viewport->viewport()->height();
51 p_oldViewportHeight = p_viewport->viewport()->height();
52 p_vertScrollBarPos = p_viewport->verticalScrollBar()->value();
53 p_oldVertScrollBarPos = p_viewport->verticalScrollBar()->value();
55 p_requestedFillArea = 0.0;
56 p_bricksOrdered =
true;
58 connect(
this, SIGNAL(ReadCube(
int,
int,
int,
int,
int,
int,
void *)),
59 p_dataThread, SLOT(ReadCube(
int,
int,
int,
int,
int,
int,
void *)));
61 connect(p_dataThread, SIGNAL(ReadReady(
void *,
int,
const Isis::Brick *)),
62 this, SLOT(DataReady(
void *,
int,
const Isis::Brick *)));
64 connect(
this, SIGNAL(DoneWithData(
int,
const Isis::Brick *)),
65 p_dataThread, SLOT(DoneWithData(
int,
const Isis::Brick *)));
72 ViewportBuffer::~ViewportBuffer() {
73 disconnect(
this, SIGNAL(ReadCube(
int,
int,
int,
int,
int,
int,
void *)),
74 p_dataThread, SLOT(ReadCube(
int,
int,
int,
int,
int,
int,
void *)));
76 disconnect(p_dataThread, SIGNAL(ReadReady(
void *,
int,
const Isis::Brick *)),
77 this, SLOT(DataReady(
void *,
int,
const Isis::Brick *)));
79 disconnect(
this, SIGNAL(DoneWithData(
int,
const Isis::Brick *)),
80 p_dataThread, SLOT(DoneWithData(
int,
const Isis::Brick *)));
85 while(!p_actions->empty()) {
106 void ViewportBuffer::fillBuffer(QRect rect) {
112 rect.intersected(bufferXYRect()),
false);
113 enqueueAction(newFill);
125 void ViewportBuffer::fillBuffer(QRect rect,
const Brick *data) {
130 rect = rect.intersected(bufferXYRect());
142 for(
int x = rect.left(); x <= rect.right(); x ++) {
150 if (samp < data->Sample())
154 if (line < data->Line())
161 int brickIndex = data->
Index((
int)(samp + 0.5), (
int)(line + 0.5),
165 p_buffer.at(yIndex).at(xIndex) = data->
at(0);
167 else if(brickIndex >= data->
size()) {
168 p_buffer.at(yIndex).at(xIndex) = data->
at(data->
size() - 1);
171 if(yIndex < 0 || xIndex < 0 || yIndex >= (
int) p_buffer.size() ||
172 xIndex >= (int) p_buffer.at(yIndex).size()) {
174 "index out of range",
178 p_buffer.at(yIndex).at(xIndex) = data->
at(brickIndex);
185 throw IException(e, IException::Programmer,
"Failed to load brick "
200 void ViewportBuffer::DataReady(
void *requester,
int cubeId,
201 const Brick *brick) {
202 if(
this != requester)
205 if(p_actions->empty()) {
211 if(curAction->
getActionType() != ViewportBufferAction::fill ||
218 const QRect *rect = fill->
getRect();
226 bool brickOrderCorrection = p_bricksOrdered;
227 if (curBrickLine != nextBrickLine &&
228 nextBrickLine == (
int) (brick->
Line() + 0.5)) {
230 p_bricksOrdered =
false;
233 p_bricksOrdered =
true;
239 for(
int x = rect->left(); x <= rect->right(); x++) {
248 int brickIndex = (int)(samp + 0.5) - brick->
Sample();
251 p_buffer.at(yIndex).at(xIndex) = brick->
at(0);
253 else if(brickIndex >= brick->
size()) {
254 p_buffer.at(yIndex).at(xIndex) = brick->
at(brick->
size() - 1);
257 if(yIndex < 0 || xIndex < 0 || yIndex >= (
int) p_buffer.size() ||
258 xIndex >= (int) p_buffer.at(yIndex).size()) {
259 IString msg =
"An index out of range error was detected. ";
262 msg +=
"The Y-Index [" +
IString(yIndex) +
"] is less than 0";
264 msg +=
"The X-Index [" +
IString(xIndex) +
"] is less than 0";
265 else if(yIndex > (
int)p_buffer.size())
266 msg +=
"The Y-Index [" +
IString(yIndex) +
"] is greater than the "
267 "Y-Size of [" +
IString((
int)p_buffer.size()) +
"]";
268 else if(xIndex > (
int)p_buffer.at(yIndex).size())
269 msg +=
"The X-Index [" +
IString(xIndex) +
" is greater than the "
270 "X-Size of [" +
IString((
int) p_buffer.at(yIndex).size()) +
"]";
275 p_buffer.at(yIndex).at(xIndex) = brick->
at(brickIndex);
283 if (p_bricksOrdered) {
284 requestCubeLine(fill);
287 if (brickOrderCorrection) {
288 requestCubeLine(fill);
289 requestCubeLine(fill);
296 p_actions->dequeue();
300 emit DoneWithData(cubeId, brick);
315 p_requestedFillArea += fillRect->width() * fillRect->height();
318 if(p_actions->empty()) {
319 p_viewport->enableProgress();
322 p_actions->enqueue(action);
334 const vector<double> &ViewportBuffer::getLine(
int line) {
335 if(!p_bufferInitialized || !p_enabled) {
339 if(line < 0 || line >= (
int)p_buffer.size()) {
341 "Invalid call to getLine",
345 return p_buffer.at(line);
356 QRect ViewportBuffer::getXYBoundingRect() {
357 int startx, starty, endx, endy;
358 p_viewport->cubeToViewport(0.5, 0.5, startx, starty);
362 double startSamp, startLine;
363 p_viewport->viewportToCube(startx, starty, startSamp, startLine);
371 double rightmost = p_viewport->cubeSamples() + 0.5;
372 double bottommost = p_viewport->cubeLines() + 0.5;
374 p_viewport->cubeToViewport(rightmost, bottommost, endx, endy);
376 if(endx < 0 || endy < 0)
379 double endSamp = -1, endLine = -1;
380 p_viewport->viewportToCube(endx, endy, endSamp, endLine);
382 if(endSamp > rightmost)
385 if(endLine > bottommost)
397 if(endx >= p_viewport->viewport()->width()) {
398 endx = p_viewport->viewport()->width() - 1;
401 if(endy >= p_viewport->viewport()->height()) {
402 endy = p_viewport->viewport()->height() - 1;
405 return QRect(startx, starty, endx - startx + 1, endy - starty + 1);
415 bool ViewportBuffer::hasEntireCube() {
416 double sampTolerance = 0.05 * p_viewport->cubeSamples();
417 double lineTolerance = 0.05 * p_viewport->cubeLines();
421 hasCube &= !working();
422 hasCube &= p_sampLineBoundingRect[rectLeft] <= (1 + sampTolerance);
423 hasCube &= p_sampLineBoundingRect[rectTop] <= (1 + lineTolerance);
424 hasCube &= p_sampLineBoundingRect[rectRight] >= (p_viewport->cubeSamples() -
426 hasCube &= p_sampLineBoundingRect[rectBottom] >= (p_viewport->cubeLines() -
440 QRect xyRect = getXYBoundingRect();
441 double ssamp, esamp, sline, eline;
442 p_viewport->viewportToCube(xyRect.left(), xyRect.top(), ssamp, sline);
443 p_viewport->viewportToCube(xyRect.right(), xyRect.bottom(), esamp, eline);
447 boundingRect.insert(rectLeft, ssamp);
448 boundingRect.insert(rectTop, sline);
449 boundingRect.insert(rectRight, esamp);
450 boundingRect.insert(rectBottom, eline);
460 void ViewportBuffer::updateBoundingRects() {
461 p_oldXYBoundingRect = p_XYBoundingRect;
462 p_XYBoundingRect = getXYBoundingRect();
464 p_oldSampLineBoundingRect = p_sampLineBoundingRect;
465 p_sampLineBoundingRect = getSampLineBoundingRect();
467 p_oldViewportHeight = p_viewportHeight;
468 p_viewportHeight = p_viewport->viewport()->height();
470 p_oldVertScrollBarPos = p_vertScrollBarPos;
472 p_vertScrollBarPos = p_viewport->verticalScrollBar()->value() + 1;
489 QRect someRect,
bool useOldY) {
490 QScrollBar *hsb = p_viewport->horizontalScrollBar();
491 int xConstCoef = hsb->value();
492 xConstCoef -= p_viewport->viewport()->width() / 2;
497 if(!someRect.isValid()) {
501 double xScale = p_viewport->scale();
506 yConstCoef = (p_vertScrollBarPos) - p_viewportHeight / 2 - 1;
508 yConstCoef = (p_oldVertScrollBarPos) - p_oldViewportHeight / 2 - 1;
510 double yScale = xScale;
515 topLeft = p_XYBoundingRect.topLeft();
518 topLeft = QPoint(p_XYBoundingRect.left(), p_oldXYBoundingRect.top());
522 xScale, yConstCoef, yScale, topLeft);
539 QRect &rect = *fill->
getRect();
545 int brickWidth = (int)(ceil(esamp) - floor(ssamp)) + 1;
551 int roundedSamp = (int)(ssamp + 0.5);
552 int roundedLine = (int)(line + 0.5);
554 emit ReadCube(p_cubeId, roundedSamp, roundedLine, roundedSamp + brickWidth,
555 roundedLine, p_band,
this);
571 void ViewportBuffer::doQueuedActions() {
572 bool doNextAction =
false;
578 if(!reinitializeActionExists() && !actionsPreserveData() &&
579 p_initialStretchDone) {
585 p_requestedFillArea = 0.0;
588 if(!p_actions->empty()) {
589 curAction = p_actions->head();
590 doNextAction = !curAction->
started();
593 while(doNextAction) {
594 if(curAction->
getActionType() == ViewportBufferAction::transform) {
597 else if(curAction->
getActionType() == ViewportBufferAction::fill) {
602 p_initialStretchDone =
true;
605 doNextAction = !p_actions->empty();
608 curAction = p_actions->head();
609 doNextAction = !curAction->
started();
613 if(p_actions->empty()) {
615 p_viewport->bufferUpdated(bufferXYRect());
625 double ViewportBuffer::currentProgress() {
628 if(p_requestedFillArea <= 0.0)
631 return 1.0 - totalUnfilledArea() / p_requestedFillArea;
641 double ViewportBuffer::totalUnfilledArea() {
642 double totalFillArea = 0.0;
646 for(
int actionIndex = 0; actionIndex < p_actions->size(); actionIndex ++) {
652 QRect unfilledRect(*fill->
getRect());
654 totalFillArea += unfilledRect.width() * unfilledRect.height();
658 return totalFillArea;
666 bool ViewportBuffer::actionsPreserveData() {
670 QRect currentBufferRect(bufferXYRect());
672 int bufferWidth = currentBufferRect.width();
673 int bufferHeight = currentBufferRect.height();
677 for(
int actionIndex = 0; actionIndex < p_actions->size(); actionIndex ++) {
680 if(action->
getActionType() == ViewportBufferAction::transform) {
688 if(abs(totalXShift) >= bufferWidth)
690 if(abs(totalYShift) >= bufferHeight)
705 if(abs(totalXShift) >= bufferWidth)
707 if(abs(totalYShift) >= bufferHeight)
722 bool ViewportBuffer::reinitializeActionExists() {
723 QRect currentBufferRect(bufferXYRect());
725 if(currentBufferRect.width() == 0 || currentBufferRect.height() == 0) {
729 for(
int actionIndex = 0; actionIndex < p_actions->size(); actionIndex ++) {
732 if(action->
getActionType() == ViewportBufferAction::transform) {
751 bool ViewportBuffer::working() {
752 return !p_actions->empty() || !p_bufferInitialized || !p_enabled;
777 p_actions->dequeue();
793 requestCubeLine(action);
796 requestCubeLine(action);
809 p_actions->dequeue();
811 p_viewport->restretch(
this);
821 void ViewportBuffer::resizeBuffer(
unsigned int width,
unsigned int height) {
822 p_buffer.resize(height);
824 for(
unsigned int i = 0; i < p_buffer.size(); i++) {
825 p_buffer[i].resize(width,
Null);
837 void ViewportBuffer::shiftBuffer(
int deltaX,
int deltaY) {
839 for(
int i = p_buffer.size() - 1; i >= deltaY; i--) {
840 p_buffer[i] = p_buffer[i - deltaY];
844 for(
unsigned int x = 0; x < p_buffer[i - deltaY].size(); x++) {
845 p_buffer[i - deltaY][x] =
Null;
850 for(
int j = p_buffer[i].size() - 1; j >= deltaX; j--) {
851 p_buffer[i][j] = p_buffer[i][j - deltaX];
852 p_buffer[i][j - deltaX] =
Null;
855 else if(deltaX < 0) {
856 for(
int j = 0; j < (int)p_buffer[i].size() + deltaX; j++) {
857 p_buffer[i][j] = p_buffer[i][j - deltaX];
858 p_buffer[i][j - deltaX] =
Null;
863 else if(deltaY < 0) {
864 for(
int i = 0; i < (int)p_buffer.size() + deltaY; i++) {
865 p_buffer[i] = p_buffer[i - deltaY];
868 for(
unsigned int x = 0; x < p_buffer[i - deltaY].size(); x++) {
869 p_buffer[i - deltaY][x] =
Null;
873 for(
int j = p_buffer[i].size() - 1; j >= deltaX; j--) {
874 p_buffer[i][j] = p_buffer[i][j - deltaX];
875 p_buffer[i][j - deltaX] =
Null;
878 else if(deltaX < 0) {
879 for(
int j = 0; j < (int)p_buffer[i].size() + deltaX; j++) {
880 p_buffer[i][j] = p_buffer[i][j - deltaX];
881 p_buffer[i][j - deltaX] =
Null;
893 void ViewportBuffer::resizedViewport() {
894 updateBoundingRects();
896 if(!p_bufferInitialized || !p_enabled)
901 if(!p_XYBoundingRect.isValid())
904 if(!p_oldXYBoundingRect.isValid()) {
910 double deltaLeftSamples = p_sampLineBoundingRect[rectLeft] -
911 p_oldSampLineBoundingRect[rectLeft];
913 int deltaLeftPixels = (int)round(deltaLeftSamples * p_viewport->scale());
915 double deltaRightSamples = p_sampLineBoundingRect[rectRight] -
916 p_oldSampLineBoundingRect[rectRight];
917 int deltaRightPixels = (int)round(deltaRightSamples * p_viewport->scale());
919 double deltaTopSamples = p_sampLineBoundingRect[rectTop] -
920 p_oldSampLineBoundingRect[rectTop];
921 int deltaTopPixels = (int)round(deltaTopSamples * p_viewport->scale());
923 double deltaBottomSamples = p_sampLineBoundingRect[rectBottom] -
924 p_oldSampLineBoundingRect[rectBottom];
925 int deltaBottomPixels = (int)round(deltaBottomSamples *
926 p_viewport->scale());
929 int deltaW = - deltaLeftPixels + deltaRightPixels;
932 int deltaH = - deltaTopPixels + deltaBottomPixels;
935 if(p_XYBoundingRect.width() != p_oldXYBoundingRect.width()) {
941 transform->
setResize(p_XYBoundingRect.width(),
942 p_oldXYBoundingRect.height());
945 enqueueAction(transform);
948 QPoint topLeftOfLeftRect(p_XYBoundingRect.left(),
949 p_oldXYBoundingRect.top());
951 QPoint bottomRightOfLeftRect(p_XYBoundingRect.left() - deltaLeftPixels,
952 p_oldXYBoundingRect.bottom());
954 QRect leftRect(topLeftOfLeftRect, bottomRightOfLeftRect);
958 enqueueAction(leftFill);
961 QPoint topLeftOfRightRect(p_XYBoundingRect.right() - deltaRightPixels,
962 p_oldXYBoundingRect.top());
964 QPoint bottomRightOfRightRect(p_XYBoundingRect.right(),
965 p_oldXYBoundingRect.bottom());
967 QRect rightRect(topLeftOfRightRect, bottomRightOfRightRect);
971 enqueueAction(rightFill);
974 else if(deltaW < 0) {
977 transform->
setResize(p_XYBoundingRect.width(),
978 p_oldXYBoundingRect.height());
980 enqueueAction(transform);
985 if(p_XYBoundingRect.height() != p_oldXYBoundingRect.height()) {
990 transform->
setResize(p_XYBoundingRect.width(),
991 p_XYBoundingRect.height());
994 enqueueAction(transform);
996 QPoint bottomRightOfTopSide(p_XYBoundingRect.right(),
997 p_XYBoundingRect.top() - deltaTopPixels);
999 QRect topSideToFill(p_XYBoundingRect.topLeft(), bottomRightOfTopSide);
1002 QPoint topLeftOfbottomSide(p_XYBoundingRect.left(),
1003 p_XYBoundingRect.bottom() -
1006 QRect bottomSideToFill(topLeftOfbottomSide,
1007 p_XYBoundingRect.bottomRight());
1011 enqueueAction(topFill);
1014 createViewportBufferFill(bottomSideToFill,
false);
1015 enqueueAction(bottomFill);
1018 else if(deltaH < 0) {
1022 transform->
setResize(p_XYBoundingRect.width(),
1023 p_oldXYBoundingRect.height());
1025 enqueueAction(transform);
1040 void ViewportBuffer::pan(
int deltaX,
int deltaY) {
1041 updateBoundingRects();
1043 if(!p_bufferInitialized || !p_enabled) {
1048 if(p_sampLineBoundingRect == p_oldSampLineBoundingRect) {
1056 double deltaLeftSamples = p_sampLineBoundingRect[rectLeft] -
1057 p_oldSampLineBoundingRect[rectLeft];
1058 int deltaLeftPixels = (int)round(deltaLeftSamples * p_viewport->scale());
1060 double deltaTopLines = p_sampLineBoundingRect[rectTop] -
1061 p_oldSampLineBoundingRect[rectTop];
1062 int deltaTopPixels = (int)round(deltaTopLines * p_viewport->scale());
1066 if(abs(deltaY) >= p_XYBoundingRect.height() ||
1067 abs(deltaX) >= p_XYBoundingRect.width()) {
1073 if(p_sampLineBoundingRect[rectLeft] != p_oldSampLineBoundingRect[rectLeft]) {
1078 transform->
setResize(p_XYBoundingRect.width(),
1079 p_oldXYBoundingRect.height());
1083 enqueueAction(transform);
1085 QPoint topLeftOfRefill(p_XYBoundingRect.left(),
1086 p_oldXYBoundingRect.top());
1088 QPoint bottomRightOfRefill(p_XYBoundingRect.left() + deltaX,
1089 p_oldXYBoundingRect.bottom());
1090 QRect fillArea(topLeftOfRefill, bottomRightOfRefill);
1093 enqueueAction(fill);
1096 else if(deltaX < 0) {
1100 transform->
setResize(p_XYBoundingRect.width(),
1101 p_oldXYBoundingRect.height());
1103 enqueueAction(transform);
1106 if(p_sampLineBoundingRect[rectRight] !=
1107 p_oldSampLineBoundingRect[rectRight]) {
1108 QPoint topLeftOfRefill(p_XYBoundingRect.right() + deltaX,
1109 p_oldXYBoundingRect.top());
1110 QPoint bottomRightOfRefill(p_XYBoundingRect.right(),
1111 p_oldXYBoundingRect.bottom());
1113 QRect refillArea(topLeftOfRefill, bottomRightOfRefill);
1117 enqueueAction(fill);
1125 transform->
setResize(p_XYBoundingRect.width(),
1126 p_oldXYBoundingRect.height());
1127 enqueueAction(transform);
1130 QPoint topLeftOfFillArea(p_XYBoundingRect.right() + deltaX,
1131 p_oldXYBoundingRect.top());
1133 QPoint bottomRightOfFillArea(p_XYBoundingRect.right(),
1134 p_oldXYBoundingRect.bottom());
1136 QRect fillArea(topLeftOfFillArea, bottomRightOfFillArea);
1139 enqueueAction(fill);
1144 if(p_sampLineBoundingRect[rectTop] != p_oldSampLineBoundingRect[rectTop]) {
1149 transform->
setResize(p_XYBoundingRect.width(),
1150 p_XYBoundingRect.height());
1152 enqueueAction(transform);
1154 QPoint topLeftOfFillArea(p_XYBoundingRect.left(),
1155 p_XYBoundingRect.top());
1156 QPoint bottomRightOfFillArea(p_XYBoundingRect.right(),
1157 p_XYBoundingRect.top() + deltaY);
1158 QRect fillArea(topLeftOfFillArea, bottomRightOfFillArea);
1160 enqueueAction(fill);
1163 else if(deltaY < 0) {
1166 transform->
setResize(p_XYBoundingRect.width(),
1167 p_XYBoundingRect.height());
1169 enqueueAction(transform);
1172 if(p_sampLineBoundingRect[rectBottom] !=
1173 p_oldSampLineBoundingRect[rectBottom]) {
1174 QPoint topLeftOfFillArea(p_XYBoundingRect.left(),
1175 p_oldXYBoundingRect.bottom() + deltaY);
1176 QPoint bottomRightOfFillArea(p_XYBoundingRect.right(),
1177 p_XYBoundingRect.bottom());
1178 QRect fillArea(topLeftOfFillArea, bottomRightOfFillArea);
1180 enqueueAction(fill);
1188 transform->
setResize(p_XYBoundingRect.width(),
1189 p_XYBoundingRect.height());
1190 enqueueAction(transform);
1193 QPoint topLeftOfFillArea(p_XYBoundingRect.left(),
1194 p_XYBoundingRect.bottom() + deltaY);
1195 QPoint bottomRightOfFillArea(p_XYBoundingRect.right(),
1196 p_XYBoundingRect.bottom());
1197 QRect fillArea(topLeftOfFillArea, bottomRightOfFillArea);
1199 enqueueAction(fill);
1212 void ViewportBuffer::addStretchAction() {
1213 for(
int i = 0; i < p_actions->size(); i++) {
1214 if((*p_actions)[i]->getActionType() == ViewportBufferAction::stretch) {
1215 p_actions->removeAt(i);
1233 void ViewportBuffer::emptyBuffer(
bool force) {
1236 p_bufferInitialized =
false;
1249 QRect ViewportBuffer::bufferXYRect() {
1250 QRect rect = p_XYBoundingRect;
1252 if(!rect.height() || !p_buffer.size())
1255 if(rect.height() > (int) p_buffer.size())
1256 rect.setBottom(rect.top() + p_buffer.size() - 1);
1258 if(rect.width() > (int) p_buffer[0].size())
1259 rect.setRight(rect.left() + p_buffer[0].size() - 1);
1273 void ViewportBuffer::scaleChanged() {
1278 updateBoundingRects();
1283 e, IException::Programmer,
"Unable to change scale.",
_FILEINFO_);
1294 void ViewportBuffer::enable(
bool enabled) {
1295 bool wasEnabled = p_enabled;
1297 p_enabled = enabled;
1299 if(!wasEnabled && p_enabled) {
1300 updateBoundingRects();
1311 void ViewportBuffer::setBand(
int band) {
1316 updateBoundingRects();
1332 void ViewportBuffer::reinitialize() {
1337 if(working() && p_initialStretchDone) {
1342 for(
int i = p_actions->size() - 1; i > 0; i--) {
1343 delete(*p_actions)[i];
1344 p_actions->pop_back();
1349 if(curAction->
getActionType() == ViewportBufferAction::fill) {
1354 p_requestedFillArea = fill->
getRect()->height() *
1361 p_requestedFillArea = 0.0;
1366 p_bufferInitialized =
true;
1370 enqueueAction(reset);
1372 if (p_XYBoundingRect.isValid()) {
1374 transform->
setResize(p_XYBoundingRect.width(), p_XYBoundingRect.height());
1375 enqueueAction(transform);
1378 enqueueAction(fill);
1385 "Unable to resize and fill buffer.",