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