File indexing completed on 2025-01-05 04:12:47
0001 /*************************************************************************** 0002 * * 0003 * copyright : (C) 2007 The University of Toronto * 0004 * netterfield@astro.utoronto.ca * 0005 * copyright : (C) 2005 by University of British Columbia 0006 * dscott@phas.ubc.ca * 0007 * * 0008 * This program is free software; you can redistribute it and/or modify * 0009 * it under the terms of the GNU General Public License as published by * 0010 * the Free Software Foundation; either version 2 of the License, or * 0011 * (at your option) any later version. * 0012 * * 0013 ***************************************************************************/ 0014 0015 #include "image.h" 0016 #include "dialoglauncher.h" 0017 #include "datacollection.h" 0018 #include "debug.h" 0019 #include "math_kst.h" 0020 #include "objectstore.h" 0021 #include "plottickcalculator.h" 0022 #include "relationscriptinterface.h" 0023 0024 0025 #include <QImage> 0026 #include <QPainter> 0027 #include <QXmlStreamWriter> 0028 0029 #include <math.h> 0030 0031 //#define BENCHMARK 0032 0033 using namespace std; 0034 0035 namespace Kst { 0036 0037 const QString Image::staticTypeString = "Image"; 0038 const QString Image::staticTypeTag = "image"; 0039 0040 static const QLatin1String& THEMATRIX = QLatin1String("THEMATRIX"); 0041 0042 Image::Image(ObjectStore *store) : Relation(store) { 0043 _typeString = staticTypeString; 0044 _type = "Image"; 0045 _initializeShortName(); 0046 0047 _hasContourMap = false; 0048 _hasColorMap = true; 0049 setColorDefaults(); 0050 setContourDefaults(); 0051 0052 } 0053 0054 0055 Image::~Image() { 0056 } 0057 0058 void Image::_initializeShortName() { 0059 _shortName = 'I'+QString::number(_imagenum); 0060 if (_imagenum>max_imagenum) 0061 max_imagenum = _imagenum; 0062 _imagenum++; 0063 } 0064 0065 ScriptInterface* Image::createScriptInterface() { 0066 return new ImageSI(this); 0067 } 0068 0069 void Image::save(QXmlStreamWriter &s) { 0070 s.writeStartElement(staticTypeTag); 0071 if (_inputMatrices.contains(THEMATRIX)) { 0072 s.writeAttribute("matrix", _inputMatrices[THEMATRIX]->Name()); 0073 } 0074 0075 if (_pal.colorCount()>0) { 0076 s.writeAttribute("palettename", _pal.paletteName()); 0077 } 0078 0079 s.writeAttribute("hascolormap", QVariant(_hasColorMap).toString()); 0080 s.writeAttribute("lowerthreshold", QString::number(_zLower)); 0081 s.writeAttribute("upperthreshold", QString::number(_zUpper)); 0082 0083 s.writeAttribute("hascontourmap", QVariant(_hasContourMap).toString()); 0084 s.writeAttribute("numcontourlines", QString::number(_numContourLines)); 0085 s.writeAttribute("contourweight", QString::number(_contourWeight)); 0086 s.writeAttribute("contourcolor", _contourColor.name()); 0087 0088 s.writeAttribute("autothreshold", QVariant(_autoThreshold).toString()); 0089 saveNameInfo(s, IMAGENUM); 0090 s.writeEndElement(); 0091 } 0092 0093 0094 void Image::internalUpdate() { 0095 Q_ASSERT(myLockStatus() == KstRWLock::WRITELOCKED); 0096 0097 writeLockInputsAndOutputs(); 0098 0099 if (_inputMatrices.contains(THEMATRIX)) { 0100 0101 MatrixPtr mp = _inputMatrices[THEMATRIX]; 0102 0103 // stats 0104 NS = mp->sampleCount(); 0105 MinX = mp->minX(); 0106 int xNumSteps = mp->xNumSteps(); 0107 double xStepSize = mp->xStepSize(); 0108 MaxX = xNumSteps*xStepSize + MinX; 0109 MinY = mp->minY(); 0110 int yNumSteps = mp->yNumSteps(); 0111 double yStepSize = mp->yStepSize(); 0112 MaxY = yNumSteps*yStepSize + MinY; 0113 _ns_maxx = MaxX; 0114 _ns_minx = MinX; 0115 _ns_maxy = MaxY; 0116 _ns_miny = MinY; 0117 MinPosY = MinY > 0 ? MinY : yStepSize*0.5; 0118 MinPosX = MinX > 0 ? MinX : xStepSize*0.5; 0119 0120 0121 //recalculate the thresholds if necessary 0122 if (_autoThreshold) { 0123 _zLower = mp->minValue(); 0124 _zUpper = mp->maxValue(); 0125 } 0126 0127 //update the contour lines 0128 if (hasContourMap()) { 0129 double min = mp->minValue(), max = mp->maxValue(); 0130 double contourStep = (max - min) / (double)(_numContourLines + 1); 0131 if (contourStep > 0) { 0132 _contourLines.clear(); 0133 for (int i = 0; i < _numContourLines; i++) { 0134 _contourLines.append(min + (i+1) * contourStep); 0135 } 0136 } 0137 } 0138 0139 _redrawRequired = true; 0140 } 0141 0142 unlockInputsAndOutputs(); 0143 return; 0144 } 0145 0146 0147 QString Image::propertyString() const { 0148 if (_inputMatrices.contains(THEMATRIX)) { 0149 return tr("Image of %1" ).arg(_inputMatrices[THEMATRIX]->Name()); 0150 } else { 0151 return QString(); 0152 } 0153 } 0154 0155 //FIXME: Inline and optimize! 0156 QColor Image::getMappedColor(double z) { 0157 int index; 0158 if (_zUpper - _zLower != 0) { 0159 index = (int)(((z - _zLower) * (_pal.colorCount() - 1)) / (_zUpper - _zLower)); 0160 } else { 0161 index = 0; 0162 } 0163 return _pal.color(index); 0164 } 0165 0166 0167 void Image::setPalette(const QString &palname) { 0168 _pal.changePaletteName(palname); 0169 } 0170 0171 0172 void Image::showNewDialog() { 0173 DialogLauncher::self()->showImageDialog(); 0174 } 0175 0176 0177 void Image::showEditDialog() { 0178 DialogLauncher::self()->showImageDialog(this); 0179 } 0180 0181 0182 void Image::setUpperThreshold(double z) { 0183 _zUpper = z; 0184 } 0185 0186 0187 void Image::setLowerThreshold(double z) { 0188 _zLower = z; 0189 } 0190 0191 void Image::setThresholdToSpikeInsensitive(double per) { 0192 if (per==0) { 0193 setAutoThreshold(true); 0194 } else { 0195 matrix()->writeLock(); 0196 matrix()->calcNoSpikeRange(per); 0197 matrix()->unlock(); 0198 setLowerThreshold(matrix()->minValueNoSpike()); 0199 setUpperThreshold(matrix()->maxValueNoSpike()); 0200 setAutoThreshold(false); 0201 } 0202 } 0203 0204 0205 void Image::setMatrix(MatrixPtr in_matrix) { 0206 if (in_matrix) { 0207 _inputMatrices[THEMATRIX] = in_matrix; 0208 } 0209 } 0210 0211 0212 void Image::changeToColorOnly(MatrixPtr in_matrix, double lowerZ, 0213 double upperZ, bool autoThreshold, const QString &paletteName) { 0214 0215 _inputMatrices[THEMATRIX] = in_matrix; 0216 0217 _zLower = lowerZ; 0218 _zUpper = upperZ; 0219 _autoThreshold = autoThreshold; 0220 if (_pal.paletteName() != paletteName) { 0221 _pal.changePaletteName(paletteName); 0222 } 0223 _hasColorMap = true; 0224 _hasContourMap = false; 0225 } 0226 0227 0228 void Image::changeToContourOnly(MatrixPtr in_matrix, int numContours, 0229 const QColor& contourColor, int contourWeight) { 0230 0231 _inputMatrices[THEMATRIX] = in_matrix; 0232 _numContourLines = numContours; 0233 _contourWeight = contourWeight; 0234 _contourColor = contourColor; 0235 _hasColorMap = false; 0236 _hasContourMap = true; 0237 0238 } 0239 0240 0241 void Image::changeToColorAndContour(MatrixPtr in_matrix, 0242 double lowerZ, double upperZ, bool autoThreshold, const QString &paletteName, 0243 int numContours, const QColor& contourColor, int contourWeight) { 0244 0245 _inputMatrices[THEMATRIX] = in_matrix; 0246 0247 _zLower = lowerZ; 0248 _zUpper = upperZ; 0249 _autoThreshold = autoThreshold; 0250 if (_pal.paletteName() != paletteName) { 0251 _pal.changePaletteName(paletteName); 0252 } 0253 _numContourLines = numContours; 0254 _contourWeight = contourWeight; 0255 _contourColor = contourColor; 0256 _hasColorMap = true; 0257 _hasContourMap = true; 0258 0259 } 0260 0261 0262 void Image::matrixDimensions(double &x, double &y, double &width, double &height) { 0263 if (_inputMatrices.contains(THEMATRIX)) { 0264 MatrixPtr mp = _inputMatrices[THEMATRIX]; 0265 if (_inputMatrices.contains(THEMATRIX)) { 0266 x = mp->minX(); 0267 y = mp->minY(); 0268 width = mp->xNumSteps() * mp->xStepSize(); 0269 height = mp->yNumSteps() * mp->yStepSize(); 0270 } else { 0271 x = y = width = height = 0; 0272 } 0273 } else { 0274 x = y = width = height = 0; 0275 } 0276 } 0277 0278 0279 //this should check for duplicates 0280 bool Image::addContourLine(double line) { 0281 _contourLines.append(line); 0282 return true; 0283 } 0284 0285 0286 bool Image::removeContourLine(double line) { 0287 return _contourLines.removeAll(line); 0288 } 0289 0290 0291 void Image::clearContourLines() { 0292 _contourLines.clear(); 0293 } 0294 0295 0296 bool Image::getNearestZ(double x, double y, double& z, QPointF &matchedPoint) { 0297 bool ok; 0298 z = _inputMatrices[THEMATRIX]->value(x, y, matchedPoint, &ok); 0299 return ok; 0300 } 0301 0302 0303 QString Image::paletteName() const { 0304 return _pal.paletteName(); 0305 } 0306 0307 0308 void Image::setColorDefaults() { 0309 _zLower = 0; 0310 _zUpper = 100; 0311 } 0312 0313 0314 void Image::setContourDefaults() { 0315 _contourColor = QColor("red"); 0316 _numContourLines = 1; 0317 _contourWeight = 0; 0318 } 0319 0320 0321 void Image::setAutoThreshold(bool yes) { 0322 _autoThreshold = yes; 0323 } 0324 0325 0326 RelationPtr Image::makeDuplicate() const { 0327 ImagePtr image = store()->createObject<Image>(); 0328 0329 if (!_hasContourMap) { 0330 image->changeToColorOnly(_inputMatrices[THEMATRIX], 0331 _zLower, 0332 _zUpper, 0333 _autoThreshold, 0334 _pal.paletteName()); 0335 } else if (!_hasColorMap) { 0336 image->changeToContourOnly(_inputMatrices[THEMATRIX], 0337 _numContourLines, 0338 _contourColor, 0339 _contourWeight); 0340 } else { 0341 image->changeToColorAndContour(_inputMatrices[THEMATRIX], 0342 _zLower, 0343 _zUpper, 0344 _autoThreshold, 0345 _pal.paletteName(), 0346 _numContourLines, 0347 _contourColor, 0348 _contourWeight); 0349 } 0350 0351 if (descriptiveNameIsManual()) { 0352 image->setDescriptiveName(descriptiveName()); 0353 } 0354 image->writeLock(); 0355 image->registerChange(); 0356 image->unlock(); 0357 0358 return RelationPtr(image); 0359 0360 } 0361 0362 MatrixPtr Image::matrix() const { 0363 if (_inputMatrices.contains(THEMATRIX)) { 0364 return _inputMatrices[THEMATRIX]; 0365 } else { 0366 return NULL; 0367 } 0368 } 0369 0370 bool Image::invertXHint() const { 0371 if (_inputMatrices.contains(THEMATRIX)) { 0372 return _inputMatrices[THEMATRIX]->invertXHint(); 0373 } else { 0374 return false; 0375 } 0376 } 0377 0378 bool Image::invertYHint() const { 0379 if (_inputMatrices.contains(THEMATRIX)) { 0380 return _inputMatrices[THEMATRIX]->invertYHint(); 0381 } else { 0382 return false; 0383 } 0384 } 0385 0386 0387 LabelInfo Image::xLabelInfo() const { 0388 if (_inputMatrices.contains(THEMATRIX)) { 0389 return (_inputMatrices[THEMATRIX]->xLabelInfo()); 0390 } else { 0391 return LabelInfo(); 0392 } 0393 } 0394 0395 0396 LabelInfo Image::yLabelInfo() const { 0397 if (_inputMatrices.contains(THEMATRIX)) { 0398 return (_inputMatrices[THEMATRIX]->yLabelInfo()); 0399 } else { 0400 return LabelInfo(); 0401 } 0402 } 0403 0404 0405 LabelInfo Image::titleInfo() const { 0406 LabelInfo label_info; 0407 if (_inputMatrices.contains(THEMATRIX)) { 0408 label_info = _inputMatrices[THEMATRIX]->titleInfo(); 0409 } else { 0410 label_info.name = descriptiveName(); 0411 } 0412 if (!_manualDescriptiveName.isEmpty()) { 0413 label_info.name = _manualDescriptiveName; 0414 } 0415 0416 return label_info; 0417 0418 } 0419 0420 double Image::distanceToPoint(double xpos, double dx, double ypos) const { 0421 Q_UNUSED(dx) 0422 // dx is not relevant for double clicks on images - clicks must be inside the image 0423 if (xpos <= MaxX && xpos >= MinX && ypos <= MaxY && ypos >= MinY) { 0424 return 0; 0425 } 0426 return 1.0E300; 0427 } 0428 0429 0430 void Image::paintObjects(const CurveRenderContext& context) { 0431 QPainter* p = context.painter; 0432 0433 if (hasColorMap()) { 0434 p->drawImage(_imageLocation, _image); 0435 } 0436 0437 if (hasContourMap()) { 0438 QColor lineColor = contourColor(); 0439 0440 foreach(const CoutourLineDetails& lineDetails, _lines) { 0441 p->setPen(QPen(lineColor, lineDetails._lineWidth, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin)); 0442 p->drawLine(lineDetails._line); 0443 } 0444 } 0445 } 0446 0447 void Image::updatePaintObjects(const CurveRenderContext& context) { 0448 double Lx = context.Lx, Hx = context.Hx, Ly = context.Ly, Hy = context.Hy; 0449 double m_X = context.m_X, m_Y = context.m_Y, b_X = context.b_X, b_Y = context.b_Y; 0450 double x_max = context.x_max, y_max = context.y_max, x_min = context.x_min, y_min = context.y_min; 0451 bool xLog = context.xLog, yLog = context.yLog; 0452 double xLogBase = context.xLogBase; 0453 double yLogBase = context.yLogBase; 0454 0455 double x, y, width, height; 0456 double img_Lx_pix = 0, img_Ly_pix = 0, img_Hx_pix = 0, img_Hy_pix = 0; 0457 0458 #ifdef BENCHMARK 0459 QTime bench_time, benchtmp; 0460 int b_1 = 0, b_2 = 0; 0461 bench_time.start(); 0462 benchtmp.start(); 0463 int numberOfLinesDrawn = 0; 0464 #endif 0465 0466 ImagePtr image = this; 0467 0468 _image = QImage(); 0469 _lines.clear(); 0470 0471 if (_inputMatrices.contains(THEMATRIX)) { // don't paint if we have no matrix 0472 image->matrixDimensions(x, y, width, height); 0473 0474 // figure out where the image will be on the plot 0475 if (xLog) { 0476 x_min = pow(xLogBase, x_min); 0477 x_max = pow(xLogBase, x_max); 0478 } 0479 if (yLog) { 0480 y_min = pow(yLogBase, y_min); 0481 y_max = pow(yLogBase, y_max); 0482 } 0483 0484 // only draw if img is visible 0485 if (!(x > x_max || y > y_max || x + width < x_min || y + height < y_min)) { 0486 if (x < x_min) { 0487 img_Lx_pix = Lx; 0488 } else { 0489 if (xLog) { 0490 img_Lx_pix = logXLo(x, xLogBase) * m_X + b_X; 0491 } else { 0492 img_Lx_pix = x * m_X + b_X; 0493 } 0494 } 0495 if (y < y_min) { 0496 img_Hy_pix = Hy; 0497 } else { 0498 if (yLog) { 0499 img_Hy_pix = logYLo(y, yLogBase) * m_Y + b_Y; 0500 } else { 0501 img_Hy_pix = y * m_Y + b_Y; 0502 } 0503 } 0504 if (x + width > x_max) { 0505 img_Hx_pix = Hx; 0506 } else { 0507 if (xLog) { 0508 img_Hx_pix = logXLo(x + width, xLogBase) * m_X + b_X; 0509 } else { 0510 img_Hx_pix = (x + width) * m_X + b_X; 0511 } 0512 } 0513 if (y + height > y_max) { 0514 img_Ly_pix = Ly; 0515 } else { 0516 if (yLog) { 0517 img_Ly_pix = logYLo(y + height, yLogBase) * m_Y + b_Y; 0518 } else { 0519 img_Ly_pix = (y + height) * m_Y + b_Y; 0520 } 0521 } 0522 0523 // color map 0524 QColor thisPixel; 0525 MatrixPtr m = _inputMatrices.value(THEMATRIX); 0526 0527 if (image->hasColorMap()) { 0528 int hXlXDiff = d2i(img_Hx_pix - img_Lx_pix); 0529 int hYlYDiff = d2i(img_Hy_pix - img_Ly_pix - 1); 0530 _image = QImage(hXlXDiff, hYlYDiff, QImage::Format_ARGB32); 0531 //_image.fill(0); 0532 int ih = _image.height(); 0533 int iw = _image.width(); 0534 double m_minX = m->minX(); 0535 double m_minY = m->minY(); 0536 double m_numY = m->yNumSteps(); 0537 double m_stepYr = 1.0/m->yStepSize(); 0538 double m_stepXr = 1.0/m->xStepSize(); 0539 int x_index; 0540 int y_index; 0541 int palCountMinus1 = _pal.colorCount() - 1; 0542 double palCountMin1_OverDZ; 0543 if (_zUpper != _zLower) { 0544 palCountMin1_OverDZ= double(palCountMinus1) / (_zUpper - _zLower); 0545 } else { 0546 palCountMin1_OverDZ= double(palCountMinus1); 0547 } 0548 0549 for (int y = 0; y < ih; ++y) { 0550 bool okY = true; 0551 0552 QRgb *scanLine = (QRgb *)_image.scanLine(y); 0553 double new_y; 0554 if (yLog) { 0555 new_y = pow(yLogBase, (y + 1 + img_Ly_pix - b_Y) / m_Y); 0556 } else { 0557 new_y = (y + 1 + img_Ly_pix - b_Y) / m_Y; 0558 } 0559 y_index = (int)((new_y - m_minY)*m_stepYr); 0560 if (y_index<0 || y_index>=m_numY) { 0561 okY = false; 0562 } 0563 double A = img_Lx_pix - b_X; 0564 double B = 1.0/m_X; 0565 for (int x = 0; x < iw; ++x) { 0566 bool okZ = true; 0567 double new_x; 0568 if (xLog) { 0569 new_x = pow(xLogBase, (x + img_Lx_pix - b_X) / m_X); 0570 } else { 0571 new_x = (x + A)*B; 0572 } 0573 x_index = (int)((new_x - m_minX)*m_stepXr); 0574 double z = m->Z(x_index * m_numY + y_index); 0575 0576 okZ = (isfinite(z)); 0577 0578 if (okZ && okY) { 0579 scanLine[x] = _pal.rgb((int)(((z - _zLower) * palCountMin1_OverDZ))); 0580 } else { 0581 scanLine[x] = Qt::transparent; 0582 } 0583 } 0584 } 0585 _imageLocation = QPoint(d2i(img_Lx_pix), d2i(img_Ly_pix + 1)); 0586 } 0587 #ifdef BENCHMARK 0588 b_1 = benchtmp.elapsed(); 0589 #endif 0590 //******************************************************************* 0591 // CONTOURS 0592 //******************************************************************* 0593 #ifndef CONTOUR_STEP 0594 #define CONTOUR_STEP 5 0595 #endif 0596 //draw the contourmap 0597 if (image->hasContourMap()) { 0598 //QColor tempColor = image->contourColor(); 0599 bool variableWeight = image->contourWeight() < 0; 0600 int lineWeight=1; 0601 if (!variableWeight) { 0602 // + 1 because 0 and 1 are the same width 0603 lineWeight = image->contourWeight() + 1; 0604 } 0605 // do the drawing for each contour line 0606 QList<double> lines = image->contourLines(); 0607 QPoint lastPoint; // used to remember the previous point 0608 bool hasPrevBottom = false; 0609 MatrixPtr mp = _inputMatrices[THEMATRIX]; 0610 for (int k = 0; k < lines.count(); ++k) { 0611 double lineK = lines[k]; 0612 if (variableWeight) { 0613 // + 1 because 0 and 1 are the same width 0614 lineWeight = k + 1; 0615 } 0616 int flImgHx = d2i(floor(img_Hx_pix)); 0617 int flImgHy = d2i(floor(img_Hy_pix)); 0618 int ceImgLy = d2i(ceil(img_Ly_pix)); 0619 for (int i = d2i(ceil(img_Lx_pix)); i + CONTOUR_STEP < flImgHx; i += CONTOUR_STEP) { 0620 for (int j = d2i(ceil(img_Ly_pix)); j + CONTOUR_STEP < flImgHy; j += CONTOUR_STEP) { 0621 // look at this group of 4 pixels and get the z values 0622 double zTL, zTR, zBL, zBR; 0623 double new_x_small = (i - b_X) / m_X, new_y_small = (j + 1 - b_Y) / m_Y; 0624 double new_x_large = (i + CONTOUR_STEP - b_X) / m_X, new_y_large = (j+1+CONTOUR_STEP - b_Y) / m_Y; 0625 0626 if (xLog) { 0627 new_x_small = pow(xLogBase, new_x_small); 0628 new_x_large = pow(xLogBase, new_x_large); 0629 } 0630 if (yLog) { 0631 new_y_small = pow(yLogBase, new_y_small); 0632 new_y_large = pow(yLogBase, new_y_large); 0633 } 0634 0635 zTL = mp->value(new_x_small, new_y_small, 0L); 0636 zTR = mp->value(new_x_large, new_y_small, 0L); 0637 zBL = mp->value(new_x_small, new_y_large, 0L); 0638 zBR = mp->value(new_x_large, new_y_large, 0L); 0639 0640 // determine the lines to draw 0641 int numPoints = 0; 0642 bool passTop = false, passBottom = false, passLeft = false, passRight = false; 0643 QPoint topPoint, bottomPoint, leftPoint, rightPoint; 0644 0645 // passes through the top 0646 if (hasPrevBottom) { 0647 topPoint = lastPoint; 0648 ++numPoints; 0649 passTop = true; 0650 } else if (j == ceImgLy && ((lineK < zTR && lineK > zTL) || (lineK < zTL && lineK > zTR))) { 0651 ++numPoints; 0652 passTop = true; 0653 topPoint.setX(int(((lineK - zTL)*CONTOUR_STEP + (zTR - zTL)*i) / (zTR - zTL))); 0654 topPoint.setY(j); 0655 } 0656 hasPrevBottom = false; 0657 0658 // passes through the bottom 0659 if ((lineK < zBR && lineK > zBL) || (lineK < zBL && lineK > zBR)) { 0660 ++numPoints; 0661 passBottom = true; 0662 bottomPoint.setX(int(((lineK - zBL)*CONTOUR_STEP + (zBR - zBL)*i) / (zBR - zBL))); 0663 bottomPoint.setY(j + CONTOUR_STEP); 0664 if (j + 2*CONTOUR_STEP < flImgHy) { 0665 lastPoint = bottomPoint; 0666 hasPrevBottom = true; 0667 } 0668 } 0669 0670 // passes through the left 0671 if ((lineK < zBL && lineK > zTL) || (lineK < zTL && lineK > zBL)) { 0672 ++numPoints; 0673 passLeft = true; 0674 leftPoint.setY(int(((lineK - zTL)*CONTOUR_STEP + (zBL - zTL)*j) / (zBL - zTL))); 0675 leftPoint.setX(i); 0676 } 0677 0678 // passes through the right 0679 if ((lineK < zBR && lineK > zTR) || (lineK < zTR && lineK > zBR)) { 0680 ++numPoints; 0681 passRight = true; 0682 rightPoint.setY(int(((lineK - zTR)*CONTOUR_STEP + (zBR - zTR)*j) / (zBR - zTR))); 0683 rightPoint.setX(i + CONTOUR_STEP); 0684 } 0685 0686 if (numPoints == 4) { 0687 // draw a cross 0688 _lines.append(CoutourLineDetails(QLine(topPoint, bottomPoint), lineWeight)); 0689 _lines.append(CoutourLineDetails(QLine(rightPoint, leftPoint), lineWeight)); 0690 #ifdef BENCHMARK 0691 numberOfLinesDrawn += 2; 0692 #endif 0693 } else if (numPoints == 3) { 0694 // draw a V opening to non-intersecting side 0695 if (!passTop) { 0696 _lines.append(CoutourLineDetails(QLine(leftPoint, bottomPoint), lineWeight)); 0697 _lines.append(CoutourLineDetails(QLine(bottomPoint, rightPoint), lineWeight)); 0698 } else if (!passLeft) { 0699 _lines.append(CoutourLineDetails(QLine(topPoint, rightPoint), lineWeight)); 0700 _lines.append(CoutourLineDetails(QLine(rightPoint, bottomPoint), lineWeight)); 0701 } else if (!passBottom) { 0702 _lines.append(CoutourLineDetails(QLine(leftPoint, topPoint), lineWeight)); 0703 _lines.append(CoutourLineDetails(QLine(topPoint, rightPoint), lineWeight)); 0704 } else { 0705 _lines.append(CoutourLineDetails(QLine(topPoint, leftPoint), lineWeight)); 0706 _lines.append(CoutourLineDetails(QLine(leftPoint, bottomPoint), lineWeight)); 0707 } 0708 #ifdef BENCHMARK 0709 numberOfLinesDrawn += 2; 0710 #endif 0711 } else if (numPoints == 2) { 0712 // two points - connect them 0713 QPoint point1, point2; 0714 bool true1 = false; 0715 0716 if (passTop) { 0717 point1 = topPoint; 0718 true1 = true; 0719 } 0720 if (passBottom) { 0721 if (true1) { 0722 point2 = bottomPoint; 0723 } else { 0724 point1 = bottomPoint; 0725 true1 = true; 0726 } 0727 } 0728 if (passLeft) { 0729 if (true1) { 0730 point2 = leftPoint; 0731 } else { 0732 point1 = leftPoint; 0733 } 0734 } 0735 if (passRight) { 0736 point2 = rightPoint; 0737 } 0738 _lines.append(CoutourLineDetails(QLine(point1, point2), lineWeight)); 0739 #ifdef BENCHMARK 0740 ++numberOfLinesDrawn; 0741 #endif 0742 } 0743 } 0744 } 0745 } 0746 } 0747 } 0748 } 0749 #ifdef BENCHMARK 0750 b_2 = benchtmp.elapsed(); 0751 int i = bench_time.elapsed(); 0752 qDebug() << endl << "Plotting image " << (void *)this << ": " << i << "ms"; 0753 qDebug() << " Without locks: " << b_2 << "ms"; 0754 qDebug() << " Number of lines drawn: " << numberOfLinesDrawn; 0755 if (b_1 > 0) qDebug() << " Color Map: " << b_1 << "ms"; 0756 if (b_2 - b_1 > 0) qDebug() << " Coutour Lines: " << (b_2 - b_1) << "ms" << endl; 0757 #endif 0758 } 0759 0760 0761 void Image::yRange(double xFrom, double xTo, double* yMin, double* yMax) { 0762 if (!yMin || !yMax) { 0763 return; 0764 } 0765 // if x range overlaps with image x range, just return image y range 0766 if ((xFrom <= MinX && xTo >= MinX) || 0767 (xTo >= MaxX && xFrom <= MaxX) || 0768 (xFrom > MinX && xFrom < MaxX) || 0769 (xTo > MinX && xTo < MaxX)) { 0770 *yMin = MinY; 0771 *yMax = MaxY; 0772 return; 0773 } 0774 *yMin = 0; 0775 *yMax = 0; 0776 return; 0777 } 0778 0779 0780 QSize Image::legendSymbolSize(QPainter *p) { 0781 return QSize(p->fontMetrics().height()*7, 2*p->fontMetrics().height()); 0782 } 0783 0784 0785 void Image::paintLegendSymbol(QPainter *p, const QSize &size) { 0786 QRect bound(QPoint(0,0),size); 0787 0788 if (hasColorMap() && (_pal.colorCount()>0)) { 0789 double spacing; 0790 int minor_ticks; 0791 computeMajorTickSpacing(&spacing, &minor_ticks, TicksCoarse, upperThreshold() - lowerThreshold()); 0792 0793 int l = bound.left(), r = bound.right(), t = bound.top(), b = bound.bottom()-p->fontMetrics().height(); 0794 // draw the color palette 0795 p->drawRect(l,t,(r-l),(b-t)); 0796 p->save(); 0797 for (int i = l; i <= r; i++) { 0798 int index = (int)floor(static_cast<double>(((i - l) * (_pal.colorCount() - 1))) / (r - l)); 0799 QColor sliceColor = _pal.color(index).rgb(); 0800 p->setPen(QPen(sliceColor, 1)); 0801 p->drawLine(i, t, i, b); 0802 } 0803 p->restore(); 0804 double min = int(lowerThreshold()/spacing)*spacing; 0805 if (min<lowerThreshold()) { 0806 min += spacing; 0807 } 0808 p->save(); 0809 for (double tick = min; tick < upperThreshold(); tick+=spacing) { 0810 int x = (tick-lowerThreshold())*(r-l)/(upperThreshold()-lowerThreshold())+l; 0811 p->drawLine(x,b,x,b-p->fontMetrics().ascent()/3); 0812 QString tickStr = QString::number(tick); 0813 QRect bound = p->boundingRect(QRect(),Qt::AlignLeft|Qt::AlignBottom, tickStr); 0814 p->drawText(QPoint(x-bound.width()/2, b+p->fontMetrics().ascent()), tickStr); 0815 } 0816 p->restore(); 0817 } else if (hasContourMap()) { 0818 // draw a box with contour color 0819 p->setPen(QPen(_contourColor, 1)); 0820 p->drawRect(bound.left(), bound.top(), bound.width(), bound.height()); 0821 } 0822 } 0823 0824 0825 QString Image::_automaticDescriptiveName() const { 0826 return matrix()->descriptiveName(); 0827 } 0828 0829 0830 QString Image::descriptionTip() const { 0831 QString tip; 0832 tip = tr("Image: %1\n" ).arg(Name()); 0833 if (_hasContourMap) { 0834 tip += " Contour Map"; 0835 } 0836 if (_hasColorMap) { 0837 tip += " Color Map"; 0838 } 0839 tip += matrix()->descriptionTip(); 0840 return tip; 0841 } 0842 0843 } 0844 // vim: ts=2 sw=2 et